configs: Migrate CONFIG_SYS_MAX_FLASH_BANKS to Kconfig
[platform/kernel/u-boot.git] / drivers / mtd / spi / spi-nor-core.c
index 24c6b8c..a70fbda 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <flash.h>
 #include <log.h>
 #include <watchdog.h>
 #include <dm.h>
 #include <linux/log2.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/spi-nor.h>
+#include <mtd/cfi_flash.h>
 #include <spi-mem.h>
 #include <spi.h>
 
@@ -40,6 +44,8 @@
 
 #define DEFAULT_READY_WAIT_JIFFIES             (40UL * HZ)
 
+#define ROUND_UP_TO(x, y)      (((x) + (y) - 1) / (y) * (y))
+
 struct sfdp_parameter_header {
        u8              id_lsb;
        u8              minor;
@@ -58,6 +64,7 @@ struct sfdp_parameter_header {
 #define SFDP_BFPT_ID           0xff00  /* Basic Flash Parameter Table */
 #define SFDP_SECTOR_MAP_ID     0xff81  /* Sector Map Table */
 #define SFDP_SST_ID            0x01bf  /* Manufacturer specific Table */
+#define SFDP_PROFILE1_ID       0xff05  /* xSPI Profile 1.0 Table */
 
 #define SFDP_SIGNATURE         0x50444653U
 #define SFDP_JESD216_MAJOR     1
@@ -79,14 +86,15 @@ struct sfdp_header {
 /* Basic Flash Parameter Table */
 
 /*
- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
+ * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
  * They are indexed from 1 but C arrays are indexed from 0.
  */
 #define BFPT_DWORD(i)          ((i) - 1)
-#define BFPT_DWORD_MAX         16
+#define BFPT_DWORD_MAX         20
 
 /* The first version of JESB216 defined only 9 DWORDs. */
 #define BFPT_DWORD_MAX_JESD216                 9
+#define BFPT_DWORD_MAX_JESD216B                        16
 
 /* 1st DWORD. */
 #define BFPT_DWORD1_FAST_READ_1_1_2            BIT(16)
@@ -148,6 +156,24 @@ struct sfdp_header {
 #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD                (0x4UL << 20)
 #define BFPT_DWORD15_QER_SR2_BIT1              (0x5UL << 20) /* Spansion */
 
+#define BFPT_DWORD16_SOFT_RST                  BIT(12)
+
+#define BFPT_DWORD18_CMD_EXT_MASK              GENMASK(30, 29)
+#define BFPT_DWORD18_CMD_EXT_REP               (0x0UL << 29) /* Repeat */
+#define BFPT_DWORD18_CMD_EXT_INV               (0x1UL << 29) /* Invert */
+#define BFPT_DWORD18_CMD_EXT_RES               (0x2UL << 29) /* Reserved */
+#define BFPT_DWORD18_CMD_EXT_16B               (0x3UL << 29) /* 16-bit opcode */
+
+/* xSPI Profile 1.0 table (from JESD216D.01). */
+#define PROFILE1_DWORD1_RD_FAST_CMD            GENMASK(15, 8)
+#define PROFILE1_DWORD1_RDSR_DUMMY             BIT(28)
+#define PROFILE1_DWORD1_RDSR_ADDR_BYTES                BIT(29)
+#define PROFILE1_DWORD4_DUMMY_200MHZ           GENMASK(11, 7)
+#define PROFILE1_DWORD5_DUMMY_166MHZ           GENMASK(31, 27)
+#define PROFILE1_DWORD5_DUMMY_133MHZ           GENMASK(21, 17)
+#define PROFILE1_DWORD5_DUMMY_100MHZ           GENMASK(11, 7)
+#define PROFILE1_DUMMY_DEFAULT                 20
+
 struct sfdp_bfpt {
        u32     dwords[BFPT_DWORD_MAX];
 };
@@ -177,6 +203,78 @@ struct spi_nor_fixups {
                          struct spi_nor_flash_parameter *params);
 };
 
+#define SPI_NOR_SRST_SLEEP_LEN                 200
+
+/**
+ * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
+ *                        extension type.
+ * @nor:               pointer to a 'struct spi_nor'
+ * @op:                        pointer to the 'struct spi_mem_op' whose properties
+ *                     need to be initialized.
+ *
+ * Right now, only "repeat" and "invert" are supported.
+ *
+ * Return: The opcode extension.
+ */
+static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
+                             const struct spi_mem_op *op)
+{
+       switch (nor->cmd_ext_type) {
+       case SPI_NOR_EXT_INVERT:
+               return ~op->cmd.opcode;
+
+       case SPI_NOR_EXT_REPEAT:
+               return op->cmd.opcode;
+
+       default:
+               dev_dbg(nor->dev, "Unknown command extension type\n");
+               return 0;
+       }
+}
+
+/**
+ * spi_nor_setup_op() - Set up common properties of a spi-mem op.
+ * @nor:               pointer to a 'struct spi_nor'
+ * @op:                        pointer to the 'struct spi_mem_op' whose properties
+ *                     need to be initialized.
+ * @proto:             the protocol from which the properties need to be set.
+ */
+static void spi_nor_setup_op(const struct spi_nor *nor,
+                            struct spi_mem_op *op,
+                            const enum spi_nor_protocol proto)
+{
+       u8 ext;
+
+       op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
+
+       if (op->addr.nbytes)
+               op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+       if (op->dummy.nbytes)
+               op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+       if (op->data.nbytes)
+               op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
+
+       if (spi_nor_protocol_is_dtr(proto)) {
+               /*
+                * spi-mem supports mixed DTR modes, but right now we can only
+                * have all phases either DTR or STR. IOW, spi-mem can have
+                * something like 4S-4D-4D, but spi-nor can't. So, set all 4
+                * phases to either DTR or STR.
+                */
+               op->cmd.dtr = op->addr.dtr = op->dummy.dtr =
+                       op->data.dtr = true;
+
+               /* 2 bytes per clock cycle in DTR mode. */
+               op->dummy.nbytes *= 2;
+
+               ext = spi_nor_get_cmd_ext(nor, op);
+               op->cmd.opcode = (op->cmd.opcode << 8) | ext;
+               op->cmd.nbytes = 2;
+       }
+}
+
 static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
                *op, void *buf)
 {
@@ -189,12 +287,14 @@ static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
 
 static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
-       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
+       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 0),
                                          SPI_MEM_OP_NO_ADDR,
                                          SPI_MEM_OP_NO_DUMMY,
-                                         SPI_MEM_OP_DATA_IN(len, NULL, 1));
+                                         SPI_MEM_OP_DATA_IN(len, NULL, 0));
        int ret;
 
+       spi_nor_setup_op(nor, &op, nor->reg_proto);
+
        ret = spi_nor_read_write_reg(nor, &op, val);
        if (ret < 0)
                dev_dbg(nor->dev, "error %d reading %x\n", ret, code);
@@ -204,33 +304,61 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 
 static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
-       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
+       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),
                                          SPI_MEM_OP_NO_ADDR,
                                          SPI_MEM_OP_NO_DUMMY,
-                                         SPI_MEM_OP_DATA_OUT(len, NULL, 1));
+                                         SPI_MEM_OP_DATA_OUT(len, NULL, 0));
+
+       spi_nor_setup_op(nor, &op, nor->reg_proto);
+
+       if (len == 0)
+               op.data.dir = SPI_MEM_NO_DATA;
 
        return spi_nor_read_write_reg(nor, &op, buf);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy,
+                                u8 *val)
+{
+       struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1),
+                                  SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+                                  SPI_MEM_OP_DUMMY(dummy / 8, 1),
+                                  SPI_MEM_OP_DATA_IN(1, NULL, 1));
+
+       return spi_nor_read_write_reg(nor, &op, val);
+}
+
+static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val)
+{
+       struct spi_mem_op op =
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1),
+                                  SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+                                  SPI_MEM_OP_NO_DUMMY,
+                                  SPI_MEM_OP_DATA_OUT(1, NULL, 1));
+
+       return spi_nor_read_write_reg(nor, &op, &val);
+}
+#endif
+
 static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
                                 u_char *buf)
 {
        struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
-                                  SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
-                                  SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
-                                  SPI_MEM_OP_DATA_IN(len, buf, 1));
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
+                                  SPI_MEM_OP_ADDR(nor->addr_width, from, 0),
+                                  SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
+                                  SPI_MEM_OP_DATA_IN(len, buf, 0));
        size_t remaining = len;
        int ret;
 
-       /* get transfer protocols. */
-       op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
-       op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
-       op.dummy.buswidth = op.addr.buswidth;
-       op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+       spi_nor_setup_op(nor, &op, nor->read_proto);
 
        /* convert the dummy cycles to the number of bytes */
        op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+       if (spi_nor_protocol_is_dtr(nor->read_proto))
+               op.dummy.nbytes *= 2;
 
        while (remaining) {
                op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
@@ -254,20 +382,17 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
                                  const u_char *buf)
 {
        struct spi_mem_op op =
-                       SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
-                                  SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
+                       SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
+                                  SPI_MEM_OP_ADDR(nor->addr_width, to, 0),
                                   SPI_MEM_OP_NO_DUMMY,
-                                  SPI_MEM_OP_DATA_OUT(len, buf, 1));
+                                  SPI_MEM_OP_DATA_OUT(len, buf, 0));
        int ret;
 
-       /* get transfer protocols. */
-       op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
-       op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
-       op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
-
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
                op.addr.nbytes = 0;
 
+       spi_nor_setup_op(nor, &op, nor->write_proto);
+
        ret = spi_mem_adjust_op_size(nor->spi, &op);
        if (ret)
                return ret;
@@ -287,16 +412,40 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
  */
 static int read_sr(struct spi_nor *nor)
 {
+       struct spi_mem_op op;
        int ret;
-       u8 val;
+       u8 val[2];
+       u8 addr_nbytes, dummy;
+
+       if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+               addr_nbytes = nor->rdsr_addr_nbytes;
+               dummy = nor->rdsr_dummy;
+       } else {
+               addr_nbytes = 0;
+               dummy = 0;
+       }
+
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 0),
+                                          SPI_MEM_OP_ADDR(addr_nbytes, 0, 0),
+                                          SPI_MEM_OP_DUMMY(dummy, 0),
+                                          SPI_MEM_OP_DATA_IN(1, NULL, 0));
 
-       ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
+       spi_nor_setup_op(nor, &op, nor->reg_proto);
+
+       /*
+        * We don't want to read only one byte in DTR mode. So, read 2 and then
+        * discard the second byte.
+        */
+       if (spi_nor_protocol_is_dtr(nor->reg_proto))
+               op.data.nbytes = 2;
+
+       ret = spi_nor_read_write_reg(nor, &op, val);
        if (ret < 0) {
                pr_debug("error %d reading SR\n", (int)ret);
                return ret;
        }
 
-       return val;
+       return *val;
 }
 
 /*
@@ -306,16 +455,40 @@ static int read_sr(struct spi_nor *nor)
  */
 static int read_fsr(struct spi_nor *nor)
 {
+       struct spi_mem_op op;
        int ret;
-       u8 val;
+       u8 val[2];
+       u8 addr_nbytes, dummy;
+
+       if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+               addr_nbytes = nor->rdsr_addr_nbytes;
+               dummy = nor->rdsr_dummy;
+       } else {
+               addr_nbytes = 0;
+               dummy = 0;
+       }
+
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
+                                          SPI_MEM_OP_ADDR(addr_nbytes, 0, 0),
+                                          SPI_MEM_OP_DUMMY(dummy, 0),
+                                          SPI_MEM_OP_DATA_IN(1, NULL, 0));
+
+       spi_nor_setup_op(nor, &op, nor->reg_proto);
 
-       ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
+       /*
+        * We don't want to read only one byte in DTR mode. So, read 2 and then
+        * discard the second byte.
+        */
+       if (spi_nor_protocol_is_dtr(nor->reg_proto))
+               op.data.nbytes = 2;
+
+       ret = spi_nor_read_write_reg(nor, &op, val);
        if (ret < 0) {
                pr_debug("error %d reading FSR\n", ret);
                return ret;
        }
 
-       return val;
+       return *val;
 }
 
 /*
@@ -491,6 +664,9 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
                }
 
                return status;
+       case SNOR_MFR_CYPRESS:
+               cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B_CYPRESS;
+               return nor->write_reg(nor, cmd, NULL, 0);
        default:
                /* Spansion style */
                nor->cmd_buf[0] = enable << 7;
@@ -498,6 +674,35 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
        }
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/*
+ * Read status register 1 by using Read Any Register command to support multi
+ * die package parts.
+ */
+static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy)
+{
+       u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V;
+       u8 sr;
+       int ret;
+
+       ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr);
+       if (ret < 0)
+               return ret;
+
+       if (sr & (SR_E_ERR | SR_P_ERR)) {
+               if (sr & SR_E_ERR)
+                       dev_dbg(nor->dev, "Erase Error occurred\n");
+               else
+                       dev_dbg(nor->dev, "Programming Error occurred\n");
+
+               nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
+               return -EIO;
+       }
+
+       return !(sr & SR_WIP);
+}
+#endif
+
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
        int sr = read_sr(nor);
@@ -542,7 +747,7 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
        return fsr & FSR_READY;
 }
 
-static int spi_nor_ready(struct spi_nor *nor)
+static int spi_nor_default_ready(struct spi_nor *nor)
 {
        int sr, fsr;
 
@@ -555,6 +760,14 @@ static int spi_nor_ready(struct spi_nor *nor)
        return sr && fsr;
 }
 
+static int spi_nor_ready(struct spi_nor *nor)
+{
+       if (nor->ready)
+               return nor->ready(nor);
+
+       return spi_nor_default_ready(nor);
+}
+
 /*
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
@@ -660,15 +873,19 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info)
 #endif
 
 /*
- * Initiate the erasure of a single sector
+ * Initiate the erasure of a single sector. Returns the number of bytes erased
+ * on success, a negative error code on error.
  */
 static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 {
        struct spi_mem_op op =
-               SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
-                          SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+               SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0),
+                          SPI_MEM_OP_ADDR(nor->addr_width, addr, 0),
                           SPI_MEM_OP_NO_DUMMY,
                           SPI_MEM_OP_NO_DATA);
+       int ret;
+
+       spi_nor_setup_op(nor, &op, nor->write_proto);
 
        if (nor->erase)
                return nor->erase(nor, addr);
@@ -677,7 +894,11 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
         * Default implementation, if driver doesn't have a specialized HW
         * control
         */
-       return spi_mem_exec_op(nor->spi, &op);
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret)
+               return ret;
+
+       return nor->mtd.erasesize;
 }
 
 /*
@@ -687,52 +908,136 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       bool addr_known = false;
        u32 addr, len, rem;
-       int ret;
+       int ret, err;
 
        dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
                (long long)instr->len);
 
-       if (!instr->len)
-               return 0;
-
        div_u64_rem(instr->len, mtd->erasesize, &rem);
-       if (rem)
-               return -EINVAL;
+       if (rem) {
+               ret = -EINVAL;
+               goto err;
+       }
 
        addr = instr->addr;
        len = instr->len;
 
+       instr->state = MTD_ERASING;
+       addr_known = true;
+
        while (len) {
                WATCHDOG_RESET();
+               if (ctrlc()) {
+                       addr_known = false;
+                       ret = -EINTR;
+                       goto erase_err;
+               }
 #ifdef CONFIG_SPI_FLASH_BAR
                ret = write_bar(nor, addr);
                if (ret < 0)
-                       return ret;
+                       goto erase_err;
 #endif
-               write_enable(nor);
+               ret = write_enable(nor);
+               if (ret < 0)
+                       goto erase_err;
 
                ret = spi_nor_erase_sector(nor, addr);
-               if (ret)
+               if (ret < 0)
                        goto erase_err;
 
-               addr += mtd->erasesize;
-               len -= mtd->erasesize;
+               addr += ret;
+               len -= ret;
 
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
                        goto erase_err;
        }
 
+       addr_known = false;
 erase_err:
 #ifdef CONFIG_SPI_FLASH_BAR
-       ret = clean_bar(nor);
+       err = clean_bar(nor);
+       if (!ret)
+               ret = err;
 #endif
-       write_disable(nor);
+       err = write_disable(nor);
+       if (!ret)
+               ret = err;
+
+err:
+       if (ret) {
+               instr->fail_addr = addr_known ? addr : MTD_FAIL_ADDR_UNKNOWN;
+               instr->state = MTD_ERASE_FAILED;
+       } else {
+               instr->state = MTD_ERASE_DONE;
+       }
 
        return ret;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/**
+ * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress
+ *                                chips
+ * @nor:       pointer to a 'struct spi_nor'
+ * @addr:      address of the sector to erase
+ * @opcode_4k: opcode for 4K sector erase
+ * @ovlsz_top: size of overlaid portion at the top address
+ * @ovlsz_btm: size of overlaid portion at the bottom address
+ *
+ * Erase an address range on the nor chip that can contain 4KB sectors overlaid
+ * on top and/or bottom. The appropriate erase opcode and size are chosen by
+ * address to erase and size of overlaid portion.
+ *
+ * Return: number of bytes erased on success, -errno otherwise.
+ */
+static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr,
+                                     u8 opcode_4k, u32 ovlsz_top,
+                                     u32 ovlsz_btm)
+{
+       struct spi_mem_op op =
+               SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0),
+                          SPI_MEM_OP_ADDR(nor->addr_width, addr, 0),
+                          SPI_MEM_OP_NO_DUMMY,
+                          SPI_MEM_OP_NO_DATA);
+       struct mtd_info *mtd = &nor->mtd;
+       u32 erasesize;
+       int ret;
+
+       /* 4KB sectors */
+       if (op.addr.val < ovlsz_btm ||
+           op.addr.val >= mtd->size - ovlsz_top) {
+               op.cmd.opcode = opcode_4k;
+               erasesize = SZ_4K;
+
+       /* Non-overlaid portion in the normal sector at the bottom */
+       } else if (op.addr.val == ovlsz_btm) {
+               op.cmd.opcode = nor->erase_opcode;
+               erasesize = mtd->erasesize - ovlsz_btm;
+
+       /* Non-overlaid portion in the normal sector at the top */
+       } else if (op.addr.val == mtd->size - mtd->erasesize) {
+               op.cmd.opcode = nor->erase_opcode;
+               erasesize = mtd->erasesize - ovlsz_top;
+
+       /* Normal sectors */
+       } else {
+               op.cmd.opcode = nor->erase_opcode;
+               erasesize = mtd->erasesize;
+       }
+
+       spi_nor_setup_op(nor, &op, nor->write_proto);
+
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret)
+               return ret;
+
+       return erasesize;
+}
+#endif
+
 #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
 /* Write status register and ensure bits in mask match written values */
 static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
@@ -1383,9 +1688,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
 
-       if (!len)
-               return 0;
-
        for (i = 0; i < len; ) {
                ssize_t written;
                loff_t addr = to + i;
@@ -1471,6 +1773,61 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/**
+ * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register.
+ * @nor:       pointer to a 'struct spi_nor'
+ * @addr_base: base address of register (can be >0 in multi-die parts)
+ * @dummy:     number of dummy cycles for register read
+ *
+ * It is recommended to update volatile registers in the field application due
+ * to a risk of the non-volatile registers corruption by power interrupt. This
+ * function sets Quad Enable bit in CFR1 volatile.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base,
+                                        u8 dummy)
+{
+       u32 addr = addr_base + SPINOR_REG_ADDR_CFR1V;
+
+       u8 cr;
+       int ret;
+
+       /* Check current Quad Enable bit value. */
+       ret = spansion_read_any_reg(nor, addr, dummy, &cr);
+       if (ret < 0) {
+               dev_dbg(nor->dev,
+                       "error while reading configuration register\n");
+               return -EINVAL;
+       }
+
+       if (cr & CR_QUAD_EN_SPAN)
+               return 0;
+
+       cr |= CR_QUAD_EN_SPAN;
+
+       write_enable(nor);
+
+       ret = spansion_write_any_reg(nor, addr, cr);
+
+       if (ret < 0) {
+               dev_dbg(nor->dev,
+                       "error while writing configuration register\n");
+               return -EINVAL;
+       }
+
+       /* Read back and check it. */
+       ret = spansion_read_any_reg(nor, addr, dummy, &cr);
+       if (ret || !(cr & CR_QUAD_EN_SPAN)) {
+               dev_dbg(nor->dev, "Spansion Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#endif
+
 #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
 /*
  * Write status Register and configuration register with 2 bytes
@@ -1925,7 +2282,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
        }
 
        /* Stop here if not JESD216 rev A or later. */
-       if (bfpt_header->length < BFPT_DWORD_MAX)
+       if (bfpt_header->length == BFPT_DWORD_MAX_JESD216)
                return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
                                                params);
 
@@ -1957,7 +2314,35 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
                break;
 #endif
        default:
+               dev_dbg(nor->dev, "BFPT QER reserved value used\n");
+               break;
+       }
+
+       /* Soft Reset support. */
+       if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST)
+               nor->flags |= SNOR_F_SOFT_RESET;
+
+       /* Stop here if JESD216 rev B. */
+       if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B)
+               return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
+                                               params);
+
+       /* 8D-8D-8D command extension. */
+       switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
+       case BFPT_DWORD18_CMD_EXT_REP:
+               nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+               break;
+
+       case BFPT_DWORD18_CMD_EXT_INV:
+               nor->cmd_ext_type = SPI_NOR_EXT_INVERT;
+               break;
+
+       case BFPT_DWORD18_CMD_EXT_RES:
                return -EINVAL;
+
+       case BFPT_DWORD18_CMD_EXT_16B:
+               dev_err(nor->dev, "16-bit opcodes not supported\n");
+               return -ENOTSUPP;
        }
 
        return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
@@ -1992,6 +2377,86 @@ spi_nor_parse_microchip_sfdp(struct spi_nor *nor,
 }
 
 /**
+ * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table
+ * @nor:               pointer to a 'struct spi_nor'
+ * @profile1_header:   pointer to the 'struct sfdp_parameter_header' describing
+ *                     the 4-Byte Address Instruction Table length and version.
+ * @params:            pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_profile1(struct spi_nor *nor,
+                                 const struct sfdp_parameter_header *profile1_header,
+                                 struct spi_nor_flash_parameter *params)
+{
+       u32 *table, opcode, addr;
+       size_t len;
+       int ret, i;
+       u8 dummy;
+
+       len = profile1_header->length * sizeof(*table);
+       table = kmalloc(len, GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       addr = SFDP_PARAM_HEADER_PTP(profile1_header);
+       ret = spi_nor_read_sfdp(nor, addr, len, table);
+       if (ret)
+               goto out;
+
+       /* Fix endianness of the table DWORDs. */
+       for (i = 0; i < profile1_header->length; i++)
+               table[i] = le32_to_cpu(table[i]);
+
+       /* Get 8D-8D-8D fast read opcode and dummy cycles. */
+       opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]);
+
+       /*
+        * We don't know what speed the controller is running at. Find the
+        * dummy cycles for the fastest frequency the flash can run at to be
+        * sure we are never short of dummy cycles. A value of 0 means the
+        * frequency is not supported.
+        *
+        * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let
+        * flashes set the correct value if needed in their fixup hooks.
+        */
+       dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]);
+       if (!dummy)
+               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]);
+       if (!dummy)
+               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]);
+       if (!dummy)
+               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]);
+       if (!dummy)
+               dummy = PROFILE1_DUMMY_DEFAULT;
+
+       /* Round up to an even value to avoid tripping controllers up. */
+       dummy = ROUND_UP_TO(dummy, 2);
+
+       /* Update the fast read settings. */
+       spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+                                 0, dummy, opcode,
+                                 SNOR_PROTO_8_8_8_DTR);
+
+       /*
+        * Set the Read Status Register dummy cycles and dummy address bytes.
+        */
+       if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY)
+               params->rdsr_dummy = 8;
+       else
+               params->rdsr_dummy = 4;
+
+       if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
+               params->rdsr_addr_nbytes = 4;
+       else
+               params->rdsr_addr_nbytes = 0;
+
+out:
+       kfree(table);
+       return ret;
+}
+
+/**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:               pointer to a 'struct spi_nor'
  * @params:            pointer to the 'struct spi_nor_flash_parameter' to be
@@ -2093,6 +2558,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
                        err = spi_nor_parse_microchip_sfdp(nor, param_header);
                        break;
 
+               case SFDP_PROFILE1_ID:
+                       err = spi_nor_parse_profile1(nor, param_header, params);
+                       break;
+
                default:
                        break;
                }
@@ -2157,18 +2626,28 @@ static int spi_nor_init_params(struct spi_nor *nor,
        params->size = info->sector_size * info->n_sectors;
        params->page_size = info->page_size;
 
+       if (!(info->flags & SPI_NOR_NO_FR)) {
+               /* Default to Fast Read for DT and non-DT platform devices. */
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
+
+               /* Mask out Fast Read if not requested at DT instantiation. */
+#if CONFIG_IS_ENABLED(DM_SPI)
+               if (!ofnode_read_bool(dev_ofnode(nor->spi->dev),
+                                     "m25p,fast-read"))
+                       params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
+#endif
+       }
+
        /* (Fast) Read settings. */
        params->hwcaps.mask |= SNOR_HWCAPS_READ;
        spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
                                  0, 0, SPINOR_OP_READ,
                                  SNOR_PROTO_1_1_1);
 
-       if (!(info->flags & SPI_NOR_NO_FR)) {
-               params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
+       if (params->hwcaps.mask & SNOR_HWCAPS_READ_FAST)
                spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
                                          0, 8, SPINOR_OP_READ_FAST,
                                          SNOR_PROTO_1_1_1);
-       }
 
        if (info->flags & SPI_NOR_DUAL_READ) {
                params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
@@ -2191,11 +2670,25 @@ static int spi_nor_init_params(struct spi_nor *nor,
                                          SNOR_PROTO_1_1_8);
        }
 
+       if (info->flags & SPI_NOR_OCTAL_DTR_READ) {
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+               spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+                                         0, 20, SPINOR_OP_READ_FAST,
+                                         SNOR_PROTO_8_8_8_DTR);
+       }
+
        /* Page Program settings. */
        params->hwcaps.mask |= SNOR_HWCAPS_PP;
        spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
                                SPINOR_OP_PP, SNOR_PROTO_1_1_1);
 
+       /*
+        * Since xSPI Page Program opcode is backward compatible with
+        * Legacy SPI, use Legacy SPI opcode there as well.
+        */
+       spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+                               SPINOR_OP_PP, SNOR_PROTO_8_8_8_DTR);
+
        if (info->flags & SPI_NOR_QUAD_READ) {
                params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
                spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
@@ -2230,7 +2723,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
        /* Override the parameters with data read from SFDP tables. */
        nor->addr_width = 0;
        nor->mtd.erasesize = 0;
-       if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
+       if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+            SPI_NOR_OCTAL_DTR_READ)) &&
            !(info->flags & SPI_NOR_SKIP_SFDP)) {
                struct spi_nor_flash_parameter sfdp_params;
 
@@ -2277,6 +2771,7 @@ static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
                { SNOR_HWCAPS_READ_1_8_8,       SNOR_CMD_READ_1_8_8 },
                { SNOR_HWCAPS_READ_8_8_8,       SNOR_CMD_READ_8_8_8 },
                { SNOR_HWCAPS_READ_1_8_8_DTR,   SNOR_CMD_READ_1_8_8_DTR },
+               { SNOR_HWCAPS_READ_8_8_8_DTR,   SNOR_CMD_READ_8_8_8_DTR },
        };
 
        return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
@@ -2293,6 +2788,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
                { SNOR_HWCAPS_PP_1_1_8,         SNOR_CMD_PP_1_1_8 },
                { SNOR_HWCAPS_PP_1_8_8,         SNOR_CMD_PP_1_8_8 },
                { SNOR_HWCAPS_PP_8_8_8,         SNOR_CMD_PP_8_8_8 },
+               { SNOR_HWCAPS_PP_8_8_8_DTR,     SNOR_CMD_PP_8_8_8_DTR },
        };
 
        return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
@@ -2339,17 +2835,17 @@ static int spi_nor_check_op(struct spi_nor *nor,
 static int spi_nor_check_readop(struct spi_nor *nor,
                                const struct spi_nor_read_command *read)
 {
-       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
-                                         SPI_MEM_OP_ADDR(3, 0, 1),
-                                         SPI_MEM_OP_DUMMY(0, 1),
-                                         SPI_MEM_OP_DATA_IN(0, NULL, 1));
+       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 0),
+                                         SPI_MEM_OP_ADDR(3, 0, 0),
+                                         SPI_MEM_OP_DUMMY(1, 0),
+                                         SPI_MEM_OP_DATA_IN(2, NULL, 0));
+
+       spi_nor_setup_op(nor, &op, read->proto);
 
-       op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
-       op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
-       op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
-       op.dummy.buswidth = op.addr.buswidth;
        op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
                          op.dummy.buswidth / 8;
+       if (spi_nor_protocol_is_dtr(nor->read_proto))
+               op.dummy.nbytes *= 2;
 
        return spi_nor_check_op(nor, &op);
 }
@@ -2364,14 +2860,12 @@ static int spi_nor_check_readop(struct spi_nor *nor,
 static int spi_nor_check_pp(struct spi_nor *nor,
                            const struct spi_nor_pp_command *pp)
 {
-       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
-                                         SPI_MEM_OP_ADDR(3, 0, 1),
+       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 0),
+                                         SPI_MEM_OP_ADDR(3, 0, 0),
                                          SPI_MEM_OP_NO_DUMMY,
-                                         SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+                                         SPI_MEM_OP_DATA_OUT(2, NULL, 0));
 
-       op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
-       op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
-       op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
+       spi_nor_setup_op(nor, &op, pp->proto);
 
        return spi_nor_check_op(nor, &op);
 }
@@ -2396,17 +2890,22 @@ spi_nor_adjust_hwcaps(struct spi_nor *nor,
        unsigned int cap;
 
        /*
-        * Enable all caps by default. We will mask them after checking what's
-        * really supported using spi_mem_supports_op().
+        * Start by assuming the controller supports every capability.
+        * We will mask them after checking what's really supported
+        * using spi_mem_supports_op().
         */
-       *hwcaps = SNOR_HWCAPS_ALL;
-
-       /* DTR modes are not supported yet, mask them all. */
-       *hwcaps &= ~SNOR_HWCAPS_DTR;
+       *hwcaps = SNOR_HWCAPS_ALL & params->hwcaps.mask;
 
        /* X-X-X modes are not supported yet, mask them all. */
        *hwcaps &= ~SNOR_HWCAPS_X_X_X;
 
+       /*
+        * If the reset line is broken, we do not want to enter a stateful
+        * mode.
+        */
+       if (nor->flags & SNOR_F_BROKEN_RESET)
+               *hwcaps &= ~(SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR);
+
        for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
                int rdidx, ppidx;
 
@@ -2619,10 +3118,449 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
        return nor->setup(nor, info, params);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+static int s25hx_t_mdp_ready(struct spi_nor *nor)
+{
+       u32 addr;
+       int ret;
+
+       for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) {
+               ret = spansion_sr_ready(nor, addr, 0);
+               if (!ret)
+                       return ret;
+       }
+
+       return 1;
+}
+
+static int s25hx_t_quad_enable(struct spi_nor *nor)
+{
+       u32 addr;
+       int ret;
+
+       for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) {
+               ret = spansion_quad_enable_volatile(nor, addr, 0);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int s25hx_t_erase_non_uniform(struct spi_nor *nor, loff_t addr)
+{
+       /* Support 32 x 4KB sectors at bottom */
+       return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0,
+                                         SZ_128K);
+}
+
+static int s25hx_t_setup(struct spi_nor *nor, const struct flash_info *info,
+                        const struct spi_nor_flash_parameter *params)
+{
+       int ret;
+       u8 cfr3v;
+
+#ifdef CONFIG_SPI_FLASH_BAR
+       return -ENOTSUPP; /* Bank Address Register is not supported */
+#endif
+       /*
+        * Read CFR3V to check if uniform sector is selected. If not, assign an
+        * erase hook that supports non-uniform erase.
+        */
+       ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V, 0, &cfr3v);
+       if (ret)
+               return ret;
+       if (!(cfr3v & CFR3V_UNHYSA))
+               nor->erase = s25hx_t_erase_non_uniform;
+
+       /*
+        * For the multi-die package parts, the ready() hook is needed to check
+        * all dies' status via read any register.
+        */
+       if (nor->mtd.size > SZ_128M)
+               nor->ready = s25hx_t_mdp_ready;
+
+       return spi_nor_default_setup(nor, info, params);
+}
+
+static void s25hx_t_default_init(struct spi_nor *nor)
+{
+       nor->setup = s25hx_t_setup;
+}
+
+static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
+                                  const struct sfdp_parameter_header *header,
+                                  const struct sfdp_bfpt *bfpt,
+                                  struct spi_nor_flash_parameter *params)
+{
+       int ret;
+       u32 addr;
+       u8 cfr3v;
+
+       /* erase size in case it is set to 4K from BFPT */
+       nor->erase_opcode = SPINOR_OP_SE_4B;
+       nor->mtd.erasesize = nor->info->sector_size;
+
+       ret = set_4byte(nor, nor->info, 1);
+       if (ret)
+               return ret;
+       nor->addr_width = 4;
+
+       /*
+        * The page_size is set to 512B from BFPT, but it actually depends on
+        * the configuration register. Look up the CFR3V and determine the
+        * page_size. For multi-die package parts, use 512B only when the all
+        * dies are configured to 512B buffer.
+        */
+       for (addr = 0; addr < params->size; addr += SZ_128M) {
+               ret = spansion_read_any_reg(nor, addr + SPINOR_REG_ADDR_CFR3V,
+                                           0, &cfr3v);
+               if (ret)
+                       return ret;
+
+               if (!(cfr3v & CFR3V_PGMBUF)) {
+                       params->page_size = 256;
+                       return 0;
+               }
+       }
+       params->page_size = 512;
+
+       return 0;
+}
+
+static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor,
+                                   struct spi_nor_flash_parameter *params)
+{
+       /* READ_FAST_4B (0Ch) requires mode cycles*/
+       params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
+       /* PP_1_1_4 is not supported */
+       params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4;
+       /* Use volatile register to enable quad */
+       params->quad_enable = s25hx_t_quad_enable;
+}
+
+static struct spi_nor_fixups s25hx_t_fixups = {
+       .default_init = s25hx_t_default_init,
+       .post_bfpt = s25hx_t_post_bfpt_fixup,
+       .post_sfdp = s25hx_t_post_sfdp_fixup,
+};
+
+static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info,
+                          const struct spi_nor_flash_parameter *params)
+{
+       return -ENOTSUPP; /* Bank Address Register is not supported */
+}
+
+static void s25fl256l_default_init(struct spi_nor *nor)
+{
+       nor->setup = s25fl256l_setup;
+}
+
+static struct spi_nor_fixups s25fl256l_fixups = {
+       .default_init = s25fl256l_default_init,
+};
+#endif
+
+#ifdef CONFIG_SPI_FLASH_S28HS512T
+/**
+ * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
+ * @nor:               pointer to a 'struct spi_nor'
+ *
+ * This also sets the memory access latency cycles to 24 to allow the flash to
+ * run at up to 200MHz.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor)
+{
+       struct spi_mem_op op;
+       u8 buf;
+       u8 addr_width = 3;
+       int ret;
+
+       /* Use 24 dummy cycles for memory array reads. */
+       ret = write_enable(nor);
+       if (ret)
+               return ret;
+
+       buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+                       SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR2V, 1),
+                       SPI_MEM_OP_NO_DUMMY,
+                       SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret) {
+               dev_warn(nor->dev,
+                        "failed to set default memory latency value: %d\n",
+                        ret);
+               return ret;
+       }
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       nor->read_dummy = 24;
+
+       /* Set the octal and DTR enable bits. */
+       ret = write_enable(nor);
+       if (ret)
+               return ret;
+
+       buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+                       SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR5V, 1),
+                       SPI_MEM_OP_NO_DUMMY,
+                       SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret) {
+               dev_warn(nor->dev, "Failed to enable octal DTR mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s28hs512t_erase_non_uniform(struct spi_nor *nor, loff_t addr)
+{
+       /* Factory default configuration: 32 x 4 KiB sectors at bottom. */
+       return spansion_erase_non_uniform(nor, addr, SPINOR_OP_S28_SE_4K,
+                                         0, SZ_128K);
+}
+
+static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info,
+                          const struct spi_nor_flash_parameter *params)
+{
+       struct spi_mem_op op;
+       u8 buf;
+       u8 addr_width = 3;
+       int ret;
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       /*
+        * Check CFR3V to check if non-uniform sector mode is selected. If it
+        * is, set the erase hook to the non-uniform erase procedure.
+        */
+       op = (struct spi_mem_op)
+               SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+                          SPI_MEM_OP_ADDR(addr_width,
+                                          SPINOR_REG_CYPRESS_CFR3V, 1),
+                          SPI_MEM_OP_NO_DUMMY,
+                          SPI_MEM_OP_DATA_IN(1, &buf, 1));
+
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret)
+               return ret;
+
+       if (!(buf & SPINOR_REG_CYPRESS_CFR3V_UNISECT))
+               nor->erase = s28hs512t_erase_non_uniform;
+
+       return spi_nor_default_setup(nor, info, params);
+}
+
+static void s28hs512t_default_init(struct spi_nor *nor)
+{
+       nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
+       nor->setup = s28hs512t_setup;
+}
+
+static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor,
+                                     struct spi_nor_flash_parameter *params)
+{
+       /*
+        * On older versions of the flash the xSPI Profile 1.0 table has the
+        * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
+        */
+       if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
+               params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
+                       SPINOR_OP_CYPRESS_RD_FAST;
+
+       params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+       /* This flash is also missing the 4-byte Page Program opcode bit. */
+       spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
+                               SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+       /*
+        * Since xSPI Page Program opcode is backward compatible with
+        * Legacy SPI, use Legacy SPI opcode there as well.
+        */
+       spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+                               SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+
+       /*
+        * The xSPI Profile 1.0 table advertises the number of additional
+        * address bytes needed for Read Status Register command as 0 but the
+        * actual value for that is 4.
+        */
+       params->rdsr_addr_nbytes = 4;
+}
+
+static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
+                                    const struct sfdp_parameter_header *bfpt_header,
+                                    const struct sfdp_bfpt *bfpt,
+                                    struct spi_nor_flash_parameter *params)
+{
+       struct spi_mem_op op;
+       u8 buf;
+       u8 addr_width = 3;
+       int ret;
+
+       /*
+        * The BFPT table advertises a 512B page size but the page size is
+        * actually configurable (with the default being 256B). Read from
+        * CFR3V[4] and set the correct size.
+        */
+       op = (struct spi_mem_op)
+               SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+                          SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR3V, 1),
+                          SPI_MEM_OP_NO_DUMMY,
+                          SPI_MEM_OP_DATA_IN(1, &buf, 1));
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret)
+               return ret;
+
+       if (buf & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
+               params->page_size = 512;
+       else
+               params->page_size = 256;
+
+       /*
+        * The BFPT advertises that it supports 4k erases, and the datasheet
+        * says the same. But 4k erases did not work when testing. So, use 256k
+        * erases for now.
+        */
+       nor->erase_opcode = SPINOR_OP_SE_4B;
+       nor->mtd.erasesize = 0x40000;
+
+       return 0;
+}
+
+static struct spi_nor_fixups s28hs512t_fixups = {
+       .default_init = s28hs512t_default_init,
+       .post_sfdp = s28hs512t_post_sfdp_fixup,
+       .post_bfpt = s28hs512t_post_bfpt_fixup,
+};
+#endif /* CONFIG_SPI_FLASH_S28HS512T */
+
+#ifdef CONFIG_SPI_FLASH_MT35XU
+static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
+{
+       struct spi_mem_op op;
+       u8 buf;
+       u8 addr_width = 3;
+       int ret;
+
+       /* Set dummy cycles for Fast Read to the default of 20. */
+       ret = write_enable(nor);
+       if (ret)
+               return ret;
+
+       buf = 20;
+       op = (struct spi_mem_op)
+               SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+                          SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1),
+                          SPI_MEM_OP_NO_DUMMY,
+                          SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret)
+               return ret;
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       nor->read_dummy = 20;
+
+       ret = write_enable(nor);
+       if (ret)
+               return ret;
+
+       buf = SPINOR_MT_OCT_DTR;
+       op = (struct spi_mem_op)
+               SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+                          SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1),
+                          SPI_MEM_OP_NO_DUMMY,
+                          SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret) {
+               dev_err(nor->dev, "Failed to enable octal DTR mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mt35xu512aba_default_init(struct spi_nor *nor)
+{
+       nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
+}
+
+static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor,
+                                        struct spi_nor_flash_parameter *params)
+{
+       /* Set the Fast Read settings. */
+       params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+       spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+                                 0, 20, SPINOR_OP_MT_DTR_RD,
+                                 SNOR_PROTO_8_8_8_DTR);
+
+       params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+       nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+       params->rdsr_dummy = 8;
+       params->rdsr_addr_nbytes = 0;
+
+       /*
+        * The BFPT quad enable field is set to a reserved value so the quad
+        * enable function is ignored by spi_nor_parse_bfpt(). Make sure we
+        * disable it.
+        */
+       params->quad_enable = NULL;
+}
+
+static struct spi_nor_fixups mt35xu512aba_fixups = {
+       .default_init = mt35xu512aba_default_init,
+       .post_sfdp = mt35xu512aba_post_sfdp_fixup,
+};
+#endif /* CONFIG_SPI_FLASH_MT35XU */
+
+/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
+ * @nor:                 pointer to a 'struct spi_nor'
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_octal_dtr_enable(struct spi_nor *nor)
+{
+       int ret;
+
+       if (!nor->octal_dtr_enable)
+               return 0;
+
+       if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
+             nor->write_proto == SNOR_PROTO_8_8_8_DTR))
+               return 0;
+
+       ret = nor->octal_dtr_enable(nor);
+       if (ret)
+               return ret;
+
+       nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+
+       return 0;
+}
+
 static int spi_nor_init(struct spi_nor *nor)
 {
        int err;
 
+       err = spi_nor_octal_dtr_enable(nor);
+       if (err) {
+               dev_dbg(nor->dev, "Octal DTR mode not supported\n");
+               return err;
+       }
+
        /*
         * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
         * with the software protection bits set
@@ -2646,6 +3584,7 @@ static int spi_nor_init(struct spi_nor *nor)
        }
 
        if (nor->addr_width == 4 &&
+           !(nor->info->flags & SPI_NOR_OCTAL_DTR_READ) &&
            (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
            !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
                /*
@@ -2663,8 +3602,100 @@ static int spi_nor_init(struct spi_nor *nor)
        return 0;
 }
 
+#ifdef CONFIG_SPI_FLASH_SOFT_RESET
+/**
+ * spi_nor_soft_reset() - perform the JEDEC Software Reset sequence
+ * @nor:       the spi_nor structure
+ *
+ * This function can be used to switch from Octal DTR mode to legacy mode on a
+ * flash that supports it. The soft reset is executed in Octal DTR mode.
+ *
+ * Return: 0 for success, -errno for failure.
+ */
+static int spi_nor_soft_reset(struct spi_nor *nor)
+{
+       struct spi_mem_op op;
+       int ret;
+       enum spi_nor_cmd_ext ext;
+
+       ext = nor->cmd_ext_type;
+       nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0),
+                       SPI_MEM_OP_NO_DUMMY,
+                       SPI_MEM_OP_NO_ADDR,
+                       SPI_MEM_OP_NO_DATA);
+       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret) {
+               dev_warn(nor->dev, "Software reset enable failed: %d\n", ret);
+               goto out;
+       }
+
+       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 0),
+                       SPI_MEM_OP_NO_DUMMY,
+                       SPI_MEM_OP_NO_ADDR,
+                       SPI_MEM_OP_NO_DATA);
+       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+       ret = spi_mem_exec_op(nor->spi, &op);
+       if (ret) {
+               dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+               goto out;
+       }
+
+       /*
+        * Software Reset is not instant, and the delay varies from flash to
+        * flash. Looking at a few flashes, most range somewhere below 100
+        * microseconds. So, wait for 200ms just to be sure.
+        */
+       udelay(SPI_NOR_SRST_SLEEP_LEN);
+
+out:
+       nor->cmd_ext_type = ext;
+       return ret;
+}
+#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
+
+int spi_nor_remove(struct spi_nor *nor)
+{
+#ifdef CONFIG_SPI_FLASH_SOFT_RESET
+       if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ &&
+           nor->flags & SNOR_F_SOFT_RESET)
+               return spi_nor_soft_reset(nor);
+#endif
+
+       return 0;
+}
+
 void spi_nor_set_fixups(struct spi_nor *nor)
 {
+#ifdef CONFIG_SPI_FLASH_SPANSION
+       if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) {
+               switch (nor->info->id[1]) {
+               case 0x2a: /* S25HL (QSPI, 3.3V) */
+               case 0x2b: /* S25HS (QSPI, 1.8V) */
+                       nor->fixups = &s25hx_t_fixups;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) &&
+           !strcmp(nor->info->name, "s25fl256l"))
+               nor->fixups = &s25fl256l_fixups;
+#endif
+
+#ifdef CONFIG_SPI_FLASH_S28HS512T
+       if (!strcmp(nor->info->name, "s28hs512t"))
+               nor->fixups = &s28hs512t_fixups;
+#endif
+
+#ifdef CONFIG_SPI_FLASH_MT35XU
+       if (!strcmp(nor->info->name, "mt35xu512aba"))
+               nor->fixups = &mt35xu512aba_fixups;
+#endif
 }
 
 int spi_nor_scan(struct spi_nor *nor)
@@ -2674,6 +3705,11 @@ int spi_nor_scan(struct spi_nor *nor)
        struct mtd_info *mtd = &nor->mtd;
        struct spi_slave *spi = nor->spi;
        int ret;
+       int cfi_mtd_nb = 0;
+
+#ifdef CONFIG_FLASH_CFI_MTD
+       cfi_mtd_nb = CFI_FLASH_BANKS;
+#endif
 
        /* Reset SPI protocol for all commands. */
        nor->reg_proto = SNOR_PROTO_1_1_1;
@@ -2686,6 +3722,33 @@ int spi_nor_scan(struct spi_nor *nor)
 
        nor->setup = spi_nor_default_setup;
 
+#ifdef CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT
+       /*
+        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
+        * is difficult to detect the mode the flash is in. One option is to
+        * read SFDP in all modes and see which one gives the correct "SFDP"
+        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
+        *
+        * Further, even if you detect the mode of the flash via SFDP, you
+        * still have the problem of actually reading the ID. The Read ID
+        * command is not standardized across flash vendors. Flashes can have
+        * different dummy cycles needed for reading the ID. Some flashes even
+        * expect a 4-byte dummy address with the Read ID command. All this
+        * information cannot be obtained from the SFDP table.
+        *
+        * So, perform a Software Reset sequence before reading the ID and
+        * initializing the flash. A Soft Reset will bring back the flash in
+        * its default protocol mode assuming no non-volatile configuration was
+        * set. This will let us detect the flash even if ROM hands it to us in
+        * Octal DTR mode.
+        *
+        * To accommodate cases where there is more than one flash on a board,
+        * and only one of them needs a soft reset, failure to reset is not
+        * made fatal, and we still try to read ID if possible.
+        */
+       spi_nor_soft_reset(nor);
+#endif /* CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT */
+
        info = spi_nor_read_id(nor);
        if (IS_ERR_OR_NULL(info))
                return -ENOENT;
@@ -2698,8 +3761,12 @@ int spi_nor_scan(struct spi_nor *nor)
        if (ret)
                return ret;
 
-       if (!mtd->name)
-               mtd->name = info->name;
+       if (!mtd->name) {
+               sprintf(nor->mtd_name, "%s%d",
+                       MTD_DEV_TYPE(MTD_DEV_TYPE_NOR),
+                       cfi_mtd_nb + dev_seq(nor->dev));
+               mtd->name = nor->mtd_name;
+       }
        mtd->dev = nor->dev;
        mtd->priv = nor;
        mtd->type = MTD_NORFLASH;
@@ -2764,7 +3831,10 @@ int spi_nor_scan(struct spi_nor *nor)
        if (ret)
                return ret;
 
-       if (nor->addr_width) {
+       if (spi_nor_protocol_is_dtr(nor->read_proto)) {
+                /* Always use 4-byte addresses in DTR mode. */
+               nor->addr_width = 4;
+       } else if (nor->addr_width) {
                /* already configured from SFDP */
        } else if (info->addr_width) {
                nor->addr_width = info->addr_width;
@@ -2799,7 +3869,9 @@ int spi_nor_scan(struct spi_nor *nor)
        if (ret)
                return ret;
 
-       nor->name = mtd->name;
+       nor->rdsr_dummy = params.rdsr_dummy;
+       nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes;
+       nor->name = info->name;
        nor->size = mtd->size;
        nor->erase_size = mtd->erasesize;
        nor->sector_size = mtd->erasesize;