From patchwork Wed Feb 3 13:26:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 8203121 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 75D409F38B for ; Wed, 3 Feb 2016 13:31:22 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7111D20253 for ; Wed, 3 Feb 2016 13:31:20 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6549B201F2 for ; Wed, 3 Feb 2016 13:31:19 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aQxV7-0001Bf-Tg; Wed, 03 Feb 2016 13:29:41 +0000 Received: from eusmtp01.atmel.com ([212.144.249.243]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aQxUd-0008Qs-HB; Wed, 03 Feb 2016 13:29:22 +0000 Received: from tenerife.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.31) with Microsoft SMTP Server id 14.3.235.1; Wed, 3 Feb 2016 14:28:37 +0100 From: Cyrille Pitchen To: , Subject: [PATCH v3 05/14] mtd: spi-nor: fix support of Winbond memories Date: Wed, 3 Feb 2016 14:26:50 +0100 Message-ID: X-Mailer: git-send-email 1.8.2.2 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160203_052912_653330_21DA4D21 X-CRM114-Status: GOOD ( 15.73 ) X-Spam-Score: -4.6 (----) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: marex@denx.de, boris.brezillon@free-electrons.com, vigneshr@ti.com, pawel.moll@arm.com, devicetree@vger.kernel.org, ijc+devicetree@hellion.org.uk, nicolas.ferre@atmel.com, linux-kernel@vger.kernel.org, robh+dt@kernel.org, galak@codeaurora.org, mark.rutland@arm.com, Cyrille Pitchen , linux-arm-kernel@lists.infradead.org, beanhuo@micron.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch fixes the support of Winbond memories. Indeed, before performing any Quad SPI command, the Quad Enable (QE) non-volatile bit MUST be set in the Status Register 2. According to the w25q16fw datasheet from Winbond: "When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3." Quad SPI instructions requires the bidirectional IO2 and IO3 pins. Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 100 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 6 +++ 2 files changed, 106 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2b2572e58a91..980da91e84a4 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1147,6 +1147,40 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int winbond_quad_enable(struct spi_nor *nor) +{ + int ret; + u8 sr2; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1); + if (ret < 0) + return ret; + + if (likely(sr2 & SR2_QUAD_EN_WINB)) + return 0; + dev_warn(nor->dev, "Winbond Quad mode disabled, enable it\n"); + + write_enable(nor); + + sr2 |= SR2_QUAD_EN_WINB; + ret = nor->write_reg(nor, SPINOR_OP_WRSR2_WINB, &sr2, 1); + if (ret < 0) + return ret; + + if (spi_nor_wait_till_ready(nor)) + return -EIO; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1); + if (ret < 0) + return ret; + if (!(sr2 & SR2_QUAD_EN_WINB)) { + dev_err(nor->dev, "Winbond Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + static int macronix_set_quad_mode(struct spi_nor *nor) { int status; @@ -1207,6 +1241,63 @@ static int macronix_set_single_mode(struct spi_nor *nor) return 0; } +static int winbond_set_quad_mode(struct spi_nor *nor) +{ + int status; + + /* Check whether the QPI mode is enabled. */ + if (nor->read_proto == SNOR_PROTO_4_4_4) { + /* Since the QPI mode is enabled, the Quad Enabled (QE) + * non-volatile bit is already set. + * If the Fast Read 1-4-4 (0xeb) were used, we should + * take care about the value M7-M0 written during + * dummy/mode cycles to avoid entering the continuous + * read mode by mistake. + * Also the Fast Read 1-1-4 (0x6b) op code is not + * supported in QPI mode. + * Hence the Fast Read 1-1-1 (0x0b) op code is chosen. + */ + nor->read_opcode = SPINOR_OP_READ_FAST; + return 0; + } + + /* + * The QPI mode is disabled but we still need to set the QE bit: + * when QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3. + * If the Fast Read 1-4-4 (0xeb) were used, we should take care + * about the value M7-M0 written during dummy/mode cycles to + * avoid entering the continuous read mode by mistake. + * Hence the Fast Read 1-1-4 (0x6b) op code is preferred. + */ + status = winbond_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Winbond quad-read nor enabled\n"); + return status; + } + nor->read_proto = SNOR_PROTO_1_1_4; + nor->read_opcode = SPINOR_OP_READ_1_1_4; + return 0; +} + +/* + * For both Winbond Dual and Single modes, we don't care about the value of + * the Quad Enabled (QE) bit since the memory still replies to Dual or Single + * SPI commands. + */ + +static int winbond_set_dual_mode(struct spi_nor *nor) +{ + nor->read_proto = SNOR_PROTO_1_1_2; + nor->read_opcode = SPINOR_OP_READ_1_1_2; + return 0; +} + +static int winbond_set_single_mode(struct spi_nor *nor) +{ + nor->read_proto = SNOR_PROTO_1_1_1; + return 0; +} + static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) { int status; @@ -1215,6 +1306,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) case SNOR_MFR_MACRONIX: return macronix_set_quad_mode(nor); + case SNOR_MFR_WINBOND: + return winbond_set_quad_mode(nor); + case SNOR_MFR_MICRON: /* Check whether Micron Quad mode is enabled. */ if (nor->read_proto != SNOR_PROTO_4_4_4) @@ -1244,6 +1338,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info) case SNOR_MFR_MACRONIX: return macronix_set_dual_mode(nor); + case SNOR_MFR_WINBOND: + return winbond_set_dual_mode(nor); + case SNOR_MFR_MICRON: /* Check whether Micron Dual mode is enabled. */ if (nor->read_proto != SNOR_PROTO_2_2_2) @@ -1265,6 +1362,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info) case SNOR_MFR_MACRONIX: return macronix_set_single_mode(nor); + case SNOR_MFR_WINBOND: + return winbond_set_single_mode(nor); + default: nor->read_proto = SNOR_PROTO_1_1_1; break; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 89e3228ec1d0..46343f5a8162 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -75,6 +75,12 @@ #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ +/* Used for Winbond flashes only. */ +#define SPINOR_OP_RDSR2_WINB 0x35 /* Read status register 2 */ +#define SPINOR_OP_WRSR2_WINB 0x31 /* Write status register 2 */ + +#define SR2_QUAD_EN_WINB BIT(1) /* Quad Enable bit */ + /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */