mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 12:14:32 +02:00
feat(spi_flash): support software resume after suspend in unicore
This commit is contained in:
@@ -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
|
* 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_WRITE_BYTES 64
|
||||||
#define SPI_FLASH_HAL_MAX_READ_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.
|
* Generic driver context structure for all chips using the SPI peripheral.
|
||||||
* Include this into the HEAD of the driver data for other driver
|
* Include this into the HEAD of the driver data for other driver
|
||||||
@@ -82,7 +86,7 @@ typedef struct {
|
|||||||
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
|
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 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 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.
|
esp_flash_io_mode_t default_io_mode; ///< Default flash io mode.
|
||||||
int freq_mhz; ///< SPI flash clock speed (MHZ).
|
int freq_mhz; ///< SPI flash clock speed (MHZ).
|
||||||
int clock_src_freq; ///< SPI flash clock source (MHZ).
|
int clock_src_freq; ///< SPI flash clock source (MHZ).
|
||||||
|
@@ -128,6 +128,10 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
|
|||||||
data_out->tsus_val = cfg->tsus_val;
|
data_out->tsus_val = cfg->tsus_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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 SOC_SPI_MEM_SUPPORT_OPI_MODE
|
||||||
if (cfg->octal_mode_en) {
|
if (cfg->octal_mode_en) {
|
||||||
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE;
|
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE;
|
||||||
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -159,6 +159,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);
|
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
|
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
|
||||||
spimem_flash_ll_sus_check_sus_setup(dev, true);
|
spimem_flash_ll_sus_check_sus_setup(dev, true);
|
||||||
|
spimem_flash_ll_res_check_sus_setup(dev, true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,9 +167,6 @@ 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);
|
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
|
||||||
spimem_flash_ll_auto_resume_init(dev, true);
|
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)
|
void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host)
|
||||||
@@ -178,6 +176,7 @@ void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host)
|
|||||||
spimem_flash_ll_auto_suspend_init(dev, false);
|
spimem_flash_ll_auto_suspend_init(dev, false);
|
||||||
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
|
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
|
||||||
spimem_flash_ll_sus_check_sus_setup(dev, false);
|
spimem_flash_ll_sus_check_sus_setup(dev, false);
|
||||||
|
spimem_flash_ll_res_check_sus_setup(dev, false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,9 +184,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);
|
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
|
||||||
spimem_flash_ll_auto_resume_init(dev, false);
|
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
|
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||||
|
|
||||||
@@ -195,6 +191,7 @@ void spi_flash_hal_resume(spi_flash_host_inst_t *host)
|
|||||||
{
|
{
|
||||||
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
|
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
|
||||||
spimem_flash_ll_resume((spi_mem_dev_t*)(((spi_flash_hal_context_t *)host)->spi));
|
spimem_flash_ll_resume((spi_mem_dev_t*)(((spi_flash_hal_context_t *)host)->spi));
|
||||||
|
host->driver->poll_cmd_done(host);
|
||||||
#else
|
#else
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
@@ -204,6 +201,7 @@ void spi_flash_hal_suspend(spi_flash_host_inst_t *host)
|
|||||||
{
|
{
|
||||||
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
|
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
|
||||||
spimem_flash_ll_suspend((spi_mem_dev_t *)(((spi_flash_hal_context_t *)host)->spi));
|
spimem_flash_ll_suspend((spi_mem_dev_t *)(((spi_flash_hal_context_t *)host)->spi));
|
||||||
|
host->driver->poll_cmd_done(host);
|
||||||
#else
|
#else
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
|
@@ -127,6 +127,29 @@ menu "Main Flash configuration"
|
|||||||
|
|
||||||
For new users, DO NOT enable this config.
|
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.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "esp_rom_spiflash.h"
|
#include "esp_rom_spiflash.h"
|
||||||
#include "esp_private/esp_clk.h"
|
#include "esp_private/esp_clk.h"
|
||||||
#include "esp_spi_flash_counters.h"
|
#include "esp_spi_flash_counters.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
#include "esp_crypto_lock.h" // for locking flash encryption peripheral
|
#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).
|
that share a key (as derived from flash address).
|
||||||
|
|
||||||
On ESP32-S2 and later, the temporary buffer need to be
|
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
|
So, on ESP32-S2 and later, here has a totally different
|
||||||
data prepare implementation.
|
data prepare implementation.
|
||||||
|
@@ -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
|
* 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 start Address to start erasing flash. Must be sector aligned.
|
||||||
* @param len Length of region to erase. Must also 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.
|
* 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
|
* Erase is performed using block (multi-sector) erases where possible (block size is specified in
|
||||||
|
@@ -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;
|
uint8_t status = 0;
|
||||||
const int interval = CHIP_WAIT_IDLE_INTERVAL_US;
|
const int interval = CHIP_WAIT_IDLE_INTERVAL_US;
|
||||||
|
bool suspend_state = false;
|
||||||
while (timeout_us > 0) {
|
while (timeout_us > 0) {
|
||||||
while (!chip->host->driver->host_status(chip->host) && 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
|
#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;
|
uint32_t read;
|
||||||
esp_err_t err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
|
esp_err_t err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
|
||||||
if (err != ESP_OK) {
|
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;
|
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) {
|
if (chip->busy == 1) {
|
||||||
chip->busy = 0;
|
chip->busy = 0;
|
||||||
if ((status & SR_WREN) != 0) { // The previous command is not accepted, leaving the WEL still set.
|
if ((status & SR_WREN) != 0) { // The previous command is not accepted, leaving the WEL still set.
|
||||||
|
@@ -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
|
//directly disable the cache and interrupts when lock is not used
|
||||||
cache_disable(NULL);
|
cache_disable(NULL);
|
||||||
#endif
|
#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);
|
on_spi_acquired((app_func_arg_t*)arg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -139,6 +153,18 @@ static IRAM_ATTR esp_err_t spi1_end(void *arg)
|
|||||||
#else
|
#else
|
||||||
cache_enable(NULL);
|
cache_enable(NULL);
|
||||||
#endif
|
#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);
|
on_spi_released((app_func_arg_t*)arg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user