mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 11:03:11 +00:00
spi_flash: Making flash works more stable when brownout detected
This commit is contained in:
@@ -24,7 +24,7 @@ else()
|
||||
list(APPEND srcs
|
||||
"src/idf/bootloader_sha.c"
|
||||
"src/idf/secure_boot_signatures.c")
|
||||
set(include_dirs "include")
|
||||
set(include_dirs "include" "include_bootloader")
|
||||
set(priv_include_dirs "include_bootloader")
|
||||
set(requires soc) #unfortunately the header directly uses SOC registers
|
||||
set(priv_requires spi_flash mbedtls efuse)
|
||||
|
||||
@@ -119,6 +119,13 @@ esp_err_t bootloader_flash_erase_sector(size_t sector);
|
||||
*/
|
||||
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Reset the flash chip (66H + 99H).
|
||||
*
|
||||
* @return ESP_OK if success, otherwise ESP_FAIL.
|
||||
*/
|
||||
esp_err_t bootloader_flash_reset_chip(void);
|
||||
|
||||
/* Cache MMU block size */
|
||||
#define MMU_BLOCK_SIZE 0x00010000
|
||||
|
||||
|
||||
@@ -58,6 +58,16 @@ uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_n
|
||||
*/
|
||||
esp_err_t bootloader_flash_xmc_startup(void);
|
||||
|
||||
/**
|
||||
* @brief Execute a flash command (for use in brownout reset flow).
|
||||
* @param command Command byte
|
||||
* @param mosi_data MOSI data
|
||||
* @param mosi_len MOSI length in bits
|
||||
* @param miso_len MISO length in bits
|
||||
* @return MISO data read
|
||||
*/
|
||||
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <esp_spi_flash.h> /* including in bootloader for error values */
|
||||
#include <esp_flash_encrypt.h>
|
||||
#include "flash_qio_mode.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/spi_struct.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
/* Normal app version maps to esp_spi_flash.h operations...
|
||||
@@ -292,3 +294,27 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
return spi_to_esp_err(rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ESP32-only: brownout flash reset (66H+99H) - built for both app and bootloader */
|
||||
static inline void bootloader_mspi_reset(void)
|
||||
{
|
||||
SPI1.slave.sync_reset = 0;
|
||||
SPI0.slave.sync_reset = 0;
|
||||
SPI1.slave.sync_reset = 1;
|
||||
SPI0.slave.sync_reset = 1;
|
||||
SPI1.slave.sync_reset = 0;
|
||||
SPI0.slave.sync_reset = 0;
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR bootloader_flash_reset_chip(void)
|
||||
{
|
||||
bootloader_mspi_reset();
|
||||
/* Send extra command so host is idle before reset command */
|
||||
bootloader_execute_flash_command(0x05, 0, 0, 0);
|
||||
if (SPI1.ext2.st != 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_execute_flash_command(0x66, 0, 0, 0);
|
||||
bootloader_execute_flash_command(0x99, 0, 0, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -345,6 +345,11 @@ static uint32_t IRAM_ATTR execute_flash_command(uint8_t command, uint32_t mosi_d
|
||||
dummy_len, mosi_len, mosi_data, miso_len);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||
{
|
||||
return execute_flash_command(command, mosi_data, mosi_len, miso_len);
|
||||
}
|
||||
|
||||
// cmd(0x5A) + 24bit address + 8 cycles dummy
|
||||
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RTC_INTR_FLAG_IRAM (BIT(0)) /*< Some rtc interrupts can be called with cache disabled */
|
||||
|
||||
/**
|
||||
* @brief Register a handler for specific RTC_CNTL interrupts
|
||||
*
|
||||
@@ -33,13 +35,15 @@ extern "C" {
|
||||
* @param handler_arg argument to be passed to the handler
|
||||
* @param rtc_intr_mask combination of RTC_CNTL_*_INT_ENA bits indicating the
|
||||
* sources to call the handler for
|
||||
* @param flags An ORred mask of the RTC_INTR_FLAG_* defines. Pass 0 for default.
|
||||
* RTC_INTR_FLAG_IRAM: interrupt can be triggered with cache disabled.
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM not enough memory to allocate handler structure
|
||||
* - other errors returned by esp_intr_alloc
|
||||
*/
|
||||
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
|
||||
uint32_t rtc_intr_mask);
|
||||
uint32_t rtc_intr_mask, uint32_t flags);
|
||||
/**
|
||||
* @brief Deregister the handler previously registered using rtc_isr_register
|
||||
* @param handler handler function to call (as passed to rtc_isr_register)
|
||||
@@ -51,6 +55,16 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
|
||||
*/
|
||||
esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg);
|
||||
|
||||
/**
|
||||
* @brief Disable the RTC interrupt that is allowed to be executed when cache is disabled.
|
||||
*/
|
||||
void rtc_isr_noniram_disable(uint32_t cpu);
|
||||
|
||||
/**
|
||||
* @brief Enable the RTC interrupt that is allowed to be executed when cache is disabled.
|
||||
*/
|
||||
void rtc_isr_noniram_enable(uint32_t cpu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,9 +30,11 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "sys/lock.h"
|
||||
#include "driver/rtc_cntl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_attr.h"
|
||||
#include "adc1_i2s_private.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -41,6 +43,11 @@
|
||||
#endif
|
||||
#include "sys/queue.h"
|
||||
|
||||
#define NOT_REGISTERED (-1)
|
||||
|
||||
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask);
|
||||
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask);
|
||||
|
||||
|
||||
#define ADC_FSM_RSTB_WAIT_DEFAULT (8)
|
||||
#define ADC_FSM_START_WAIT_DEFAULT (5)
|
||||
@@ -440,7 +447,7 @@ inline static touch_pad_t touch_pad_num_wrap(touch_pad_t touch_num)
|
||||
esp_err_t touch_pad_isr_register(intr_handler_t fn, void* arg)
|
||||
{
|
||||
RTC_MODULE_CHECK(fn, "Touch_Pad ISR null", ESP_ERR_INVALID_ARG);
|
||||
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M);
|
||||
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0);
|
||||
}
|
||||
|
||||
esp_err_t touch_pad_isr_deregister(intr_handler_t fn, void *arg)
|
||||
@@ -1949,15 +1956,20 @@ typedef struct rtc_isr_handler_ {
|
||||
uint32_t mask;
|
||||
intr_handler_t handler;
|
||||
void* handler_arg;
|
||||
uint32_t flags;
|
||||
SLIST_ENTRY(rtc_isr_handler_) next;
|
||||
} rtc_isr_handler_t;
|
||||
|
||||
static SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
|
||||
static DRAM_ATTR uint32_t rtc_intr_cache;
|
||||
static DRAM_ATTR uint32_t rtc_intr_enabled;
|
||||
static DRAM_ATTR int rtc_isr_cpu = NOT_REGISTERED;
|
||||
|
||||
static DRAM_ATTR SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
|
||||
SLIST_HEAD_INITIALIZER(s_rtc_isr_handler_list);
|
||||
portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static DRAM_ATTR portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static intr_handle_t s_rtc_isr_handle;
|
||||
|
||||
static void rtc_isr(void* arg)
|
||||
IRAM_ATTR static void rtc_isr(void* arg)
|
||||
{
|
||||
uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG);
|
||||
rtc_isr_handler_t* it;
|
||||
@@ -1983,10 +1995,11 @@ static esp_err_t rtc_isr_ensure_installed()
|
||||
|
||||
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
|
||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
|
||||
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, &rtc_isr, NULL, &s_rtc_isr_handle);
|
||||
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_isr, NULL, &s_rtc_isr_handle);
|
||||
if (err != ESP_OK) {
|
||||
goto out;
|
||||
}
|
||||
rtc_isr_cpu = esp_intr_get_cpu(s_rtc_isr_handle);
|
||||
|
||||
out:
|
||||
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
|
||||
@@ -1994,21 +2007,27 @@ out:
|
||||
}
|
||||
|
||||
|
||||
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask)
|
||||
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask, uint32_t flags)
|
||||
{
|
||||
esp_err_t err = rtc_isr_ensure_installed();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
rtc_isr_handler_t* item = malloc(sizeof(*item));
|
||||
rtc_isr_handler_t* item = heap_caps_malloc(sizeof(*item), MALLOC_CAP_INTERNAL);
|
||||
if (item == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
item->handler = handler;
|
||||
item->handler_arg = handler_arg;
|
||||
item->mask = rtc_intr_mask;
|
||||
item->flags = flags;
|
||||
portENTER_CRITICAL(&s_rtc_isr_handler_list_lock);
|
||||
if (flags & RTC_INTR_FLAG_IRAM) {
|
||||
s_rtc_isr_noniram_hook(rtc_intr_mask);
|
||||
} else {
|
||||
s_rtc_isr_noniram_hook_relieve(rtc_intr_mask);
|
||||
}
|
||||
SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next);
|
||||
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
|
||||
return ESP_OK;
|
||||
@@ -2028,6 +2047,9 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
|
||||
SLIST_REMOVE_AFTER(prev, next);
|
||||
}
|
||||
found = true;
|
||||
if (it->flags & RTC_INTR_FLAG_IRAM) {
|
||||
s_rtc_isr_noniram_hook_relieve(it->mask);
|
||||
}
|
||||
free(it);
|
||||
break;
|
||||
}
|
||||
@@ -2036,3 +2058,29 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
|
||||
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
|
||||
return found ? ESP_OK : ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask)
|
||||
{
|
||||
rtc_intr_cache |= rtc_intr_mask;
|
||||
}
|
||||
|
||||
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask)
|
||||
{
|
||||
rtc_intr_cache &= ~rtc_intr_mask;
|
||||
}
|
||||
|
||||
IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu)
|
||||
{
|
||||
if (rtc_isr_cpu == cpu) {
|
||||
rtc_intr_enabled |= RTCCNTL.int_ena.val;
|
||||
RTCCNTL.int_ena.val &= rtc_intr_cache;
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu)
|
||||
{
|
||||
if (rtc_isr_cpu == cpu) {
|
||||
RTCCNTL.int_ena.val = rtc_intr_enabled;
|
||||
rtc_intr_enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ menu "ESP32-specific"
|
||||
|
||||
config ESP32_REV_MIN_0
|
||||
bool "Rev 0"
|
||||
# Brownout on Rev 0 is bugged, must use interrupt
|
||||
select ESP_SYSTEM_BROWNOUT_INTR
|
||||
config ESP32_REV_MIN_1
|
||||
bool "Rev 1"
|
||||
config ESP32_REV_MIN_2
|
||||
@@ -586,6 +588,11 @@ menu "ESP32-specific"
|
||||
default 6 if ESP32_BROWNOUT_DET_LVL_SEL_6
|
||||
default 7 if ESP32_BROWNOUT_DET_LVL_SEL_7
|
||||
|
||||
config ESP_SYSTEM_BROWNOUT_INTR
|
||||
bool
|
||||
default n
|
||||
help
|
||||
Brownout restart via interrupt (for ESP32 Rev0 or XMC flash brownout reset).
|
||||
|
||||
#Reduce PHY TX power when brownout reset
|
||||
config ESP32_REDUCE_PHY_TX_POWER
|
||||
|
||||
+41
-17
@@ -20,43 +20,67 @@
|
||||
#include "soc/soc.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "driver/rtc_cntl.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32_BROWNOUT_DET_LVL
|
||||
#define BROWNOUT_DET_LVL CONFIG_ESP32_BROWNOUT_DET_LVL
|
||||
#else
|
||||
#define BROWNOUT_DET_LVL 0
|
||||
#endif //CONFIG_ESP32_BROWNOUT_DET_LVL
|
||||
#endif
|
||||
|
||||
static void rtc_brownout_isr_handler()
|
||||
IRAM_ATTR static void rtc_brownout_isr_handler(void *arg)
|
||||
{
|
||||
/* Normally RTC ISR clears the interrupt flag after the application-supplied
|
||||
* handler returns. Since restart is called here, the flag needs to be
|
||||
* cleared manually.
|
||||
*/
|
||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_BROWN_OUT_INT_CLR);
|
||||
/* Stall the other CPU to make sure the code running there doesn't use UART
|
||||
* at the same time as the following ets_printf.
|
||||
*/
|
||||
esp_cpu_stall(!xPortGetCoreID());
|
||||
esp_reset_reason_set_hint(ESP_RST_BROWNOUT);
|
||||
ets_printf("\r\nBrownout detector was triggered\r\n\r\n");
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
if (spi_flash_brownout_need_reset()) {
|
||||
if (spi_flash_brownout_check_erase()) {
|
||||
bootloader_flash_reset_chip();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ets_printf(DRAM_STR("\r\nBrownout detector was triggered\r\n\r\n"));
|
||||
esp_restart_noos();
|
||||
}
|
||||
|
||||
void esp_brownout_init()
|
||||
void esp_brownout_init(void)
|
||||
{
|
||||
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
|
||||
REG_WRITE(RTC_CNTL_BROWN_OUT_REG,
|
||||
RTC_CNTL_BROWN_OUT_ENA /* Enable BOD */
|
||||
| RTC_CNTL_BROWN_OUT_PD_RF_ENA /* Automatically power down RF */
|
||||
/* Reset timeout must be set to >1 even if BOR feature is not used */
|
||||
RTC_CNTL_BROWN_OUT_ENA
|
||||
| RTC_CNTL_BROWN_OUT_CLOSE_FLASH_ENA_M
|
||||
| RTC_CNTL_BROWN_OUT_PD_RF_ENA_M
|
||||
| (2 << RTC_CNTL_BROWN_OUT_RST_WAIT_S)
|
||||
| (BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S));
|
||||
|
||||
ESP_ERROR_CHECK( rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M) );
|
||||
|
||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_BROWN_OUT_INT_CLR);
|
||||
#else
|
||||
REG_WRITE(RTC_CNTL_BROWN_OUT_REG,
|
||||
RTC_CNTL_BROWN_OUT_ENA
|
||||
| RTC_CNTL_BROWN_OUT_RST_ENA
|
||||
| RTC_CNTL_BROWN_OUT_PD_RF_ENA_M
|
||||
| (2 << RTC_CNTL_BROWN_OUT_RST_WAIT_S)
|
||||
| (BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S));
|
||||
#endif
|
||||
ESP_ERROR_CHECK(rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M, RTC_INTR_FLAG_IRAM));
|
||||
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_BROWN_OUT_INT_ENA_M);
|
||||
|
||||
}
|
||||
|
||||
void esp_brownout_disable(void)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_BROWN_OUT_INT_ENA_M);
|
||||
rtc_isr_deregister(rtc_brownout_isr_handler, NULL);
|
||||
REG_WRITE(RTC_CNTL_BROWN_OUT_REG, 0);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
|
||||
# Access bootloader_support private headers (bootloader_flash.h) used by brownout.c
|
||||
COMPONENT_PRIV_INCLUDEDIRS += ../bootloader_support/include_bootloader
|
||||
|
||||
ifdef CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||
# This linker script must come before esp32.project.ld
|
||||
LINKER_SCRIPTS += esp32.extram.bss.ld
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_private/dbg_stubs.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp32/spiram.h"
|
||||
#include "esp_clk_internal.h"
|
||||
#include "esp_timer.h"
|
||||
@@ -431,6 +432,9 @@ void start_cpu0_default(void)
|
||||
esp_flash_app_init();
|
||||
esp_err_t flash_ret = esp_flash_init_default_chip();
|
||||
assert(flash_ret == ESP_OK);
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
spi_flash_needs_reset_check();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_impl_init();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/rtc_cntl.h"
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
@@ -866,6 +867,7 @@ void IRAM_ATTR esp_intr_noniram_disable()
|
||||
{
|
||||
int oldint;
|
||||
int cpu=xPortGetCoreID();
|
||||
rtc_isr_noniram_disable(cpu);
|
||||
int intmask=~non_iram_int_mask[cpu];
|
||||
if (non_iram_int_disabled_flag[cpu]) abort();
|
||||
non_iram_int_disabled_flag[cpu]=true;
|
||||
@@ -884,6 +886,7 @@ void IRAM_ATTR esp_intr_noniram_disable()
|
||||
void IRAM_ATTR esp_intr_noniram_enable()
|
||||
{
|
||||
int cpu=xPortGetCoreID();
|
||||
rtc_isr_noniram_enable(cpu);
|
||||
int intmask=non_iram_int_disabled[cpu];
|
||||
if (!non_iram_int_disabled_flag[cpu]) abort();
|
||||
non_iram_int_disabled_flag[cpu]=false;
|
||||
|
||||
@@ -13,6 +13,7 @@ else()
|
||||
set(srcs
|
||||
"partition.c"
|
||||
"spi_flash_rom_patch.c"
|
||||
"flash_brownout_hook.c"
|
||||
)
|
||||
# New implementation after IDF v4.0
|
||||
list(APPEND cache_srcs
|
||||
|
||||
@@ -122,6 +122,26 @@ menu "SPI Flash driver"
|
||||
Enable this option to override flash size with latest ESPTOOLPY_FLASHSIZE value from
|
||||
the app header if the size in the bootloader header is incorrect.
|
||||
|
||||
menu "SPI Flash behavior when brownout"
|
||||
|
||||
config SPI_FLASH_BROWNOUT_RESET_XMC
|
||||
bool "Enable sending reset when brownout for XMC flash chips"
|
||||
default y
|
||||
select SPI_FLASH_BROWNOUT_RESET
|
||||
help
|
||||
When this option is selected, the patch will be enabled for XMC.
|
||||
Follow the recommended flow by XMC for better stability.
|
||||
|
||||
config SPI_FLASH_BROWNOUT_RESET
|
||||
bool
|
||||
default n
|
||||
select ESP_SYSTEM_BROWNOUT_INTR
|
||||
help
|
||||
When brownout happens during flash erase/write operations,
|
||||
send reset command to stop the flash operations to improve stability.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Auto-detect flash chips"
|
||||
|
||||
config SPI_FLASH_SUPPORT_ISSI_CHIP
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
|
||||
static bool flash_brownout_needs_reset = false;
|
||||
static bool flash_erasing = false;
|
||||
|
||||
void spi_flash_needs_reset_check(void)
|
||||
{
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC
|
||||
if ((g_rom_flashchip.device_id >> 16) == 0x20) {
|
||||
flash_brownout_needs_reset = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR spi_flash_set_erasing_flag(bool status)
|
||||
{
|
||||
flash_erasing = status;
|
||||
}
|
||||
|
||||
bool spi_flash_brownout_need_reset(void)
|
||||
{
|
||||
return flash_brownout_needs_reset;
|
||||
}
|
||||
|
||||
bool spi_flash_brownout_check_erase(void)
|
||||
{
|
||||
return flash_erasing;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SPI_FLASH_BROWNOUT_RESET */
|
||||
@@ -36,6 +36,9 @@
|
||||
#include "cache_utils.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_timer.h"
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#endif
|
||||
|
||||
/* bytes erased by SPIEraseBlock() ROM function */
|
||||
#define BLOCK_ERASE_SIZE 65536
|
||||
@@ -246,6 +249,9 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
|
||||
int64_t start_time_us = esp_timer_get_time();
|
||||
#endif
|
||||
spi_flash_guard_start();
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
spi_flash_set_erasing_flag(true);
|
||||
#endif
|
||||
#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE
|
||||
if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
|
||||
rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
|
||||
@@ -258,6 +264,9 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
|
||||
++sector;
|
||||
COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
|
||||
}
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
spi_flash_set_erasing_flag(false);
|
||||
#endif
|
||||
spi_flash_guard_end();
|
||||
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
|
||||
no_yield_time_us += (esp_timer_get_time() - start_time_us);
|
||||
|
||||
@@ -53,6 +53,10 @@ typedef struct {
|
||||
|
||||
/** Yield to other tasks. Called during erase operations. */
|
||||
esp_err_t (*yield)(void *arg);
|
||||
|
||||
#define SPI_FLASH_OS_IS_ERASING_STATUS_FLAG (1u << 0)
|
||||
/** Call to set flash operation status (e.g. erasing). */
|
||||
void (*set_flash_op_status)(uint32_t op_status);
|
||||
} esp_flash_os_functions_t;
|
||||
|
||||
/** @brief Structure to describe a SPI flash chip connected to the system.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void spi_flash_needs_reset_check(void);
|
||||
void spi_flash_set_erasing_flag(bool status);
|
||||
bool spi_flash_brownout_need_reset(void);
|
||||
bool spi_flash_brownout_check_erase(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
archive: libspi_flash.a
|
||||
entries:
|
||||
spi_flash_rom_patch (noflash_text)
|
||||
flash_brownout_hook (noflash)
|
||||
spi_flash_chip_generic (noflash)
|
||||
spi_flash_chip_issi (noflash)
|
||||
spi_flash_chip_gd(noflash)
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#include "spi_flash_chip_generic.h"
|
||||
#include "spi_flash_defs.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
|
||||
#define SET_FLASH_ERASE_STATUS(chip, status) do { \
|
||||
if ((chip)->os_func->set_flash_op_status) { \
|
||||
(chip)->os_func->set_flash_op_status(status); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const char TAG[] = "chip_generic";
|
||||
|
||||
@@ -86,15 +93,18 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
|
||||
chip->host->erase_chip(chip->host);
|
||||
//to save time, flush cache here
|
||||
if (chip->host->flush_cache) {
|
||||
err = chip->host->flush_cache(chip->host, 0, chip->size);
|
||||
if (err != ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000);
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -106,15 +116,18 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
|
||||
chip->host->erase_sector(chip->host, start_address);
|
||||
//to save time, flush cache here
|
||||
if (chip->host->flush_cache) {
|
||||
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
|
||||
if (err != ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS * 1000);
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -126,15 +139,18 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
|
||||
chip->host->erase_block(chip->host, start_address);
|
||||
//to save time, flush cache here
|
||||
if (chip->host->flush_cache) {
|
||||
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
|
||||
if (err != ESP_OK) {
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT_MS * 1000);
|
||||
SET_FLASH_ERASE_STATUS(chip, 0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "esp_spi_flash.h" //for ``g_flash_guard_default_ops``
|
||||
#include "esp_flash.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
@@ -103,6 +104,14 @@ static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_a
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
static IRAM_ATTR void main_flash_op_status(uint32_t op_status)
|
||||
{
|
||||
bool is_erasing = (op_status & SPI_FLASH_OS_IS_ERASING_STATUS_FLAG) != 0;
|
||||
spi_flash_set_erasing_flag(is_erasing);
|
||||
}
|
||||
#endif
|
||||
|
||||
static DRAM_ATTR spi1_app_func_arg_t spi1_arg = {
|
||||
.host_id = 0, //for SPI1,
|
||||
.no_protect = true,
|
||||
@@ -128,13 +137,19 @@ const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functions = {
|
||||
.region_protected = main_flash_region_protected,
|
||||
.delay_us = delay_us,
|
||||
.yield = spi_flash_os_yield,
|
||||
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||
.set_flash_op_status = main_flash_op_status,
|
||||
#else
|
||||
.set_flash_op_status = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = {
|
||||
.start = spi23_start,
|
||||
.end = spi23_end,
|
||||
.delay_us = delay_us,
|
||||
.yield = spi_flash_os_yield
|
||||
.yield = spi_flash_os_yield,
|
||||
.set_flash_op_status = NULL,
|
||||
};
|
||||
|
||||
esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id)
|
||||
|
||||
Reference in New Issue
Block a user