From a3b62bc3c433e4bdfb6c2a40db41cd8fa910b2ea Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 10 Aug 2026 16:56:53 +0800 Subject: [PATCH] fix(esp_hw_support): fix ESP32-S31 CPU/DFS clk_tree refcount and keep clock source during DFS --- .../esp32s31/include/hal/clk_tree_ll.h | 8 + .../esp32s31/include/hal/mspi_ll.h | 26 ++- .../esp_hal_pmu/esp32s31/include/hal/pmu_ll.h | 18 ++ .../include/esp_private/rtc_clk.h | 4 +- components/esp_hw_support/linker.lf | 3 +- .../port/esp32p4/CMakeLists.txt | 6 +- .../esp_hw_support/port/esp32p4/rtc_clk.c | 4 + .../port/esp32s31/CMakeLists.txt | 9 +- .../port/esp32s31/esp_clk_tree.c | 110 ++++++----- .../port/esp32s31/include/soc/rtc.h | 9 +- .../esp_hw_support/port/esp32s31/pmu_init.c | 8 +- .../esp_hw_support/port/esp32s31/pmu_param.c | 1 + .../esp_hw_support/port/esp32s31/rtc_clk.c | 186 +++++++++--------- 13 files changed, 235 insertions(+), 157 deletions(-) diff --git a/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h b/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h index 9bf7a1bd0aa..7c4d9434af1 100644 --- a/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h +++ b/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h @@ -95,6 +95,7 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_enable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_XPD_CPLL | PMU_TIE_HIGH_XPD_CPLL_I2C); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_GLOBAL_CPLL_ICG); SET_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_CPLL_300M_CLK_EN); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_CPLL_I2C | PMU_HP_ACTIVE_XPD_CPLL); } /** @@ -105,6 +106,7 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_disable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_GLOBAL_CPLL_ICG) ; SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_XPD_CPLL | PMU_TIE_LOW_XPD_CPLL_I2C); CLEAR_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_CPLL_300M_CLK_EN); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_CPLL_I2C | PMU_HP_ACTIVE_XPD_CPLL); } /** @@ -115,6 +117,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtalx2_enable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_0_REG, PMU_TIE_HIGH_XPD_XTALX2); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_0_REG, PMU_TIE_HIGH_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_XTALX2_80M_CLK_EN); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** @@ -125,6 +128,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtalx2_disable(void) CLEAR_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_XTALX2_80M_CLK_EN); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_0_REG, PMU_TIE_LOW_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_0_REG, PMU_TIE_LOW_XPD_XTALX2); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** @@ -156,6 +160,7 @@ static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_GLOBAL_BBPLL_ICG); SET_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_SPLL_480M_CLK_EN); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -166,6 +171,7 @@ static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_GLOBAL_BBPLL_ICG) ; SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_XPD_BBPLL | PMU_TIE_LOW_XPD_BBPLL_I2C); CLEAR_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_SPLL_480M_CLK_EN); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -176,6 +182,7 @@ static inline __attribute__((always_inline)) void clk_ll_apll_enable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_XPD_APLL | PMU_TIE_HIGH_XPD_APLL_I2C); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_HIGH_GLOBAL_APLL_ICG); SET_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_AUDIO_PLL_CLK_EN); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_APLL_I2C | PMU_HP_ACTIVE_XPD_APLL); } /** @@ -186,6 +193,7 @@ static inline __attribute__((always_inline)) void clk_ll_apll_disable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_GLOBAL_APLL_ICG) ; SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_1_REG, PMU_TIE_LOW_XPD_APLL | PMU_TIE_LOW_XPD_APLL_I2C); CLEAR_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_AUDIO_PLL_CLK_EN); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_APLL_I2C | PMU_HP_ACTIVE_XPD_APLL); } /** diff --git a/components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h b/components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h index dabe3a8868f..6944dc02fac 100644 --- a/components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h +++ b/components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h @@ -48,7 +48,7 @@ extern "C" { #define MSPI_LL_PERIPH_NUM 4 #define MSPI_TIMING_LL_MSPI_ID_0 0 #define MSPI_TIMING_LL_MSPI_ID_1 1 -#define MSPI_TIMING_LL_FLASH_CORE_80M_CLK_DIV 4 +#define MSPI_TIMING_LL_FLASH_CORE_80M_CLK_DIV 4 // clk src is 320M CPLL // PSRAM frequency should be constrained by AXI frequency to avoid FIFO underflow. #define MSPI_TIMING_LL_PSRAM_FREQ_AXI_CONSTRAINED 1 @@ -218,6 +218,30 @@ static inline void _mspi_timing_ll_set_flash_clk_src(uint32_t mspi_id, soc_perip HP_SYS_CLKRST.flash_ctrl0.reg_flash_clk_src_sel = clk_val; } +/** + * @brief Get FLASH clock source + * + * @param mspi_id mspi_id + * + * @return clock source, see valid sources in type `soc_periph_flash_clk_src_t` + */ +__attribute__((always_inline)) +static inline soc_periph_flash_clk_src_t _mspi_timing_ll_get_flash_clk_src(uint32_t mspi_id) +{ + HAL_ASSERT(mspi_id == MSPI_TIMING_LL_MSPI_ID_0); + switch (HP_SYS_CLKRST.flash_ctrl0.reg_flash_clk_src_sel) { + case 0: + return FLASH_CLK_SRC_XTAL; + case 1: + return FLASH_CLK_SRC_BBPLL; + case 2: + return FLASH_CLK_SRC_CPLL; + default: + HAL_ASSERT(false); + return FLASH_CLK_SRC_XTAL; + } +} + /** * Set MSPI Flash core clock * diff --git a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h index d76d5cf23de..f4c5def701d 100644 --- a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h @@ -122,6 +122,24 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode hw->hp_sys[mode].clk_power.val = xpd_flag; } +/** + * @brief Set the power and isolation of the analog i2c master shared by all the PLLs + * + * @param hw Beginning address of the peripheral registers. + * @param mode The pmu mode + * @param xpd_bb_i2c Power up the analog i2c master + * @param iso_en Isolate the analog i2c master interface + * @param retention Retain the analog i2c master registers + * + * @return None + */ +FORCE_INLINE_ATTR void pmu_ll_hp_set_ana_i2c_power(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_bb_i2c, bool iso_en, bool retention) +{ + hw->hp_sys[mode].clk_power.xpd_bb_i2c = xpd_bb_i2c; + hw->hp_sys[mode].clk_power.i2c_iso_en = iso_en; + hw->hp_sys[mode].clk_power.i2c_retention = retention; +} + FORCE_INLINE_ATTR void pmu_ll_hp_set_xtal_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_xtal) { hw->hp_sys[mode].xtal.xpd_xtal = xpd_xtal; 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 9a27820d969..4d4402c92a5 100644 --- a/components/esp_hw_support/include/esp_private/rtc_clk.h +++ b/components/esp_hw_support/include/esp_private/rtc_clk.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,7 @@ extern "C" { */ void rtc_clk_cpu_set_to_default_config(void); +#ifndef BOOTLOADER_BUILD /** * @brief Switch CPU clock source to XTAL, the PLL has different processing methods for different chips. * 1. For earlier chips without PMU, there is no PMU module that can turn off the CPU's PLL, so it has to be @@ -39,6 +40,7 @@ void rtc_clk_cpu_set_to_default_config(void); * to 40MHz to speed up the retention speed. */ void rtc_clk_cpu_freq_set_xtal_for_sleep(void); +#endif /** * @brief Notify that the BBPLL has a new in-use consumer diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index f9d16a2af72..abb6b0b2e93 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -15,7 +15,8 @@ entries: clk_utils (noflash) esp_clk_tree: esp_clk_tree_enable_src (noflash) if RTC_CLK_FUNC_IN_IRAM = y: - esp_clk_tree: esp_clk_tree_enable_power (noflash) + esp_clk_tree:esp_clk_tree_enable_power (noflash) + esp_clk_tree:esp_clk_tree_port_is_power_on (noflash) esp_clk_tree_common:esp_clk_tree_is_power_on (noflash) if SOC_CLK_MPLL_SUPPORTED = y: esp_clk_tree_common:esp_clk_tree_mpll_release (noflash) diff --git a/components/esp_hw_support/port/esp32p4/CMakeLists.txt b/components/esp_hw_support/port/esp32p4/CMakeLists.txt index a10e7cc751b..5f9c6254e30 100644 --- a/components/esp_hw_support/port/esp32p4/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32p4/CMakeLists.txt @@ -3,14 +3,14 @@ target_include_directories(${COMPONENT_LIB} PUBLIC .) set(srcs "rtc_clk_init.c" "rtc_clk.c" "pmu_param.c" - "pmu_init.c" - "pmu_sleep.c" "rtc_time.c" "chip_info.c" ) if(NOT BOOTLOADER_BUILD) - list(APPEND srcs "sar_periph_ctrl.c") + list(APPEND srcs "pmu_init.c" + "pmu_sleep.c" + "sar_periph_ctrl.c") if(CONFIG_PM_SLEEP_CLK_ICG_ENABLE AND NOT CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) list(APPEND srcs "pmu_sleep_clock_icg.c") diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index b1f3f57404c..fafd89082b4 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -30,7 +30,9 @@ ESP_HW_LOG_ATTR_TAG(TAG, "rtc_clk"); static int s_cur_cpll_freq = 0; // MPLL frequency option, 400MHz. Zero if MPLL is not enabled. +#ifndef BOOTLOADER_BUILD static SPM_DRAM_ATTR uint32_t s_cur_mpll_freq = 0; +#endif void rtc_clk_32k_enable(bool enable) { @@ -641,6 +643,7 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } +#ifndef BOOTLOADER_BUILD //------------------------------------MPLL-------------------------------------// SPM_IRAM_ATTR void rtc_clk_mpll_disable(void) { @@ -680,3 +683,4 @@ SPM_IRAM_ATTR uint32_t rtc_clk_mpll_get_freq(void) { return s_cur_mpll_freq; } +#endif diff --git a/components/esp_hw_support/port/esp32s31/CMakeLists.txt b/components/esp_hw_support/port/esp32s31/CMakeLists.txt index e732bc61ba6..a532e998522 100644 --- a/components/esp_hw_support/port/esp32s31/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s31/CMakeLists.txt @@ -5,13 +5,14 @@ set(srcs "rtc_clk.c" "rtc_time.c" "chip_info.c" - "pmu_param.c" - "pmu_init.c" - "pmu_sleep.c" ) if(NOT BOOTLOADER_BUILD) - list(APPEND srcs "sar_periph_ctrl.c") + list(APPEND srcs "sar_periph_ctrl.c" + "pmu_param.c" + "pmu_init.c" + "pmu_sleep.c" + ) endif() add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") diff --git a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c index 6387311983b..55893a72ed6 100644 --- a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c @@ -6,6 +6,7 @@ #include #include +#include "sdkconfig.h" #include "esp_clk_tree.h" #include "esp_attr.h" #include "esp_err.h" @@ -17,6 +18,7 @@ #include "hal/clk_gate_ll.h" #include "hal/clk_tree_hal.h" #include "hal/clk_tree_ll.h" +#include "hal/mspi_ll.h" #include "esp_private/esp_clk_tree_common.h" #include "esp_private/esp_clk_tree_derived.h" #include "esp_private/periph_ctrl.h" @@ -431,49 +433,45 @@ esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_f void esp_clk_tree_initialize(void) { soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); - if ((rst_reason == RESET_REASON_CPU_SW) || (rst_reason == RESET_REASON_CPU_MWDT) || - (rst_reason == RESET_REASON_CPU_RWDT) || (rst_reason == RESET_REASON_CPU_JTAG) || - (rst_reason == RESET_REASON_CPU_LOCKUP)) { - s_clk_tree_initialized = true; - return; - } - - // Cold boot only + soc_periph_flash_clk_src_t flash_clk_src = _mspi_timing_ll_get_flash_clk_src(MSPI_TIMING_LL_MSPI_ID_0); soc_cpu_clk_src_t cpu_src = clk_ll_cpu_get_src(); - if (cpu_src == SOC_CPU_CLK_SRC_PLL_F240M) { - s_mod_clk_gate_ref_cnt[SOC_MOD_CLK_PLL_F240M] = 1; - s_root_pll_power_ref_cnt[SOC_ROOT_CIRCUIT_CLK_BBPLL] = 1; - } else if (cpu_src == SOC_CPU_CLK_SRC_CPLL) { - s_root_pll_power_ref_cnt[SOC_ROOT_CIRCUIT_CLK_CPLL] = 1; + bool cpu_reset = (rst_reason == RESET_REASON_CPU_SW) || (rst_reason == RESET_REASON_CPU_MWDT) || + (rst_reason == RESET_REASON_CPU_RWDT) || (rst_reason == RESET_REASON_CPU_JTAG) || + (rst_reason == RESET_REASON_CPU_LOCKUP); + if (!cpu_reset) { + /* Cold boot only: gate / power-down clocks not in use. */ + if (cpu_src != SOC_CPU_CLK_SRC_PLL_F240M) { + _clk_gate_ll_ref_240m_clk_en(false); + } + if (cpu_src != SOC_CPU_CLK_SRC_CPLL && flash_clk_src != FLASH_CLK_SRC_CPLL) { + clk_ll_cpll_disable(); + } + _clk_gate_ll_ref_160m_clk_en(false); + _clk_gate_ll_ref_120m_clk_en(false); + _clk_gate_ll_ref_80m_clk_en(false); + _clk_gate_ll_ref_60m_clk_en(false); + _clk_gate_ll_ref_20m_clk_en(false); + _clk_gate_ll_ref_50m_clk_en(false); + _clk_gate_ll_ref_25m_clk_en(false); + clk_ll_xtalx2_disable(); + HP_ALIVE_SYS.hp_clk_ctrl.hp_audio_pll_clk_en = 0; + HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll2_clk_en = 0; + HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll1_clk_en = 0; + HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll0_clk_en = 0; } - if (cpu_src != SOC_CPU_CLK_SRC_PLL_F240M) { - _clk_gate_ll_ref_240m_clk_en(false); - // Not do clk_ll_bbpll_disable since MSPI depends on BBPLL: TODO: IDF-15889 - } - // Add ref count for Flash using. // TODO: IDF-15889 - s_root_pll_power_ref_cnt[SOC_ROOT_CIRCUIT_CLK_BBPLL]++; - - if (cpu_src != SOC_CPU_CLK_SRC_CPLL) { - clk_ll_cpll_disable(); - } - - _clk_gate_ll_ref_160m_clk_en(false); - _clk_gate_ll_ref_120m_clk_en(false); - _clk_gate_ll_ref_80m_clk_en(false); - _clk_gate_ll_ref_60m_clk_en(false); - _clk_gate_ll_ref_20m_clk_en(false); - _clk_gate_ll_ref_50m_clk_en(false); - _clk_gate_ll_ref_25m_clk_en(false); - - clk_ll_xtalx2_disable(); - - HP_ALIVE_SYS.hp_clk_ctrl.hp_audio_pll_clk_en = 0; - HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll2_clk_en = 0; - HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll1_clk_en = 0; - HP_ALIVE_SYS.hp_clk_ctrl.hp_sdio_pll0_clk_en = 0; - s_clk_tree_initialized = true; +#if CONFIG_USJ_ENABLE_USB_SERIAL_JTAG || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + /* Bootloader / USJ may keep BBPLL 480M on; declare a permanent hold. */ + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); +#endif + /* Flash + CPU: sync clk_tree refs with HW already selected at boot. */ + esp_clk_tree_enable_src((soc_module_clk_t)flash_clk_src, true); + if (cpu_src == SOC_CPU_CLK_SRC_CPLL) { + esp_clk_tree_enable_src(SOC_MOD_CLK_CPLL, true); + } else if (cpu_src == SOC_CPU_CLK_SRC_PLL_F240M) { + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F240M, true); + } } bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable) @@ -548,31 +546,33 @@ static const esp_clk_tree_gated_clk_t s_gated_ref_clks[] = { FORCE_INLINE_ATTR esp_err_t esp_clk_tree_enable_gated_clk(const esp_clk_tree_gated_clk_t *entry, bool enable) { int16_t prev_ref_cnt; + bool released_too_many = false; esp_os_enter_critical(&s_clk_tree_spinlock); if (enable) { prev_ref_cnt = s_mod_clk_gate_ref_cnt[entry->clk_id]++; + if (prev_ref_cnt == 0) { + if (entry->parent_power != NULL) { + entry->parent_power(true); + } + ENABLE_CLK_GATE(entry->set_gate, true); + } } else { prev_ref_cnt = s_mod_clk_gate_ref_cnt[entry->clk_id]--; if (prev_ref_cnt <= 0) { s_mod_clk_gate_ref_cnt[entry->clk_id] = 0; - esp_os_exit_critical(&s_clk_tree_spinlock); - ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", entry->clk_id); - return ESP_OK; + released_too_many = true; + } else if (prev_ref_cnt == 1) { + ENABLE_CLK_GATE(entry->set_gate, false); + if (entry->parent_power != NULL) { + entry->parent_power(false); + } } } esp_os_exit_critical(&s_clk_tree_spinlock); - if (prev_ref_cnt == 0 && enable) { - if (entry->parent_power != NULL) { - entry->parent_power(true); - } - ENABLE_CLK_GATE(entry->set_gate, true); - } else if (prev_ref_cnt == 1 && !enable) { - ENABLE_CLK_GATE(entry->set_gate, false); - if (entry->parent_power != NULL) { - entry->parent_power(false); - } + if (released_too_many) { + ESP_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", entry->clk_id); } return ESP_OK; } @@ -605,6 +605,12 @@ esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) esp_clk_tree_mpll_release(); return ESP_OK; } + case SOC_MOD_CLK_BBPLL: + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, enable); + return ESP_OK; + case SOC_MOD_CLK_CPLL: + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_CPLL, enable); + return ESP_OK; case SOC_MOD_CLK_RC_FAST: gated_clk_id = ESP_CLK_TREE_GATED_CLK_RC_FAST; break; case SOC_MOD_CLK_PLL_F20M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F20M; break; case SOC_MOD_CLK_PLL_F60M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F60M; break; diff --git a/components/esp_hw_support/port/esp32s31/include/soc/rtc.h b/components/esp_hw_support/port/esp32s31/include/soc/rtc.h index 44c5ee342e3..3dcefc3e484 100644 --- a/components/esp_hw_support/port/esp32s31/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32s31/include/soc/rtc.h @@ -109,7 +109,7 @@ typedef struct { .rc32k_dfreq = RTC_CNTL_RC32K_DFREQ_DEFAULT, \ .disable_apll = 1, \ .disable_mpll = 1, \ - .disable_cpll = 0, \ + .disable_cpll = 0, /* Keep CPLL: Flash (bootloader) and typical CPU freqs use it */ \ .disable_bbpll = 1, \ } @@ -233,6 +233,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou */ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config); +#ifndef BOOTLOADER_BUILD /** * @brief Switch CPU frequency (optimized for speed) * @@ -254,6 +255,7 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config); * @param config CPU frequency configuration structure */ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config); +#endif /** * @brief Get the currently used CPU frequency configuration @@ -261,17 +263,16 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config); */ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config); +#ifndef BOOTLOADER_BUILD /** * @brief Switch CPU clock source to XTAL * * Short form for filling in rtc_cpu_freq_config_t structure and calling * rtc_clk_cpu_freq_set_config when a switch to XTAL is needed. * Assumes that XTAL frequency has been determined — don't call in startup code. - * - * @note On ESP32S31, this function always disables CPLL after switching the CPU clock source to XTAL, - * since there is no peripheral relies on CPLL clock (except Flash/PSRAM if their clock source selects CPLL). */ void rtc_clk_cpu_freq_set_xtal(void); +#endif /** * @brief Get the current APB frequency. diff --git a/components/esp_hw_support/port/esp32s31/pmu_init.c b/components/esp_hw_support/port/esp32s31/pmu_init.c index 1ece660d905..d4f63ce8f41 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_init.c +++ b/components/esp_hw_support/port/esp32s31/pmu_init.c @@ -76,7 +76,13 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_pa assert(ctx->hal); /* Default configuration of hp-system power in active, modem and sleep modes */ pmu_ll_hp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val); - pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); + if (mode == PMU_MODE_HP_ACTIVE) { + // In active mode the root clock circuit power (BBPLL/CPLL/MPLL/APLL/XTALx2, etc.) is owned by esp_clk_tree. + // The analog i2c master is shared by all the PLLs and is not refcounted there, so it is still configured here. + pmu_ll_hp_set_ana_i2c_power(ctx->hal->dev, mode, power->clk_power.xpd_bb_i2c, power->clk_power.i2c_iso_en, power->clk_power.i2c_retention); + } else { + pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); + } pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal); /* Default configuration of hp-system clock in active, modem and sleep modes */ diff --git a/components/esp_hw_support/port/esp32s31/pmu_param.c b/components/esp_hw_support/port/esp32s31/pmu_param.c index 23a4f26ea96..4ee3f386689 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_param.c +++ b/components/esp_hw_support/port/esp32s31/pmu_param.c @@ -36,6 +36,7 @@ ESP_HW_LOG_ATTR_TAG(TAG, "pmu_param"); .top_pd_en = 0 \ }, \ .clk_power = { \ + .xpd_xtalx2 = 0, \ .i2c_iso_en = 0, \ .i2c_retention = 0, \ .xpd_bb_i2c = 1, \ diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk.c b/components/esp_hw_support/port/esp32s31/rtc_clk.c index 31bb1433ca5..80421b6d386 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk.c @@ -20,17 +20,24 @@ #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" #include "esp_attr.h" +#include "esp_private/esp_clk_tree_common.h" +#include "hal/clk_gate_ll.h" static const char *TAG = "rtc_clk"; -// CPLL frequency option, in 320MHz. Zero if CPLL is not enabled. +#ifndef BOOTLOADER_BUILD +// CPLL frequency option, in 320MHz. Zero if CPLL is not enabled / needs recalibration. static int s_cur_cpll_freq = 0; +// BBPLL frequency option, in 480MHz. Zero if BBPLL is not enabled / needs recalibration. +static int s_cur_bbpll_freq = 0; // MPLL frequency option, 500MHz. Zero if MPLL is not enabled. static uint32_t s_cur_mpll_freq = 0; -#if !BOOTLOADER_BUILD -// Indicate whether the specific clock sources are acquired by the hp root clock (i.e. whether ref_cnt in esp_clk_tree.c is incremented by the hp root clock) +/** + * Whether HP ROOT clock currently holds a clk_tree ref on CPLL / PLL_F240M. + * Survives DFS set_config_fast(XTAL) (keep-hot) and light-sleep (PMU restores ACTIVE XPD on wake). Cleared only on real leave via set_config/set_xtal. + */ static bool s_is_cpll_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 80 || CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 160 || CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 320); static bool s_is_pll_f240m_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 240); #endif @@ -122,19 +129,6 @@ soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void) return clk_ll_rtc_fast_get_src(); } -#if BOOTLOADER_BUILD -static void rtc_clk_cpll_disable(void) -{ - clk_ll_cpll_disable(); - s_cur_cpll_freq = 0; -} - -static void rtc_clk_cpll_enable(void) -{ - clk_ll_cpll_enable(); -} -#endif - static void rtc_clk_cpll_configure(soc_xtal_freq_t xtal_freq, int cpll_freq) { /* Digital part */ @@ -152,7 +146,9 @@ static void rtc_clk_cpll_configure(soc_xtal_freq_t xtal_freq, int cpll_freq) clk_ll_cpll_calibration_stop(); ANALOG_CLOCK_DISABLE(); +#ifndef BOOTLOADER_BUILD s_cur_cpll_freq = cpll_freq; +#endif } /** @@ -340,63 +336,69 @@ __attribute__((weak)) void rtc_clk_set_cpu_switch_to_pll(int event_id) { } -static void rtc_clk_cpu_src_clk_enable(soc_cpu_clk_src_t new_src, uint32_t new_src_freq_mhz) +static void rtc_clk_update_pll_state_on_cpu_src_switching_start(soc_cpu_clk_src_t new_src, uint32_t new_src_freq_mhz) { +#ifdef BOOTLOADER_BUILD if (new_src == SOC_CPU_CLK_SRC_CPLL) { - bool truly_enabled = false; -#if BOOTLOADER_BUILD - rtc_clk_cpll_enable(); - truly_enabled = true; + clk_ll_cpll_enable(); + rtc_clk_cpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); + } else if (new_src == SOC_CPU_CLK_SRC_PLL_F240M) { + clk_ll_bbpll_enable(); + _clk_gate_ll_ref_240m_clk_en(true); + } #else + if (new_src == SOC_CPU_CLK_SRC_CPLL) { + bool need_configure = false; if (!s_is_cpll_acquired) { - truly_enabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_CPLL, true); + need_configure = !esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_CPLL); + esp_clk_tree_enable_src(SOC_MOD_CLK_CPLL, true); s_is_cpll_acquired = true; } -#endif - if (truly_enabled || (s_cur_cpll_freq != new_src_freq_mhz)) { + if (need_configure || (s_cur_cpll_freq != (int)new_src_freq_mhz)) { rtc_clk_cpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); } } else if (new_src == SOC_CPU_CLK_SRC_PLL_F240M) { -#if BOOTLOADER_BUILD - clk_ll_bbpll_enable(); -#else if (!s_is_pll_f240m_acquired) { esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F240M, true); s_is_pll_f240m_acquired = true; } -#endif + s_cur_bbpll_freq = CLK_LL_PLL_480M_FREQ_MHZ; } +#endif } -static void rtc_clk_cpu_src_clk_disable(soc_cpu_clk_src_t old_src) +#ifndef BOOTLOADER_BUILD +static void rtc_clk_update_pll_state_on_cpu_src_switching_end(soc_cpu_clk_src_t old_src) { if (old_src == SOC_CPU_CLK_SRC_CPLL) { -#if BOOTLOADER_BUILD - rtc_clk_cpll_disable(); -#else assert(s_is_cpll_acquired); - bool truly_disabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_CPLL, false); + esp_clk_tree_enable_src(SOC_MOD_CLK_CPLL, false); s_is_cpll_acquired = false; - if (truly_disabled) { + if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_CPLL)) { s_cur_cpll_freq = 0; } -#endif } else if (old_src == SOC_CPU_CLK_SRC_PLL_F240M) { -#if BOOTLOADER_BUILD - /* Do not clk_ll_bbpll_disable(): Flash may still use BBPLL (reg_flash_clk_src_sel==1) */ -#else assert(s_is_pll_f240m_acquired); s_is_pll_f240m_acquired = false; esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F240M, false); -#endif + if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL)) { + s_cur_bbpll_freq = 0; + } } } +#endif void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) { +#ifdef BOOTLOADER_BUILD + // Always trigger clock source preparing in bootloader + bool src_changed = true; +#else soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); - if (old_cpu_clk_src != config->source) { - rtc_clk_cpu_src_clk_enable(config->source, config->source_freq_mhz); + bool src_changed = (old_cpu_clk_src != config->source); +#endif + if (src_changed) { + rtc_clk_update_pll_state_on_cpu_src_switching_start(config->source, config->source_freq_mhz); } if (config->source == SOC_CPU_CLK_SRC_XTAL) { @@ -411,9 +413,11 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) rtc_clk_cpu_freq_to_rc_fast(); } - if (old_cpu_clk_src != config->source) { - rtc_clk_cpu_src_clk_disable(old_cpu_clk_src); +#ifndef BOOTLOADER_BUILD + if (src_changed) { + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); } +#endif } static uint32_t rtc_clk_hp_root_get_freq_mhz(soc_cpu_clk_src_t clk_src) @@ -463,53 +467,6 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) }; } -void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config) -{ - if (config->source == SOC_CPU_CLK_SRC_XTAL) { - rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div.integer, false); - } else if (config->source == SOC_CPU_CLK_SRC_CPLL && - s_cur_cpll_freq == config->source_freq_mhz) { - rtc_clk_cpu_freq_to_cpll_mhz(config->freq_mhz, (hal_utils_clk_div_t *)&config->div); - } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) { - rtc_clk_cpu_freq_to_rc_fast(); - } else if (config->source == SOC_CPU_CLK_SRC_PLL_F240M -#if !BOOTLOADER_BUILD - && s_is_pll_f240m_acquired -#endif - ) { - rtc_clk_cpu_freq_to_pll_240_mhz(config->freq_mhz); - } else { - /* fallback */ - rtc_clk_cpu_freq_set_config(config); - } -} - -void rtc_clk_cpu_freq_set_xtal(void) -{ - soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); - int freq_mhz = (int)rtc_clk_xtal_freq_get(); - - rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); - if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) { - rtc_clk_cpu_src_clk_disable(old_cpu_clk_src); - } -} - -FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) -{ - int freq_mhz = (int)rtc_clk_xtal_freq_get(); - - rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, true); -} - -void rtc_clk_cpu_freq_set_xtal_for_sleep(void) -{ - int freq_mhz = (int)rtc_clk_xtal_freq_get(); - - rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); - s_cur_cpll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep -} - FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_get_freq_mhz(); @@ -532,6 +489,54 @@ uint32_t rtc_clk_apb_freq_get(void) return sys_freq_hz / clk_ll_apb_get_divider(); } +#ifndef BOOTLOADER_BUILD +void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config) +{ + /* Mux only — Fall back to set_config when PLL must be reacquired or recalibrated (s_cur_* == 0 after sleep). */ + if (config->source == SOC_CPU_CLK_SRC_XTAL) { + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div.integer, false); + } else if (config->source == SOC_CPU_CLK_SRC_CPLL && + s_cur_cpll_freq == (int)config->source_freq_mhz) { + rtc_clk_cpu_freq_to_cpll_mhz(config->freq_mhz, (hal_utils_clk_div_t *)&config->div); + } else if (config->source == SOC_CPU_CLK_SRC_PLL_F240M && + s_is_pll_f240m_acquired && + s_cur_bbpll_freq == CLK_LL_PLL_480M_FREQ_MHZ) { + rtc_clk_cpu_freq_to_pll_240_mhz(config->freq_mhz); + } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) { + rtc_clk_cpu_freq_to_rc_fast(); + } else { + /* fallback */ + rtc_clk_cpu_freq_set_config(config); + } +} + +void rtc_clk_cpu_freq_set_xtal(void) +{ + soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); + int freq_mhz = (int)rtc_clk_xtal_freq_get(); + + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); +} + +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) +{ + int freq_mhz = (int)rtc_clk_xtal_freq_get(); + + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, true); +} + +void rtc_clk_cpu_freq_set_xtal_for_sleep(void) +{ + int freq_mhz = (int)rtc_clk_xtal_freq_get(); + + /* Mux only — do not release CPU clk_tree hold. PMU restores ACTIVE XPD on + * wake; clearing s_cur_* forces recalibration via set_config fallback. */ + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); + s_cur_cpll_freq = 0; + s_cur_bbpll_freq = 0; +} + void rtc_clk_apll_enable(bool enable) { if (enable) { @@ -672,3 +677,4 @@ IRAM_ATTR uint32_t rtc_clk_mpll_get_freq(void) { return s_cur_mpll_freq; } +#endif