diff --git a/components/hal/esp32c2/include/hal/spimem_flash_ll.h b/components/hal/esp32c2/include/hal/spimem_flash_ll.h index 8c1d1608b1..5ef9711a68 100644 --- a/components/hal/esp32c2/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c2/include/hal/spimem_flash_ll.h @@ -18,7 +18,7 @@ #include // For MIN/MAX #include #include - +#include "hal/misc.h" #include "soc/spi_periph.h" #include "hal/spi_types.h" #include "hal/spi_flash_types.h" @@ -144,7 +144,7 @@ static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool aut */ static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd) { - dev->flash_sus_cmd.flash_pes_command = sus_cmd; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, flash_pes_command, sus_cmd); } /** @@ -156,7 +156,7 @@ static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_ */ static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd) { - dev->flash_sus_cmd.flash_per_command = res_cmd; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, flash_per_command, res_cmd); } /** @@ -168,7 +168,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) { - dev->flash_sus_cmd.wait_pesr_command = pesr_cmd; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, wait_pesr_command, pesr_cmd); } /** @@ -205,7 +205,7 @@ 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_conf) { dev->flash_sus_ctrl.frd_sus_2b = 0; - dev->flash_sus_ctrl.pesr_end_msk = sus_conf; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf); } /** @@ -236,13 +236,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { - dev->flash_waiti_ctrl.waiti_cmd = 0x05; - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -518,11 +519,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/esp32c3/include/hal/spimem_flash_ll.h b/components/hal/esp32c3/include/hal/spimem_flash_ll.h index fd9bc38ed9..7210343b8b 100644 --- a/components/hal/esp32c3/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c3/include/hal/spimem_flash_ll.h @@ -238,13 +238,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -520,11 +521,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/esp32c5/include/hal/spimem_flash_ll.h b/components/hal/esp32c5/include/hal/spimem_flash_ll.h index 83f5e6bada..a57c3e2093 100644 --- a/components/hal/esp32c5/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c5/include/hal/spimem_flash_ll.h @@ -243,13 +243,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -530,11 +531,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/esp32c6/include/hal/spimem_flash_ll.h b/components/hal/esp32c6/include/hal/spimem_flash_ll.h index ba68cc3bc7..1971f41d05 100644 --- a/components/hal/esp32c6/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c6/include/hal/spimem_flash_ll.h @@ -239,13 +239,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -521,11 +522,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** @@ -561,7 +559,7 @@ static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr) { dev->cache_fctrl.usr_addr_4byte = 0; - dev->rd_status.wb_mode = extra_addr; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rd_status, wb_mode, extra_addr); } /** diff --git a/components/hal/esp32c61/include/hal/spimem_flash_ll.h b/components/hal/esp32c61/include/hal/spimem_flash_ll.h index 4a2507d03f..69e2716b2f 100644 --- a/components/hal/esp32c61/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c61/include/hal/spimem_flash_ll.h @@ -242,13 +242,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -523,11 +524,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** @@ -563,7 +561,7 @@ static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr) { dev->cache_fctrl.cache_usr_addr_4byte = 0; - dev->rd_status.wb_mode = extra_addr; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rd_status, wb_mode, extra_addr); } /** diff --git a/components/hal/esp32h2/include/hal/spimem_flash_ll.h b/components/hal/esp32h2/include/hal/spimem_flash_ll.h index caf551023f..470c7dedd3 100644 --- a/components/hal/esp32h2/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32h2/include/hal/spimem_flash_ll.h @@ -240,13 +240,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -542,11 +543,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** @@ -582,7 +580,7 @@ static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr) { dev->cache_fctrl.usr_addr_4byte = 0; - dev->rd_status.wb_mode = extra_addr; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rd_status, wb_mode, extra_addr); } /** diff --git a/components/hal/esp32p4/include/hal/spimem_flash_ll.h b/components/hal/esp32p4/include/hal/spimem_flash_ll.h index 95d11df008..27f619ad25 100644 --- a/components/hal/esp32p4/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32p4/include/hal/spimem_flash_ll.h @@ -245,13 +245,14 @@ static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t c * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); - dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; - dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_per_wait_en = per_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = pes_waiti; } /** @@ -531,11 +532,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/esp32s2/include/hal/spimem_flash_ll.h b/components/hal/esp32s2/include/hal/spimem_flash_ll.h index 42a0fba45b..a7c3d66106 100644 --- a/components/hal/esp32s2/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32s2/include/hal/spimem_flash_ll.h @@ -209,12 +209,13 @@ static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { - 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. + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); + dev->flash_waiti_ctrl.waiti_en = (per_waiti | pes_waiti); // enable auto wait-idle function. } /** @@ -460,11 +461,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/esp32s3/include/hal/spimem_flash_ll.h b/components/hal/esp32s3/include/hal/spimem_flash_ll.h index 41c1e8b388..cde21e1443 100644 --- a/components/hal/esp32s3/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32s3/include/hal/spimem_flash_ll.h @@ -264,14 +264,15 @@ static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *de * Initialize auto wait idle mode * * @param dev Beginning address of the peripheral registers. - * @param auto_waiti Enable/disable auto wait-idle function + * @param per_waiti Enable wait-idle with time delay function after resume. + * @param pes_waiti Enable wait-idle with time delay function after suspend. */ -static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool per_waiti, bool pes_waiti) { - 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; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); + dev->flash_waiti_ctrl.waiti_en = (per_waiti | pes_waiti); // enable auto wait-idle function. + dev->flash_sus_cmd.flash_per_wait_en = per_waiti; + dev->flash_sus_cmd.flash_pes_wait_en = pes_waiti; } /** @@ -538,11 +539,8 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) { dev->user.usr_command = 1; - typeof(dev->user2) user2 = { - .usr_command_value = command, - .usr_command_bitlen = (bitlen - 1), - }; - dev->user2.val = user2.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_value, command); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user2, usr_command_bitlen, (bitlen - 1)); } /** diff --git a/components/hal/include/hal/spi_flash_hal.h b/components/hal/include/hal/spi_flash_hal.h index 593bb5b1a1..b50ac7726b 100644 --- a/components/hal/include/hal/spi_flash_hal.h +++ b/components/hal/include/hal/spi_flash_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,10 @@ extern "C" { #define SPI_FLASH_HAL_MAX_WRITE_BYTES 64 #define SPI_FLASH_HAL_MAX_READ_BYTES 64 +/* spi flash state */ +#define SPI_FLASH_HAL_STATUS_BUSY BIT0 +#define SPI_FLASH_HAL_STATUS_SUSPEND BIT1 + /** * Generic driver context structure for all chips using the SPI peripheral. * Include this into the HEAD of the driver data for other driver @@ -53,6 +57,7 @@ typedef struct { #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. uint8_t tsus_val; ///< Tsus value of suspend (us) + bool auto_waiti_pes; ///< True for auto-wait idle after suspend command. False for using time delay. } spi_flash_hal_context_t; ESP_STATIC_ASSERT(sizeof(spi_flash_hal_context_t) == 48, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM"); @@ -82,11 +87,12 @@ typedef struct { int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1). bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable. bool octal_mode_en; ///< Octal spi flash mode enable bit 1: enable, 0: disable. - bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directely if set to 1. + bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directly if set to 1. esp_flash_io_mode_t default_io_mode; ///< Default flash io mode. int freq_mhz; ///< SPI flash clock speed (MHZ). int clock_src_freq; ///< SPI flash clock source (MHZ). - uint8_t tsus_val; ///< Tsus value of suspend (us) + uint8_t tsus_val; ///< Tsus value of suspend (us). + bool auto_waiti_pes; ///< True for auto-wait idle after suspend command. False for using time delay. } spi_flash_hal_config_t; /** diff --git a/components/hal/spi_flash_hal.c b/components/hal/spi_flash_hal.c index d758608c8b..27f3d0d14e 100644 --- a/components/hal/spi_flash_hal.c +++ b/components/hal/spi_flash_hal.c @@ -130,8 +130,13 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_ data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND; data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME; data_out->tsus_val = cfg->tsus_val; + data_out->auto_waiti_pes = cfg->auto_waiti_pes; } +#if CONFIG_SPI_FLASH_SOFTWARE_RESUME + data_out->flags &= ~SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME; +#endif + #if SOC_SPI_MEM_SUPPORT_OPI_MODE if (cfg->octal_mode_en) { data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE; diff --git a/components/hal/spi_flash_hal_iram.c b/components/hal/spi_flash_hal_iram.c index e73ead6ad9..e4f62e956c 100644 --- a/components/hal/spi_flash_hal_iram.c +++ b/components/hal/spi_flash_hal_iram.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -145,7 +145,8 @@ 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); + bool pes_waiti_delay = ctx->auto_waiti_pes ? false : true; + spimem_flash_ll_auto_wait_idle_init(dev, true, pes_waiti_delay); if (ctx->freq_mhz == 120) { spimem_flash_ll_set_wait_idle_dummy_phase(dev, ctx->extra_dummy); } @@ -159,6 +160,7 @@ void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host) 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); + spimem_flash_ll_res_check_sus_setup(dev, true); #endif } @@ -166,18 +168,16 @@ void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host) { spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST); spimem_flash_ll_auto_resume_init(dev, true); -#if SOC_SPI_MEM_SUPPORT_CHECK_SUS - spimem_flash_ll_res_check_sus_setup(dev, true); -#endif } void spi_flash_hal_disable_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); - spimem_flash_ll_auto_wait_idle_init(dev, false); + spimem_flash_ll_auto_wait_idle_init(dev, false, false); spimem_flash_ll_auto_suspend_init(dev, false); #if SOC_SPI_MEM_SUPPORT_CHECK_SUS spimem_flash_ll_sus_check_sus_setup(dev, false); + spimem_flash_ll_res_check_sus_setup(dev, false); #endif } @@ -185,9 +185,6 @@ void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host) { spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST); spimem_flash_ll_auto_resume_init(dev, false); -#if SOC_SPI_MEM_SUPPORT_CHECK_SUS - spimem_flash_ll_res_check_sus_setup(dev, false); -#endif } #endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND @@ -195,6 +192,7 @@ void spi_flash_hal_resume(spi_flash_host_inst_t *host) { #if SOC_SPI_MEM_SUPPORT_SW_SUSPEND spimem_flash_ll_resume((spi_mem_dev_t*)(((spi_flash_hal_context_t *)host)->spi)); + host->driver->poll_cmd_done(host); #else abort(); #endif @@ -204,6 +202,7 @@ void spi_flash_hal_suspend(spi_flash_host_inst_t *host) { #if SOC_SPI_MEM_SUPPORT_SW_SUSPEND spimem_flash_ll_suspend((spi_mem_dev_t *)(((spi_flash_hal_context_t *)host)->spi)); + host->driver->poll_cmd_done(host); #else abort(); #endif diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 80a48a1b7e..e3011eb8f7 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -120,6 +120,40 @@ menu "Main Flash configuration" For new users, DO NOT enable this config. + config SPI_FLASH_SOFTWARE_RESUME + bool "Resume flash program/erase form suspend state by software control" + default n + depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE && IDF_EXPERIMENTAL_FEATURES + help + Enable this config will disable auto-resume from hardware. Thus the software will resume the chip + after any higher priority task/interrupt which suspend the chip. The benefit is that the suspend-resume + will not disturb the higher priority task and interrupt. + + This currently is only valid on single core chip. + + config SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND + bool "Disable task scheduler when suspend is enabled when SPI1 operation is ongoing" + default n + # Only valid on single core because no protection is supported on multi core + depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE + help + Disable freertos task scheduler when CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled. + Thus only interrupt can trigger a suspend. When SPI_FLASH_AUTO_SUSPEND is enabled, + default behavior is not disable the task scheduler, so both interrupt and high priority + task can suspend the erase/program operation. When this option is enabled, task + scheduler is disabled, only interrupt can suspend erase/program operation. + + config SPI_FLASH_AUTO_CHECK_SUSPEND_STATUS + bool "Check flash status automatically after flash suspend" + default n + depends on SPI_FLASH_AUTO_SUSPEND + help + Majority flash supports to use flash register to judge if flash suspend status is + done or not. So enable this config, the behavior would use flash register WIP bit to judge + whether suspend is valid instead of waiting for a specific long time, which can save a + lot of time and benefit for performance improvement. + + endmenu endmenu diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index aafaa32233..a4cb822718 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -21,6 +21,7 @@ #include "esp_rom_spiflash.h" #include "esp_private/esp_clk.h" #include "esp_spi_flash_counters.h" +#include "esp_check.h" #if CONFIG_IDF_TARGET_ESP32S2 #include "esp_crypto_lock.h" // for locking flash encryption peripheral @@ -1269,7 +1270,7 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres that share a key (as derived from flash address). On ESP32-S2 and later, the temporary buffer need to be - seperated into 16-bytes, 32-bytes, 64-bytes(if supported). + separated into 16-bytes, 32-bytes, 64-bytes(if supported). So, on ESP32-S2 and later, here has a totally different data prepare implementation. diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 9f6c54678f..1e9eb050bc 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -386,6 +386,10 @@ esp_err_t esp_flash_init_default_chip(void) cfg.tsus_val = TSUS_VAL_SUSPEND; #endif // CONFIG_SPI_FLASH_AUTO_SUSPEND + #if CONFIG_SPI_FLASH_AUTO_CHECK_SUSPEND_STATUS + cfg.auto_waiti_pes = true; + #endif + //the host is already initialized, only do init for the data and load it to the host esp_err_t err = memspi_host_init_pointers(&esp_flash_default_host, &cfg); if (err != ESP_OK) { diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index f9b6d11f3a..062e1c598f 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -204,7 +204,7 @@ esp_err_t esp_flash_erase_chip(esp_flash_t *chip); * @param start Address to start erasing flash. Must be sector aligned. * @param len Length of region to erase. Must also be sector aligned. * - * Sector size is specifyed in chip->drv->sector_size field (typically 4096 bytes.) ESP_ERR_INVALID_ARG will be + * Sector size is specified in chip->drv->sector_size field (typically 4096 bytes.) ESP_ERR_INVALID_ARG will be * returned if the start & length are not a multiple of this size. * * Erase is performed using block (multi-sector) erases where possible (block size is specified in diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index d71b279e36..9481b7d82d 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -376,6 +376,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u uint8_t status = 0; const int interval = CHIP_WAIT_IDLE_INTERVAL_US; + bool suspend_state = false; while (timeout_us > 0) { while (!chip->host->driver->host_status(chip->host) && timeout_us > 0) { @@ -388,6 +389,15 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u #endif } +#if CONFIG_SPI_FLASH_SOFTWARE_RESUME + suspend_state = ((chip->host->driver->host_status(chip->host) & SPI_FLASH_HAL_STATUS_SUSPEND) != 0) ? true : false; + + if (suspend_state) { + // Oh! find you are in suspend state + chip->host->driver->resume(chip->host); + } +#endif + uint32_t read; esp_err_t err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read); if (err != ESP_OK) { @@ -395,7 +405,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u } status = read; - if ((status & SR_WIP) == 0) { // Verify write in progress is complete + if ((status & SR_WIP) == 0 && (suspend_state == false)) { // Verify write in progress is complete if (chip->busy == 1) { chip->busy = 0; if ((status & SR_WREN) != 0) { // The previous command is not accepted, leaving the WEL still set. diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c index 51f0671f09..4bbfbb9e36 100644 --- a/components/spi_flash/spi_flash_os_func_app.c +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -121,6 +121,20 @@ static IRAM_ATTR esp_err_t spi1_start(void *arg) //directly disable the cache and interrupts when lock is not used cache_disable(NULL); #endif + +#if CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND + // Disable scheduler + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { +#ifdef CONFIG_FREERTOS_SMP + //Note: Scheduler suspension behavior changed in FreeRTOS SMP + vTaskPreemptionDisable(NULL); +#else + // Disable scheduler on the current CPU + vTaskSuspendAll(); +#endif // CONFIG_FREERTOS_SMP + } +#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND + on_spi_acquired((app_func_arg_t*)arg); return ret; } @@ -139,6 +153,18 @@ static IRAM_ATTR esp_err_t spi1_end(void *arg) #else cache_enable(NULL); #endif + +#if CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { +#ifdef CONFIG_FREERTOS_SMP + //Note: Scheduler suspension behavior changed in FreeRTOS SMP + vTaskPreemptionEnable(NULL); +#else + xTaskResumeAll(); +#endif // CONFIG_FREERTOS_SMP + } +#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND + on_spi_released((app_func_arg_t*)arg); return ret; } diff --git a/components/spi_flash/test_apps/esp_flash/CMakeLists.txt b/components/spi_flash/test_apps/esp_flash/CMakeLists.txt index 91389d9e26..889416b847 100644 --- a/components/spi_flash/test_apps/esp_flash/CMakeLists.txt +++ b/components/spi_flash/test_apps/esp_flash/CMakeLists.txt @@ -10,3 +10,8 @@ set(COMPONENTS main esptool_py) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_esp_flash_drv) + +message(STATUS "Checking memspi registers are not read-write by half-word") +include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake) +check_register_rw_half_word(SOC_MODULES "spi_mem*" "spi1_mem*" + HAL_MODULES "spimem_flash")