diff --git a/components/esp_hw_support/include/esp_private/rtc_clk.h b/components/esp_hw_support/include/esp_private/rtc_clk.h index 7edf69be06..17c1a939b6 100644 --- a/components/esp_hw_support/include/esp_private/rtc_clk.h +++ b/components/esp_hw_support/include/esp_private/rtc_clk.h @@ -44,6 +44,12 @@ void rtc_clk_bbpll_add_consumer(void); */ void rtc_clk_bbpll_remove_consumer(void); +/** + * @brief Workaround for C2, S3, C6, H2. Trigger the calibration of PLL. Should be called when the bootloader doesn't provide a good enough PLL accuracy. +*/ +void rtc_clk_recalib_bbpll(void); + + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/port/esp32c2/rtc_clk.c b/components/esp_hw_support/port/esp32c2/rtc_clk.c index c065b4476a..2501c2f6df 100644 --- a/components/esp_hw_support/port/esp32c2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c2/rtc_clk.c @@ -128,6 +128,7 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_set_config(pll_freq, xtal_freq); /* WAIT CALIBRATION DONE */ while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + esp_rom_delay_us(10); /* BBPLL CALIBRATION STOP */ regi2c_ctrl_ll_bbpll_calibration_stop(); @@ -357,6 +358,24 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +void rtc_clk_recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk.c b/components/esp_hw_support/port/esp32c6/rtc_clk.c index 53644617ca..da6ab452f1 100644 --- a/components/esp_hw_support/port/esp32c6/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c6/rtc_clk.c @@ -168,6 +168,7 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_set_config(pll_freq, xtal_freq); /* WAIT CALIBRATION DONE */ while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + esp_rom_delay_us(10); /* BBPLL CALIBRATION STOP */ regi2c_ctrl_ll_bbpll_calibration_stop(); rtc_clk_enable_i2c_ana_master_clock(false); @@ -421,6 +422,25 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +void rtc_clk_recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} + + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk.c b/components/esp_hw_support/port/esp32h2/rtc_clk.c index bb8e288b53..1f6fd3b8fe 100644 --- a/components/esp_hw_support/port/esp32h2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h2/rtc_clk.c @@ -185,6 +185,7 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_set_config(pll_freq, xtal_freq); /* WAIT CALIBRATION DONE */ while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + esp_rom_delay_us(10); /* BBPLL CALIBRATION STOP */ regi2c_ctrl_ll_bbpll_calibration_stop(); rtc_clk_enable_i2c_ana_master_clock(false); @@ -474,3 +475,21 @@ bool rtc_dig_8m_enabled(void) { return clk_ll_rc_fast_digi_is_enabled(); } + +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +void rtc_clk_recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. Flash_PLL comes from the same source as PLL. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL || old_config.source == SOC_CPU_CLK_SRC_FLASH_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index a17ccc80ed..07f609c5f3 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s3/rtc_clk.c @@ -172,6 +172,7 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_set_config(pll_freq, xtal_freq); /* WAIT CALIBRATION DONE */ while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + esp_rom_delay_us(10); /* BBPLL CALIBRATION STOP */ regi2c_ctrl_ll_bbpll_calibration_stop(); @@ -459,6 +460,25 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +void rtc_clk_recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} + + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 3006f40b60..f3ab7b0c80 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -561,6 +561,15 @@ menu "ESP System Settings" (2). For special workflow, the chip needs do more things instead of restarting directly. This part needs to be done in callback function of interrupt. + config ESP_SYSTEM_BBPLL_RECALIB + bool "Re-calibration BBPLL at startup" + depends on IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32H2 + default y + help + This configuration helps to address an BBPLL inaccurate issue when boot from certain bootloader version, + which may increase about the boot-up time by about 200 us. Disable this when your bootloader is built with + ESP-IDF version v5.2 and above. + endmenu # ESP System Settings menu "IPC (Inter-Processor Call)" diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 97a3f767f5..085d37686f 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -17,6 +17,8 @@ #include "esp_efuse.h" #include "esp_private/cache_err_int.h" #include "esp_clk_internal.h" +// For workaround `rtc_clk_recalib_bbpll()` +#include "esp_private/rtc_clk.h" #include "esp_rom_efuse.h" #include "esp_rom_uart.h" @@ -454,7 +456,14 @@ void IRAM_ATTR call_start_cpu0(void) * In this stage, we re-configure the Flash (and MSPI) to required configuration */ spi_flash_init_chip_state(); + + // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. + // Do calibration again here so that we can use better clock for the timing tuning. +#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB + rtc_clk_recalib_bbpll(); +#endif #if SOC_MEMSPI_SRC_FREQ_120M + // This function needs to be called when PLL is enabled mspi_timing_flash_tuning(); #endif