[PATCH v3 04/14] mtd: spi-nor: fix support of Macronix memories

From: Cyrille Pitchen
Date: Wed Feb 03 2016 - 08:28:18 EST


This patch fixes the support of Macronix memories. Especially we avoid
updating the Status Register when not needed as the Quad Enable (QE) bit
is a non-volatile bit.

Also we add comments to explain why we use some Fast Read op codes rather
than others.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@xxxxxxxxx>
---
drivers/mtd/spi-nor/spi-nor.c | 81 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 72 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index e6438d63246d..2b2572e58a91 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1088,6 +1088,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
val = read_sr(nor);
if (val < 0)
return val;
+
+ if (likely(val & SR_QUAD_EN_MX))
+ return 0;
+ dev_warn(nor->dev, "Macronix Quad mode disabled, enable it\n");
+
write_enable(nor);

write_sr(nor, val | SR_QUAD_EN_MX);
@@ -1142,21 +1147,73 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0;
}

+static int macronix_set_quad_mode(struct spi_nor *nor)
+{
+ int status;
+
+ /* Check whether the QPI mode is enabled. */
+ if (nor->read_proto == SNOR_PROTO_4_4_4) {
+ /*
+ * Since the QPI mode is enabled, the Quad Enabled (QE)
+ * non-volatile bit is already set.
+ * However in QPI mode, only the Fast Read 1-4-4 (0xeb)
+ * op code is supported.
+ * WARNING: we should take care about the performance
+ * enhance toggling bits P0-P7 written during the
+ * dummy/mode cycles to avoid entering the continuous
+ * read (performance enhance) mode by mistake!
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+ return 0;
+ }
+
+ /*
+ * The QPI mode is disabled but we still need to set the QE bit:
+ * this disables the reset and write protect features and
+ * frees the associated pins so they can be used as the 3rd
+ * and 4th I/O lines required by Quad SPI commands.
+ * Also we'd rather use the Fast Read 1-1-4 (0x6b) op code than
+ * the Fast Read 1-4-4 (0xeb) op code so we don't care about
+ * entering the continuous read mode by mistake if some
+ * performance enhance toggling bits P0-P7 were written during
+ * dummy/mode cycles.
+ */
+ status = macronix_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev, "Macronix quad-read not enabled\n");
+ return status;
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+ return 0;
+}
+
+/*
+ * For both Macronix Dual and Single modes, we don't care about the value of
+ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
+ * SPI commands.
+ */
+
+static int macronix_set_dual_mode(struct spi_nor *nor)
+{
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+ return 0;
+}
+
+static int macronix_set_single_mode(struct spi_nor *nor)
+{
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ return 0;
+}
+
static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
{
int status;

switch (JEDEC_MFR(info)) {
case SNOR_MFR_MACRONIX:
- status = macronix_quad_enable(nor);
- if (status) {
- dev_err(nor->dev, "Macronix quad-read not enabled\n");
- return -EINVAL;
- }
- /* Check whether Macronix QPI mode is enabled. */
- if (nor->read_proto != SNOR_PROTO_4_4_4)
- nor->read_proto = SNOR_PROTO_1_1_4;
- break;
+ return macronix_set_quad_mode(nor);

case SNOR_MFR_MICRON:
/* Check whether Micron Quad mode is enabled. */
@@ -1184,6 +1241,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
{
switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_dual_mode(nor);
+
case SNOR_MFR_MICRON:
/* Check whether Micron Dual mode is enabled. */
if (nor->read_proto != SNOR_PROTO_2_2_2)
@@ -1202,6 +1262,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
{
switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_single_mode(nor);
+
default:
nor->read_proto = SNOR_PROTO_1_1_1;
break;
--
1.8.2.2