Skip to content

Commit c4bb6a3

Browse files
committed
feat(spi_flash): support software resume after suspend in unicore
1 parent 0fb61ec commit c4bb6a3

File tree

8 files changed

+79
-13
lines changed

8 files changed

+79
-13
lines changed

components/hal/include/hal/spi_flash_hal.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -27,6 +27,10 @@ extern "C" {
2727
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
2828
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
2929

30+
/* spi flash state */
31+
#define SPI_FLASH_HAL_STATUS_BUSY BIT0
32+
#define SPI_FLASH_HAL_STATUS_SUSPEND BIT1
33+
3034
/**
3135
* Generic driver context structure for all chips using the SPI peripheral.
3236
* Include this into the HEAD of the driver data for other driver
@@ -82,7 +86,7 @@ typedef struct {
8286
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
8387
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
8488
bool octal_mode_en; ///< Octal spi flash mode enable bit 1: enable, 0: disable.
85-
bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directely if set to 1.
89+
bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directly if set to 1.
8690
esp_flash_io_mode_t default_io_mode; ///< Default flash io mode.
8791
int freq_mhz; ///< SPI flash clock speed (MHZ).
8892
int clock_src_freq; ///< SPI flash clock source (MHZ).

components/hal/spi_flash_hal.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
132132
data_out->tsus_val = cfg->tsus_val;
133133
}
134134

135+
#if CONFIG_SPI_FLASH_SOFTWARE_RESUME
136+
data_out->flags &= ~SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME;
137+
#endif
138+
135139
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
136140
if (cfg->octal_mode_en) {
137141
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE;

components/hal/spi_flash_hal_iram.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -159,16 +159,14 @@ void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host)
159159
spimem_flash_ll_sus_set_spi0_lock_trans(dev, SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS);
160160
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
161161
spimem_flash_ll_sus_check_sus_setup(dev, true);
162+
spimem_flash_ll_res_check_sus_setup(dev, true);
162163
#endif
163164
}
164165

165166
void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host)
166167
{
167168
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
168169
spimem_flash_ll_auto_resume_init(dev, true);
169-
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
170-
spimem_flash_ll_res_check_sus_setup(dev, true);
171-
#endif
172170
}
173171

174172
void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host)
@@ -178,23 +176,22 @@ void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host)
178176
spimem_flash_ll_auto_suspend_init(dev, false);
179177
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
180178
spimem_flash_ll_sus_check_sus_setup(dev, false);
179+
spimem_flash_ll_res_check_sus_setup(dev, false);
181180
#endif
182181
}
183182

184183
void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host)
185184
{
186185
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
187186
spimem_flash_ll_auto_resume_init(dev, false);
188-
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
189-
spimem_flash_ll_res_check_sus_setup(dev, false);
190-
#endif
191187
}
192188
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
193189

194190
void spi_flash_hal_resume(spi_flash_host_inst_t *host)
195191
{
196192
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
197193
spimem_flash_ll_resume((spi_mem_dev_t*)(((spi_flash_hal_context_t *)host)->spi));
194+
host->driver->poll_cmd_done(host);
198195
#else
199196
abort();
200197
#endif
@@ -204,6 +201,7 @@ void spi_flash_hal_suspend(spi_flash_host_inst_t *host)
204201
{
205202
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
206203
spimem_flash_ll_suspend((spi_mem_dev_t *)(((spi_flash_hal_context_t *)host)->spi));
204+
host->driver->poll_cmd_done(host);
207205
#else
208206
abort();
209207
#endif

components/spi_flash/Kconfig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,29 @@ menu "Main Flash configuration"
120120

121121
For new users, DO NOT enable this config.
122122

123+
config SPI_FLASH_SOFTWARE_RESUME
124+
bool "Resume flash program/erase form suspend state by software control"
125+
default n
126+
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE && IDF_EXPERIMENTAL_FEATURES
127+
help
128+
Enable this config will disable auto-resume from hardware. Thus the software will resume the chip
129+
after any higher priority task/interrupt which suspend the chip. The benefit is that the suspend-resume
130+
will not disturb the higher priority task and interrupt.
131+
132+
This currently is only valid on single core chip.
133+
134+
config SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
135+
bool "Disable task scheduler when suspend is enabled when SPI1 operation is ongoing"
136+
default n
137+
# Only valid on single core because no protection is supported on multi core
138+
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE
139+
help
140+
Disable freertos task scheduler when CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled.
141+
Thus only interrupt can trigger a suspend. When SPI_FLASH_AUTO_SUSPEND is enabled,
142+
default behavior is not disable the task scheduler, so both interrupt and high priority
143+
task can suspend the erase/program operation. When this option is enabled, task
144+
scheduler is disabled, only interrupt can suspend erase/program operation.
145+
123146
endmenu
124147
endmenu
125148

components/spi_flash/esp_flash_api.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "esp_rom_spiflash.h"
2222
#include "esp_private/esp_clk.h"
2323
#include "esp_spi_flash_counters.h"
24+
#include "esp_check.h"
2425

2526
#if CONFIG_IDF_TARGET_ESP32S2
2627
#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
12691270
that share a key (as derived from flash address).
12701271
12711272
On ESP32-S2 and later, the temporary buffer need to be
1272-
seperated into 16-bytes, 32-bytes, 64-bytes(if supported).
1273+
separated into 16-bytes, 32-bytes, 64-bytes(if supported).
12731274
12741275
So, on ESP32-S2 and later, here has a totally different
12751276
data prepare implementation.

components/spi_flash/include/esp_flash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -204,7 +204,7 @@ esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
204204
* @param start Address to start erasing flash. Must be sector aligned.
205205
* @param len Length of region to erase. Must also be sector aligned.
206206
*
207-
* Sector size is specifyed in chip->drv->sector_size field (typically 4096 bytes.) ESP_ERR_INVALID_ARG will be
207+
* Sector size is specified in chip->drv->sector_size field (typically 4096 bytes.) ESP_ERR_INVALID_ARG will be
208208
* returned if the start & length are not a multiple of this size.
209209
*
210210
* Erase is performed using block (multi-sector) erases where possible (block size is specified in

components/spi_flash/spi_flash_chip_generic.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
376376

377377
uint8_t status = 0;
378378
const int interval = CHIP_WAIT_IDLE_INTERVAL_US;
379+
bool suspend_state = false;
379380
while (timeout_us > 0) {
380381
while (!chip->host->driver->host_status(chip->host) && timeout_us > 0) {
381382

@@ -388,14 +389,23 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
388389
#endif
389390
}
390391

392+
#if CONFIG_SPI_FLASH_SOFTWARE_RESUME
393+
suspend_state = ((chip->host->driver->host_status(chip->host) & SPI_FLASH_HAL_STATUS_SUSPEND) != 0) ? true : false;
394+
395+
if (suspend_state) {
396+
// Oh! find you are in suspend state
397+
chip->host->driver->resume(chip->host);
398+
}
399+
#endif
400+
391401
uint32_t read;
392402
esp_err_t err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
393403
if (err != ESP_OK) {
394404
return err;
395405
}
396406
status = read;
397407

398-
if ((status & SR_WIP) == 0) { // Verify write in progress is complete
408+
if ((status & SR_WIP) == 0 && (suspend_state == false)) { // Verify write in progress is complete
399409
if (chip->busy == 1) {
400410
chip->busy = 0;
401411
if ((status & SR_WREN) != 0) { // The previous command is not accepted, leaving the WEL still set.

components/spi_flash/spi_flash_os_func_app.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ static IRAM_ATTR esp_err_t spi1_start(void *arg)
121121
//directly disable the cache and interrupts when lock is not used
122122
cache_disable(NULL);
123123
#endif
124+
125+
#if CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
126+
// Disable scheduler
127+
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
128+
#ifdef CONFIG_FREERTOS_SMP
129+
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
130+
vTaskPreemptionDisable(NULL);
131+
#else
132+
// Disable scheduler on the current CPU
133+
vTaskSuspendAll();
134+
#endif // CONFIG_FREERTOS_SMP
135+
}
136+
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
137+
124138
on_spi_acquired((app_func_arg_t*)arg);
125139
return ret;
126140
}
@@ -139,6 +153,18 @@ static IRAM_ATTR esp_err_t spi1_end(void *arg)
139153
#else
140154
cache_enable(NULL);
141155
#endif
156+
157+
#if CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
158+
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
159+
#ifdef CONFIG_FREERTOS_SMP
160+
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
161+
vTaskPreemptionEnable(NULL);
162+
#else
163+
xTaskResumeAll();
164+
#endif // CONFIG_FREERTOS_SMP
165+
}
166+
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
167+
142168
on_spi_released((app_func_arg_t*)arg);
143169
return ret;
144170
}

0 commit comments

Comments
 (0)