From patchwork Fri Jan 8 16:10:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 564956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 68C09140311 for ; Sat, 9 Jan 2016 03:28:49 +1100 (AEDT) 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 1aHZsT-00051D-FH; Fri, 08 Jan 2016 16:27:01 +0000 Received: from eusmtp01.atmel.com ([212.144.249.242]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aHZcy-0006Ic-Qa; Fri, 08 Jan 2016 16:11:25 +0000 Received: from tenerife.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.30) with Microsoft SMTP Server id 14.3.235.1; Fri, 8 Jan 2016 17:10:17 +0100 From: Cyrille Pitchen To: , Subject: [PATCH linux-next v2 11/14] mtd: spi-nor: configure the number of dummy clock cycles on Spansion memories Date: Fri, 8 Jan 2016 17:10:53 +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-20160108_081102_275576_9177FD5D X-CRM114-Status: GOOD ( 18.96 ) X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [212.144.249.242 listed in list.dnswl.org] -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Linux MTD discussion mailing list 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 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org On Spansion memories, the number of dummy clock cycles to be used during Fast Read commands is configured through the 2bit latency code (LC). These bits are non-volatile inside the Configuration Register. To avoid breaking the configuration expected at reset by some bootloaders, we'd rather read the latency code and set the nor->read_dummy value accordingly than update those non-volatile bits. Since the Quad Enable non-volatile bit can be read at the same time from the Control Register, we now check its value to avoid some calls of the spansion_quad_enable() function when they are not needed. Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 159 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 137 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 68abae5c72e9..9ee271b2e5cb 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1695,47 +1695,162 @@ static int micron_set_single_mode(struct spi_nor *nor) return micron_set_dummy_cycles(nor, read_dummy); } -static int spansion_set_quad_mode(struct spi_nor *nor) +static inline int spansion_get_config(struct spi_nor *nor, + bool *quad_enabled, + u8 *latency_code) { - int status; + int cr; - status = spansion_quad_enable(nor); - if (status) { - dev_err(nor->dev, "Spansion quad-read not enabled\n"); + cr = read_cr(nor); + if (cr < 0) { + dev_err(nor->dev, + "error while reading the configuration register\n"); + return cr; + } + + if (quad_enabled) + *quad_enabled = !!(cr & CR_QUAD_EN_SPAN); + + if (latency_code) + *latency_code = (u8)((cr & GENMASK(7, 6)) >> 6); + + return 0; +} + +static int spansion_set_dummy_cycles(struct spi_nor *nor, u8 latency_code) +{ + /* SDR dummy cycles */ + switch (nor->read_opcode) { + case SPINOR_OP_READ: + case SPINOR_OP_READ4: + nor->read_dummy = 0; + break; + + case SPINOR_OP_READ_FAST: + case SPINOR_OP_READ_1_1_2: + case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ4_FAST: + case SPINOR_OP_READ4_1_1_2: + case SPINOR_OP_READ4_1_1_4: + nor->read_dummy = (latency_code == 3) ? 0 : 8; + break; + + case SPINOR_OP_READ_1_2_2: + case SPINOR_OP_READ4_1_2_2: + switch (latency_code) { + default: + case 0: + case 3: + nor->read_dummy = 4; + break; + case 1: + nor->read_dummy = 5; + break; + case 2: + nor->read_dummy = 6; + break; + } + break; + + + case SPINOR_OP_READ_1_4_4: + case SPINOR_OP_READ4_1_4_4: + switch (latency_code) { + default: + case 0: + case 1: + nor->read_dummy = 4; + break; + case 2: + nor->read_dummy = 5; + break; + case 3: + nor->read_dummy = 1; + break; + } + + default: return -EINVAL; } + + return 0; +} + +static int spansion_set_quad_mode(struct spi_nor *nor) +{ + bool quad_enabled; + u8 latency_code; + int ret; + + /* + * The QUAD bit of Configuration Register must be set (CR Bit1=1) for + * using any Quad SPI command. + */ + ret = spansion_get_config(nor, &quad_enabled, &latency_code); + if (ret) + return ret; + + /* The Quad mode should be enabled ... */ + if (!quad_enabled) { + /* ... if not try to enable it. */ + dev_warn(nor->dev, "Spansion Quad mode disabled, enable it\n"); + ret = spansion_quad_enable(nor); + if (ret) + return ret; + } + + /* + * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as their + * number of dummy cycles can not be set to a multiple of 8: some SPI + * controllers, especially those relying on the m25p80 driver, expect + * the number of dummy cycles to be a multiple of 8. + * Also when using a Fast Read Quad I/O command, the memory checks the + * value of the first mode/dummy cycles to decice whether it enters or + * leaves the Countinuous Read mode. We should never enter the + * Countinuous Read mode as the spi-nor framework doesn't support it. + * For all these reason, we'd rather use the Fast Read Quad Output + * 1-1-4 (0x6b / 0x6c) commands instead. + */ nor->read_proto = SNOR_PROTO_1_1_4; nor->read_opcode = SPINOR_OP_READ_1_1_4; - nor->read_dummy = 8; - return 0; + return spansion_set_dummy_cycles(nor, latency_code); } static int spansion_set_dual_mode(struct spi_nor *nor) { + u8 latency_code; + int ret; + + /* We don't care about the quad mode status */ + ret = spansion_get_config(nor, NULL, &latency_code); + if (ret) + return ret; + + /* + * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as their + * number of dummy cycles can not bet set to a multiple of 8: some SPI + * controllers, especially those relying on the m25p80 driver, expect + * the number of dummy cycles to be a multiple of 8. + * For this reason, w'd rather use the Fast Read Dual Output 1-1-2 + * (0x3b / 0x3c) commands instead. + */ nor->read_proto = SNOR_PROTO_1_1_2; nor->read_opcode = SPINOR_OP_READ_1_1_2; - nor->read_dummy = 8; - return 0; + return spansion_set_dummy_cycles(nor, latency_code); } static int spansion_set_single_mode(struct spi_nor *nor) { - u8 read_dummy; - - switch (nor->read_opcode) { - case SPINOR_OP_READ: - case SPINOR_OP_READ4: - read_dummy = 0; - break; + u8 latency_code; + int ret; - default: - read_dummy = 8; - break; - } + /* We don't care about the quad mode status */ + ret = spansion_get_config(nor, NULL, &latency_code); + if (ret) + return ret; nor->read_proto = SNOR_PROTO_1_1_1; - nor->read_dummy = read_dummy; - return 0; + return spansion_set_dummy_cycles(nor, latency_code); } static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)