diff --git a/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h b/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h index be59ef7dfb6..55c00908dd8 100644 --- a/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h +++ b/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h @@ -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); +/** + * @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. * @note This API is cache safe, it will freeze both D$ and I$ and restore them after MSPI is switched diff --git a/components/esp_hw_support/mspi_timing_tuning.c b/components/esp_hw_support/mspi_timing_tuning.c index 2bff3eea155..490b6e9641c 100644 --- a/components/esp_hw_support/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi_timing_tuning.c @@ -15,6 +15,7 @@ #include "soc/soc.h" #include "hal/spi_flash_hal.h" #include "esp_private/esp_cache_private.h" +#include "esp_private/cache_utils.h" #include "esp_private/mspi_timing_tuning.h" #include "esp_private/mspi_timing_config.h" #include "mspi_timing_by_mspi_delay.h" @@ -347,9 +348,9 @@ void mspi_timing_flash_tuning(void) { /** * 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`) */ - mspi_timing_enter_low_speed_mode(true); + mspi_timing_enter_low_speed_early(); #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY mspi_tuning_cfg_drv_t drv = { @@ -377,7 +378,7 @@ void mspi_timing_flash_tuning(void) s_do_tuning(reference_data, &timing_configs, true); - mspi_timing_enter_high_speed_mode(true); + mspi_timing_enter_high_speed_early(); } #else void mspi_timing_flash_tuning(void) @@ -395,9 +396,9 @@ void mspi_timing_psram_tuning(void) { /** * 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`) */ - mspi_timing_enter_low_speed_mode(true); + mspi_timing_enter_low_speed_early(); // write data into psram, used to do timing tuning test. uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN]; @@ -460,7 +461,7 @@ void mspi_timing_psram_tuning(void) s_do_tuning(reference_data, &timing_configs, false); #endif - mspi_timing_enter_high_speed_mode(true); + mspi_timing_enter_high_speed_early(); } #else @@ -584,6 +585,26 @@ void mspi_timing_change_speed_mode_cache_safe(bool switch_down) #endif } + +/*------------------------------------------------------------------------------ + * Early-init MSPI speed switch (see mspi_timing_tuning.h) + *----------------------------------------------------------------------------*/ +void mspi_timing_enter_low_speed_early(void) +{ + uint32_t cache_state = 0; + spi_flash_disable_cache(0, &cache_state); + mspi_timing_enter_low_speed_mode(true); + spi_flash_restore_cache(0, cache_state); +} + +void mspi_timing_enter_high_speed_early(void) +{ + uint32_t cache_state = 0; + spi_flash_disable_cache(0, &cache_state); + mspi_timing_enter_high_speed_mode(true); + spi_flash_restore_cache(0, cache_state); +} + /*------------------------------------------------------------------------------ * APIs to inform SPI1 Flash driver of necessary timing configurations *----------------------------------------------------------------------------*/ diff --git a/components/esp_psram/device/esp_psram_impl_ap_quad.c b/components/esp_psram/device/esp_psram_impl_ap_quad.c index 412141fbac2..c4eeb0b86e1 100644 --- a/components/esp_psram/device/esp_psram_impl_ap_quad.c +++ b/components/esp_psram/device/esp_psram_impl_ap_quad.c @@ -280,8 +280,8 @@ esp_err_t esp_psram_impl_enable(void) psram_set_cs_timing(); #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING - //enter MSPI slow mode to init PSRAM device registers - mspi_timing_enter_low_speed_mode(true); + //enter MSPI slow mode to init PSRAM device registers (early init: see mspi_timing_enter_low_speed_early) + mspi_timing_enter_low_speed_early(); #endif // SOC_SPI_MEM_SUPPORT_TIMING_TUNING uint32_t psram_id = 0; @@ -330,7 +330,7 @@ esp_err_t esp_psram_impl_enable(void) //Configure SPI0 PSRAM related 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 - mspi_timing_enter_high_speed_mode(true); + mspi_timing_enter_high_speed_early(); #else s_config_psram_clock(); //Configure SPI0 PSRAM related SPI Phases diff --git a/components/esp_psram/esp32s3/esp_psram_impl_octal.c b/components/esp_psram/esp32s3/esp_psram_impl_octal.c index 1f3254499ee..672c163135e 100644 --- a/components/esp_psram/esp32s3/esp_psram_impl_octal.c +++ b/components/esp_psram/esp32s3/esp_psram_impl_octal.c @@ -341,8 +341,8 @@ esp_err_t esp_psram_impl_enable(void) s_set_psram_cs_timing(); s_configure_psram_ecc(); - //enter MSPI slow mode to init PSRAM device registers - mspi_timing_enter_low_speed_mode(true); + //enter MSPI slow mode to init PSRAM device registers (early init: see mspi_timing_enter_low_speed_early) + mspi_timing_enter_low_speed_early(); //set to variable dummy mode SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); @@ -377,7 +377,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 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 - 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.