Merge branch '2022-08-04-Kconfig-migrations'
[platform/kernel/u-boot.git] / drivers / mtd / spi / spi-nor-core.c
index 50460fe..26a356b 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <common.h>
-#include <flash.h>
 #include <log.h>
 #include <watchdog.h>
 #include <dm.h>
@@ -65,6 +64,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
@@ -174,6 +177,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];
 };
@@ -1308,13 +1314,13 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 }
 
 /*
- * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * Check if a region of the flash is (completely) unlocked. See stm_lock() for
  * more info.
  *
- * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * Returns 1 if entire region is unlocked, 0 if any portion is locked, and
  * negative on errors.
  */
-static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int stm_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
        int status;
 
@@ -1322,7 +1328,7 @@ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
        if (status < 0)
                return status;
 
-       return stm_is_locked_sr(nor, ofs, len, status);
+       return stm_is_unlocked_sr(nor, ofs, len, status);
 }
 #endif /* CONFIG_SPI_FLASH_STMICRO */
 
@@ -1555,16 +1561,16 @@ static int sst26_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 }
 
 /*
- * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
- * and negative on errors.
+ * Returns EACCES (positive value) if region is (partially) locked, 0 if region
+ * is completely unlocked, and negative on errors.
  */
-static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int sst26_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
        /*
-        * is_locked function is used for check before reading or erasing flash
-        * region, so offset and length might be not 64k allighned, so adjust
-        * them to be 64k allighned as sst26_lock_ctl works only with 64k
-        * allighned regions.
+        * is_unlocked function is used for check before reading or erasing
+        * flash region, so offset and length might be not 64k aligned, so
+        * adjust them to be 64k aligned as sst26_lock_ctl works only with 64k
+        * aligned regions.
         */
        ofs -= ofs & (SZ_64K - 1);
        len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
@@ -2457,6 +2463,44 @@ out:
 }
 
 /**
+ * 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, addr;
+       size_t len;
+       int ret, i;
+
+       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'
  * @params:            pointer to the 'struct spi_nor_flash_parameter' to be
@@ -2562,6 +2606,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
                        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;
                }
@@ -3620,6 +3668,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;
@@ -3872,7 +3923,7 @@ int spi_nor_scan(struct spi_nor *nor)
                        info->flags & SPI_NOR_HAS_LOCK) {
                nor->flash_lock = stm_lock;
                nor->flash_unlock = stm_unlock;
-               nor->flash_is_locked = stm_is_locked;
+               nor->flash_is_unlocked = stm_is_unlocked;
        }
 #endif
 
@@ -3884,7 +3935,7 @@ int spi_nor_scan(struct spi_nor *nor)
        if (info->flags & SPI_NOR_HAS_SST26LOCK) {
                nor->flash_lock = sst26_lock;
                nor->flash_unlock = sst26_unlock;
-               nor->flash_is_locked = sst26_is_locked;
+               nor->flash_is_unlocked = sst26_is_unlocked;
        }
 #endif