diff mbox

[linux-next,v2,10/14] mtd: spi-nor: configure the number of dummy clock cycles on Macronix memories

Message ID caaf19555ae684e0a1ccdd79cd7326ee1fbf1197.1452268345.git.cyrille.pitchen@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Cyrille Pitchen Jan. 8, 2016, 4:02 p.m. UTC
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 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 147 insertions(+), 8 deletions(-)

Comments

Cyrille Pitchen Jan. 29, 2016, 1:29 p.m. UTC | #1
Hi all,

I've found a small issue within this patch when I test with a Macronix
mx25l51245g (JEDEC ID C2201A so reported as "mx66l51235l" by spi-nor.c).
It deals with a wrong op code used when reading the Configuration Register.
See below for more details.

So I will send a new patch to fix this issue.

Otherwise, I tested on a sama5d2 xplained board and it works :)


Le 08/01/2016 17:02, Cyrille Pitchen a écrit :
> 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>
> ---
[...]
> +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);
Macronix memories use the 0x15 op code (not 0x35) to read the Configuration Register.
The 0x35 op code is used to enter the QPI mode. So read_cr() cannot be used here.

> +	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);
Here again, we must use the 0x15 op code instead of 0x35.

> +	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;
> +}
> +

Best regards,

Cyrille
diff mbox

Patch

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)