From patchwork Wed Feb 3 13:26:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 8203231 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 4A0A2BEEE5 for ; Wed, 3 Feb 2016 13:36:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4938B20253 for ; Wed, 3 Feb 2016 13:36:38 +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 51AE020212 for ; Wed, 3 Feb 2016 13:36:37 +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 1aQxa5-0007HZ-Qh; Wed, 03 Feb 2016 13:34:49 +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 1aQxY5-0008Qs-Jn; Wed, 03 Feb 2016 13:33:32 +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:30:31 +0100 From: Cyrille Pitchen To: , Subject: [PATCH v3 11/14] mtd: spi-nor: configure the number of dummy clock cycles on Spansion memories Date: Wed, 3 Feb 2016 14:26:56 +0100 Message-ID: <90dbc93adb34c4bbb7d6ea752f9f7a00219944d6.1454505161.git.cyrille.pitchen@atmel.com> 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_053246_656774_834F1B2B X-CRM114-Status: GOOD ( 19.18 ) 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 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 c560fbbb8479..356db141dcb2 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1668,47 +1668,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)