diff --git a/Kconfig b/Kconfig index 7fc829569d7..7fdc422815f 100644 --- a/Kconfig +++ b/Kconfig @@ -522,3 +522,12 @@ mainmenu "Espressif IoT Development Framework Configuration" menu "Component config" source "$COMPONENT_KCONFIGS_SOURCE_FILE" endmenu + + config IDF_EXPERIMENTAL_FEATURES + bool "Make experimental features visible" + default "n" + help + By enabling this option, ESP-IDF experimental feature options will be visible. + + Note you should still enable a certain experimental feature option to use it, and you + should read the corresponding risk warning and known issue list carefully. diff --git a/components/esp_hw_support/mspi_timing_config.h b/components/esp_hw_support/mspi_timing_config.h index 16ea72789ac..78de3dadf93 100644 --- a/components/esp_hw_support/mspi_timing_config.h +++ b/components/esp_hw_support/mspi_timing_config.h @@ -139,43 +139,45 @@ void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t le /*------------------------------------------------------------------------------------------------- * SPI1 Timing Tuning APIs - * These APIs are only used in `spi_flash_timing_tuning.c/sweep_for_success_sample_points()` for - * configuring SPI1 timing tuning related registers to find best tuning parameter + * + * These APIs are only used in `mspi_timing_tuning.c` for configuring SPI1 timing + * tuning related registers to find best tuning parameter for Flash and PSRAM *-------------------------------------------------------------------------------------------------*/ /** - * @brief Tune Flash Din Mode and Num of SPI1 - * @param din_mode Din mode - * @param din_num Din num + * @brief Tune Flash timing registers for SPI1 accessing Flash + * + * @param[in] params Timing parameters */ -void mspi_timing_config_flash_tune_din_num_mode(uint8_t din_mode, uint8_t din_num); +void mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t *params); /** - * @brief Tune Flash extra dummy of SPI1 - * @param extra_dummy extra dummy bits + * @brief Tune PSRAM timing registers for SPI1 accessing PSRAM + * + * @param[in] params Timing parameters */ -void mspi_timing_config_flash_tune_dummy(uint8_t extra_dummy); +void mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t *params); -/** - * @brief Tune PSRAM Din Mode and Num of SPI1 - * @param din_mode Din mode - * @param din_num Din num - */ -void mspi_timing_config_psram_tune_din_num_mode(uint8_t din_mode, uint8_t din_num); +/*------------------------------------------------------------------------------------------------- + * APIs for coordination with ESP Flash driver + *-------------------------------------------------------------------------------------------------*/ /** - * @brief Tune PSRAM extra dummy of SPI1 - * @param extra_dummy extra dummy bits + * SPI1 register info get APIs. These APIs inform `mspi_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 (`mspi_timing_tuning.c`). */ -void mspi_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 (`spi_flash_timing_tuning.c`). + * @brief Get CS timing + * + * @param[out] setup_time Setup time + * @param[out] hold_time Hold time */ void mspi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time); /** * @brief Get Flash clock reg val + * + * @return Flash clock reg val */ uint32_t mspi_timing_config_get_flash_clock_reg(void); diff --git a/components/esp_hw_support/mspi_timing_tuning.c b/components/esp_hw_support/mspi_timing_tuning.c index ee565b353f7..64f05074b9d 100644 --- a/components/esp_hw_support/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi_timing_tuning.c @@ -15,8 +15,11 @@ #include "soc/io_mux_reg.h" #include "esp_private/mspi_timing_tuning.h" #include "soc/soc.h" +#include "soc/rtc.h" #include "hal/spi_flash_hal.h" #include "hal/mspi_timing_tuning_ll.h" +#include "hal/clk_tree_ll.h" +#include "hal/regi2c_ctrl_ll.h" #include "mspi_timing_config.h" #if CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/cache.h" @@ -107,7 +110,7 @@ static void init_spi1_for_tuning(bool is_flash) * We use different SPI1 timing tuning config to read data to see if current MSPI sampling is successful. * The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0. */ -static void sweep_for_success_sample_points(uint8_t *reference_data, const mspi_timing_config_t *config, bool is_flash, uint8_t *out_array) +static void sweep_for_success_sample_points(const uint8_t *reference_data, const mspi_timing_config_t *config, bool is_flash, uint8_t *out_array) { uint32_t config_idx = 0; uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0}; @@ -116,20 +119,21 @@ static void sweep_for_success_sample_points(uint8_t *reference_data, const mspi_ memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN); #if MSPI_TIMING_FLASH_NEEDS_TUNING if (is_flash) { - mspi_timing_config_flash_tune_din_num_mode(config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num); - mspi_timing_config_flash_tune_dummy(config->tuning_config_table[config_idx].extra_dummy_len); + mspi_timing_config_flash_set_tuning_regs(&(config->tuning_config_table[config_idx])); mspi_timing_config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data)); } #endif #if MSPI_TIMING_PSRAM_NEEDS_TUNING if (!is_flash) { - mspi_timing_config_psram_tune_din_num_mode(config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num); - mspi_timing_config_psram_tune_dummy(config->tuning_config_table[config_idx].extra_dummy_len); + mspi_timing_config_psram_set_tuning_regs(&(config->tuning_config_table[config_idx])); mspi_timing_config_psram_read_data(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN); } #endif if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) { out_array[config_idx] = 1; + ESP_EARLY_LOGD(TAG, "%d, good", config_idx); + } else { + ESP_EARLY_LOGD(TAG, "%d, bad", config_idx); } } } @@ -164,14 +168,77 @@ static void find_max_consecutive_success_points(uint8_t *array, uint32_t size, u *out_end_index = match_num == size ? size : end; } +#if (MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE) && (MSPI_TIMING_CORE_CLOCK_MHZ == 240) +static bool get_working_pll_freq(const uint8_t *reference_data, bool is_flash, uint32_t *out_max_freq, uint32_t *out_min_freq) +{ + uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0}; + rtc_cpu_freq_config_t previous_config; + rtc_clk_cpu_freq_get_config(&previous_config); + + uint32_t big_num = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX * 2; //This number should be larger than MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX, for error handling + uint32_t max_freq = 0; + uint32_t min_freq = big_num; + rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); + + //BBPLL CALIBRATION START + regi2c_ctrl_ll_bbpll_calibration_start(); + for (int pll_mhz_tuning = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN; pll_mhz_tuning <= MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX; pll_mhz_tuning += 8) { + /** + * pll_mhz = xtal_mhz * (oc_div + 4) / (oc_ref_div + 1) + */ + clk_ll_bbpll_set_frequency_for_mspi_tuning(xtal_freq, pll_mhz_tuning, ((pll_mhz_tuning / 4) - 4), 9); + + memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN); + if (is_flash) { + mspi_timing_config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN); + } else { + mspi_timing_config_psram_read_data(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN); + } + + if (memcmp(read_data, reference_data, MSPI_TIMING_TEST_DATA_LEN) == 0) { + max_freq = MAX(pll_mhz_tuning, max_freq); + min_freq = MIN(pll_mhz_tuning, min_freq); + + //Continue to find successful cases + continue; + } + + if (max_freq != 0) { + //The first fail case after successful case(s) is the end + break; + } + + //If no break, no successful case found, continue to find successful cases + } + + //restore PLL config + clk_ll_bbpll_set_freq_mhz(previous_config.source_freq_mhz); + clk_ll_bbpll_set_config(previous_config.source_freq_mhz, xtal_freq); + + //WAIT CALIBRATION DONE + while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + + //BBPLL CALIBRATION STOP + regi2c_ctrl_ll_bbpll_calibration_stop(); + + + *out_max_freq = max_freq; + *out_min_freq = min_freq; + + return (max_freq != 0); +} +#endif //Frequency Scanning + #if MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE -static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end) +static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash) { #if (MSPI_TIMING_CORE_CLOCK_MHZ == 160) //Core clock 160M DTR best point scheme - uint32_t best_point; + (void) reference_data; + (void) is_flash; + uint32_t best_point = 0; - //Define these magic number in macros in `spi_timing_config.h`. TODO: IDF-3663 + //These numbers will probably be same on other chips, if this version of algorithm is utilised if (consecutive_length <= 2 || consecutive_length >= 6) { //tuning is FAIL, select default point, and generate a warning best_point = config->default_config_id; @@ -187,6 +254,41 @@ static uint32_t select_best_tuning_config_dtr(mspi_timing_config_t *config, uint } return best_point; + +#elif (MSPI_TIMING_CORE_CLOCK_MHZ == 240) + + uint32_t best_point = 0; + uint32_t current_point = end + 1 - consecutive_length; + bool ret = false; + + //This `max_freq` is the max pll frequency that per MSPI timing tuning config can work + uint32_t max_freq = 0; + uint32_t temp_max_freq = 0; + uint32_t temp_min_freq = 0; + + for (; current_point <= end; current_point++) { + if (is_flash) { + mspi_timing_config_flash_set_tuning_regs(&(config->tuning_config_table[current_point])); + } else { + mspi_timing_config_psram_set_tuning_regs(&(config->tuning_config_table[current_point])); + } + + ret = get_working_pll_freq(reference_data, is_flash, &temp_max_freq, &temp_min_freq); + if (ret && temp_min_freq <= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW && temp_max_freq >= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH && temp_max_freq > max_freq) { + max_freq = temp_max_freq; + best_point = current_point; + } + ESP_EARLY_LOGD(TAG, "sample point %d, max pll is %d mhz, min pll is %d\n", current_point, temp_max_freq, temp_min_freq); + } + if (max_freq == 0) { + ESP_EARLY_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %d", end + 1 - consecutive_length); + best_point = end + 1 - consecutive_length; + } else { + ESP_EARLY_LOGD(TAG, "freq scan success, max pll is %dmhz, best point is index %d", max_freq, best_point); + } + + return best_point; + #else //won't reach here abort(); @@ -221,19 +323,19 @@ static uint32_t select_best_tuning_config_str(mspi_timing_config_t *config, uint } #endif -static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, bool is_flash) +static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash) { uint32_t best_point = 0; if (is_flash) { #if MSPI_TIMING_FLASH_DTR_MODE - best_point = select_best_tuning_config_dtr(config, consecutive_length, end); + best_point = select_best_tuning_config_dtr(config, consecutive_length, end, reference_data, is_flash); #elif MSPI_TIMING_FLASH_STR_MODE best_point = select_best_tuning_config_str(config, consecutive_length, end); #endif s_flash_best_timing_tuning_config = config->tuning_config_table[best_point]; } else { #if MSPI_TIMING_PSRAM_DTR_MODE - best_point = select_best_tuning_config_dtr(config, consecutive_length, end); + best_point = select_best_tuning_config_dtr(config, consecutive_length, end, reference_data, is_flash); #elif MSPI_TIMING_PSRAM_STR_MODE best_point = select_best_tuning_config_str(config, consecutive_length, end); #endif @@ -241,7 +343,7 @@ static void select_best_tuning_config(mspi_timing_config_t *config, uint32_t con } } -static void do_tuning(uint8_t *reference_data, mspi_timing_config_t *timing_config, bool is_flash) +static void do_tuning(const uint8_t *reference_data, mspi_timing_config_t *timing_config, bool is_flash) { /** * We use SPI1 to tune the timing: @@ -256,7 +358,7 @@ static void do_tuning(uint8_t *reference_data, mspi_timing_config_t *timing_conf init_spi1_for_tuning(is_flash); sweep_for_success_sample_points(reference_data, timing_config, is_flash, sample_result); find_max_consecutive_success_points(sample_result, MSPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point); - select_best_tuning_config(timing_config, consecutive_length, last_success_point, is_flash); + select_best_tuning_config(timing_config, consecutive_length, last_success_point, reference_data, is_flash); } #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING diff --git a/components/esp_hw_support/port/esp32s3/mspi_timing_config.c b/components/esp_hw_support/port/esp32s3/mspi_timing_config.c index 4f09c316045..7beecc59c17 100644 --- a/components/esp_hw_support/port/esp32s3/mspi_timing_config.c +++ b/components/esp_hw_support/port/esp32s3/mspi_timing_config.c @@ -290,40 +290,33 @@ void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t le * These APIs are only used in `spi_flash_timing_tuning.c/sweep_for_success_sample_points()` for * configuring SPI1 timing tuning related registers to find best tuning parameter *-------------------------------------------------------------------------------------------------*/ -void mspi_timing_config_flash_tune_din_num_mode(uint8_t din_mode, uint8_t din_num) +void mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t *params) { /** * 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless * SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning * 2. We use SPI1 to get the best Flash timing tuning (mode and num) config */ - mspi_timing_config_flash_set_din_mode_num(0, din_mode, din_num); + mspi_timing_config_flash_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num); + mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len); } -void mspi_timing_config_flash_tune_dummy(uint8_t extra_dummy) -{ - mspi_timing_config_flash_set_extra_dummy(1, extra_dummy); -} - -void mspi_timing_config_psram_tune_din_num_mode(uint8_t din_mode, uint8_t din_num) +void mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t *params) { /** * 1. SPI_MEM_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless * SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning * 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config */ - mspi_timing_config_psram_set_din_mode_num(0, din_mode, din_num); -} + mspi_timing_config_psram_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num); -void mspi_timing_config_psram_tune_dummy(uint8_t extra_dummy) -{ #if CONFIG_SPIRAM_MODE_OCT //On 728, for SPI1, flash and psram share the extra dummy register - mspi_timing_config_flash_set_extra_dummy(1, extra_dummy); + mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len); #elif CONFIG_SPIRAM_MODE_QUAD //Update this `s_psram_extra_dummy`, the `s_psram_read_data` will set dummy according to this `s_psram_extra_dummy` - s_psram_extra_dummy = extra_dummy; - mspi_timing_ll_set_quad_flash_dummy(1, extra_dummy - 1); + s_psram_extra_dummy = params->extra_dummy_len; + mspi_timing_ll_set_quad_flash_dummy(1, s_psram_extra_dummy - 1); #endif } diff --git a/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h b/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h index 3a538ae387e..274dbd3dec5 100644 --- a/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h +++ b/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h @@ -128,6 +128,11 @@ #endif #endif //PSRAM 120M STR +//PSRAM 120M STR +#if MSPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_120M +#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 240 +#endif //PSRAM 120M DTR + //------------------------------------------Determine the Core Clock-----------------------------------------------// /** @@ -233,3 +238,20 @@ ESP_STATIC_ASSERT(CHECK_POWER_OF_2(MSPI_TIMING_CORE_CLOCK_MHZ / MSPI_TIMING_PSRA #define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE {{2, 0, 1}, {0, 0, 0}, {2, 2, 2}, {1, 0, 1}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {1, 0, 2}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {1, 0, 3}} #define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12 #define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 2 + +//PSRAM: core clock 240M, module clock 120M, DTR mode +#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE {{0, 0, 0}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 1, 4}, {1, 0, 3}, {4, 0, 4}, {0, 0, 3}, {4, 1, 5}} +#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 14 +#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 1 + +//------------------------------------------Frequency Scanning Related-----------------------------------------------// +/** + * On ESP32S3, only module clock 120M, DDR mode needs frequency scan. Frequency scanning is to get the max workable PLL + * frequency under each successfull timing tuning configuration. PLL frequency may fluctuate under high temperature, + * this method is to get the tuning configuration that can work under higher PLL frequency. + */ +#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 440 +#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX 600 +#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW 448 +#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH 520 +#define MSPI_TIMING_PLL_FREQ_SCAN_STEP_MHZ_MODULE_CLK_120M 8 diff --git a/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr b/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr new file mode 100644 index 00000000000..9289b41d456 --- /dev/null +++ b/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr @@ -0,0 +1,6 @@ +# F8R8, Flash 120M DDR, PSRAM disable + +CONFIG_ESPTOOLPY_OCT_FLASH=y +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y +CONFIG_ESPTOOLPY_FLASHFREQ_120M=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y diff --git a/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr_120ddr b/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr_120ddr new file mode 100644 index 00000000000..290f4c92d9f --- /dev/null +++ b/components/esp_hw_support/test_apps/mspi/sdkconfig.ci.f8r8_120ddr_120ddr @@ -0,0 +1,10 @@ +# F8R8, Flash 120M DDR, PSRAM 120M DDR + +CONFIG_ESPTOOLPY_OCT_FLASH=y +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y +CONFIG_ESPTOOLPY_FLASHFREQ_120M=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_120M=y diff --git a/components/esp_hw_support/test_apps/mspi/sdkconfig.defaults b/components/esp_hw_support/test_apps/mspi/sdkconfig.defaults index 8e11bd6bd30..1a9b8b56c15 100644 --- a/components/esp_hw_support/test_apps/mspi/sdkconfig.defaults +++ b/components/esp_hw_support/test_apps/mspi/sdkconfig.defaults @@ -1,5 +1,6 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_ESP_TASK_WDT_EN=n -CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" diff --git a/components/esp_psram/esp32s3/Kconfig.spiram b/components/esp_psram/esp32s3/Kconfig.spiram index 771019c6006..c69016f8de6 100644 --- a/components/esp_psram/esp32s3/Kconfig.spiram +++ b/components/esp_psram/esp32s3/Kconfig.spiram @@ -82,8 +82,20 @@ menu "SPI RAM config" Select the speed for the SPI RAM chip. config SPIRAM_SPEED_120M - depends on SPIRAM_MODE_QUAD + depends on SPIRAM_MODE_QUAD || IDF_EXPERIMENTAL_FEATURES bool "120MHz clock speed" + + help + - Quad PSRAM 120 MHz is stable. + + - Octal PSRAM 120 MHz is an experimental feature, it works when + the temperature is stable. + + Risks: + If your chip powers on at a certain temperature, then after the temperature + increases or decreases by approximately 20 Celsius degrees (depending on the + chip), the accesses to / from PSRAM will crash randomly. + config SPIRAM_SPEED_80M bool "80MHz clock speed" config SPIRAM_SPEED_40M @@ -97,5 +109,4 @@ menu "SPI RAM config" default 40 if SPIRAM_SPEED_40M source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here - endmenu diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 15eab2919ae..e59c2fbc041 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -95,7 +95,18 @@ menu "Serial flasher config" config ESPTOOLPY_FLASHFREQ_120M bool "120 MHz" select SPI_FLASH_HPM_ENABLE - depends on SOC_MEMSPI_SRC_FREQ_120M && ESPTOOLPY_FLASH_SAMPLE_MODE_STR + depends on SOC_MEMSPI_SRC_FREQ_120M && \ + (ESPTOOLPY_FLASH_SAMPLE_MODE_STR || IDF_EXPERIMENTAL_FEATURES) + help + - Flash 120 MHz SDR mode is stable. + - Flash 120 MHz DDR mode is an experimental feature, it works when + the temperature is stable. + + Risks: + If your chip powers on at a certain temperature, then after the temperature + increases or decreases by approximately 20 Celsius degrees (depending on the + chip), the program will crash randomly. + config ESPTOOLPY_FLASHFREQ_80M bool "80 MHz" depends on SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED diff --git a/components/hal/esp32s3/include/hal/clk_tree_ll.h b/components/hal/esp32s3/include/hal/clk_tree_ll.h index c2534134a70..c333775d6b4 100644 --- a/components/hal/esp32s3/include/hal/clk_tree_ll.h +++ b/components/hal/esp32s3/include/hal/clk_tree_ll.h @@ -12,6 +12,7 @@ #include "soc/rtc.h" #include "soc/system_reg.h" #include "soc/rtc_cntl_reg.h" +#include "soc/regi2c_defs.h" #include "hal/regi2c_ctrl.h" #include "soc/regi2c_bbpll.h" #include "hal/assert.h" @@ -682,6 +683,45 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_rtc_slow_load_cal(v return REG_READ(RTC_SLOW_CLK_CAL_REG); } +/** + * @brief Configure PLL frequency for MSPI timing tuning + * @note Only used by the MSPI Timing tuning driver + * + * @param xtal_freq Xtal frequency + * @param pll_freq PLL frequency + * @param oc_div OC divider + * @param oc_ref_div OC ref divider + */ +static inline __attribute__((always_inline)) +void clk_ll_bbpll_set_frequency_for_mspi_tuning(rtc_xtal_freq_t xtal_freq, int pll_freq, uint8_t oc_div, uint8_t oc_ref_div) +{ + HAL_ASSERT(xtal_freq == RTC_XTAL_FREQ_40M); + uint32_t pll_reg = GET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | + RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD); + HAL_ASSERT(pll_reg == 0); + + /* Set this register to let the digital part know 480M PLL is used */ + SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); + uint8_t dr1 = 0; + uint8_t dr3 = 0; + uint8_t dchgp = 5; + uint8_t dcur = 3; + uint8_t dbias = 2; + uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (oc_ref_div); + uint8_t i2c_bbpll_div_7_0 = oc_div; + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B); + + uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur; + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref); + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3); + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 3); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/spimem_flash_ll.h b/components/hal/esp32s3/include/hal/spimem_flash_ll.h index 3c325bf8391..4e8d5744f65 100644 --- a/components/hal/esp32s3/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32s3/include/hal/spimem_flash_ll.h @@ -575,6 +575,9 @@ static inline uint8_t spimem_flash_ll_get_source_freq_mhz(void) case 2: clock_val = 160; break; + case 3: + clock_val = 240; + break; default: abort(); } diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 1383f8b79d9..c10a7b46d0e 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -310,5 +310,4 @@ menu "SPI Flash driver" help This option is invisible, and will be selected automatically when ``ESPTOOLPY_FLASHFREQ_120M`` is selected. - endmenu diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index 731df0601c8..c70f951dff8 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -160,17 +160,22 @@ Restrictions External RAM use has the following restrictions: - * When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below). +* When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible. Any read operations from or write operations to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below). - * External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffer that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL)`` and can be freed using a standard ``free()`` call. +.. only:: SOC_PSRAM_DMA_CAPABLE and not esp32s3 - .. only:: SOC_PSRAM_DMA_CAPABLE + * External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffer that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL)`` and can be freed using a standard ``free()`` call. Note, although {IDF_TARGET_NAME} has hardware support for DMA to / from external RAM, this is not yet supported in ESP-IDF. - Note, although {IDF_TARGET_NAME} has hardware support for DMA to/from external RAM, this is not yet supported in ESP-IDF. +.. only:: esp32s3 - * External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can "push out" cached flash, possibly making the execution of code slower afterwards. + * Although {IDF_TARGET_NAME} has hardware support for DMA to / from external RAM, there are still limitations: - * In general, external RAM will not be used as task stack memory. :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory for stack and task TCBs. + - The bandwidth that DMA accesses external RAM is very limited, especially when CPU is trying to access the external RAM at the same time. + - You can configure :ref:`CONFIG_SPIRAM_SPEED` as 120 MHz for an Octal PSRAM. The bandwidth will be improved. However there are still restrictions for this option, see :ref:`All Supported PSRAM Modes and Speeds ` for more details. + +* External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can "push out" cached flash, possibly making the execution of code slower afterwards. + +* In general, external RAM will not be used as task stack memory. :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory for stack and task TCBs. The option :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` can be used to allow placing task stacks into external memory. In these cases :cpp:func:`xTaskCreateStatic` must be used to specify a task stack buffer allocated from external memory, otherwise task stacks will still be allocated from internal memory. diff --git a/docs/en/api-guides/flash_psram_config.rst b/docs/en/api-guides/flash_psram_config.rst index f77321e8d16..a2358869a24 100644 --- a/docs/en/api-guides/flash_psram_config.rst +++ b/docs/en/api-guides/flash_psram_config.rst @@ -74,20 +74,34 @@ All Supported Modes and Speeds For MSPI DDR mode, the data are sampled on both the positive edge and the negative edge. e.g.: if a Flash is set to 80 MHz and DDR mode, then the final speed of the Flash is 160 MHz. This is faster than the Flash setting to 120 Mhz and STR mode. +.. important:: + + 120 MHz DDR mode is an experimental feature. You will only see it when: + + - :ref:`CONFIG_IDF_EXPERIMENTAL_FEATURES` is enabled + + With above step, you will find 120 MHz option is visible. + + Risks: + + If your chip powers on at a certain temperature, then after the temperature increases or decreases over 20 celsius degree, the accesses to / from PSRAM / Flash will crash randomly. Flash access crash will lead to program crash. + + Note 20 celsius degree is not a totally correct number. This value may changes among chips. F8R8 Hardware ^^^^^^^^^^^^^ -======= =============== ======= ============ +======= =============== ======= ============= Group Flash mode Group PSRAM mode -======= =============== ======= ============ - A 120 MHz SDR A N.A. +======= =============== ======= ============= + A 120 MHz DDR A 120 MHz DDR + A 120 MHz SDR A B 80 MHz DDR B 80 MHz DDR C 80 MHz SDR C 40 MHz DDR C 40 MHz DDR C C < 40 MHz C D D disable -======= =============== ======= ============ +======= =============== ======= ============= 1. Flash mode in group A works with PSRAM mode in group A/D 2. Flash mode in group B/C works with PSRAM mode in group B/C/D @@ -99,7 +113,7 @@ F4R8 Hardware ======= =============== ======= ============ Group Flash mode Group PSRAM mode ======= =============== ======= ============ - A 120 MHz SDR A N.A. + A 120 MHz SDR A 120MHz DDR B 80 MHz SDR B 80MHz DDR C 40 MHz SDR C 40MHz DDR C 20 MHz SDR C