From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
To: <computersforpeace@gmail.com>, <linux-mtd@lists.infradead.org>
Cc: <nicolas.ferre@atmel.com>, <boris.brezillon@free-electrons.com>,
<marex@denx.de>, <vigneshr@ti.com>, <beanhuo@micron.com>,
<linux-kernel@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<devicetree@vger.kernel.org>, <robh+dt@kernel.org>,
<pawel.moll@arm.com>, <mark.rutland@arm.com>,
<ijc+devicetree@hellion.org.uk>, <galak@codeaurora.org>,
Cyrille Pitchen <cyrille.pitchen@atmel.com>
Subject: [PATCH v3 10/14] mtd: spi-nor: configure the number of dummy clock cycles on Macronix memories
Date: Wed, 3 Feb 2016 14:26:55 +0100 [thread overview]
Message-ID: <fe3d12a04383048a54dd2ffe927f854142fa8db7.1454505161.git.cyrille.pitchen@atmel.com> (raw)
In-Reply-To: <cover.1454505161.git.cyrille.pitchen@atmel.com>
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 <cyrille.pitchen@atmel.com>
---
drivers/mtd/spi-nor/spi-nor.c | 155 +++++++++++++++++++++++++++++++++++++++---
include/linux/mtd/spi-nor.h | 3 +
2 files changed, 150 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 2b1a26588ae6..c560fbbb8479 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1163,6 +1163,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, mask, val;
+ u16 sr_cr;
+ u8 dc, cr;
+
+ /* 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;
+
+ ret = nor->read_reg(nor, SPINOR_OP_RDCR_MX, &cr, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while reading the config register\n");
+ return ret;
+ }
+
+ 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;
+
+ ret = nor->read_reg(nor, SPINOR_OP_RDCR_MX, &cr, 1);
+ if (ret < 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;
@@ -1180,8 +1310,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);
}
/*
@@ -1194,6 +1323,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) {
@@ -1202,8 +1334,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);
}
/*
@@ -1214,16 +1345,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:
@@ -1236,8 +1376,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)
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 2dc0f8b429ca..8e0f43cecaca 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -75,6 +75,9 @@
#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
+/* Used for Macronix flashes only. */
+#define SPINOR_OP_RDCR_MX 0x15 /* Read configuration register */
+
/* 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 */
--
1.8.2.2
next prev parent reply other threads:[~2016-02-03 13:30 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-03 13:26 [PATCH v3 00/14] mtd: spi-nor: add driver for Atmel QSPI controller Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 01/14] mtd: spi-nor: remove micron_quad_enable() Cyrille Pitchen
2016-02-12 21:00 ` Brian Norris
2016-02-03 13:26 ` [PATCH v3 02/14] mtd: spi-nor: properly detect the memory when it boots in Quad or Dual mode Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 03/14] mtd: spi-nor: select op codes and SPI NOR protocols by manufacturer Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 04/14] mtd: spi-nor: fix support of Macronix memories Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 05/14] mtd: spi-nor: fix support of Winbond memories Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 06/14] mtd: spi-nor: fix support of Micron memories Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 07/14] mtd: spi-nor: fix support of Spansion memories Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 08/14] mtd: spi-nor: configure the number of dummy clock cycles by manufacturer Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 09/14] mtd: spi-nor: configure the number of dummy clock cycles on Micron memories Cyrille Pitchen
2016-02-03 13:26 ` Cyrille Pitchen [this message]
2016-02-03 13:26 ` [PATCH v3 11/14] mtd: spi-nor: configure the number of dummy clock cycles on Spansion memories Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 12/14] mtd: m25p80: add support of dual and quad spi protocols to all commands Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 13/14] Documentation: atmel-quadspi: add binding file for Atmel QSPI driver Cyrille Pitchen
2016-02-03 13:26 ` [PATCH v3 14/14] mtd: atmel-quadspi: add driver for Atmel QSPI controller Cyrille Pitchen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fe3d12a04383048a54dd2ffe927f854142fa8db7.1454505161.git.cyrille.pitchen@atmel.com \
--to=cyrille.pitchen@atmel.com \
--cc=beanhuo@micron.com \
--cc=boris.brezillon@free-electrons.com \
--cc=computersforpeace@gmail.com \
--cc=devicetree@vger.kernel.org \
--cc=galak@codeaurora.org \
--cc=ijc+devicetree@hellion.org.uk \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=marex@denx.de \
--cc=mark.rutland@arm.com \
--cc=nicolas.ferre@atmel.com \
--cc=pawel.moll@arm.com \
--cc=robh+dt@kernel.org \
--cc=vigneshr@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).