Parse SCCR 22nd dword and check DTR Octal Mode Enable
Volatile bit for Octal DTR enable

Signed-off-by: JaimeLiao <jaimeliao...@gmail.com>
---
 drivers/mtd/spi/spi-nor-core.c | 52 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    |  1 +
 2 files changed, 53 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 2b6947cefc..14c33aea10 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -63,6 +63,10 @@ struct sfdp_parameter_header {
 #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_SCCR_MAP_ID       0xff87  /*
+                                        * Status, Control and Configuration
+                                        * Register Map.
+                                        */
 
 #define SFDP_SIGNATURE         0x50444653U
 #define SFDP_JESD216_MAJOR     1
@@ -172,6 +176,9 @@ struct sfdp_header {
 #define PROFILE1_DWORD5_DUMMY_100MHZ           GENMASK(11, 7)
 #define PROFILE1_DUMMY_DEFAULT                 20
 
+/* Status, Control and Configuration Register Map(SCCR) */
+#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE     BIT(31)
+
 struct sfdp_bfpt {
        u32     dwords[BFPT_DWORD_MAX];
 };
@@ -2434,6 +2441,45 @@ out:
        return ret;
 }
 
+/**
+ * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register
+ *                       Map.
+ * @nor:                 pointer to a 'struct spi_nor'
+ * @sccr_header:         pointer to the 'struct sfdp_parameter_header' 
describing
+ *                       the SCCR Map table length and version.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_sccr(struct spi_nor *nor,
+                             const struct sfdp_parameter_header *sccr_header)
+{
+       u32 *table, opcode, addr;
+       size_t len;
+       int ret, i;
+       u8 dummy;
+
+       len = sccr_header->length * sizeof(*table);
+       table = kmalloc(len, GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       addr = SFDP_PARAM_HEADER_PTP(sccr_header);
+       ret = spi_nor_read_sfdp(nor, addr, len, table);
+       if (ret)
+               goto out;
+
+       /* Fix endianness of the table DWORDs. */
+       for (i = 0; i < sccr_header->length; i++)
+               table[i] = le32_to_cpu(table[i]);
+
+       if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[22]))
+               nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
+
+out:
+       kfree(table);
+       return ret;
+}
+
 /**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:               pointer to a 'struct spi_nor'
@@ -2539,6 +2585,9 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
                case SFDP_PROFILE1_ID:
                        err = spi_nor_parse_profile1(nor, param_header, params);
                        break;
+               case SFDP_SCCR_MAP_ID:
+                       err = spi_nor_parse_sccr(nor, param_header);
+                       break;
 
                default:
                        break;
@@ -3584,6 +3633,9 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor)
              nor->write_proto == SNOR_PROTO_8_8_8_DTR))
                return 0;
 
+       if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
+               return 0;
+
        ret = nor->octal_dtr_enable(nor);
        if (ret)
                return ret;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8682368f2f..10c7b6e4c3 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -287,6 +287,7 @@ enum spi_nor_option_flags {
        SNOR_F_USE_CLSR         = BIT(5),
        SNOR_F_BROKEN_RESET     = BIT(6),
        SNOR_F_SOFT_RESET       = BIT(7),
+       SNOR_F_IO_MODE_EN_VOLATILE = BIT(8),
 };
 
 struct spi_nor;
-- 
2.17.1

Reply via email to