From patchwork Fri Jan 8 16:02:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 7987621 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 BA3FFBEEE5 for ; Fri, 8 Jan 2016 16:12:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BFED62017D for ; Fri, 8 Jan 2016 16:12:45 +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 B826B20172 for ; Fri, 8 Jan 2016 16:12:44 +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 1aHZd5-0008QV-1e; Fri, 08 Jan 2016 16:11:07 +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 1aHZaw-000271-Ji; Fri, 08 Jan 2016 16:09:37 +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; Fri, 8 Jan 2016 17:06:28 +0100 From: Cyrille Pitchen To: , Subject: [PATCH linux-next v2 10/14] mtd: spi-nor: configure the number of dummy clock cycles on Macronix memories Date: Fri, 8 Jan 2016 17:02:22 +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_080855_921969_378699F0 X-CRM114-Status: GOOD ( 13.61 ) X-Spam-Score: -4.2 (----) 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 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.2 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 The spi-nor framework currently expects all Fast Read operations to use 8 dummy clock cycles. Especially some drivers like m25p80 can only support multiple of 8 dummy clock cycles. On Macronix memories, the number of dummy clock cycles to be used by Fast Read commands can be safely set to 8 by updating the DC0 and DC1 volatile bits inside the Configuration Register. According to the mx66l1g45g datasheet from Macronix, using 8 dummy clock cycles should be enough to set the SPI bus clock frequency up to: - 133 MHz for Fast Read 1-1-1, 1-1-2, 1-1-4 and 1-2-2 commands in Single Transfer Rate (STR) - 104 MHz for Fast Read 1-4-4 (or 4-4-4 in QPI mode) commands (STR) Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 155 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 147 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3f79619aea52..68abae5c72e9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1190,6 +1190,136 @@ static int winbond_quad_enable(struct spi_nor *nor) return 0; } +static int macronix_dummy2code(u8 read_opcode, u8 read_dummy, u8 *dc) +{ + switch (read_opcode) { + case SPINOR_OP_READ: + case SPINOR_OP_READ4: + *dc = 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: + switch (read_dummy) { + case 6: + *dc = 1; + break; + case 8: + *dc = 0; + break; + case 10: + *dc = 3; + break; + default: + return -EINVAL; + } + break; + + case SPINOR_OP_READ_1_2_2: + case SPINOR_OP_READ4_1_2_2: + switch (read_dummy) { + case 4: + *dc = 0; + break; + case 6: + *dc = 1; + break; + case 8: + *dc = 2; + break; + case 10: + *dc = 3; + default: + return -EINVAL; + } + break; + + case SPINOR_OP_READ_1_4_4: + case SPINOR_OP_READ4_1_4_4: + switch (read_dummy) { + case 4: + *dc = 1; + break; + case 6: + *dc = 0; + break; + case 8: + *dc = 2; + break; + case 10: + *dc = 3; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int macronix_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy) +{ + int ret, sr, cr, mask, val; + u16 sr_cr; + u8 dc; + + /* Convert the number of dummy cycles into Macronix DC volatile bits */ + ret = macronix_dummy2code(nor->read_opcode, read_dummy, &dc); + if (ret) + return ret; + + mask = GENMASK(7, 6); + val = (dc << 6) & mask; + + cr = read_cr(nor); + if (cr < 0) { + dev_err(nor->dev, "error while reading the config register\n"); + return cr; + } + + if ((cr & mask) == val) { + nor->read_dummy = read_dummy; + return 0; + } + + sr = read_sr(nor); + if (sr < 0) { + dev_err(nor->dev, "error while reading the status register\n"); + return sr; + } + + cr = (cr & ~mask) | val; + sr_cr = (sr & 0xff) | ((cr & 0xff) << 8); + write_enable(nor); + ret = write_sr_cr(nor, sr_cr); + if (ret) { + dev_err(nor->dev, + "error while writing the SR and CR registers\n"); + return ret; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + cr = read_cr(nor); + if (cr < 0 || (cr & mask) != val) { + dev_err(nor->dev, "Macronix Dummy Cycle bits not updated\n"); + return -EINVAL; + } + + /* Save the number of dummy cycles to use with Fast Read commands */ + nor->read_dummy = read_dummy; + return 0; +} + static int macronix_set_quad_mode(struct spi_nor *nor) { int status; @@ -1207,8 +1337,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor) * read (performance enhance) mode by mistake! */ nor->read_opcode = SPINOR_OP_READ_1_4_4; - nor->read_dummy = 8; - return 0; + return macronix_set_dummy_cycles(nor, 8); } /* @@ -1221,6 +1350,9 @@ static int macronix_set_quad_mode(struct spi_nor *nor) * entering the continuous read mode by mistake if some * performance enhance toggling bits P0-P7 were written during * dummy/mode cycles. + * + * Use the Fast Read Quad Output 1-1-4 (0x6b) command with 8 dummy + * cycles (up to 133MHz for STR and 66MHz for DTR). */ status = macronix_quad_enable(nor); if (status) { @@ -1229,8 +1361,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor) } nor->read_proto = SNOR_PROTO_1_1_4; nor->read_opcode = SPINOR_OP_READ_1_1_4; - nor->read_dummy = 8; - return 0; + return macronix_set_dummy_cycles(nor, 8); } /* @@ -1241,16 +1372,25 @@ static int macronix_set_quad_mode(struct spi_nor *nor) static int macronix_set_dual_mode(struct spi_nor *nor) { + /* + * Use the Fast Read Dual Output 1-1-2 (0x3b) command with 8 dummy + * cycles (up to 133MHz for STR and 66MHz for DTR). + */ nor->read_proto = SNOR_PROTO_1_1_2; nor->read_opcode = SPINOR_OP_READ_1_1_2; - nor->read_dummy = 8; - return 0; + return macronix_set_dummy_cycles(nor, 8); } static int macronix_set_single_mode(struct spi_nor *nor) { u8 read_dummy; + /* + * Configure 8 dummy cycles for Fast Read 1-1-1 (0x0b) command (up to + * 133MHz for STR and 66MHz for DTR). The Read 1-1-1 (0x03) command + * expects no dummy cycle. + * read_opcode should not be overridden here! + */ switch (nor->read_opcode) { case SPINOR_OP_READ: case SPINOR_OP_READ4: @@ -1263,8 +1403,7 @@ static int macronix_set_single_mode(struct spi_nor *nor) } nor->read_proto = SNOR_PROTO_1_1_1; - nor->read_dummy = read_dummy; - return 0; + return macronix_set_dummy_cycles(nor, read_dummy); } static int winbond_set_quad_mode(struct spi_nor *nor)