This Flash part does not use octal mode. But soft reset seems to
be required to boot from SPI NOR Flash in Rock Pi 4B.

Cc: Jagan Teki <ja...@amarulasolutions.com>
Cc: Vignesh R <vigne...@ti.com>

Signed-off-by: Xavier Drudis Ferran <xdru...@tinet.cat>
---
 drivers/mtd/spi/spi-nor-core.c | 54 ++++++++++++++++++++++++++++++----
 include/linux/mtd/spi-nor.h    |  5 ++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 3b7c817c02..d6e7067320 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -3526,6 +3526,19 @@ static struct spi_nor_fixups mt35xu512aba_fixups = {
 };
 #endif /* CONFIG_SPI_FLASH_MT35XU */
 
+#ifdef CONFIG_SPI_FLASH_XTX
+static void xtx25f32b_post_sfdp_fixup(struct spi_nor *nor,
+                                     struct spi_nor_flash_parameter *params)
+{
+       nor->flags |= SNOR_F_SOFT_RESET;
+       nor->reset_proto = SNOR_PROTO_1_1_1; /* at least for Rock Pi 4 */
+}
+
+static struct spi_nor_fixups xtx25f32b_fixups = {
+       .post_sfdp = xtx25f32b_post_sfdp_fixup,
+};
+#endif
+
 /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
  * @nor:                 pointer to a 'struct spi_nor'
  *
@@ -3625,7 +3638,7 @@ static int spi_nor_soft_reset(struct spi_nor *nor)
                        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);
+       spi_nor_setup_op(nor, &op, nor->reset_proto ? nor->reset_proto : 
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);
@@ -3636,7 +3649,7 @@ static int spi_nor_soft_reset(struct spi_nor *nor)
                        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);
+       spi_nor_setup_op(nor, &op, nor->reset_proto ? nor->reset_proto : 
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);
@@ -3656,16 +3669,34 @@ out:
 }
 #endif /* CONFIG_SPI_FLASH_SOFT_RESET */
 
+#ifdef CONFIG_SPI_FLASH_SOFT_RESET
+static bool flash_supports_proto(const struct flash_info *flash,  enum 
spi_nor_protocol proto)
+{
+       switch (spi_nor_get_protocol_data_nbits(proto)) {
+       case 8:
+               return flash->flags & (spi_nor_protocol_is_dtr(proto)
+                                      ? SPI_NOR_OCTAL_DTR_READ
+                                      : SPI_NOR_OCTAL_READ);
+       case 4: return flash->flags & SPI_NOR_QUAD_READ;
+       case 2: return flash->flags & SPI_NOR_DUAL_READ;
+       default:
+               return 1;
+       }
+}
+
 int spi_nor_remove(struct spi_nor *nor)
 {
-#ifdef CONFIG_SPI_FLASH_SOFT_RESET
-       if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ &&
+       if (flash_supports_proto(nor->info, nor->reset_proto) &&
            nor->flags & SNOR_F_SOFT_RESET)
                return spi_nor_soft_reset(nor);
-#endif
-
        return 0;
 }
+#else
+int spi_nor_remove(struct spi_nor *nor)
+{
+       return 0;
+}
+#endif
 
 void spi_nor_set_fixups(struct spi_nor *nor)
 {
@@ -3696,6 +3727,11 @@ void spi_nor_set_fixups(struct spi_nor *nor)
        if (!strcmp(nor->info->name, "mt35xu512aba"))
                nor->fixups = &mt35xu512aba_fixups;
 #endif
+
+#ifdef CONFIG_SPI_FLASH_XTX
+       if (!strcmp(nor->info->name, "xt25f32b"))
+               nor->fixups = &xtx25f32b_fixups;
+#endif
 }
 
 int spi_nor_scan(struct spi_nor *nor)
@@ -3715,6 +3751,12 @@ int spi_nor_scan(struct spi_nor *nor)
        nor->reg_proto = SNOR_PROTO_1_1_1;
        nor->read_proto = SNOR_PROTO_1_1_1;
        nor->write_proto = SNOR_PROTO_1_1_1;
+       /**
+        * XTX25F32B in RockPi 4 seems to need soft reset and can't do octal,
+        * but we don't know yet whether we have it, and it seems to tolerate
+        * it until we do. We'll change it later.
+        */
+       nor->reset_proto = SNOR_PROTO_8_8_8_DTR;
        nor->read = spi_nor_read_data;
        nor->write = spi_nor_write_data;
        nor->read_reg = spi_nor_read_reg;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4ceeae623d..a0d6c19468 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -490,6 +490,8 @@ struct spi_flash {
  * @read_proto:                the SPI protocol for read operations
  * @write_proto:       the SPI protocol for write operations
  * @reg_proto          the SPI protocol for read_reg/write_reg/erase operations
+ * @reset_proto:       The SPI protocol for soft reset to return to state 
expected
+ *                     by OS before running the OS (at remove time)
  * @cmd_buf:           used by the write_reg
  * @cmd_ext_type:      the command opcode extension for DTR mode.
  * @fixups:            flash-specific fixup hooks.
@@ -535,6 +537,9 @@ struct spi_nor {
        enum spi_nor_protocol   read_proto;
        enum spi_nor_protocol   write_proto;
        enum spi_nor_protocol   reg_proto;
+#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY)
+       enum spi_nor_protocol   reset_proto;
+#endif
        bool                    sst_write_second;
        u32                     flags;
        u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
-- 
2.20.1

Reply via email to