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 <[email protected]>
---
 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

Reply via email to