diff --git a/components/esp_hw_support/port/esp32s3/rtc_init.c b/components/esp_hw_support/port/esp32s3/rtc_init.c index 9067843c40..92fc50c833 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_init.c +++ b/components/esp_hw_support/port/esp32s3/rtc_init.c @@ -21,18 +21,7 @@ #include "esp_attr.h" #include "esp_efuse.h" #include "esp_efuse_table.h" - -#ifndef BOOTLOADER_BUILD -/** - * TODO: IDF-3204 - * Temporarily solution. Depends on MSPI - * Final solution: the rtc should not depend on MSPI. We should do rtc related before Flash init - */ #include "esp_private/spi_flash_os.h" -#include "esp32s3/rom/cache.h" -#include "freertos/portmacro.h" -portMUX_TYPE rtc_init_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; -#endif #define RTC_CNTL_MEM_FORCE_NOISO (RTC_CNTL_SLOWMEM_FORCE_NOISO | RTC_CNTL_FASTMEM_FORCE_NOISO) @@ -248,39 +237,23 @@ static void set_ocode_by_efuse(int calib_version) REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1); } -#ifndef BOOTLOADER_BUILD -//TODO: IDF-3204 -//Temporary solution, these 2 functions should be defined elsewhere, because similar operations are also needed elsewhere -//Final solution: the rtc should not depend on MSPI. We should do rtc related before Flash init -static void IRAM_ATTR enter_mspi_low_speed_mode_safe(void) -{ - portENTER_CRITICAL(&rtc_init_spinlock); - Cache_Freeze_ICache_Enable(1); - Cache_Freeze_DCache_Enable(1); - spi_timing_enter_mspi_low_speed_mode(false); - Cache_Freeze_DCache_Disable(); - Cache_Freeze_ICache_Disable(); - portEXIT_CRITICAL(&rtc_init_spinlock); -} - -static void IRAM_ATTR enter_mspi_high_speed_mode_safe(void) -{ - portENTER_CRITICAL(&rtc_init_spinlock); - Cache_Freeze_ICache_Enable(1); - Cache_Freeze_DCache_Enable(1); - spi_timing_enter_mspi_high_speed_mode(false); - Cache_Freeze_DCache_Disable(); - Cache_Freeze_ICache_Disable(); - portEXIT_CRITICAL(&rtc_init_spinlock); -} -#endif - -//TODO: IDF-3204 -//This function will change the system clock source to XTAL. Under lower frequency (e.g. XTAL), MSPI timing tuning configures should be modified accordingly. -static void IRAM_ATTR calibrate_ocode(void) +/** + * TODO: IDF-4141 + * 1. This function will change the system clock source to XTAL. Under lower frequency (e.g. XTAL), MSPI timing tuning configures should be modified accordingly. + * 2. RTC related should be done before SPI0 initialisation + */ +static void calibrate_ocode(void) { #ifndef BOOTLOADER_BUILD - enter_mspi_low_speed_mode_safe(); + /** + * Background: + * 1. Following code will switch the system clock to XTAL first, to self-calibrate the OCode. + * 2. For some of the MSPI high frequency setting (e.g. 80M DDR mode Flash or PSRAM), timing tuning is required. + * Certain delay will be added to the MSPI RX direction. + * + * When CPU clock switches down, the delay should be cleared. Therefore here we call this function to remove the delays. + */ + spi_timing_change_speed_mode_cache_safe(true); #endif /* Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL). @@ -330,6 +303,7 @@ static void IRAM_ATTR calibrate_ocode(void) } rtc_clk_cpu_freq_set_config(&old_config); #ifndef BOOTLOADER_BUILD - enter_mspi_high_speed_mode_safe(); + //System clock is switched back to PLL. Here we switch to the MSPI high speed mode, add the delays back + spi_timing_change_speed_mode_cache_safe(false); #endif } diff --git a/components/spi_flash/esp32s3/spi_timing_config.c b/components/spi_flash/esp32s3/spi_timing_config.c index 75745cdfd7..e7ddfeffdb 100644 --- a/components/spi_flash/esp32s3/spi_timing_config.c +++ b/components/spi_flash/esp32s3/spi_timing_config.c @@ -359,25 +359,20 @@ void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy) #endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING -static bool spi_timing_config_cs_setup_enable(void) + +/*------------------------------------------------------------------------------------------------- + * To let upper lay (spi_flash_timing_tuning.c) to know the necessary timing registers + *-------------------------------------------------------------------------------------------------*/ +static bool s_get_cs_setup_enable(void) { return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_SETUP); } -static bool spi_timing_config_cs_hold_enable(void) +static bool s_get_cs_hold_enable(void) { return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD); } -bool spi_timine_config_flash_is_tuned(void) -{ -#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING - return true; -#else - return false; -#endif -} - /** * Get the SPI1 Flash CS timing setting. The setup time and hold time are both realistic cycles. * @note On ESP32-S3, SPI0/1 share the Flash CS timing registers. Therefore, we should not change these values. @@ -392,12 +387,12 @@ void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time) * The logic here is, if setup_en / hold_en is false, then we return the realistic cycle number, * which is 0. If true, then the realistic cycle number is (reg_value + 1) */ - if (spi_timing_config_cs_setup_enable()) { + if (s_get_cs_setup_enable()) { *setup_time += 1; } else { *setup_time = 0; } - if (spi_timing_config_cs_hold_enable()) { + if (s_get_cs_hold_enable()) { *hold_time += 1; } else { *hold_time = 0; diff --git a/components/spi_flash/esp32s3/spi_timing_config.h b/components/spi_flash/esp32s3/spi_timing_config.h index 167232e43c..06af783c9f 100644 --- a/components/spi_flash/esp32s3/spi_timing_config.h +++ b/components/spi_flash/esp32s3/spi_timing_config.h @@ -245,7 +245,7 @@ void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy); /** * SPI1 register info get APIs. These APIs inform `spi_flash_timing_tuning.c` (driver layer) of the SPI1 flash settings. - * In this way, other components (e.g.: esp_flash driver) can get the info from it. + * In this way, other components (e.g.: esp_flash driver) can get the info from it (`spi_flash_timing_tuning.c`). */ void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time); uint32_t spi_timing_config_get_flash_clock_reg(void); diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 4ac935f6c0..8fce5a47de 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -296,7 +296,7 @@ esp_err_t esp_flash_init_default_chip(void) // For chips need time tuning, get value directely from system here. #if SOC_SPI_MEM_SUPPORT_TIME_TUNING - if (spi_timine_config_flash_is_tuned()) { + if (spi_timing_is_tuned()) { cfg.using_timing_tuning = 1; spi_timing_get_flash_timing_param(&cfg.timing_reg); } diff --git a/components/spi_flash/include/esp_private/spi_flash_os.h b/components/spi_flash/include/esp_private/spi_flash_os.h index e302df86ea..e73511bc11 100644 --- a/components/spi_flash/include/esp_private/spi_flash_os.h +++ b/components/spi_flash/include/esp_private/spi_flash_os.h @@ -45,17 +45,26 @@ extern "C" { esp_err_t spi_flash_init_chip_state(void); /** - * @brief Make MSPI work under 20Mhz + * @brief Make MSPI work under 20Mhz, remove the timing tuning required delays. * @param control_spi1 Select whether to control SPI1. For tuning, we need to use SPI1. After tuning (during startup stage), let the flash driver to control SPI1 */ void spi_timing_enter_mspi_low_speed_mode(bool control_spi1); /** - * @brief Make MSPI work under the frequency as users set + * @brief Make MSPI work under the frequency as users set, may add certain delays to MSPI RX direction to meet timing requirements. * @param control_spi1 Select whether to control SPI1. For tuning, we need to use SPI1. After tuning (during startup stage), let the flash driver to control SPI1 */ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1); +/** + * @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 For some of the MSPI high frequency settings (e.g. 80M DDR mode Flash or PSRAM), timing tuning is required. + * Certain delays will be added to the MSPI RX direction. When CPU clock switches from PLL to XTAL, should call + * this API first to enter MSPI low speed mode to remove the delays, and vice versa. + */ +void spi_timing_change_speed_mode_cache_safe(bool switch_down); + /** * @brief Tune MSPI flash timing to make it work under high frequency */ @@ -90,9 +99,9 @@ esp_err_t esp_flash_init_main(esp_flash_t *chip); void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config); /** - * @brief Judge if the flash in tuned + * @brief Get the knowledge if the MSPI timing is tuned or not */ -bool spi_timine_config_flash_is_tuned(void); +bool spi_timing_is_tuned(void); /** * @brief Set Flash chip specifically required MSPI register settings here diff --git a/components/spi_flash/spi_flash_timing_tuning.c b/components/spi_flash/spi_flash_timing_tuning.c index 42748f0100..8b2efd1450 100644 --- a/components/spi_flash/spi_flash_timing_tuning.c +++ b/components/spi_flash/spi_flash_timing_tuning.c @@ -17,6 +17,7 @@ #include "soc/soc.h" #if CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/spi_timing_config.h" +#include "esp32s3/rom/cache.h" #endif #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr))) @@ -377,6 +378,7 @@ void spi_timing_psram_tuning(void) } #endif //SPI_TIMING_PSRAM_NEEDS_TUNING + /*------------------------------------------------------------------------------ * APIs to make SPI0 (and SPI1) FLASH work for high/low freq *----------------------------------------------------------------------------*/ @@ -460,9 +462,33 @@ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1) #endif } -/** - * Should be only used by SPI1 Flash driver to know the necessary timing registers - */ +void spi_timing_change_speed_mode_cache_safe(bool switch_down) +{ + Cache_Freeze_ICache_Enable(1); + Cache_Freeze_DCache_Enable(1); + if (switch_down) { + //enter MSPI low speed mode, extra delays should be removed + spi_timing_enter_mspi_low_speed_mode(false); + } else { + //enter MSPI high speed mode, extra delays should be considered + spi_timing_enter_mspi_high_speed_mode(false); + } + Cache_Freeze_DCache_Disable(); + Cache_Freeze_ICache_Disable(); +} + +/*------------------------------------------------------------------------------ + * APIs to inform SPI1 Flash driver of necessary timing configurations + *----------------------------------------------------------------------------*/ +bool spi_timing_is_tuned(void) +{ +#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING + return true; +#else + return false; +#endif +} + #if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config) { diff --git a/tools/test_apps/system/flash_psram/main/test_flash_psram.c b/tools/test_apps/system/flash_psram/main/test_flash_psram.c index a44dce24de..2fb38e096b 100644 --- a/tools/test_apps/system/flash_psram/main/test_flash_psram.c +++ b/tools/test_apps/system/flash_psram/main/test_flash_psram.c @@ -17,7 +17,6 @@ #include "esp32s3/rom/opi_flash.h" #endif -const static char *TAG = "SPI0"; //-----------------------------------------SPI0 PSRAM TEST-----------------------------------------------// #if CONFIG_SPIRAM @@ -80,8 +79,7 @@ extern void spi_flash_enable_interrupts_caches_and_other_cpu(void); static DRAM_ATTR uint8_t rd_buf[SPI1_FLASH_TEST_LEN]; static DRAM_ATTR uint8_t wr_buf[SPI1_FLASH_TEST_LEN]; - -static IRAM_ATTR esp_err_t spi1_flash_test(void) +static NOINLINE_ATTR IRAM_ATTR esp_err_t spi1_flash_test(void) { printf(DRAM_STR("----------SPI1 Flash Test----------\n")); @@ -124,7 +122,7 @@ static IRAM_ATTR esp_err_t spi1_flash_test(void) #define SPI0_FLASH_TEST_BUF {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F} -uint8_t flash_rd_buf[SPI0_FLASH_TEST_LEN] __attribute__((section (".flash.rodata"))) = SPI0_FLASH_TEST_BUF; +static const uint8_t flash_rd_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF; extern int _flash_rodata_start; extern int _rodata_reserved_end; @@ -133,7 +131,7 @@ static IRAM_ATTR esp_err_t spi0_flash_test(void) { printf("----------SPI0 Flash Test----------\n"); //Check if the flash_rd_buf is in .rodata - ESP_RETURN_ON_ERROR(((intptr_t)flash_rd_buf >= (intptr_t)_flash_rodata_start) && ((intptr_t)flash_rd_buf < (intptr_t)_rodata_reserved_end), TAG, "psram_rd_buf not in rodata"); + assert(((intptr_t)flash_rd_buf >= (intptr_t)&_flash_rodata_start) && ((intptr_t)flash_rd_buf < (intptr_t)&_rodata_reserved_end)); uint8_t cmp_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF; diff --git a/tools/test_apps/system/flash_psram/sdkconfig.ci.f4r4_120sdr_os_silent b/tools/test_apps/system/flash_psram/sdkconfig.ci.f4r4_120sdr_os_silent new file mode 100644 index 0000000000..41cbec6a1e --- /dev/null +++ b/tools/test_apps/system/flash_psram/sdkconfig.ci.f4r4_120sdr_os_silent @@ -0,0 +1,9 @@ +# Legacy, F4R4, Flash 120M SDR, PSRAM disable, compiler -Os and silent + +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y + +CONFIG_SPI_FLASH_USE_LEGACY_IMPL=y +CONFIG_ESPTOOLPY_FLASHFREQ_120M=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y