Эх сурвалжийг харах

spi_flash: 2nd stage for supporting flash suspend. (1). Support more esp chips (2). Improve real-time performance (3). Making timing more stable (4) Add documents

Cao Sen Miao 2 жил өмнө
parent
commit
ed96dadd06
34 өөрчлөгдсөн 514 нэмэгдсэн , 103 устгасан
  1. 10 0
      components/hal/esp32/include/hal/spi_flash_ll.h
  2. 10 0
      components/hal/esp32c2/include/hal/gpspi_flash_ll.h
  3. 2 0
      components/hal/esp32c2/include/hal/spi_flash_ll.h
  4. 65 0
      components/hal/esp32c2/include/hal/spimem_flash_ll.h
  5. 10 0
      components/hal/esp32c3/include/hal/gpspi_flash_ll.h
  6. 2 0
      components/hal/esp32c3/include/hal/spi_flash_ll.h
  7. 66 0
      components/hal/esp32c3/include/hal/spimem_flash_ll.h
  8. 11 1
      components/hal/esp32c6/include/hal/gpspi_flash_ll.h
  9. 3 1
      components/hal/esp32c6/include/hal/spi_flash_ll.h
  10. 67 1
      components/hal/esp32c6/include/hal/spimem_flash_ll.h
  11. 11 1
      components/hal/esp32h2/include/hal/gpspi_flash_ll.h
  12. 3 1
      components/hal/esp32h2/include/hal/spi_flash_ll.h
  13. 66 0
      components/hal/esp32h2/include/hal/spimem_flash_ll.h
  14. 10 0
      components/hal/esp32s2/include/hal/gpspi_flash_ll.h
  15. 2 0
      components/hal/esp32s2/include/hal/spi_flash_ll.h
  16. 11 0
      components/hal/esp32s2/include/hal/spimem_flash_ll.h
  17. 10 0
      components/hal/esp32s3/include/hal/gpspi_flash_ll.h
  18. 3 0
      components/hal/esp32s3/include/hal/spi_flash_ll.h
  19. 70 2
      components/hal/esp32s3/include/hal/spimem_flash_ll.h
  20. 2 1
      components/hal/include/hal/spi_flash_hal.h
  21. 1 0
      components/hal/include/hal/spi_flash_types.h
  22. 1 0
      components/hal/spi_flash_hal.c
  23. 3 0
      components/hal/spi_flash_hal_common.inc
  24. 14 1
      components/hal/spi_flash_hal_iram.c
  25. 8 1
      components/soc/esp32c3/include/soc/spi_mem_struct.h
  26. 0 4
      components/soc/esp32s2/include/soc/Kconfig.soc_caps.in
  27. 0 1
      components/soc/esp32s2/include/soc/soc_caps.h
  28. 8 0
      components/spi_flash/.build-test-rules.yml
  29. 10 3
      components/spi_flash/Kconfig
  30. 2 21
      components/spi_flash/esp_flash_spi_init.c
  31. 25 1
      components/spi_flash/spi_flash_chip_gd.c
  32. 8 13
      components/spi_flash/spi_flash_chip_winbond.c
  33. 0 49
      components/spi_flash/test_apps/esp_flash/main/test_esp_flash_drv.c
  34. 0 1
      tools/ci/check_copyright_ignore.txt

+ 10 - 0
components/hal/esp32/include/hal/spi_flash_ll.h

@@ -399,6 +399,16 @@ static inline void spi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_t
     dev->ctrl2.setup_time = cs_setup_time - 1;
 }
 
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on esp32
+}
+
 /**
  * Get the spi flash source clock frequency. Used for calculating
  * the divider parameters.

+ 10 - 0
components/hal/esp32c2/include/hal/gpspi_flash_ll.h

@@ -149,6 +149,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 2 - 0
components/hal/esp32c2/include/hal/spi_flash_ll.h

@@ -64,6 +64,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 #else
 #define spi_flash_ll_reset(dev)                              spimem_flash_ll_reset((spi_mem_dev_t*)dev)
 #define spi_flash_ll_cmd_is_done(dev)                        spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@@ -91,6 +92,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
 
 #endif
 

+ 65 - 0
components/hal/esp32c2/include/hal/spimem_flash_ll.h

@@ -31,6 +31,7 @@ extern "C" {
 #define spimem_flash_ll_hw_get_id(dev)   ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
 
 #define SPIMEM_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ  (60)
+#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS  (0x1f)
 
 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
 
@@ -207,6 +208,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
     dev->flash_sus_ctrl.pesr_end_msk = sus_conf;
 }
 
+/**
+ * Configure the delay after Suspend/Resume
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param dly_val delay time
+ */
+static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
+{
+    dev->ctrl1.cs_hold_dly_res = dly_val;
+    dev->sus_status.flash_pes_dly_128 = 1;
+    dev->sus_status.flash_per_dly_128 = 1;
+}
+
+/**
+ * Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param cs_hold_delay cs hold delay time
+ */
+static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
+{
+    SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
+}
+
 /**
  * Initialize auto wait idle mode
  *
@@ -232,6 +257,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
     return dev->sus_status.flash_sus;
 }
 
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param lock_time Lock delay time
+ */
+static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
+{
+    dev->sus_status.spi0_lock_en = 1;
+    SPIMEM0.fsm.cspi_lock_delay_time = lock_time;
+}
+
+/**
+ * @brief Get tsus unit values in SPI_CLK cycles
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @return uint32_t tsus unit values
+ */
+static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
+{
+    uint32_t tsus_unit = 0;
+    if (dev->sus_status.flash_pes_dly_128 == 1) {
+        tsus_unit = 128;
+    } else {
+        tsus_unit = 4;
+    }
+    return tsus_unit;
+}
+
 /**
  * Enable/disable write protection for the flash chip.
  *
@@ -320,6 +374,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 10 - 0
components/hal/esp32c3/include/hal/gpspi_flash_ll.h

@@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Set HD pin high when flash work at spi mode.
  *

+ 2 - 0
components/hal/esp32c3/include/hal/spi_flash_ll.h

@@ -64,6 +64,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 #else
 #define spi_flash_ll_reset(dev)                              spimem_flash_ll_reset((spi_mem_dev_t*)dev)
 #define spi_flash_ll_cmd_is_done(dev)                        spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@@ -91,6 +92,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
 
 #endif
 

+ 66 - 0
components/hal/esp32c3/include/hal/spimem_flash_ll.h

@@ -32,6 +32,8 @@ extern "C" {
 #define spimem_flash_ll_get_hw(host_id)  (((host_id)==SPI1_HOST ?  &SPIMEM1 : NULL ))
 #define spimem_flash_ll_hw_get_id(dev)   ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
 
+#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS  (0x1f)
+
 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
 
 /*------------------------------------------------------------------------------
@@ -207,6 +209,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
     HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
 }
 
+/**
+ * Configure the delay after Suspend/Resume
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param dly_val delay time
+ */
+static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
+{
+    dev->ctrl1.cs_hold_dly_res = dly_val;
+    dev->sus_status.pes_dly_128 = 1;
+    dev->sus_status.per_dly_128 = 1;
+}
+
+/**
+ * Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param cs_hold_delay cs hold delay time
+ */
+static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
+{
+    SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
+}
+
 /**
  * Initialize auto wait idle mode
  *
@@ -232,6 +258,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
     return dev->sus_status.flash_sus;
 }
 
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param lock_time Lock delay time
+ */
+static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
+{
+    dev->sus_status.spi0_lock_en = 1;
+    SPIMEM0.fsm.cspi_lock_delay_time = lock_time;
+}
+
+/**
+ * @brief Get tsus unit values in SPI_CLK cycles
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @return uint32_t tsus unit values
+ */
+static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
+{
+    uint32_t tsus_unit = 0;
+    if (dev->sus_status.pes_dly_128 == 1) {
+        tsus_unit = 128;
+    } else {
+        tsus_unit = 4;
+    }
+    return tsus_unit;
+}
+
 /**
  * Enable/disable write protection for the flash chip.
  *
@@ -320,6 +375,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 11 - 1
components/hal/esp32c6/include/hal/gpspi_flash_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Set HD pin high when flash work at spi mode.
  *

+ 3 - 1
components/hal/esp32c6/include/hal/spi_flash_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -65,6 +65,7 @@ typedef union  {
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
 #define spi_flash_ll_set_extra_address(dev, extra_addr)      { /* Not supported on gpspi on ESP32-C6*/ }
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 #else
 #define spi_flash_ll_reset(dev)                              spimem_flash_ll_reset((spi_mem_dev_t*)dev)
 #define spi_flash_ll_cmd_is_done(dev)                        spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@@ -92,6 +93,7 @@ typedef union  {
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
 #define spi_flash_ll_set_extra_address(dev, extra_addr)      spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
 
 #endif
 

+ 67 - 1
components/hal/esp32c6/include/hal/spimem_flash_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -33,6 +33,8 @@ extern "C" {
 #define spimem_flash_ll_get_hw(host_id)  (((host_id)==SPI1_HOST ?  &SPIMEM1 : NULL ))
 #define spimem_flash_ll_hw_get_id(dev)   ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
 
+#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS  (0x1f)
+
 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
 
 /*------------------------------------------------------------------------------
@@ -208,6 +210,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
     HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
 }
 
+/**
+ * Configure the delay after Suspend/Resume
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param dly_val delay time
+ */
+static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
+{
+    dev->ctrl1.cs_hold_dly_res = dly_val;
+    dev->sus_status.flash_per_dly_128 = 1;
+    dev->sus_status.flash_pes_dly_128 = 1;
+}
+
+/**
+ * Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param cs_hold_delay cs hold delay time
+ */
+static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
+{
+    SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
+}
+
 /**
  * Initialize auto wait idle mode
  *
@@ -233,6 +259,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
     return dev->sus_status.flash_sus;
 }
 
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param lock_time Lock delay time
+ */
+static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
+{
+    dev->sus_status.spi0_lock_en = 1;
+    SPIMEM0.fsm.lock_delay_time = lock_time;
+}
+
+/**
+ * @brief Get tsus unit values in SPI_CLK cycles
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @return uint32_t tsus unit values
+ */
+static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
+{
+    uint32_t tsus_unit = 0;
+    if (dev->sus_status.flash_pes_dly_128 == 1) {
+        tsus_unit = 128;
+    } else {
+        tsus_unit = 4;
+    }
+    return tsus_unit;
+}
+
 /**
  * Enable/disable write protection for the flash chip.
  *
@@ -321,6 +376,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 11 - 1
components/hal/esp32h2/include/hal/gpspi_flash_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Set HD pin high when flash work at spi mode.
  *

+ 3 - 1
components/hal/esp32h2/include/hal/spi_flash_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -65,6 +65,7 @@ typedef union  {
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
 #define spi_flash_ll_set_extra_address(dev, extra_addr)      { /* Not supported on gpspi on ESP32-H2*/ }
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 #else
 #define spi_flash_ll_reset(dev)                              spimem_flash_ll_reset((spi_mem_dev_t*)dev)
 #define spi_flash_ll_cmd_is_done(dev)                        spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@@ -92,6 +93,7 @@ typedef union  {
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
 #define spi_flash_ll_set_extra_address(dev, extra_addr)      spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
 
 #endif
 

+ 66 - 0
components/hal/esp32h2/include/hal/spimem_flash_ll.h

@@ -35,6 +35,8 @@ extern "C" {
 #define spimem_flash_ll_get_hw(host_id)  (((host_id)==SPI1_HOST ?  &SPIMEM1 : NULL ))
 #define spimem_flash_ll_hw_get_id(dev)   ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
 
+#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS  (0x1f)
+
 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
 
 /*------------------------------------------------------------------------------
@@ -210,6 +212,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
     HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
 }
 
+/**
+ * Configure the delay after Suspend/Resume
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param dly_val delay time
+ */
+static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
+{
+    dev->ctrl1.cs_hold_dly_res = dly_val;
+    dev->sus_status.flash_per_dly_128 = 1;
+    dev->sus_status.flash_pes_dly_128 = 1;
+}
+
+/**
+ * Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param cs_hold_delay cs hold delay time
+ */
+static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
+{
+    SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
+}
+
 /**
  * Initialize auto wait idle mode
  *
@@ -235,6 +261,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
     return dev->sus_status.flash_sus;
 }
 
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param lock_time Lock delay time
+ */
+static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
+{
+    dev->sus_status.spi0_lock_en = 1;
+    SPIMEM0.fsm.lock_delay_time = lock_time;
+}
+
+/**
+ * @brief Get tsus unit values in SPI_CLK cycles
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @return uint32_t tsus unit values
+ */
+static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
+{
+    uint32_t tsus_unit = 0;
+    if (dev->sus_status.flash_pes_dly_128 == 1) {
+        tsus_unit = 128;
+    } else {
+        tsus_unit = 4;
+    }
+    return tsus_unit;
+}
+
 /**
  * Enable/disable write protection for the flash chip.
  *
@@ -323,6 +378,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 10 - 0
components/hal/esp32s2/include/hal/gpspi_flash_ll.h

@@ -134,6 +134,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Set HD pin high when flash work at spi mode.
  *

+ 2 - 0
components/hal/esp32s2/include/hal/spi_flash_ll.h

@@ -65,6 +65,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 
 #else
 
@@ -94,6 +95,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
 
 #endif
 

+ 11 - 0
components/hal/esp32s2/include/hal/spimem_flash_ll.h

@@ -316,6 +316,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 10 - 0
components/hal/esp32s3/include/hal/gpspi_flash_ll.h

@@ -145,6 +145,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
+{
+    // Not supported on GPSPI
+}
+
 /**
  * Set HD pin high when flash work at spi mode.
  *

+ 3 - 0
components/hal/esp32s3/include/hal/spi_flash_ll.h

@@ -63,6 +63,7 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
 
 #else
 #define spi_flash_ll_reset(dev)                              spimem_flash_ll_reset((spi_mem_dev_t*)dev)
@@ -91,6 +92,8 @@ typedef union  {
 #define spi_flash_ll_set_dummy_out(dev, en, lev)             spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
 #define spi_flash_ll_set_hold(dev, hold_n)                   spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
 #define spi_flash_ll_set_cs_setup(dev, cs_setup_time)        spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
+#define spi_flash_ll_set_pe_bit(dev)                         spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
+
 #endif
 
 #ifdef __cplusplus

+ 70 - 2
components/hal/esp32s3/include/hal/spimem_flash_ll.h

@@ -32,6 +32,8 @@ extern "C" {
 #define spimem_flash_ll_get_hw(host_id)  (((host_id)==SPI1_HOST ?  &SPIMEM1 : NULL ))
 #define spimem_flash_ll_hw_get_id(dev)  ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
 
+#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS  (0x1f)
+
 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
 
 /*------------------------------------------------------------------------------
@@ -120,6 +122,7 @@ static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
 static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
 {
     dev->flash_sus_ctrl.flash_pes_en = auto_sus; // enable Flash Auto-Suspend.
+    dev->flash_sus_cmd.pes_per_en = auto_sus;
 }
 
 /**
@@ -167,7 +170,7 @@ static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t
  */
 static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
 {
-    abort(); //Not support on esp32s3
+    //Not support on esp32s3
 }
 
 /**
@@ -201,7 +204,59 @@ static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool
  */
 static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask)
 {
-    abort();// Not supported on esp32s3
+    // Not supported on esp32s3
+}
+
+/**
+ * Configure the delay after Suspend/Resume
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param dly_val delay time
+ */
+static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
+{
+    dev->ctrl1.cs_hold_dly_res = dly_val;
+    dev->sus_status.flash_per_dly_256 = 1;
+    dev->sus_status.flash_pes_dly_256 = 1;
+}
+
+/**
+ * Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param cs_hold_delay cs hold delay time
+ */
+static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
+{
+    SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
+}
+
+/**
+ * @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @param lock_time Lock delay time
+ */
+static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
+{
+    // Not support on esp32s3
+}
+
+/**
+ * @brief Get tsus unit values in SPI_CLK cycles
+ *
+ * @param dev Beginning address of the peripheral registers.
+ * @return uint32_t tsus unit values
+ */
+static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
+{
+    uint32_t tsus_unit = 0;
+    if (dev->sus_status.flash_pes_dly_256 == 1) {
+        tsus_unit = 128;
+    } else {
+        tsus_unit = 4;
+    }
+    return tsus_unit;
 }
 
 /**
@@ -214,6 +269,8 @@ static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool
 {
     HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); // Set the command to send, to fetch flash status reg value.
     dev->flash_waiti_ctrl.waiti_en = auto_waiti;  // enable auto wait-idle function.
+    dev->flash_sus_cmd.flash_per_wait_en = 1;
+    dev->flash_sus_cmd.flash_pes_wait_en = 1;
 }
 
 /**
@@ -316,6 +373,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
     dev->cmd.usr = 1;
 }
 
+/**
+ * In user mode, it is set to indicate that program/erase operation will be triggered.
+ * This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
+ *
+ * @param dev Beginning address of the peripheral registers.
+ */
+static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
+{
+    dev->cmd.flash_pe = 1;
+}
+
 /**
  * Check whether the host is idle to perform new commands.
  *

+ 2 - 1
components/hal/include/hal/spi_flash_hal.h

@@ -47,8 +47,9 @@ typedef struct {
     spi_flash_sus_cmd_conf sus_cfg;        ///< To store suspend command/mask information.
     uint32_t slicer_flags;      /// Slicer flags for configuring how to slice data correctly while reading or writing.
 #define SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR           BIT(0)  ///< Slice data according to DTR mode, the address and length must be even (A0=0).
+    int freq_mhz;               /// Flash clock frequency.
 } spi_flash_hal_context_t;
-ESP_STATIC_ASSERT(sizeof(spi_flash_hal_context_t) == 40, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
+ESP_STATIC_ASSERT(sizeof(spi_flash_hal_context_t) == 44, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
 
 /// This struct provide MSPI Flash necessary timing related config, should be consistent with that in union in `spi_flash_hal_config_t`.
 typedef struct {

+ 1 - 0
components/hal/include/hal/spi_flash_types.h

@@ -27,6 +27,7 @@ typedef struct {
 #define SPI_FLASH_TRANS_FLAG_CMD16          BIT(0)  ///< Send command of 16 bits
 #define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO  BIT(1)  ///< Not applying the basic io mode configuration for this transaction
 #define SPI_FLASH_TRANS_FLAG_BYTE_SWAP      BIT(2)  ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
+#define SPI_FLASH_TRANS_FLAG_PE_CMD         BIT(3)  ///< Indicates that this transaction is to erase/program flash chip.
     uint16_t command;           ///< Command to send
     uint8_t dummy_bitlen;       ///< Basic dummy bits to use
     uint32_t io_mode;           ///< Flash working mode when `SPI_FLASH_IGNORE_BASEIO` is specified.

+ 1 - 0
components/hal/spi_flash_hal.c

@@ -103,6 +103,7 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
         .cs_hold = cfg->cs_hold,
         .cs_setup = cfg->cs_setup,
         .base_io_mode = cfg->default_io_mode,
+        .freq_mhz = cfg->freq_mhz,
     };
 #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
     if (cfg->using_timing_tuning) {

+ 3 - 0
components/hal/spi_flash_hal_common.inc

@@ -170,6 +170,9 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_tr
     spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len);
 
     spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8);
+    if ((trans->flags & SPI_FLASH_TRANS_FLAG_PE_CMD) != 0) {
+        spi_flash_ll_set_pe_bit(dev);
+    }
     spi_flash_ll_user_start(dev);
     host->driver->poll_cmd_done(host);
     if (trans->miso_len > 0) {

+ 14 - 1
components/hal/spi_flash_hal_iram.c

@@ -6,11 +6,14 @@
 #include "sdkconfig.h"
 
 #include "hal/spi_flash_hal.h"
+
 #if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
 void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host);
 void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host);
 void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host);
 void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host);
+#define SPI_FLASH_TSUS_SAFE_VAL_US   (30)
+#define SPI_FLASH_TSHSL2_SAFE_VAL_NS (30)
 #endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
 
 #ifndef CONFIG_SPI_FLASH_ROM_IMPL
@@ -128,10 +131,12 @@ esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const sp
     spi_mem_dev_t *dev = (spi_mem_dev_t *)spi_flash_ll_get_hw(SPI1_HOST);
     spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
     memcpy(&(ctx->sus_cfg), sus_conf, sizeof(spi_flash_sus_cmd_conf));
-    spimem_flash_ll_set_read_sus_status(dev, sus_conf->sus_mask);
     spimem_flash_ll_suspend_cmd_setup(dev, sus_conf->sus_cmd);
     spimem_flash_ll_resume_cmd_setup(dev, sus_conf->res_cmd);
+#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
+    spimem_flash_ll_set_read_sus_status(dev, sus_conf->sus_mask);
     spimem_flash_ll_rd_sus_cmd_setup(dev, sus_conf->cmd_rdsr);
+#endif // SOC_SPI_MEM_SUPPORT_CHECK_SUS
 #endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
     return ESP_OK;
 }
@@ -140,8 +145,16 @@ esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const sp
 void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host)
 {
     spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
+    spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
     spimem_flash_ll_auto_wait_idle_init(dev, true);
     spimem_flash_ll_auto_suspend_init(dev, true);
+    // tsus = ceil(SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz / spimem_flash_ll_get_tsus_unit_in_cycles);
+    uint32_t tsus = (SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz / spimem_flash_ll_get_tsus_unit_in_cycles(dev)) + ((SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz) % spimem_flash_ll_get_tsus_unit_in_cycles(dev) != 0);
+    spimem_flash_ll_set_sus_delay(dev, tsus);
+    // tshsl2 = ceil(SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz() * 0.001);
+    uint32_t tshsl2 = (SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz() / 1000) + ((SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz()) % 1000 != 0);
+    spimem_flash_set_cs_hold_delay(dev, tshsl2);
+    spimem_flash_ll_sus_set_spi0_lock_trans(dev, SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS);
 #if SOC_SPI_MEM_SUPPORT_CHECK_SUS
     spimem_flash_ll_sus_check_sus_setup(dev, true);
 #endif

+ 8 - 1
components/soc/esp32c3/include/soc/spi_mem_struct.h

@@ -238,7 +238,14 @@ typedef volatile struct spi_mem_dev_s {
     union {
         struct {
             uint32_t flash_sus:     1;                  /*The status of flash suspend  only used in SPI1.*/
-            uint32_t reserved1:    31;                  /*reserved*/
+            uint32_t wait_pesr_cmd_2b:1;
+            uint32_t hpm_dly_128:   1;
+            uint32_t res_dly_128:   1;
+            uint32_t dp_dly_128:    1;
+            uint32_t per_dly_128:   1;
+            uint32_t pes_dly_128:   1;
+            uint32_t spi0_lock_en:  1;
+            uint32_t reserved1:    24;                  /*reserved*/
         };
         uint32_t val;
     } sus_status;

+ 0 - 4
components/soc/esp32s2/include/soc/Kconfig.soc_caps.in

@@ -951,10 +951,6 @@ config SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
     bool
     default y
 
-config SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
-    bool
-    default y
-
 config SOC_SPI_MEM_SUPPORT_SW_SUSPEND
     bool
     default y

+ 0 - 1
components/soc/esp32s2/include/soc/soc_caps.h

@@ -414,7 +414,6 @@
 
 /*-------------------------- SPI MEM CAPS ---------------------------------------*/
 #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE                (1)
-#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND                  (1)
 #define SOC_SPI_MEM_SUPPORT_SW_SUSPEND                    (1)
 #define SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE          (1)
 #define SOC_SPI_MEM_SUPPORT_WRAP                          (1)

+ 8 - 0
components/spi_flash/.build-test-rules.yml

@@ -11,3 +11,11 @@ components/spi_flash/test_apps/flash_encryption:
     - if: IDF_TARGET in ["esp32c2", "esp32s2", "esp32c6", "esp32h2"]
       temporary: true
       reason: No runners # IDF-5634
+
+components/spi_flash/test_apps/flash_suspend:
+  disable:
+    - if: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND != 1
+  disable_test:
+    - if: IDF_TARGET != "esp32c3"
+      temporary: true
+      reason: lack of runners

+ 10 - 3
components/spi_flash/Kconfig

@@ -147,17 +147,24 @@ menu "SPI Flash driver"
         help
             Defines how many ticks will be before returning to continue a erasing.
 
+    config SPI_FLASH_SUSPEND_QVL_SUPPORTED
+        # Internally usage
+        bool
+        default y if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
+        default n
+
     config SPI_FLASH_AUTO_SUSPEND
         bool "Auto suspend long erase/write operations (READ DOCS FIRST)"
         default n
-        depends on IDF_TARGET_ESP32C3 && !SPI_FLASH_ROM_IMPL
+        depends on SPI_FLASH_SUSPEND_QVL_SUPPORTED && !SPI_FLASH_ROM_IMPL
         help
-            This option is default n before ESP32-C3, because it needs bootloader support.
+            This option is default n because it can't be used in every situation. You need to
+            evaluate this feature through suspend part in `SPI Flash API` document.
 
             CAUTION: If you want to OTA to an app with this feature turned on, please make
             sure the bootloader has the support for it. (later than IDF v4.3)
 
-            Auto-suspend feature only supported by XMC chip.
+            Auto-suspend feature only supported by specific flash chips.
             If you are using an official module, please contact Espressif Business support.
             Also reading auto suspend part in `SPI Flash API` document before you enable this function.
 

+ 2 - 21
components/spi_flash/esp_flash_spi_init.c

@@ -97,26 +97,7 @@ esp_flash_t *esp_flash_default_chip = NULL;
     .input_delay_ns = 0,\
     .cs_setup = 1,\
 }
-#elif CONFIG_IDF_TARGET_ESP32S2
-#define ESP_FLASH_HOST_CONFIG_DEFAULT()  (memspi_host_config_t){ \
-    .host_id = SPI1_HOST,\
-    .freq_mhz = DEFAULT_FLASH_SPEED, \
-    .cs_num = 0, \
-    .iomux = true, \
-    .input_delay_ns = 0,\
-    .cs_setup = 1,\
-}
-#elif CONFIG_IDF_TARGET_ESP32S3
-#include "esp32s3/rom/efuse.h"
-#define ESP_FLASH_HOST_CONFIG_DEFAULT()  (memspi_host_config_t){ \
-    .host_id = SPI1_HOST,\
-    .freq_mhz = DEFAULT_FLASH_SPEED, \
-    .cs_num = 0, \
-    .iomux = true, \
-    .input_delay_ns = 0,\
-    .cs_setup = 1,\
-}
-#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#else // Other target
 #if !CONFIG_SPI_FLASH_AUTO_SUSPEND
 #define ESP_FLASH_HOST_CONFIG_DEFAULT()  (memspi_host_config_t){ \
     .host_id = SPI1_HOST,\
@@ -137,7 +118,7 @@ esp_flash_t *esp_flash_default_chip = NULL;
     .cs_setup = 1,\
 }
 #endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
-#endif
+#endif // Other target
 
 static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id)
 {

+ 25 - 1
components/spi_flash/spi_flash_chip_gd.c

@@ -11,6 +11,7 @@
 #include "spi_flash_chip_generic.h"
 #include "spi_flash_chip_gd.h"
 #include "spi_flash_defs.h"
+#include "sdkconfig.h"
 
 #define ADDR_32BIT(addr)            (addr >= (1<<24))
 
@@ -33,6 +34,17 @@ spi_flash_caps_t spi_flash_chip_gd_get_caps(esp_flash_t *chip)
     if ((chip->chip_id & 0xFF) >= 0x19) {
         caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT;
     }
+#if CONFIG_SPI_FLASH_AUTO_SUSPEND
+    switch (chip->chip_id) {
+    /* The flash listed here can support suspend */
+    case 0xC84017:
+    case 0xC84018:
+        caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
+        break;
+    default:
+        break;
+    }
+#endif
     // flash-suspend is not supported
     // flash read unique id.
     caps_flags |= SPI_FLASH_CHIP_CAP_UNIQUE_ID;
@@ -112,6 +124,18 @@ esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t*
 }
 #endif //CONFIG_SPI_FLASH_ROM_IMPL
 
+esp_err_t spi_flash_chip_gd_suspend_cmd_conf(esp_flash_t *chip)
+{
+    spi_flash_sus_cmd_conf sus_conf = {
+        .sus_mask = 0x84,
+        .cmd_rdsr = CMD_RDSR2,
+        .sus_cmd = CMD_SUSPEND,
+        .res_cmd = CMD_RESUME,
+    };
+
+    return chip->host->driver->sus_setup(chip->host, &sus_conf);
+}
+
 static const char chip_name[] = "gd";
 
 // The issi chip can use the functions for generic chips except from set read mode and probe,
@@ -148,7 +172,7 @@ const spi_flash_chip_t esp_flash_chip_gd = {
 
     .read_reg = spi_flash_chip_generic_read_reg,
     .yield = spi_flash_chip_generic_yield,
-    .sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
+    .sus_setup = spi_flash_chip_gd_suspend_cmd_conf,
     .read_unique_id = spi_flash_chip_generic_read_unique_id,
     .get_chip_caps = spi_flash_chip_gd_get_caps,
     .config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,

+ 8 - 13
components/spi_flash/spi_flash_chip_winbond.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #include <stdlib.h>
 #include <string.h>
@@ -209,6 +201,7 @@ static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const v
         .address = address,
         .mosi_len = length,
         .mosi_data = buffer,
+        .flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
     };
     return chip->host->driver->common_command(chip->host, &t);
 }
@@ -220,6 +213,7 @@ esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t
         .command = (addr_4b? CMD_SECTOR_ERASE_4B: CMD_SECTOR_ERASE),
         .address_bitlen = (addr_4b? 32: 24),
         .address = start_address,
+        .flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
     };
     return chip->host->driver->common_command(chip->host, &t);
 }
@@ -231,6 +225,7 @@ esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_add
         .command = (addr_4b? CMD_LARGE_BLOCK_ERASE_4B: CMD_LARGE_BLOCK_ERASE),
         .address_bitlen = (addr_4b? 32: 24),
         .address = start_address,
+        .flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
     };
     return chip->host->driver->common_command(chip->host, &t);
 }

+ 0 - 49
components/spi_flash/test_apps/esp_flash/main/test_esp_flash_drv.c

@@ -459,55 +459,6 @@ static void test_flash_erase_not_trigger_wdt(const esp_partition_t *part)
 
 TEST_CASE_MULTI_FLASH_LONG("Test erasing flash chip not triggering WDT", test_flash_erase_not_trigger_wdt);
 
-
-#if CONFIG_SPI_FLASH_AUTO_SUSPEND
-void esp_test_for_suspend(void)
-{
-    /*clear content in cache*/
-#if !CONFIG_IDF_TARGET_ESP32C3
-    Cache_Invalidate_DCache_All();
-#endif
-    Cache_Invalidate_ICache_All();
-    ESP_LOGI(TAG, "suspend test begins:");
-    printf("run into test suspend function\n");
-    printf("print something when flash is erasing:\n");
-    printf("aaaaa bbbbb zzzzz fffff qqqqq ccccc\n");
-}
-
-static volatile bool task_erase_end, task_suspend_end = false;
-void task_erase_large_region(void *arg)
-{
-    esp_partition_t *part = (esp_partition_t *)arg;
-    test_erase_large_region(part);
-    task_erase_end = true;
-    vTaskDelete(NULL);
-}
-
-void task_request_suspend(void *arg)
-{
-    vTaskDelay(2);
-    ESP_LOGI(TAG, "flash go into suspend");
-    esp_test_for_suspend();
-    task_suspend_end = true;
-    vTaskDelete(NULL);
-}
-
-static void test_flash_suspend_resume(const esp_partition_t* part)
-{
-    xTaskCreatePinnedToCore(task_request_suspend, "suspend", 2048, (void *)"test_for_suspend", UNITY_FREERTOS_PRIORITY + 3, NULL, 0);
-    xTaskCreatePinnedToCore(task_erase_large_region, "test", 2048, (void *)part, UNITY_FREERTOS_PRIORITY + 2, NULL, 0);
-    while (!task_erase_end || !task_suspend_end) {
-    }
-    vTaskDelay(200);
-}
-
-TEST_CASE("SPI flash suspend and resume test", "[esp_flash][test_env=UT_T1_Flash_Suspend]")
-{
-    flash_test_func(test_flash_suspend_resume, 1 /* first index reserved for main flash */ );
-}
-
-#endif //CONFIG_SPI_FLASH_AUTO_SUSPEND
-
 static void test_write_protection(const esp_partition_t* part)
 {
     esp_flash_t* chip = part->flash_chip;

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -999,7 +999,6 @@ components/spi_flash/include/spi_flash_chip_winbond.h
 components/spi_flash/spi_flash_chip_boya.c
 components/spi_flash/spi_flash_chip_issi.c
 components/spi_flash/spi_flash_chip_mxic.c
-components/spi_flash/spi_flash_chip_winbond.c
 components/spi_flash/test/test_esp_flash.c
 components/spi_flash/test/test_flash_encryption.c
 components/spi_flash/test/test_mmap.c