Răsfoiți Sursa

Merge branch 'bugfix/add_support_for_mspi_to_work_with_cpu_clock_switch' into 'master'

mspi: make cpu clock source switch safe

Closes IDFCI-902

See merge request espressif/esp-idf!15557
Michael (XIAO Xufeng) 4 ani în urmă
părinte
comite
390f71cbcb

+ 17 - 43
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
 }

+ 8 - 13
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;

+ 1 - 1
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);

+ 1 - 1
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);
     }

+ 13 - 4
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

+ 29 - 3
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)
 {

+ 3 - 5
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;
 

+ 9 - 0
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