layerscape: add linux 4.9 support
[openwrt/staging/dedeckeh.git] / target / linux / layerscape / patches-4.9 / 401-mtd-spi-nor-support-layerscape.patch
diff --git a/target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch b/target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch
new file mode 100644 (file)
index 0000000..f61ae06
--- /dev/null
@@ -0,0 +1,1042 @@
+From 120fa458ffe2250ea58578ccfc85e674005463dc Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 25 Sep 2017 10:53:50 +0800
+Subject: [PATCH] mtd: spi-nor: support layerscape
+
+This is a integrated patch for layerscape qspi support.
+
+Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+Signed-off-by: Yunhui Cui <B56489@freescale.com>
+Signed-off-by: mar.krzeminski <mar.krzeminski@gmail.com>
+Signed-off-by: Alison Wang <b18965@freescale.com>
+Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@hitachi.com>
+Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
+Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
+Signed-off-by: Alexander Kurz <akurz@blala.de>
+Signed-off-by: L. D. Pinney <ldpinney@gmail.com>
+Signed-off-by: Ash Benz <ash.benz@bk.ru>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/mtd/mtdchar.c             |   2 +-
+ drivers/mtd/spi-nor/fsl-quadspi.c | 356 +++++++++++++++++++++++++++++++-------
+ drivers/mtd/spi-nor/spi-nor.c     | 136 +++++++++++++--
+ include/linux/mtd/spi-nor.h       |  14 +-
+ 4 files changed, 432 insertions(+), 76 deletions(-)
+
+diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
+index 2a47a3f0..4f21401d 100644
+--- a/drivers/mtd/mtdchar.c
++++ b/drivers/mtd/mtdchar.c
+@@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
+        * data. For our userspace tools it is important to dump areas
+        * with ECC errors!
+        * For kernel internal usage it also might return -EUCLEAN
+-       * to signal the caller that a bitflip has occured and has
++       * to signal the caller that a bitflip has occurred and has
+        * been corrected by the ECC algorithm.
+        *
+        * Note: currently the standard NAND function, nand_read_oob_std,
+diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
+index 5c82e4ef..8fb75532 100644
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -41,6 +41,8 @@
+ #define QUADSPI_QUIRK_TKT253890               (1 << 2)
+ /* Controller cannot wake up from wait mode, TKT245618 */
+ #define QUADSPI_QUIRK_TKT245618         (1 << 3)
++/* QSPI_AMBA_BASE is internally added by SOC design */
++#define QUADSPI_AMBA_BASE_INTERNAL    (0x10000)
+ /* The registers */
+ #define QUADSPI_MCR                   0x00
+@@ -193,7 +195,7 @@
+ #define QUADSPI_LUT_NUM               64
+ /* SEQID -- we can have 16 seqids at most. */
+-#define SEQID_QUAD_READ               0
++#define SEQID_READ            0
+ #define SEQID_WREN            1
+ #define SEQID_WRDI            2
+ #define SEQID_RDSR            3
+@@ -205,15 +207,22 @@
+ #define SEQID_RDCR            9
+ #define SEQID_EN4B            10
+ #define SEQID_BRWR            11
++#define SEQID_RDAR_OR_RD_EVCR 12
++#define SEQID_WRAR            13
++#define SEQID_WD_EVCR           14
+ #define QUADSPI_MIN_IOMAP SZ_4M
++#define FLASH_VENDOR_SPANSION_FS      "s25fs"
++#define SPANSION_S25FS_FAMILY (1 << 1)
++
+ enum fsl_qspi_devtype {
+       FSL_QUADSPI_VYBRID,
+       FSL_QUADSPI_IMX6SX,
+       FSL_QUADSPI_IMX7D,
+       FSL_QUADSPI_IMX6UL,
+       FSL_QUADSPI_LS1021A,
++      FSL_QUADSPI_LS2080A,
+ };
+ struct fsl_qspi_devtype_data {
+@@ -224,7 +233,7 @@ struct fsl_qspi_devtype_data {
+       int driver_data;
+ };
+-static struct fsl_qspi_devtype_data vybrid_data = {
++static const struct fsl_qspi_devtype_data vybrid_data = {
+       .devtype = FSL_QUADSPI_VYBRID,
+       .rxfifo = 128,
+       .txfifo = 64,
+@@ -232,7 +241,7 @@ static struct fsl_qspi_devtype_data vybrid_data = {
+       .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
+ };
+-static struct fsl_qspi_devtype_data imx6sx_data = {
++static const struct fsl_qspi_devtype_data imx6sx_data = {
+       .devtype = FSL_QUADSPI_IMX6SX,
+       .rxfifo = 128,
+       .txfifo = 512,
+@@ -241,7 +250,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = {
+                      | QUADSPI_QUIRK_TKT245618,
+ };
+-static struct fsl_qspi_devtype_data imx7d_data = {
++static const struct fsl_qspi_devtype_data imx7d_data = {
+       .devtype = FSL_QUADSPI_IMX7D,
+       .rxfifo = 512,
+       .txfifo = 512,
+@@ -250,7 +259,7 @@ static struct fsl_qspi_devtype_data imx7d_data = {
+                      | QUADSPI_QUIRK_4X_INT_CLK,
+ };
+-static struct fsl_qspi_devtype_data imx6ul_data = {
++static const struct fsl_qspi_devtype_data imx6ul_data = {
+       .devtype = FSL_QUADSPI_IMX6UL,
+       .rxfifo = 128,
+       .txfifo = 512,
+@@ -267,6 +276,14 @@ static struct fsl_qspi_devtype_data ls1021a_data = {
+       .driver_data = 0,
+ };
++static struct fsl_qspi_devtype_data ls2080a_data = {
++      .devtype = FSL_QUADSPI_LS2080A,
++      .rxfifo = 128,
++      .txfifo = 64,
++      .ahb_buf_size = 1024,
++      .driver_data = QUADSPI_AMBA_BASE_INTERNAL | QUADSPI_QUIRK_TKT253890,
++};
++
+ #define FSL_QSPI_MAX_CHIP     4
+ struct fsl_qspi {
+       struct spi_nor nor[FSL_QSPI_MAX_CHIP];
+@@ -282,6 +299,7 @@ struct fsl_qspi {
+       u32 nor_size;
+       u32 nor_num;
+       u32 clk_rate;
++      u32 ddr_smp;
+       unsigned int chip_base_addr; /* We may support two chips. */
+       bool has_second_chip;
+       bool big_endian;
+@@ -309,6 +327,23 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
+       return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
+ }
++static inline int has_added_amba_base_internal(struct fsl_qspi *q)
++{
++      return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL;
++}
++
++static u32 fsl_get_nor_vendor(struct spi_nor *nor)
++{
++      u32 vendor_id;
++
++      if (nor->vendor) {
++              if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS,
++                                      sizeof(FLASH_VENDOR_SPANSION_FS) - 1))
++                      vendor_id = SPANSION_S25FS_FAMILY;
++      }
++      return vendor_id;
++}
++
+ /*
+  * R/W functions for big- or little-endian registers:
+  * The qSPI controller's endian is independent of the CPU core's endian.
+@@ -331,6 +366,31 @@ static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr)
+               return ioread32(addr);
+ }
++static inline u32 *u8tou32(u32 *dest, const u8 *src, size_t n)
++{
++      size_t i;
++      *dest = 0;
++
++      n = n > 4 ? 4 : n;
++      for (i = 0; i < n; i++)
++              *dest |= *src++ << i * 8;
++
++      return dest;
++
++}
++
++static inline u8 *u32tou8(u8 *dest, const u32 *src, size_t n)
++{
++      size_t i;
++      u8 *xdest = dest;
++
++      n = n > 4 ? 4 : n;
++      for (i = 0; i < n; i++)
++              *xdest++ = *src >> i * 8;
++
++      return dest;
++}
++
+ /*
+  * An IC bug makes us to re-arrange the 32-bit data.
+  * The following chips, such as IMX6SLX, have fixed this bug.
+@@ -373,8 +433,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+       void __iomem *base = q->iobase;
+       int rxfifo = q->devtype_data->rxfifo;
+       u32 lut_base;
+-      u8 cmd, addrlen, dummy;
+       int i;
++      u32 vendor;
++
++      struct spi_nor *nor = &q->nor[0];
++      u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
++      u8 read_op = nor->read_opcode;
++      u8 read_dm = nor->read_dummy;
++
++      vendor = fsl_get_nor_vendor(nor);
+       fsl_qspi_unlock_lut(q);
+@@ -382,25 +449,51 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+       for (i = 0; i < QUADSPI_LUT_NUM; i++)
+               qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
+-      /* Quad Read */
+-      lut_base = SEQID_QUAD_READ * 4;
+-
+-      if (q->nor_size <= SZ_16M) {
+-              cmd = SPINOR_OP_READ_1_1_4;
+-              addrlen = ADDR24BIT;
+-              dummy = 8;
+-      } else {
+-              /* use the 4-byte address */
+-              cmd = SPINOR_OP_READ_1_1_4;
+-              addrlen = ADDR32BIT;
+-              dummy = 8;
+-      }
+-
+-      qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
++      /* Read */
++      lut_base = SEQID_READ * 4;
++
++      if (nor->flash_read == SPI_NOR_FAST) {
++              qspi_writel(q, LUT0(CMD, PAD1, read_op) |
++                          LUT1(ADDR, PAD1, addrlen),
++                              base + QUADSPI_LUT(lut_base));
++              qspi_writel(q,  LUT0(DUMMY, PAD1, read_dm) |
++                          LUT1(FSL_READ, PAD1, rxfifo),
++                              base + QUADSPI_LUT(lut_base + 1));
++      } else if (nor->flash_read == SPI_NOR_QUAD) {
++              if (q->nor_size == 0x4000000) {
++                      read_op = 0xEC;
++              qspi_writel(q,
++                      LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen),
++                      base + QUADSPI_LUT(lut_base));
++              qspi_writel(q,
++                      LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm),
++                      base + QUADSPI_LUT(lut_base + 1));
++              qspi_writel(q,
++                      LUT0(FSL_READ, PAD4, rxfifo),
++                      base + QUADSPI_LUT(lut_base + 2));
++              } else {
++                      qspi_writel(q, LUT0(CMD, PAD1, read_op) |
++                                  LUT1(ADDR, PAD1, addrlen),
++                                  base + QUADSPI_LUT(lut_base));
++                      qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
++                                  LUT1(FSL_READ, PAD4, rxfifo),
++                                  base + QUADSPI_LUT(lut_base + 1));
++              }
++      } else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
++              /* read mode : 1-4-4, such as Spansion s25fl128s. */
++              qspi_writel(q, LUT0(CMD, PAD1, read_op)
++                      | LUT1(ADDR_DDR, PAD4, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+-      qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
++
++              qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff)
++                      | LUT1(DUMMY, PAD1, read_dm),
+                       base + QUADSPI_LUT(lut_base + 1));
++              qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo)
++                      | LUT1(JMP_ON_CS, PAD1, 0),
++                      base + QUADSPI_LUT(lut_base + 2));
++      }
++
+       /* Write enable */
+       lut_base = SEQID_WREN * 4;
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
+@@ -409,16 +502,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+       /* Page Program */
+       lut_base = SEQID_PP * 4;
+-      if (q->nor_size <= SZ_16M) {
+-              cmd = SPINOR_OP_PP;
+-              addrlen = ADDR24BIT;
+-      } else {
+-              /* use the 4-byte address */
+-              cmd = SPINOR_OP_PP;
+-              addrlen = ADDR32BIT;
+-      }
+-
+-      qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
++      qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) |
++                  LUT1(ADDR, PAD1, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+       qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
+                       base + QUADSPI_LUT(lut_base + 1));
+@@ -432,10 +517,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+       /* Erase a sector */
+       lut_base = SEQID_SE * 4;
+-      cmd = q->nor[0].erase_opcode;
+-      addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
+-
+-      qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
++      qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
++                  LUT1(ADDR, PAD1, addrlen),
+                       base + QUADSPI_LUT(lut_base));
+       /* Erase the whole chip */
+@@ -476,6 +559,44 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+       qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
+                       base + QUADSPI_LUT(lut_base));
++
++      /*
++       * Flash Micron and Spansion command confilict
++       * use the same value 0x65. But it indicates different meaning.
++       */
++      lut_base = SEQID_RDAR_OR_RD_EVCR * 4;
++
++      if (vendor == SPANSION_S25FS_FAMILY) {
++              /*
++              * Read any device register.
++              * Used for Spansion S25FS-S family flash only.
++              */
++              qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_RDAR) |
++                          LUT1(ADDR, PAD1, ADDR24BIT),
++                          base + QUADSPI_LUT(lut_base));
++              qspi_writel(q, LUT0(DUMMY, PAD1, 8) | LUT1(FSL_READ, PAD1, 1),
++                          base + QUADSPI_LUT(lut_base + 1));
++      } else {
++              qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR),
++                          base + QUADSPI_LUT(lut_base));
++      }
++
++      /*
++       * Write any device register.
++       * Used for Spansion S25FS-S family flash only.
++       */
++      lut_base = SEQID_WRAR * 4;
++      qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_WRAR) |
++                      LUT1(ADDR, PAD1, ADDR24BIT),
++                      base + QUADSPI_LUT(lut_base));
++      qspi_writel(q, LUT0(FSL_WRITE, PAD1, 1),
++                      base + QUADSPI_LUT(lut_base + 1));
++
++      /* Write EVCR register */
++      lut_base = SEQID_WD_EVCR * 4;
++      qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR),
++                  base + QUADSPI_LUT(lut_base));
++
+       fsl_qspi_lock_lut(q);
+ }
+@@ -483,8 +604,24 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
+ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+ {
+       switch (cmd) {
++      case SPINOR_OP_READ_1_4_4_D:
++      case SPINOR_OP_READ4_1_4_4_D:
++      case SPINOR_OP_READ4_1_1_4:
+       case SPINOR_OP_READ_1_1_4:
+-              return SEQID_QUAD_READ;
++      case SPINOR_OP_READ_FAST:
++      case SPINOR_OP_READ4_FAST:
++              return SEQID_READ;
++      /*
++       * Spansion & Micron use the same command value 0x65
++       * Spansion: SPINOR_OP_SPANSION_RDAR, read any register.
++       * Micron: SPINOR_OP_RD_EVCR,
++       * read enhanced volatile configuration register.
++       * case SPINOR_OP_RD_EVCR:
++       */
++      case SPINOR_OP_SPANSION_RDAR:
++              return SEQID_RDAR_OR_RD_EVCR;
++      case SPINOR_OP_SPANSION_WRAR:
++              return SEQID_WRAR;
+       case SPINOR_OP_WREN:
+               return SEQID_WREN;
+       case SPINOR_OP_WRDI:
+@@ -496,6 +633,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+       case SPINOR_OP_CHIP_ERASE:
+               return SEQID_CHIP_ERASE;
+       case SPINOR_OP_PP:
++      case SPINOR_OP_PP_4B:
+               return SEQID_PP;
+       case SPINOR_OP_RDID:
+               return SEQID_RDID;
+@@ -507,6 +645,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+               return SEQID_EN4B;
+       case SPINOR_OP_BRWR:
+               return SEQID_BRWR;
++      case SPINOR_OP_WD_EVCR:
++              return SEQID_WD_EVCR;
+       default:
+               if (cmd == q->nor[0].erase_opcode)
+                       return SEQID_SE;
+@@ -531,8 +671,11 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
+       /* save the reg */
+       reg = qspi_readl(q, base + QUADSPI_MCR);
+-      qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
+-                      base + QUADSPI_SFAR);
++      if (has_added_amba_base_internal(q))
++              qspi_writel(q, q->chip_base_addr + addr, base + QUADSPI_SFAR);
++      else
++              qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
++                          base + QUADSPI_SFAR);
+       qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+                       base + QUADSPI_RBCT);
+       qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
+@@ -582,10 +725,10 @@ static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
+                               q->chip_base_addr, tmp);
+               if (len >= 4) {
+-                      *((u32 *)rxbuf) = tmp;
++                      u32tou8(rxbuf, &tmp, 4);
+                       rxbuf += 4;
+               } else {
+-                      memcpy(rxbuf, &tmp, len);
++                      u32tou8(rxbuf, &tmp, len);
+                       break;
+               }
+@@ -619,11 +762,12 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
+ }
+ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+-                              u8 opcode, unsigned int to, u32 *txbuf,
++                              u8 opcode, unsigned int to, u8 *txbuf,
+                               unsigned count)
+ {
+       int ret, i, j;
+       u32 tmp;
++      u8 byts;
+       dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
+               q->chip_base_addr, to, count);
+@@ -633,10 +777,13 @@ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+       qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
+       /* fill the TX data to the FIFO */
++      byts = count;
+       for (j = 0, i = ((count + 3) / 4); j < i; j++) {
+-              tmp = fsl_qspi_endian_xchg(q, *txbuf);
++              u8tou32(&tmp, txbuf, byts);
++              tmp = fsl_qspi_endian_xchg(q, tmp);
+               qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
+-              txbuf++;
++              txbuf += 4;
++              byts -= 4;
+       }
+       /* fill the TXFIFO upto 16 bytes for i.MX7d */
+@@ -657,11 +804,43 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
+ {
+       int nor_size = q->nor_size;
+       void __iomem *base = q->iobase;
++      u32 mem_base;
++
++      if (has_added_amba_base_internal(q))
++              mem_base = 0x0;
++      else
++              mem_base = q->memmap_phy;
++
++      qspi_writel(q, nor_size + mem_base, base + QUADSPI_SFA1AD);
++      qspi_writel(q, nor_size * 2 + mem_base, base + QUADSPI_SFA2AD);
++      qspi_writel(q, nor_size * 3 + mem_base, base + QUADSPI_SFB1AD);
++      qspi_writel(q, nor_size * 4 + mem_base, base + QUADSPI_SFB2AD);
++}
++
++/*
++ * enable controller ddr quad mode to support different
++ * vender flashes ddr quad mode.
++ */
++static void set_ddr_quad_mode(struct fsl_qspi *q)
++{
++      u32 reg, reg2;
++
++      reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
++
++      /* Firstly, disable the module */
++      qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
++
++      /* Set the Sampling Register for DDR */
++      reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR);
++      reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK;
++      reg2 |= (((q->ddr_smp) << QUADSPI_SMPR_DDRSMP_SHIFT) &
++                      QUADSPI_SMPR_DDRSMP_MASK);
++      qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR);
++
++      /* Enable the module again (enable the DDR too) */
++      reg |= QUADSPI_MCR_DDR_EN_MASK;
++      qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
+-      qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
+-      qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
+-      qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
+-      qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
+ }
+ /*
+@@ -681,19 +860,36 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+ {
+       void __iomem *base = q->iobase;
+       int seqid;
++      const struct fsl_qspi_devtype_data *devtype_data = q->devtype_data;
+       /* AHB configuration for access buffer 0/1/2 .*/
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+       qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
++
+       /*
+-       * Set ADATSZ with the maximum AHB buffer size to improve the
+-       * read performance.
++       * Errata: A-009282: QuadSPI data prefetch may result in incorrect data
++       * Workaround: Keep the read data size to 64 bits (8 bytes).
++       * This disables the prefetch on the AHB buffer and
++       * prevents this issue from occurring.
+        */
+-      qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
+-                      ((q->devtype_data->ahb_buf_size / 8)
+-                      << QUADSPI_BUF3CR_ADATSZ_SHIFT),
+-                      base + QUADSPI_BUF3CR);
++      if (devtype_data->devtype == FSL_QUADSPI_LS2080A ||
++          devtype_data->devtype == FSL_QUADSPI_LS1021A) {
++
++              qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
++                              (1 << QUADSPI_BUF3CR_ADATSZ_SHIFT),
++                              base + QUADSPI_BUF3CR);
++
++      } else {
++              /*
++               * Set ADATSZ with the maximum AHB buffer size to improve the
++               * read performance.
++              */
++              qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
++                              ((q->devtype_data->ahb_buf_size / 8)
++                              << QUADSPI_BUF3CR_ADATSZ_SHIFT),
++                              base + QUADSPI_BUF3CR);
++      }
+       /* We only use the buffer3 */
+       qspi_writel(q, 0, base + QUADSPI_BUF0IND);
+@@ -704,6 +900,11 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+       seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+       qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+               q->iobase + QUADSPI_BFGENCR);
++
++      /* enable the DDR quad read */
++      if (q->nor->flash_read == SPI_NOR_DDR_QUAD)
++              set_ddr_quad_mode(q);
++
+ }
+ /* This function was used to prepare and enable QSPI clock */
+@@ -822,6 +1023,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
+       { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
+       { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
+       { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
++      { .compatible = "fsl,ls2080a-qspi", .data = (void *)&ls2080a_data, },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
+@@ -835,8 +1037,12 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+       int ret;
+       struct fsl_qspi *q = nor->priv;
++      u32 to = 0;
++
++      if (opcode == SPINOR_OP_SPANSION_RDAR)
++              u8tou32(&to, nor->cmd_buf, 4);
+-      ret = fsl_qspi_runcmd(q, opcode, 0, len);
++      ret = fsl_qspi_runcmd(q, opcode, to, len);
+       if (ret)
+               return ret;
+@@ -848,9 +1054,13 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+       struct fsl_qspi *q = nor->priv;
+       int ret;
++      u32 to = 0;
++
++      if (opcode == SPINOR_OP_SPANSION_WRAR)
++              u8tou32(&to, nor->cmd_buf, 4);
+       if (!buf) {
+-              ret = fsl_qspi_runcmd(q, opcode, 0, 1);
++              ret = fsl_qspi_runcmd(q, opcode, to, 1);
+               if (ret)
+                       return ret;
+@@ -859,7 +1069,7 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+       } else if (len > 0) {
+               ret = fsl_qspi_nor_write(q, nor, opcode, 0,
+-                                      (u32 *)buf, len);
++                                      buf, len);
+               if (ret > 0)
+                       return 0;
+       } else {
+@@ -875,7 +1085,7 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
+ {
+       struct fsl_qspi *q = nor->priv;
+       ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+-                                       (u32 *)buf, len);
++                                       (u8 *)buf, len);
+       /* invalid the data in the AHB buffer. */
+       fsl_qspi_invalid(q);
+@@ -922,7 +1132,7 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
+               len);
+       /* Read out the data directly from the AHB buffer.*/
+-      memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
++      memcpy_toio(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
+               len);
+       return len;
+@@ -980,6 +1190,8 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+       struct spi_nor *nor;
+       struct mtd_info *mtd;
+       int ret, i = 0;
++      int find_node;
++      enum read_mode mode = SPI_NOR_QUAD;
+       q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
+       if (!q)
+@@ -1027,6 +1239,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+               goto clk_failed;
+       }
++      /* find ddrsmp value */
++      ret = of_property_read_u32(dev->of_node, "fsl,ddr-sampling-point",
++                              &q->ddr_smp);
++      if (ret)
++              q->ddr_smp = 0;
++
+       /* find the irq */
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+@@ -1050,6 +1268,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+       mutex_init(&q->lock);
++      find_node = 0;
+       /* iterate the subnodes. */
+       for_each_available_child_of_node(dev->of_node, np) {
+               /* skip the holes */
+@@ -1076,18 +1295,25 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+               ret = of_property_read_u32(np, "spi-max-frequency",
+                               &q->clk_rate);
+               if (ret < 0)
+-                      goto mutex_failed;
++                      continue;
+               /* set the chip address for READID */
+               fsl_qspi_set_base_addr(q, nor);
+-              ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
++              ret = of_property_read_bool(np, "m25p,fast-read");
++              mode = (ret) ? SPI_NOR_FAST : SPI_NOR_QUAD;
++              /* Can we enable the DDR Quad Read? */
++              ret = of_property_read_bool(np, "ddr-quad-read");
+               if (ret)
+-                      goto mutex_failed;
++                      mode = SPI_NOR_DDR_QUAD;
++
++              ret = spi_nor_scan(nor, NULL, mode);
++              if (ret)
++                      continue;
+               ret = mtd_device_register(mtd, NULL, 0);
+               if (ret)
+-                      goto mutex_failed;
++                      continue;
+               /* Set the correct NOR size now. */
+               if (q->nor_size == 0) {
+@@ -1110,8 +1336,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+                       nor->page_size = q->devtype_data->txfifo;
+               i++;
++              find_node++;
+       }
++      if (find_node == 0)
++              goto mutex_failed;
++
+       /* finish the rest init. */
+       ret = fsl_qspi_nor_setup_last(q);
+       if (ret)
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 793d321d..190e0e45 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -40,6 +40,13 @@
+ #define SPI_NOR_MAX_ID_LEN    6
+ #define SPI_NOR_MAX_ADDR_WIDTH        4
++#define SPI_NOR_MICRON_WRITE_ENABLE    0x7f
++/* Added for S25FS-S family flash */
++#define SPINOR_CONFIG_REG3_OFFSET      0x800004
++#define CR3V_4KB_ERASE_UNABLE  0x8
++#define SPINOR_S25FS_FAMILY_ID 0x81
++
++
+ struct flash_info {
+       char            *name;
+@@ -68,7 +75,8 @@ struct flash_info {
+ #define SECT_4K_PMC           BIT(4)  /* SPINOR_OP_BE_4K_PMC works uniformly */
+ #define SPI_NOR_DUAL_READ     BIT(5)  /* Flash supports Dual Read */
+ #define SPI_NOR_QUAD_READ     BIT(6)  /* Flash supports Quad Read */
+-#define USE_FSR                       BIT(7)  /* use flag status register */
++#define USE_FSR                       BIT(13) /* use flag status register */
++#define SPI_NOR_DDR_QUAD_READ BIT(7)  /* Flash supports DDR Quad Read */
+ #define SPI_NOR_HAS_LOCK      BIT(8)  /* Flash supports lock/unlock via SR */
+ #define SPI_NOR_HAS_TB                BIT(9)  /*
+                                        * Flash SR has Top/Bottom (TB) protect
+@@ -85,9 +93,11 @@ struct flash_info {
+                                        * Use dedicated 4byte address op codes
+                                        * to support memory size above 128Mib.
+                                        */
++#define NO_CHIP_ERASE         BIT(12) /* Chip does not support chip erase */
+ };
+ #define JEDEC_MFR(info)       ((info)->id[0])
++#define EXT_ID(info)  ((info)->id[5])
+ static const struct flash_info *spi_nor_match_id(const char *name);
+@@ -132,7 +142,7 @@ static int read_fsr(struct spi_nor *nor)
+ /*
+  * Read configuration register, returning its value in the
+  * location. Return the configuration register value.
+- * Returns negative if error occured.
++ * Returns negative if error occurred.
+  */
+ static int read_cr(struct spi_nor *nor)
+ {
+@@ -160,6 +170,8 @@ static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+       case SPI_NOR_DUAL:
+       case SPI_NOR_QUAD:
+               return 8;
++      case SPI_NOR_DDR_QUAD:
++              return 6;
+       case SPI_NOR_NORMAL:
+               return 0;
+       }
+@@ -961,6 +973,8 @@ static const struct flash_info spi_nor_ids[] = {
+       /* ESMT */
+       { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
++      { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
++      { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) },
+       /* Everspin */
+       { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+@@ -1014,12 +1028,15 @@ static const struct flash_info spi_nor_ids[] = {
+       { "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
+       { "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+       { "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
++      { "mx25u2033e",  INFO(0xc22532, 0, 64 * 1024,   4, SECT_4K) },
++      { "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
++      { "mx25u8035",   INFO(0xc22534, 0, 64 * 1024,  16, SECT_4K) },
+       { "mx25u3235f",  INFO(0xc22536, 0, 64 * 1024, 64, 0) },
+       { "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+       { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+       { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+-      { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
++      { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
+       { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+       { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
+@@ -1033,10 +1050,11 @@ static const struct flash_info spi_nor_ids[] = {
+       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
++      { "n25q256ax1",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+       { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+-      { "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+-      { "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
++      { "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
++      { "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+       /* PMC */
+       { "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
+@@ -1054,8 +1072,11 @@ static const struct flash_info spi_nor_ids[] = {
+       { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
+       { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
+       { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
+-      { "s25fl128s",  INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++      { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)},
++      { "s25fl128s",  INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ
++                      | SPI_NOR_DDR_QUAD_READ) },
+       { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++      { "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)},
+       { "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
+       { "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
+@@ -1130,6 +1151,9 @@ static const struct flash_info spi_nor_ids[] = {
+       { "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
+       { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
++      { "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
++      { "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
++      { "w25q20ew", INFO(0xef6012, 0, 64 * 1024,  4, SECT_4K) },
+       { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+       {
+               "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
+@@ -1192,6 +1216,53 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+               id[0], id[1], id[2]);
+       return ERR_PTR(-ENODEV);
+ }
++/*
++ * The S25FS-S family physical sectors may be configured as a
++ * hybrid combination of eight 4-kB parameter sectors
++ * at the top or bottom of the address space with all
++ * but one of the remaining sectors being uniform size.
++ * The Parameter Sector Erase commands (20h or 21h) must
++ * be used to erase the 4-kB parameter sectors individually.
++ * The Sector (uniform sector) Erase commands (D8h or DCh)
++ * must be used to erase any of the remaining
++ * sectors, including the portion of highest or lowest address
++ * sector that is not overlaid by the parameter sectors.
++ * The uniform sector erase command has no effect on parameter sectors.
++ */
++static int spansion_s25fs_disable_4kb_erase(struct spi_nor *nor)
++{
++      struct fsl_qspi *q;
++      u32 cr3v_addr  = SPINOR_CONFIG_REG3_OFFSET;
++      u8 cr3v = 0x0;
++      int ret = 0x0;
++
++      q = nor->priv;
++
++      nor->cmd_buf[2] = cr3v_addr >> 16;
++      nor->cmd_buf[1] = cr3v_addr >> 8;
++      nor->cmd_buf[0] = cr3v_addr >> 0;
++
++      ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
++      if (ret)
++              return ret;
++      if (cr3v & CR3V_4KB_ERASE_UNABLE)
++              return 0;
++      ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
++      if (ret)
++              return ret;
++      cr3v = CR3V_4KB_ERASE_UNABLE;
++      nor->program_opcode = SPINOR_OP_SPANSION_WRAR;
++      nor->write(nor, cr3v_addr, 1, &cr3v);
++
++      ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
++      if (ret)
++              return ret;
++      if (!(cr3v & CR3V_4KB_ERASE_UNABLE))
++              return -EPERM;
++
++      return 0;
++}
++
+ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
+@@ -1411,7 +1482,7 @@ static int macronix_quad_enable(struct spi_nor *nor)
+  * Write status Register and configuration register with 2 bytes
+  * The first byte will be written to the status register, while the
+  * second byte will be written to the configuration register.
+- * Return negative if error occured.
++ * Return negative if error occurred.
+  */
+ static int write_sr_cr(struct spi_nor *nor, u16 val)
+ {
+@@ -1459,6 +1530,24 @@ static int spansion_quad_enable(struct spi_nor *nor)
+       return 0;
+ }
++static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
++{
++      int status;
++
++      switch (JEDEC_MFR(info)) {
++      case SNOR_MFR_SPANSION:
++              status = spansion_quad_enable(nor);
++              if (status) {
++                      dev_err(nor->dev, "Spansion DDR quad-read not enabled\n");
++                      return status;
++              }
++              return status;
++      default:
++              return -EINVAL;
++      }
++}
++
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+       int status;
+@@ -1604,9 +1693,25 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+               write_sr(nor, 0);
+               spi_nor_wait_till_ready(nor);
+       }
++      if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
++              ret = read_sr(nor);
++              ret &= SPI_NOR_MICRON_WRITE_ENABLE;
++
++              write_enable(nor);
++              write_sr(nor, ret);
++      }
++
++      if (EXT_ID(info) == SPINOR_S25FS_FAMILY_ID) {
++              ret = spansion_s25fs_disable_4kb_erase(nor);
++              if (ret)
++                      return ret;
++      }
++
+       if (!mtd->name)
+               mtd->name = dev_name(dev);
++      if (info->name)
++              nor->vendor = info->name;
+       mtd->priv = nor;
+       mtd->type = MTD_NORFLASH;
+       mtd->writesize = 1;
+@@ -1639,6 +1744,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+               nor->flags |= SNOR_F_USE_FSR;
+       if (info->flags & SPI_NOR_HAS_TB)
+               nor->flags |= SNOR_F_HAS_SR_TB;
++      if (info->flags & NO_CHIP_ERASE)
++              nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
+ #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+       /* prefer "small sector" erase if possible */
+@@ -1676,9 +1783,15 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+       /* Some devices cannot do fast-read, no matter what DT tells us */
+       if (info->flags & SPI_NOR_NO_FR)
+               nor->flash_read = SPI_NOR_NORMAL;
+-
+-      /* Quad/Dual-read mode takes precedence over fast/normal */
+-      if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
++      /* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
++      if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
++              ret = set_ddr_quad_mode(nor, info);
++              if (ret) {
++                      dev_err(dev, "DDR quad mode not supported\n");
++                      return ret;
++              }
++              nor->flash_read = SPI_NOR_DDR_QUAD;
++      } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+               ret = set_quad_mode(nor, info);
+               if (ret) {
+                       dev_err(dev, "quad mode not supported\n");
+@@ -1691,6 +1804,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+       /* Default commands */
+       switch (nor->flash_read) {
++      case SPI_NOR_DDR_QUAD:
++              nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
++              break;
+       case SPI_NOR_QUAD:
+               nor->read_opcode = SPINOR_OP_READ_1_1_4;
+               break;
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index f2a71803..5003ff64 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -31,10 +31,10 @@
+ /*
+  * Note on opcode nomenclature: some opcodes have a format like
+- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
++ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number
+  * of I/O lines used for the opcode, address, and data (respectively). The
+  * FUNCTION has an optional suffix of '4', to represent an opcode which
+- * requires a 4-byte (32-bit) address.
++ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
+  */
+ /* Flash opcodes. */
+@@ -46,7 +46,9 @@
+ #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 Output SPI) */
++#define SPINOR_OP_READ_1_4_4_D        0xed    /* Read data bytes (DDR Quad SPI) */
+ #define SPINOR_OP_READ_1_4_4  0xeb    /* Read data bytes (Quad I/O SPI) */
++#define SPINOR_OP_READ4_1_4_4_D       0xee    /* Read data bytes (DDR Quad SPI) */
+ #define SPINOR_OP_PP          0x02    /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_PP_1_1_4    0x32    /* Quad page program */
+ #define SPINOR_OP_PP_1_4_4    0x38    /* Quad page program */
+@@ -62,9 +64,11 @@
+ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+ #define SPINOR_OP_READ_4B     0x13    /* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ_FAST_4B        0x0c    /* Read data bytes (high frequency) */
++#define SPINOR_OP_READ4_FAST    0x0c    /* Read data bytes (high frequency) */
+ #define SPINOR_OP_READ_1_1_2_4B       0x3c    /* Read data bytes (Dual Output SPI) */
+ #define SPINOR_OP_READ_1_2_2_4B       0xbc    /* Read data bytes (Dual I/O SPI) */
+ #define SPINOR_OP_READ_1_1_4_4B       0x6c    /* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ4_1_1_4  0x6c    /* Read data bytes (Quad SPI) */
+ #define SPINOR_OP_READ_1_4_4_4B       0xec    /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B               0x12    /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_PP_1_1_4_4B 0x34    /* Quad page program */
+@@ -94,6 +98,10 @@
+ /* Used for Spansion flashes only. */
+ #define SPINOR_OP_BRWR                0x17    /* Bank register write */
++/* Used for Spansion S25FS-S family flash only. */
++#define SPINOR_OP_SPANSION_RDAR       0x65    /* Read any device register */
++#define SPINOR_OP_SPANSION_WRAR       0x71    /* Write any device register */
++
+ /* Used for Micron flashes only. */
+ #define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
+ #define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
+@@ -124,6 +132,7 @@ enum read_mode {
+       SPI_NOR_FAST,
+       SPI_NOR_DUAL,
+       SPI_NOR_QUAD,
++      SPI_NOR_DDR_QUAD,
+ };
+ #define SPI_NOR_MAX_CMD_SIZE  8
+@@ -189,6 +198,7 @@ struct spi_nor {
+       bool                    sst_write_second;
+       u32                     flags;
+       u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
++      char                    *vendor;
+       int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+       void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+-- 
+2.14.1
+