[PATCH linux-next v2 09/14] mtd: spi-nor: configure the number of dummy clock cycles on Micron memories

Cyrille Pitchen cyrille.pitchen at atmel.com
Fri Jan 8 08:02:21 PST 2016


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 Micron memories, the number of dummy clock cycles to be used by Fast
Read commands can be safely set to 8 by updating the Volatile
Configuration Register (VCR).

Also the XIP bit is set at the same time when updating the VCR so the
Continuous Read mode is disabled: this prevents us from entering it by
mistake.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 72 ++++++++++++++++++++++++++++++++++++++-----
 include/linux/mtd/spi-nor.h   |  2 ++
 2 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 353a0f6ac3fe..3f79619aea52 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1341,6 +1341,53 @@ static int winbond_set_single_mode(struct spi_nor *nor)
 	return 0;
 }
 
+static int micron_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
+{
+	u8 vcr, val, mask;
+	int ret;
+
+	/* Set bit3 (XIP) to disable the Continuous Read mode */
+	mask = GENMASK(7, 4) | BIT(3);
+	val = ((read_dummy << 4) | BIT(3)) & mask;
+
+	/* Read the Volatile Configuration Register (VCR). */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
+	if (ret < 0) {
+		dev_err(nor->dev, "error while reading VCR register\n");
+		return ret;
+	}
+
+	/* Check whether we need to update the number of dummy cycles. */
+	if ((vcr & mask) == val) {
+		nor->read_dummy = read_dummy;
+		return 0;
+	}
+
+	/* Update the number of dummy into the VCR. */
+	write_enable(nor);
+	vcr = (vcr & ~mask) | val;
+	ret = nor->write_reg(nor, SPINOR_OP_WR_VCR, &vcr, 1);
+	if (ret < 0) {
+		dev_err(nor->dev, "error while writing VCR register\n");
+		return ret;
+	}
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	/* Read VCR and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
+	if (ret < 0 || (vcr & mask) != val) {
+		dev_err(nor->dev, "Micron VCR dummy cycles 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 micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
 			       enum spi_nor_protocol proto)
 {
@@ -1425,12 +1472,15 @@ static int micron_set_quad_mode(struct spi_nor *nor)
 	/*
 	 * Whatever the Quad mode is enabled or not, the
 	 * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
+	 * Force the number of dummy cycles to 8 and disable the Continuous Read
+	 * mode to prevent some drivers from using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
 	 */
 	if (nor->read_proto != SNOR_PROTO_4_4_4)
 		nor->read_proto = SNOR_PROTO_1_1_4;
 	nor->read_opcode = SPINOR_OP_READ_1_1_4;
-	nor->read_dummy = 8;
-	return 0;
+	return micron_set_dummy_cycles(nor, 8);
 }
 
 static int micron_set_dual_mode(struct spi_nor *nor)
@@ -1455,12 +1505,15 @@ static int micron_set_dual_mode(struct spi_nor *nor)
 	/*
 	 * Whatever the Dual mode is enabled or not, the
 	 * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
+	 * Force the number of dummy cycles to 8 and disable the Continuous Read
+	 * mode to prevent some drivers from using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
 	 */
 	if (nor->read_proto != SNOR_PROTO_2_2_2)
 		nor->read_proto = SNOR_PROTO_1_1_2;
 	nor->read_opcode = SPINOR_OP_READ_1_1_2;
-	nor->read_dummy = 8;
-	return 0;
+	return micron_set_dummy_cycles(nor, 8);
 }
 
 static int micron_set_single_mode(struct spi_nor *nor)
@@ -1483,7 +1536,13 @@ static int micron_set_single_mode(struct spi_nor *nor)
 		nor->read_proto = SNOR_PROTO_1_1_1;
 	}
 
-	/* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
+	/*
+	 * Force the number of dummy cycles to 8 for Fast Read, 0 for Read
+	 * and disable the Continuous Read mode to prevent some drivers from
+	 * using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
+	 */
 	switch (nor->read_opcode) {
 	case SPINOR_OP_READ:
 	case SPINOR_OP_READ4:
@@ -1494,8 +1553,7 @@ static int micron_set_single_mode(struct spi_nor *nor)
 		read_dummy = 8;
 		break;
 	}
-	nor->read_dummy = read_dummy;
-	return 0;
+	return micron_set_dummy_cycles(nor, read_dummy);
 }
 
 static int spansion_set_quad_mode(struct spi_nor *nor)
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index d0a6f343a063..2dc0f8b429ca 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -86,6 +86,8 @@
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_MIO_RDID	0xaf	/* Multiple I/O Read JEDEC ID */
+#define SPINOR_OP_RD_VCR	0x85	/* Read VCR register */
+#define SPINOR_OP_WR_VCR	0x81	/* Write VCR register */
 #define SPINOR_OP_RD_EVCR	0x65    /* Read EVCR register */
 #define SPINOR_OP_WD_EVCR	0x61    /* Write EVCR register */
 
-- 
1.8.2.2




More information about the linux-arm-kernel mailing list