Micron:
Once their Quad SPI protocol enabled, Micron spi-nor memories expect all
commands to use the SPI 4-4-4 protocol. Also when the Dual SPI protocol is
enabled, all commands must use the SPI 2-2-2 protocol.

Macronix:
When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol.
If the QPI mode is disabled, the Fast Read Dual Output (0x3b) command uses
the SPI 1-1-2 protocol whereas other commands use the SPI 1-1-1 protocol.

Spansion:
When Quad I/O operations are enabled, the Fast Read Quad Output (0x6b / 0x6c)
commands use the SPI 1-1-4 protocol.
Also when using the Fast Read Dual Output (0x3b / 0x3c) commands, the
SPI 1-1-2 protocol must be used. Other commands use the SPI 1-1-1 protocol.

Signed-off-by: Cyrille Pitchen <[email protected]>
---
 drivers/mtd/spi-nor/spi-nor.c | 544 ++++++++++++++++++++++++++++++++++++------
 include/linux/mtd/spi-nor.h   |  10 +-
 2 files changed, 481 insertions(+), 73 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 1908038c8f2e..7fbcccb3d02e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -900,27 +900,110 @@ write_err:
        return ret;
 }
 
-static int macronix_quad_enable(struct spi_nor *nor)
+static int macronix_set_qpi_mode(struct spi_nor *nor, bool enable)
 {
-       int ret, val;
+       int sr, mask, qpi_bit;
+
+       mask = SR_QUAD_EN_MX;
+       qpi_bit = (enable) ? SR_QUAD_EN_MX : 0;
+
+       sr = read_sr(nor);
+       if ((sr & mask) == qpi_bit)
+               return 0;
 
-       val = read_sr(nor);
        write_enable(nor);
+       write_sr(nor, (sr & ~mask) | qpi_bit);
 
-       write_sr(nor, val | SR_QUAD_EN_MX);
+       /* Set the reg protocol now before accessing any other register. */
+       nor->reg_proto = (enable) ? SPI_PROTO_4_4_4 : SPI_PROTO_1_1_1;
 
-       if (spi_nor_wait_till_ready(nor))
+       if (spi_nor_wait_till_ready(nor)) {
+               dev_err(nor->dev, "Failed to %s the QPI mode.\n",
+                       enable ? "enable" : "disable");
                return 1;
+       }
 
-       ret = read_sr(nor);
-       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-               dev_err(nor->dev, "Macronix Quad bit not set\n");
+       sr = read_sr(nor);
+       if (!(sr > 0 && ((sr & mask) != qpi_bit))) {
+               dev_err(nor->dev, "Macronix Quad bit was not %s.\n",
+                       enable ? "set" : "cleared");
                return -EINVAL;
        }
 
        return 0;
 }
 
+static int macronix_set_quad_io(struct spi_nor *nor)
+{
+       /* Enable the QPI mode if not done yet. */
+       if (macronix_set_qpi_mode(nor, true))
+               return -EINVAL;
+
+       /* Use SPI 4-4-4 protocol for all commands. */
+       nor->read_proto = SPI_PROTO_4_4_4;
+       nor->write_proto = SPI_PROTO_4_4_4;
+       nor->erase_proto = SPI_PROTO_4_4_4;
+
+       /*
+        * The Fast Read Quad Output 1-1-4 command (0x6b) command is not
+        * supported in QPI mode, use the Fast Read Quad I/O 1-4-4 (0xeb)
+        * instead.
+        */
+       nor->read_opcode = SPINOR_OP_READ_1_4_4;
+
+       return 0;
+}
+
+static int macronix_set_quad_output(struct spi_nor *nor)
+{
+       /* Disable the QPI mode if not done yet. */
+       if (macronix_set_qpi_mode(nor, false))
+               return -EINVAL;
+
+       /* Use the Fast Read Quad Output 1-1-4 command. */
+       nor->read_proto = SPI_PROTO_1_1_4;
+       nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+       return 0;
+}
+
+static int macronix_set_dual_io(struct spi_nor *nor)
+{
+       /* Disable the QPI mode if not done yet. */
+       if (macronix_set_qpi_mode(nor, false))
+               return -EINVAL;
+
+       /* Use the Fast Read Dual I/O 1-2-2 command. */
+       nor->read_proto = SPI_PROTO_1_2_2;
+       nor->read_opcode = SPINOR_OP_READ_1_2_2;
+
+       return 0;
+}
+
+static int macronix_set_dual_output(struct spi_nor *nor)
+{
+       /* Disable the QPI mode if not done yet. */
+       if (macronix_set_qpi_mode(nor, false))
+               return -EINVAL;
+
+       /* Use the Fast Read Dual Output 1-1-2 command. */
+       nor->read_proto = SPI_PROTO_1_1_2;
+       nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+       return 0;
+}
+
+static int macronix_set_single(struct spi_nor *nor)
+{
+       /* Disable the QPI mode if not done yet. */
+       if (macronix_set_qpi_mode(nor, false))
+               return -EINVAL;
+
+       nor->read_proto = SPI_PROTO_1_1_1;
+
+       return 0;
+}
+
 /*
  * Write status Register and configuration register with 2 bytes
  * The first byte will be written to the status register, while the
@@ -935,96 +1018,416 @@ static int write_sr_cr(struct spi_nor *nor, u16 val)
        return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
 }
 
-static int spansion_quad_enable(struct spi_nor *nor)
+static int spansion_write_cr(struct spi_nor *nor, bool quad_mode, u8 lc)
 {
-       int ret;
-       int quad_en = CR_QUAD_EN_SPAN << 8;
+       int cr, mask, value;
 
-       write_enable(nor);
+       mask = CR_QUAD_EN_SPAN | CR_LC_MASK;
+       value = (lc << 6) & CR_LC_MASK;
+       if (quad_mode)
+               value |= CR_QUAD_EN_SPAN;
 
-       ret = write_sr_cr(nor, quad_en);
-       if (ret < 0) {
+       /* Read the control register */
+       cr = read_cr(nor);
+       if (cr < 0) {
+               dev_err(nor->dev,
+                       "error while reading configuration register\n");
+               return -EINVAL;
+       }
+
+       /* Check whether the Quad bit and the Latency Code need to be updated */
+       if ((cr & mask) == value)
+               return 0;
+
+       /* Update the configuration register. */
+       cr = (cr & ~mask) | value;
+       write_enable(nor);
+       if (write_sr_cr(nor, cr << 8) < 0) {
                dev_err(nor->dev,
                        "error while writing configuration register\n");
                return -EINVAL;
        }
 
        /* read back and check it */
-       ret = read_cr(nor);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
+       cr = read_cr(nor);
+       if (!(cr > 0 && ((cr & mask) == value))) {
+               dev_err(nor->dev,
+                       "error while updating configuration register\n");
                return -EINVAL;
        }
 
        return 0;
 }
 
-static int micron_quad_enable(struct spi_nor *nor)
+static int spansion_set_quad_output(struct spi_nor *nor)
+{
+       int ret;
+
+       /*
+        * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+        * processing a Fast Read Quad Output 1-1-4 command.
+        */
+       ret = spansion_write_cr(nor, true, 0);
+       if (ret)
+               return ret;
+
+       /* Use the Fast Read Quad Output 1-1-4 command. */
+       nor->read_proto = SPI_PROTO_1_1_4;
+       nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+       return 0;
+}
+
+static int spansion_set_dual_output(struct spi_nor *nor)
+{
+       int ret;
+
+       /*
+        * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+        * processing a Fast Read Dual Output 1-1-2 command.
+        */
+       ret = spansion_write_cr(nor, false, 0);
+       if (ret)
+               return ret;
+
+       /* Use the Fast Read Dual Output 1-1-2 command. */
+       nor->read_proto = SPI_PROTO_1_1_2;
+       nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+       return 0;
+}
+
+static int spansion_set_single(struct spi_nor *nor)
 {
        int ret;
-       u8 val;
 
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+       /*
+        * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+        * processing a Fast Read 1-1-1 command. The Latency Code is not
+        * relevant for Read command since no dummy cycle is expected.
+        */
+       ret = spansion_write_cr(nor, false, 0);
+       if (ret)
+               return ret;
+
+       nor->read_proto = SPI_PROTO_1_1_1;
+
+       return 0;
+}
+
+static int micron_set_dummy_cycles(struct spi_nor *nor, u8 num_dummy_cycles)
+{
+       u8 vcr, val, mask;
+       int ret;
+
+       mask = GENMASK(7, 4);
+       val = (num_dummy_cycles << 4) & 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 %d reading EVCR\n", ret);
+               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)
+               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;
 
-       /* set EVCR, enable quad I/O */
-       nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+       /* Read VCR and check it. */
+       ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while reading VCR\n");
+               return ret;
+       }
+       if ((vcr & mask) != val) {
+               dev_err(nor->dev, "Micron VCR dummy cycles not updated\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int micron_set_protocol(struct spi_nor *nor, u8 val,
+                              enum spi_protocol proto)
+{
+       u8 evcr, mask;
+       int ret;
+
+       mask = EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON;
+
+       /* Read the Exhanced Volatile Configuration Register (EVCR). */
+       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while reading EVCR register\n");
+               return ret;
+       }
+
+       /* Check whether we need to update the protocol bits. */
+       if ((evcr & mask) == val)
+               return 0;
+
+       /* Set EVCR protocol bits. */
+       write_enable(nor);
+       evcr = (evcr & ~mask) | val;
+       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
        if (ret < 0) {
                dev_err(nor->dev, "error while writing EVCR register\n");
                return ret;
        }
 
+       /* Switch reg protocol now before accessing any other registers. */
+       nor->reg_proto = proto;
+
        ret = spi_nor_wait_till_ready(nor);
        if (ret)
                return ret;
 
-       /* read EVCR and check it */
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+       /* Read EVCR and check it. */
+       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
        if (ret < 0) {
-               dev_err(nor->dev, "error %d reading EVCR\n", ret);
+               dev_err(nor->dev, "error while reading EVCR\n");
                return ret;
        }
-       if (val & EVCR_QUAD_EN_MICRON) {
-               dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+       if ((evcr & mask) != val) {
+               dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
                return -EINVAL;
        }
 
        return 0;
 }
 
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+static inline int micron_set_extended_spi_protocol(struct spi_nor *nor)
 {
-       int status;
+       int ret;
 
+       /* Set both the Quad and Dual bits to select the Extended SPI mode */
+       ret = micron_set_protocol(nor,
+                                 EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
+                                 SPI_PROTO_1_1_1);
+       if (ret) {
+               dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int micron_set_quad_io(struct spi_nor *nor)
+{
+       int ret;
+
+       /* Clear at least the Quad bit to enable quad mode */
+       ret = micron_set_protocol(nor,
+                                 EVCR_DUAL_EN_MICRON,
+                                 SPI_PROTO_4_4_4);
+       if (ret) {
+               dev_err(nor->dev, "Failed to set Micron Quad mode\n");
+               return ret;
+       }
+
+       /* Force the number of dummy cycles to 8 */
+       ret = micron_set_dummy_cycles(nor, 8);
+       if (ret)
+               return ret;
+
+       /* Use SPI 4-4-4 protocol for all commands. */
+       nor->read_proto = SPI_PROTO_4_4_4;
+       nor->write_proto = SPI_PROTO_4_4_4;
+       nor->erase_proto = SPI_PROTO_4_4_4;
+
+       /*
+        * The Fast Read Quad Output 1-1-4 command (0x6b) is processed with
+        * SPI 4-4-4 protocol.
+        */
+       nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+       return 0;
+}
+
+static int micron_set_quad_output(struct spi_nor *nor)
+{
+       int ret;
+
+       ret = micron_set_extended_spi_protocol(nor);
+       if (ret)
+               return ret;
+
+       /* Force the number of dummy cycles to 8 */
+       ret = micron_set_dummy_cycles(nor, 8);
+       if (ret)
+               return ret;
+
+       /* Use the Fast Read Quad Output 1-1-4 command. */
+       nor->read_proto = SPI_PROTO_1_1_4;
+       nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+       return 0;
+}
+
+static int micron_set_dual_io(struct spi_nor *nor)
+{
+       int ret;
+
+       /* Clear Dual bit but keep Quad bit set to enable dual mode */
+       ret = micron_set_protocol(nor,
+                                 EVCR_QUAD_EN_MICRON,
+                                 SPI_PROTO_2_2_2);
+       if (ret) {
+               dev_err(nor->dev, "Failed to set Micron Dual mode\n");
+               return ret;
+       }
+
+       /* Force the number of dummy cycles to 8 */
+       ret = micron_set_dummy_cycles(nor, 8);
+       if (ret)
+               return ret;
+
+       /* Use SPI 2-2-2 protocol for all commands. */
+       nor->read_proto = SPI_PROTO_2_2_2;
+       nor->write_proto = SPI_PROTO_2_2_2;
+       nor->erase_proto = SPI_PROTO_2_2_2;
+
+       /*
+        * The Fast Read Dual Output 1-1-2 command (0x3b) is processed with
+        * SPI 2-2-2 protocol.
+        */
+       nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+       return 0;
+}
+
+static int micron_set_dual_output(struct spi_nor *nor)
+{
+       int ret;
+
+       ret = micron_set_extended_spi_protocol(nor);
+       if (ret)
+               return ret;
+
+       /* Force the number of dummy cycles to 8 */
+       ret = micron_set_dummy_cycles(nor, 8);
+       if (ret)
+               return ret;
+
+       /* Use the Fast Read Dual Output 1-1-4 command. */
+       nor->read_proto = SPI_PROTO_1_1_2;
+       nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+       return 0;
+}
+
+static int micron_set_single(struct spi_nor *nor)
+{
+       int ret;
+
+       ret = micron_set_extended_spi_protocol(nor);
+       if (ret)
+               return ret;
+
+       /* Force the number of dummy cycles to 8 (Fast Read only) */
+       ret = micron_set_dummy_cycles(nor, 8);
+       if (ret)
+               return ret;
+
+       nor->read_proto = SPI_PROTO_1_1_1;
+
+       return 0;
+}
+
+static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info,
+                        u16 mode)
+{
        switch (JEDEC_MFR(info)) {
        case CFI_MFR_MACRONIX:
-               status = macronix_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Macronix quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
+               if (mode & SPI_TX_QUAD)
+                       return macronix_set_quad_io(nor);
+               return macronix_set_quad_output(nor);
+
        case CFI_MFR_ST:
-               status = micron_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Micron quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
+               if (mode & SPI_TX_QUAD)
+                       return micron_set_quad_io(nor);
+               return micron_set_quad_output(nor);
+
+       case CFI_MFR_AMD:
+               /*
+                * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as
+                * their number of dummy cycles is not a multiple of 8. Some
+                * SPI controllers, especially those relying on the m25p80
+                * driver, expect the number of dummy cycles to be a multiple
+                * of 8.
+                */
+               return spansion_set_quad_output(nor);
+
        default:
-               status = spansion_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Spansion quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info,
+                        u16 mode)
+{
+       switch (JEDEC_MFR(info)) {
+       case CFI_MFR_MACRONIX:
+               if (mode & SPI_TX_DUAL)
+                       return macronix_set_dual_io(nor);
+               return macronix_set_dual_output(nor);
+
+       case CFI_MFR_ST:
+               if (mode & SPI_TX_DUAL)
+                       return micron_set_dual_io(nor);
+               return micron_set_dual_output(nor);
+
+       case CFI_MFR_AMD:
+               /*
+                * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as
+                * their number of dummy cycles is not a multiple of 8. Some
+                * SPI controllers, especially those relying on the m25p80
+                * driver, expect the number of dummy cycles to be a multiple
+                * of 8.
+                */
+               return spansion_set_dual_output(nor);
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int set_single_mode(struct spi_nor *nor, const struct flash_info *info,
+                          u16 mode)
+{
+       switch (JEDEC_MFR(info)) {
+       case CFI_MFR_MACRONIX:
+               return macronix_set_single(nor);
+
+       case CFI_MFR_ST:
+               return micron_set_single(nor);
+
+       case CFI_MFR_AMD:
+               return spansion_set_single(nor);
+
+       default:
+               break;
        }
+
+       return -EINVAL;
 }
 
 static int spi_nor_check(struct spi_nor *nor)
@@ -1170,39 +1573,38 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, 
u16 mode)
        if (info->flags & SPI_NOR_NO_FR)
                nor->flash_read = SPI_NOR_NORMAL;
 
+       /* Default commands */
+       nor->program_opcode = SPINOR_OP_PP;
+       if (nor->flash_read == SPI_NOR_NORMAL)
+               nor->read_opcode = SPINOR_OP_READ;
+       else
+               nor->read_opcode = SPINOR_OP_READ_FAST;
+
        /* Quad/Dual-read mode takes precedence over fast/normal */
        if (mode & SPI_RX_QUAD && info->flags & SPI_NOR_QUAD_READ) {
-               ret = set_quad_mode(nor, info);
+               /* At least SPI 1-1-4 should be supported */
+               ret = set_quad_mode(nor, info, mode);
                if (ret) {
                        dev_err(dev, "quad mode not supported\n");
                        return ret;
                }
                nor->flash_read = SPI_NOR_QUAD;
        } else if (mode & SPI_RX_DUAL && info->flags & SPI_NOR_DUAL_READ) {
+               /* At lest SPI 1-1-2 should be supported */
+               ret = set_dual_mode(nor, info, mode);
+               if (ret) {
+                       dev_err(dev, "dual mode not supported\n");
+                       return ret;
+               }
                nor->flash_read = SPI_NOR_DUAL;
+       } else if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) {
+               ret = set_single_mode(nor, info, mode);
+               if (ret) {
+                       dev_err(dev, "failed to switch back to single mode\n");
+                       return ret;
+               }
        }
 
-       /* Default commands */
-       switch (nor->flash_read) {
-       case SPI_NOR_QUAD:
-               nor->read_opcode = SPINOR_OP_READ_1_1_4;
-               break;
-       case SPI_NOR_DUAL:
-               nor->read_opcode = SPINOR_OP_READ_1_1_2;
-               break;
-       case SPI_NOR_FAST:
-               nor->read_opcode = SPINOR_OP_READ_FAST;
-               break;
-       case SPI_NOR_NORMAL:
-               nor->read_opcode = SPINOR_OP_READ;
-               break;
-       default:
-               dev_err(dev, "No Read opcode defined\n");
-               return -EINVAL;
-       }
-
-       nor->program_opcode = SPINOR_OP_PP;
-
        if (info->addr_width)
                nor->addr_width = info->addr_width;
        else if (mtd->size > 0x1000000) {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 32339e82cb9d..1cdc905a3077 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -24,8 +24,10 @@
 #define SPINOR_OP_WRSR         0x01    /* Write status register 1 byte */
 #define SPINOR_OP_READ         0x03    /* Read data bytes (low frequency) */
 #define SPINOR_OP_READ_FAST    0x0b    /* Read data bytes (high frequency) */
-#define SPINOR_OP_READ_1_1_2   0x3b    /* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ_1_1_4   0x6b    /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_1_2   0x3b    /* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2   0xbb    /* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4   0x6b    /* Read data bytes (Quad Out SPI) */
+#define SPINOR_OP_READ_1_4_4   0xeb    /* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP           0x02    /* Page program (up to 256 bytes) */
 #define SPINOR_OP_BE_4K                0x20    /* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC    0xd7    /* Erase 4KiB block on PMC chips */
@@ -58,6 +60,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 */
 
@@ -74,12 +78,14 @@
 
 /* Enhanced Volatile Configuration Register bits */
 #define EVCR_QUAD_EN_MICRON    0x80    /* Micron Quad I/O */
+#define EVCR_DUAL_EN_MICRON    0x40    /* Micron Dual I/O */
 
 /* Flag Status Register bits */
 #define FSR_READY              0x80
 
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
+#define CR_LC_MASK             0xc0    /* Spansion Latency Code */
 
 enum read_mode {
        SPI_NOR_NORMAL = 0,
-- 
1.8.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to