Merge branch 'fix/s3_xip_opt_os_startup_v6.0' into 'release/v6.0'

fix(mspi): fixed possible boot failure in some builds when psram is enabled (v6.0)

See merge request espressif/esp-idf!48583
This commit is contained in:
Jiang Jiang Jian
2026-05-16 10:26:41 +08:00
8 changed files with 105 additions and 12 deletions
@@ -36,6 +36,21 @@ uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void);
*/ */
void mspi_timing_enter_high_speed_mode(bool control_spi1); void mspi_timing_enter_high_speed_mode(bool control_spi1);
/**
* @brief Switch MSPI to low speed while suspending external memory cache to avoid in-flight cache line fills across the
* clock change.
*
* @note Early init only. Not safe for general runtime use: does not coordinate with other cores or freeze cache.
*/
void mspi_timing_enter_low_speed_early(void);
/**
* @brief Switch MSPI to high speed while suspending external memory cache.
*
* @note Same usage constraints as @ref mspi_timing_enter_low_speed_early.
*/
void mspi_timing_enter_high_speed_early(void);
/** /**
* @brief Switch MSPI into low speed mode / high speed mode. * @brief Switch MSPI into low speed mode / high speed mode.
* @note This API is cache safe, it will freeze both D$ and I$ and restore them after MSPI is switched * @note This API is cache safe, it will freeze both D$ and I$ and restore them after MSPI is switched
@@ -21,6 +21,7 @@
#include "hal/cache_ll.h" #include "hal/cache_ll.h"
#include "hal/cache_hal.h" #include "hal/cache_hal.h"
#endif #endif
#include "esp_private/cache_utils.h"
#include "esp_private/mspi_timing_tuning.h" #include "esp_private/mspi_timing_tuning.h"
#include "esp_private/mspi_timing_config.h" #include "esp_private/mspi_timing_config.h"
#include "esp_private/mspi_timing_by_mspi_delay.h" #include "esp_private/mspi_timing_by_mspi_delay.h"
@@ -352,10 +353,10 @@ void mspi_timing_flash_tuning(void)
{ {
/** /**
* set MSPI related regs to 20mhz configuration, to get reference data from FLASH * set MSPI related regs to 20mhz configuration, to get reference data from FLASH
* see detailed comments in this function (`mspi_timing_enter_low_speed_mode`) * see detailed comments in this function (`mspi_timing_enter_low_speed_early`)
*/ */
ESP_EARLY_LOGI(TAG, "Enter flash timing tuning"); ESP_EARLY_LOGI(TAG, "Enter flash timing tuning");
mspi_timing_enter_low_speed_mode(true); mspi_timing_enter_low_speed_early();
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
mspi_tuning_cfg_drv_t drv = { mspi_tuning_cfg_drv_t drv = {
@@ -383,7 +384,7 @@ void mspi_timing_flash_tuning(void)
s_do_tuning(reference_data, &timing_configs, true); s_do_tuning(reference_data, &timing_configs, true);
mspi_timing_enter_high_speed_mode(true); mspi_timing_enter_high_speed_early();
} }
#else #else
void mspi_timing_flash_tuning(void) void mspi_timing_flash_tuning(void)
@@ -401,10 +402,10 @@ void mspi_timing_psram_tuning(void)
{ {
/** /**
* set MSPI related regs to 20mhz configuration, to write reference data to PSRAM * set MSPI related regs to 20mhz configuration, to write reference data to PSRAM
* see detailed comments in this function (`mspi_timing_enter_low_speed_mode`) * see detailed comments in this function (`mspi_timing_enter_low_speed_early`)
*/ */
ESP_EARLY_LOGI(TAG, "Enter psram timing tuning"); ESP_EARLY_LOGI(TAG, "Enter psram timing tuning");
mspi_timing_enter_low_speed_mode(true); mspi_timing_enter_low_speed_early();
// write data into psram, used to do timing tuning test. // write data into psram, used to do timing tuning test.
uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN]; uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN];
@@ -467,7 +468,7 @@ void mspi_timing_psram_tuning(void)
s_do_tuning(reference_data, &timing_configs, false); s_do_tuning(reference_data, &timing_configs, false);
#endif #endif
mspi_timing_enter_high_speed_mode(true); mspi_timing_enter_high_speed_early();
} }
#else #else
@@ -606,6 +607,53 @@ void mspi_timing_change_speed_mode_cache_safe(bool switch_down)
#endif #endif
} }
/*------------------------------------------------------------------------------
* Early-init MSPI speed switch (see mspi_timing_tuning.h)
*----------------------------------------------------------------------------*/
#if ESP_TEE_BUILD
#include "riscv/rv_utils.h"
extern void rom_spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state);
extern void rom_spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
static void disable_cache(uint32_t cpuid, uint32_t *saved_state)
{
#if SOC_BRANCH_PREDICTOR_SUPPORTED
rv_utils_dis_branch_predictor();
#endif
rom_spi_flash_disable_cache(cpuid, saved_state);
}
static void restore_cache(uint32_t cpuid, uint32_t saved_state)
{
rom_spi_flash_restore_cache(cpuid, saved_state);
#if SOC_BRANCH_PREDICTOR_SUPPORTED
rv_utils_en_branch_predictor();
#endif
}
#else // ESP_TEE_BUILD
#define disable_cache(cpuid, saved_state) spi_flash_disable_cache(cpuid, saved_state)
#define restore_cache(cpuid, saved_state) spi_flash_restore_cache(cpuid, saved_state)
#endif
void mspi_timing_enter_low_speed_early(void)
{
uint32_t cache_state = 0;
disable_cache(0, &cache_state);
mspi_timing_enter_low_speed_mode(true);
restore_cache(0, cache_state);
}
void mspi_timing_enter_high_speed_early(void)
{
uint32_t cache_state = 0;
disable_cache(0, &cache_state);
mspi_timing_enter_high_speed_mode(true);
restore_cache(0, cache_state);
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* APIs to inform SPI1 Flash driver of necessary timing configurations * APIs to inform SPI1 Flash driver of necessary timing configurations
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@@ -345,8 +345,8 @@ esp_err_t esp_psram_impl_enable(void)
#endif #endif
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
//enter MSPI slow mode to init PSRAM device registers //enter MSPI slow mode to init PSRAM device registers (early init: see mspi_timing_enter_low_speed_early)
mspi_timing_enter_low_speed_mode(true); mspi_timing_enter_low_speed_early();
#else #else
s_config_psram_clock(true); s_config_psram_clock(true);
#endif // SOC_SPI_MEM_SUPPORT_TIMING_TUNING #endif // SOC_SPI_MEM_SUPPORT_TIMING_TUNING
@@ -413,7 +413,7 @@ esp_err_t esp_psram_impl_enable(void)
//Configure SPI0 PSRAM related SPI Phases //Configure SPI0 PSRAM related SPI Phases
config_psram_spi_phases(); config_psram_spi_phases();
//Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly //Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly
mspi_timing_enter_high_speed_mode(true); mspi_timing_enter_high_speed_early();
#else #else
s_config_psram_clock(false); s_config_psram_clock(false);
//Configure SPI0 PSRAM related SPI Phases //Configure SPI0 PSRAM related SPI Phases
@@ -342,8 +342,8 @@ esp_err_t esp_psram_impl_enable(void)
s_set_psram_cs_timing(); s_set_psram_cs_timing();
s_configure_psram_ecc(); s_configure_psram_ecc();
//enter MSPI slow mode to init PSRAM device registers //enter MSPI slow mode to init PSRAM device registers (early init: see mspi_timing_enter_low_speed_early)
mspi_timing_enter_low_speed_mode(true); mspi_timing_enter_low_speed_early();
//set to variable dummy mode //set to variable dummy mode
SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
@@ -378,7 +378,7 @@ esp_err_t esp_psram_impl_enable(void)
//Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM timing related registers accordingly //Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM timing related registers accordingly
mspi_timing_psram_tuning(); mspi_timing_psram_tuning();
//Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly //Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly
mspi_timing_enter_high_speed_mode(true); mspi_timing_enter_high_speed_early();
/** /**
* Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs. * Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs.
@@ -120,6 +120,14 @@ secure_services:
type: IDF type: IDF
function: spi_timing_get_flash_timing_param function: spi_timing_get_flash_timing_param
args: 1 args: 1
- id: 29
type: IDF
function: mspi_timing_enter_low_speed_early
args: 0
- id: 10
type: IDF
function: mspi_timing_enter_high_speed_early
args: 0
# ID: 30-53 (24) - Interrupt Handling # ID: 30-53 (24) - Interrupt Handling
- family: interrupt_handling - family: interrupt_handling
entries: entries:
@@ -491,6 +491,16 @@ void IRAM_ATTR __wrap_mspi_timing_enter_high_speed_mode(bool control_spi1)
esp_tee_service_call(2, SS_MSPI_TIMING_ENTER_HIGH_SPEED_MODE, control_spi1); esp_tee_service_call(2, SS_MSPI_TIMING_ENTER_HIGH_SPEED_MODE, control_spi1);
} }
void IRAM_ATTR __wrap_mspi_timing_enter_low_speed_early(void)
{
esp_tee_service_call(1, SS_MSPI_TIMING_ENTER_LOW_SPEED_EARLY);
}
void IRAM_ATTR __wrap_mspi_timing_enter_high_speed_early(void)
{
esp_tee_service_call(1, SS_MSPI_TIMING_ENTER_HIGH_SPEED_EARLY);
}
void IRAM_ATTR __wrap_mspi_timing_change_speed_mode_cache_safe(bool switch_down) void IRAM_ATTR __wrap_mspi_timing_change_speed_mode_cache_safe(bool switch_down)
{ {
esp_tee_service_call(2, SS_MSPI_TIMING_CHANGE_SPEED_MODE_CACHE_SAFE, switch_down); esp_tee_service_call(2, SS_MSPI_TIMING_CHANGE_SPEED_MODE_CACHE_SAFE, switch_down);
@@ -552,6 +552,16 @@ void _ss_mspi_timing_enter_high_speed_mode(bool control_spi1)
mspi_timing_enter_high_speed_mode(control_spi1); mspi_timing_enter_high_speed_mode(control_spi1);
} }
void _ss_mspi_timing_enter_low_speed_early(void)
{
mspi_timing_enter_low_speed_early();
}
void _ss_mspi_timing_enter_high_speed_early(void)
{
mspi_timing_enter_high_speed_early();
}
void _ss_mspi_timing_change_speed_mode_cache_safe(bool switch_down) void _ss_mspi_timing_change_speed_mode_cache_safe(bool switch_down)
{ {
mspi_timing_change_speed_mode_cache_safe(switch_down); mspi_timing_change_speed_mode_cache_safe(switch_down);
@@ -36,6 +36,8 @@ PROVIDE ( esp_tee_app_config = SRAM_REE_SEG_START + 0x2b0 );
PROVIDE ( GDMA = 0x60080000 ); PROVIDE ( GDMA = 0x60080000 );
/* SPI Flash functions required from the ROM (refer esp32c5.rom.spiflash.ld) */ /* SPI Flash functions required from the ROM (refer esp32c5.rom.spiflash.ld) */
PROVIDE ( rom_spi_flash_disable_cache = 0x40000204 );
PROVIDE ( rom_spi_flash_restore_cache = 0x40000208 );
PROVIDE ( spi_flash_check_and_flush_cache = 0x40000230 ); PROVIDE ( spi_flash_check_and_flush_cache = 0x40000230 );
PROVIDE ( spi_flash_chip_generic_config_host_io_mode = 0x400002d4 ); PROVIDE ( spi_flash_chip_generic_config_host_io_mode = 0x400002d4 );
PROVIDE ( memspi_host_flush_cache = 0x40000318 ); PROVIDE ( memspi_host_flush_cache = 0x40000318 );