From f9428ecc1e28d10043f05a8077d899373aa6b09d Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 6 Jul 2026 17:01:31 +0800 Subject: [PATCH 1/8] feat(esp_hw_support): support esp32s31 clock tree management --- components/esp_adc/linker.lf | 2 + .../esp32s31/include/hal/clk_gate_ll.h | 39 ++ .../esp32s31/include/hal/clk_tree_ll.h | 73 +++ .../esp32s31/include/hal/gpio_ll.h | 2 +- .../include/esp_private/esp_clk_tree_common.h | 7 + .../esp_private/esp_clk_tree_derived.h | 4 +- components/esp_hw_support/linker.lf | 13 +- .../esp_hw_support/port/esp32/esp_clk_tree.c | 2 +- .../port/esp32c2/esp_clk_tree.c | 2 +- .../port/esp32c3/esp_clk_tree.c | 2 +- .../port/esp32c5/esp_clk_tree.c | 2 +- .../port/esp32c6/esp_clk_tree.c | 2 +- .../port/esp32c61/esp_clk_tree.c | 2 +- .../port/esp32h2/esp_clk_tree.c | 2 +- .../port/esp32h21/esp_clk_tree.c | 10 +- .../port/esp32h4/esp_clk_tree.c | 10 +- .../port/esp32p4/esp_clk_tree.c | 179 ++++-- .../port/esp32s2/esp_clk_tree.c | 2 +- .../port/esp32s3/esp_clk_tree.c | 2 +- .../port/esp32s31/esp_clk_tree.c | 560 ++++++++++++++---- .../esp_hw_support/port/esp32s31/rtc_clk.c | 8 +- .../esp_hw_support/port/esp_clk_tree_common.c | 88 ++- .../soc/esp32s31/include/soc/clk_tree_defs.h | 9 +- 23 files changed, 795 insertions(+), 227 deletions(-) diff --git a/components/esp_adc/linker.lf b/components/esp_adc/linker.lf index e3c1ea4ee25..c189a1f9bbb 100644 --- a/components/esp_adc/linker.lf +++ b/components/esp_adc/linker.lf @@ -9,6 +9,8 @@ archive: libesp_hw_support.a entries: if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y: esp_clk_tree: esp_clk_tree_enable_src (noflash) + if IDF_TARGET_ESP32P4 || IDF_TARGET_ESP32S31 = y: + esp_clk_tree: s_gated_ref_clks (noflash) [mapping:adc_hal] archive: libesp_hal_ana_conv.a diff --git a/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h index 9c0c219e399..c37fa64fa20 100644 --- a/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h @@ -256,6 +256,19 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_50m_clk_en(bool enable) _clk_gate_ll_ref_50m_clk_en(__VA_ARGS__); \ } while(0) +/** + * Enable or disable the clock gate for ref_60m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_60m_clk_en(bool enable) +{ + HP_SYS_CLKRST.ref_60m_ctrl0.reg_ref_60m_clk_en = enable; +} +#define clk_gate_ll_ref_60m_clk_en(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _clk_gate_ll_ref_60m_clk_en(__VA_ARGS__); \ + } while (0) + /** * Enable or disable the clock gate for ref_80m (derived from BBPLL). * @param enable Enable / disable @@ -271,6 +284,32 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_80m_clk_en(bool enable) _clk_gate_ll_ref_80m_clk_en(__VA_ARGS__); \ } while(0) +/** + * Enable or disable the ref_80m mux clock gate. + * @param en 0: disable 1: enable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_80m_mux_clk_en(bool en) +{ + HP_SYS_CLKRST.ref_80m_ctrl0.reg_ref_80m_mux_clk_en = en; +} +#define clk_gate_ll_ref_80m_mux_clk_en(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _clk_gate_ll_ref_80m_mux_clk_en(__VA_ARGS__); \ + } while (0) + +/** + * Enable or disable the clock gate for ref_120m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_120m_clk_en(bool enable) +{ + HP_SYS_CLKRST.ref_120m_ctrl0.reg_ref_120m_clk_en = enable; +} +#define clk_gate_ll_ref_120m_clk_en(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _clk_gate_ll_ref_120m_clk_en(__VA_ARGS__); \ + } while (0) + /** * Enable or disable the clock gate for ref_160m (derived from BBPLL). * @param enable Enable / disable 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 c672a308cea..7e386382b70 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 @@ -29,7 +29,9 @@ #define CLK_LL_PLL_8M_FREQ_MHZ (8) +#define CLK_LL_PLL_60M_FREQ_MHZ (60) #define CLK_LL_PLL_80M_FREQ_MHZ (80) +#define CLK_LL_PLL_120M_FREQ_MHZ (120) #define CLK_LL_PLL_160M_FREQ_MHZ (160) #define CLK_LL_PLL_240M_FREQ_MHZ (240) #define CLK_LL_PLL_320M_FREQ_MHZ (320) @@ -105,6 +107,47 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_disable(void) CLEAR_PERI_REG_MASK(HP_ALIVE_SYS_HP_CLK_CTRL_REG, HP_ALIVE_SYS_HP_CPLL_300M_CLK_EN); } +/** + * @brief Power up XTALX2 circuit + */ +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); +} + +/** + * @brief Power down XTALX2 circuit + */ +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); +} + +/** + * @brief Get ref_80m clock source mux selection + * + * @return false: BBPLL divided path, true: XTALx2 80MHz (`clk_xtalx2_80m`) + */ +static inline __attribute__((always_inline)) bool clk_ll_ref_80m_get_src(void) +{ + return (bool)HP_SYS_CLKRST.ref_80m_ctrl0.reg_ref_80m_sel; +} + +/** + * @brief Select REF_80M_CLK source + * + * @param in_sel 0 selects BBPLL divided 80MHz, 1 selects XTALx2 80MHz. + */ +static inline __attribute__((always_inline)) void clk_ll_ref_80m_set_src(uint8_t in_sel) +{ + HAL_ASSERT(in_sel == 0 || in_sel == 1); + HP_SYS_CLKRST.ref_80m_ctrl0.reg_ref_80m_sel = in_sel; +} + /** * @brief Power up BBPLL circuit */ @@ -722,6 +765,16 @@ static inline __attribute__((always_inline)) void clk_ll_ref_500m_set_src(uint8_ HP_SYS_CLKRST.ref_500m_ctrl0.reg_ref_500m_sel = in_sel; } +/** + * @brief Get ref_500m clock source mux selection + * + * @return false: CPLL (320MHz), true: MPLL (500MHz) + */ +static inline __attribute__((always_inline)) bool clk_ll_ref_500m_get_src(void) +{ + return (bool)HP_SYS_CLKRST.ref_500m_ctrl0.reg_ref_500m_sel; +} + /** * @brief Set PLL_F50M_CLK divider. freq of PLL_F50M_CLK = freq of MPLL_CLK / divider * @@ -765,6 +818,26 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_pll_f20m_get_divide return HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.ref_20m_ctrl0, reg_ref_20m_clk_div_num) + 1; } +/** + * @brief Get PLL_F50M_CLK divider + * + * @return Divider. Divider = (CLK_DIV_NUM + 1). + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_pll_f50m_get_divider(void) +{ + return HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.ref_50m_ctrl0, reg_ref_50m_clk_div_num) + 1; +} + +/** + * @brief Get PLL_F25M_CLK divider + * + * @return Divider. Divider = (CLK_DIV_NUM + 1). + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_pll_f25m_get_divider(void) +{ + return HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.ref_25m_ctrl0, reg_ref_25m_clk_div_num) + 1; +} + /** * @brief Select the frequency calculation clock source for timergroup0 * diff --git a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h index cad4bdeffe5..d151fa5f0ae 100644 --- a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h @@ -712,7 +712,7 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) case SOC_MOD_CLK_XTAL: HP_SYS_CLKRST.iomux_ctrl0.reg_iomux_clk_src_sel = 0; break; - case SOC_MOD_CLK_PLL_F80M: + case SOC_MOD_CLK_REF_F80M: HP_SYS_CLKRST.iomux_ctrl0.reg_iomux_clk_src_sel = 1; break; default: diff --git a/components/esp_hw_support/include/esp_private/esp_clk_tree_common.h b/components/esp_hw_support/include/esp_private/esp_clk_tree_common.h index c7b2a724341..f555b0ba801 100644 --- a/components/esp_hw_support/include/esp_private/esp_clk_tree_common.h +++ b/components/esp_hw_support/include/esp_private/esp_clk_tree_common.h @@ -124,6 +124,13 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable); */ bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit); +/** + * @brief Chip-specific root clock circuit power status (port/esp_clk_tree.c per target). + * + * Handles all soc_root_clk_circuit_t values except MPLL/APLL (those are in esp_clk_tree_common.c). + */ +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit); + #if SOC_CLK_APLL_SUPPORTED /** * @brief Enable APLL power if it has not enabled diff --git a/components/esp_hw_support/include/esp_private/esp_clk_tree_derived.h b/components/esp_hw_support/include/esp_private/esp_clk_tree_derived.h index b95db4df21f..63276638644 100644 --- a/components/esp_hw_support/include/esp_private/esp_clk_tree_derived.h +++ b/components/esp_hw_support/include/esp_private/esp_clk_tree_derived.h @@ -60,11 +60,13 @@ typedef struct { typedef struct { soc_module_clk_t clk_id; /*!< Module clock id this descriptor belongs to */ void (*set_src)(uint8_t mux_sel); /*!< Optional: program the upstream PLL mux. NULL when the clock has no mux (e.g. ESP32-P4 PLL_F50M is fixed to MPLL). */ - void (*set_divider)(uint32_t divider); /*!< Required: program the divider register (divider value, not the raw "div_num - 1" form). */ + void (*set_divider)(uint32_t divider); /*!< Optional: program the divider register (divider value, not div_num - 1). NULL when HW divider is fixed. */ void (*set_gate)(bool enable); /*!< Required: enable/disable the clock gate. */ const esp_clk_tree_derived_upstream_t *upstreams; /*!< Required: candidate upstream PLLs in preference order (used by both auto-pick and explicit-upstream paths). */ size_t upstream_count; /*!< Required: number of entries in `upstreams[]`. */ esp_clk_tree_derived_clk_state_t *state; /*!< Required: pointer to a statically-allocated mutable state slot owned by the target. Engine reads/writes ref_cnt / cur_upstream / cur_divider through this pointer. */ + esp_err_t (*acquire_parent)(void); /*!< Optional: power upstream (first acquire or after mux/div commit). Called with s_derived_clk_spinlock held.*/ + esp_err_t (*release_parent)(void); /*!< Optional: release upstream on last release. Called with s_derived_clk_spinlock held.*/ } esp_clk_tree_derived_clk_desc_t; /** diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index 663410aad69..28eb74ad292 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -13,12 +13,15 @@ entries: cpu: esp_cpu_compare_and_set (noflash) esp_memory_utils (noflash) clk_utils (noflash) - # TODO: PM-630 - if IDF_TARGET_ESP32S31 != y: - esp_clk_tree: esp_clk_tree_enable_src (noflash) - esp_clk_tree: esp_clk_tree_enable_power (noflash) - esp_clk_tree: esp_clk_tree_is_power_on (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_common:esp_clk_tree_is_power_on (noflash) + if SOC_CLK_MPLL_SUPPORTED = y: + esp_clk_tree_common:esp_clk_tree_mpll_release (noflash) + if SOC_CLK_APLL_SUPPORTED = y: + esp_clk_tree_common:esp_clk_tree_apll_acquire (noflash) + esp_clk_tree_common:esp_clk_tree_apll_release (noflash) rtc_clk (noflash) if IDF_TARGET_ESP32 = y: rtc_clk:rtc_clk_cpu_freq_to_pll_mhz (noflash) diff --git a/components/esp_hw_support/port/esp32/esp_clk_tree.c b/components/esp_hw_support/port/esp32/esp_clk_tree.c index 73eec5531e0..5bbdbee70f1 100644 --- a/components/esp_hw_support/port/esp32/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32/esp_clk_tree.c @@ -99,7 +99,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32c2/esp_clk_tree.c b/components/esp_hw_support/port/esp32c2/esp_clk_tree.c index d6919477c02..d1193434511 100644 --- a/components/esp_hw_support/port/esp32c2/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c2/esp_clk_tree.c @@ -79,7 +79,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32c3/esp_clk_tree.c b/components/esp_hw_support/port/esp32c3/esp_clk_tree.c index 66e8d506f82..96db21dea84 100644 --- a/components/esp_hw_support/port/esp32c3/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c3/esp_clk_tree.c @@ -79,7 +79,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32c5/esp_clk_tree.c b/components/esp_hw_support/port/esp32c5/esp_clk_tree.c index 8d602463923..83aba77a904 100644 --- a/components/esp_hw_support/port/esp32c5/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c5/esp_clk_tree.c @@ -112,7 +112,7 @@ void esp_clk_tree_initialize(void) esp_clk_tree_initialized = true; } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32c6/esp_clk_tree.c b/components/esp_hw_support/port/esp32c6/esp_clk_tree.c index 4aa62f33762..d4edaf63742 100644 --- a/components/esp_hw_support/port/esp32c6/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c6/esp_clk_tree.c @@ -79,7 +79,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32c61/esp_clk_tree.c b/components/esp_hw_support/port/esp32c61/esp_clk_tree.c index a2f9f86f430..01a6ae4d324 100644 --- a/components/esp_hw_support/port/esp32c61/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c61/esp_clk_tree.c @@ -79,7 +79,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32h2/esp_clk_tree.c b/components/esp_hw_support/port/esp32h2/esp_clk_tree.c index dd3a800d919..74e372b0811 100644 --- a/components/esp_hw_support/port/esp32h2/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32h2/esp_clk_tree.c @@ -76,7 +76,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32h21/esp_clk_tree.c b/components/esp_hw_support/port/esp32h21/esp_clk_tree.c index 3e4fe553c07..b06f0bb66db 100644 --- a/components/esp_hw_support/port/esp32h21/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32h21/esp_clk_tree.c @@ -90,15 +90,13 @@ void esp_clk_tree_initialize(void) // PLL_F64M ++ for MSPI } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { - switch (clk_circuit) { - case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2) { return s_xtal_x2_ref_cnt > 0; - case SOC_ROOT_CIRCUIT_CLK_BBPLL: + } + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL) { return s_bbpll_ref_cnt > 0; - default: - break; } return false; } diff --git a/components/esp_hw_support/port/esp32h4/esp_clk_tree.c b/components/esp_hw_support/port/esp32h4/esp_clk_tree.c index 638531c833f..c58a183f8b6 100644 --- a/components/esp_hw_support/port/esp32h4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32h4/esp_clk_tree.c @@ -92,15 +92,13 @@ void esp_clk_tree_initialize(void) // PLL_F64M ++ for MSPI } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { - switch (clk_circuit) { - case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2) { return s_xtal_x2_ref_cnt > 0; - case SOC_ROOT_CIRCUIT_CLK_BBPLL: + } + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL) { return s_bbpll_ref_cnt > 0; - default: - break; } return false; } diff --git a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c index e28ba8dc422..0fc482d081b 100644 --- a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c @@ -5,9 +5,9 @@ */ #include -#include #include "sdkconfig.h" #include "esp_clk_tree.h" +#include "esp_attr.h" #include "esp_err.h" #include "esp_check.h" #include "esp_log.h" @@ -21,6 +21,7 @@ #include "esp_private/esp_clk_tree_common.h" #include "esp_private/esp_clk_tree_derived.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/critical_section.h" ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree"); @@ -166,8 +167,12 @@ esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_f return ret; } -static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; -static bool esp_clk_tree_initialized = false; +DEFINE_CRIT_SECTION_LOCK_STATIC(s_clk_tree_spinlock); + +/** Per soc_module_clk_t: record clock gate consumers */ +static int16_t s_mod_clk_gate_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; + +static bool s_clk_tree_initialized = false; void esp_clk_tree_initialize(void) { @@ -175,7 +180,7 @@ void esp_clk_tree_initialize(void) 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)) { - esp_clk_tree_initialized = true; + s_clk_tree_initialized = true; return; } @@ -189,10 +194,10 @@ void esp_clk_tree_initialize(void) _clk_gate_ll_ref_160m_clk_en(false); #endif _clk_gate_ll_ref_240m_clk_en(false); - esp_clk_tree_initialized = true; + s_clk_tree_initialized = true; } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; @@ -204,77 +209,129 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable) return false; // TODO: PM-653 } -#define ENABLE_CLK_GATE(clk_src_en_func, enable) \ - PERIPH_RCC_ATOMIC() { \ - clk_src_en_func(enable); \ +/* -------------------------------------------------------------------------- */ +/* Fixed ref clocks: gate only (no parent power management on ESP32-P4) */ +/* -------------------------------------------------------------------------- */ + +typedef void (*esp_clk_tree_gate_fn_t)(bool enable); + +typedef struct { + soc_module_clk_t clk_id; + esp_clk_tree_gate_fn_t set_gate; +} esp_clk_tree_gated_clk_t; + +static void esp_clk_tree_gate_rc_fast(bool enable) +{ + if (enable) { + rtc_dig_clk8m_enable(); + } else { + rtc_dig_clk8m_disable(); } +} + +typedef enum { + ESP_CLK_TREE_GATED_CLK_RC_FAST, + ESP_CLK_TREE_GATED_CLK_PLL_F20M, + ESP_CLK_TREE_GATED_CLK_PLL_F25M, + ESP_CLK_TREE_GATED_CLK_PLL_F80M, + ESP_CLK_TREE_GATED_CLK_PLL_F120M, + ESP_CLK_TREE_GATED_CLK_PLL_F160M, + ESP_CLK_TREE_GATED_CLK_PLL_F240M, + ESP_CLK_TREE_GATED_CLK_NUM, +} esp_clk_tree_gated_clk_id_t; + +static const esp_clk_tree_gated_clk_t s_gated_ref_clks[] = { + [ESP_CLK_TREE_GATED_CLK_RC_FAST] = { SOC_MOD_CLK_RC_FAST, esp_clk_tree_gate_rc_fast }, + [ESP_CLK_TREE_GATED_CLK_PLL_F20M] = { SOC_MOD_CLK_PLL_F20M, _clk_gate_ll_ref_20m_clk_en }, + [ESP_CLK_TREE_GATED_CLK_PLL_F25M] = { SOC_MOD_CLK_PLL_F25M, _clk_gate_ll_ref_25m_clk_en }, + [ESP_CLK_TREE_GATED_CLK_PLL_F80M] = { SOC_MOD_CLK_PLL_F80M, _clk_gate_ll_ref_80m_clk_en }, + [ESP_CLK_TREE_GATED_CLK_PLL_F120M] = { SOC_MOD_CLK_PLL_F120M, _clk_gate_ll_ref_120m_clk_en }, + [ESP_CLK_TREE_GATED_CLK_PLL_F160M] = { SOC_MOD_CLK_PLL_F160M, _clk_gate_ll_ref_160m_clk_en }, + [ESP_CLK_TREE_GATED_CLK_PLL_F240M] = { SOC_MOD_CLK_PLL_F240M, _clk_gate_ll_ref_240m_clk_en }, +}; + +#define ENABLE_CLK_GATE(clk_src_en_func, enable) \ + do { \ + if ((clk_src_en_func) != NULL) { \ + PERIPH_RCC_ATOMIC() { \ + (clk_src_en_func)(enable); \ + }; \ + } \ + } while (0) + +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; + + esp_os_enter_critical(&s_clk_tree_spinlock); + if (enable) { + prev_ref_cnt = s_mod_clk_gate_ref_cnt[entry->clk_id]++; + } 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; + } + } + esp_os_exit_critical(&s_clk_tree_spinlock); + + if (prev_ref_cnt == 0 && enable) { + ENABLE_CLK_GATE(entry->set_gate, true); + } else if (prev_ref_cnt == 1 && !enable) { + ENABLE_CLK_GATE(entry->set_gate, false); + } + return ESP_OK; +} esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) { - if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) { - // some conditions is legal, e.g. -1 means external clock source + if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID || clk_src == SOC_MOD_CLK_XTAL) { + /* Not managed by esp_clk_tree */ return ESP_OK; } - if (!esp_clk_tree_initialized) { + if (!s_clk_tree_initialized) { return ESP_OK; } - // Derived PLL clocks (PLL_F50M, ...) that participate in the shared - // refcount/lock engine route through that engine instead of the - // global s_pll_src_cg_ref_cnt array below. - if (esp_clk_tree_get_derived_clk_desc(clk_src) != NULL) { - return enable ? esp_clk_tree_derived_clk_acquire(clk_src) - : esp_clk_tree_derived_clk_release(clk_src); - } - + esp_clk_tree_gated_clk_id_t gated_clk_id; // these clock sources have their own reference counting switch (clk_src) { - case SOC_MOD_CLK_APLL: - if (enable) { - esp_clk_tree_apll_acquire(); - } else { - esp_clk_tree_apll_release(); - } - return ESP_OK; - case SOC_MOD_CLK_MPLL: - if (enable) { - return esp_clk_tree_mpll_acquire(); - } else { - esp_clk_tree_mpll_release(); - } - return ESP_OK; - default: - break; - } - - // other clock sources use the global reference counting - int16_t prev_ref_cnt = 0; - if (enable) { - prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1); - } else { - prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1); - if (prev_ref_cnt <= 0) { - ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src); - atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0); + case SOC_MOD_CLK_APLL: + if (enable) { + esp_clk_tree_apll_acquire(); + } else { + esp_clk_tree_apll_release(); + } + return ESP_OK; + case SOC_MOD_CLK_MPLL: + if (enable) { + return esp_clk_tree_mpll_acquire(); + } else { + esp_clk_tree_mpll_release(); return ESP_OK; } - } - if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) { - switch (clk_src) { - case SOC_MOD_CLK_RC_FAST: enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable(); break; - case SOC_MOD_CLK_PLL_F20M: ENABLE_CLK_GATE(clk_gate_ll_ref_20m_clk_en, enable); break; - case SOC_MOD_CLK_PLL_F25M: ENABLE_CLK_GATE(clk_gate_ll_ref_25m_clk_en, enable); break; - case SOC_MOD_CLK_PLL_F80M: ENABLE_CLK_GATE(clk_gate_ll_ref_80m_clk_en, enable); break; - case SOC_MOD_CLK_PLL_F120M: ENABLE_CLK_GATE(clk_gate_ll_ref_120m_clk_en, enable); break; + 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_F25M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F25M; break; + case SOC_MOD_CLK_PLL_F80M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F80M; break; + case SOC_MOD_CLK_PLL_F120M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F120M; break; #if !CONFIG_ESP_ENABLE_PVT - // PLL_F160M must always on if PVT is enabled. - case SOC_MOD_CLK_PLL_F160M: ENABLE_CLK_GATE(clk_gate_ll_ref_160m_clk_en, enable); break; + // PLL_F160M must always on if PVT is enabled. + case SOC_MOD_CLK_PLL_F160M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F160M; break; #endif - case SOC_MOD_CLK_PLL_F240M: ENABLE_CLK_GATE(clk_gate_ll_ref_240m_clk_en, enable); break; - default: break; + case SOC_MOD_CLK_PLL_F240M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F240M; break; + default: + // Derived PLL clocks (PLL_F50M, ...) that participate in the shared + // refcount/lock engine route through that engine instead of the + // global s_pll_src_cg_ref_cnt array below. + if (esp_clk_tree_get_derived_clk_desc(clk_src) != NULL) { + return enable ? esp_clk_tree_derived_clk_acquire(clk_src) + : esp_clk_tree_derived_clk_release(clk_src); } + return ESP_OK; } - - return ESP_OK; + return esp_clk_tree_enable_gated_clk(&s_gated_ref_clks[gated_clk_id], enable); } diff --git a/components/esp_hw_support/port/esp32s2/esp_clk_tree.c b/components/esp_hw_support/port/esp32s2/esp_clk_tree.c index 6bb4ec4f122..a6633e5e6da 100644 --- a/components/esp_hw_support/port/esp32s2/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s2/esp_clk_tree.c @@ -97,7 +97,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; diff --git a/components/esp_hw_support/port/esp32s3/esp_clk_tree.c b/components/esp_hw_support/port/esp32s3/esp_clk_tree.c index efe7430ea6c..c756d99e6d8 100644 --- a/components/esp_hw_support/port/esp32s3/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s3/esp_clk_tree.c @@ -89,7 +89,7 @@ void esp_clk_tree_initialize(void) { } -bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { (void)clk_circuit; return false; 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 fb95c7c93e9..6387311983b 100644 --- a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c @@ -5,59 +5,316 @@ */ #include -#include -#include "sdkconfig.h" +#include #include "esp_clk_tree.h" +#include "esp_attr.h" #include "esp_err.h" #include "esp_check.h" #include "esp_log.h" -#include "soc/clk_tree_defs.h" +#include "esp_rom_sys.h" #include "soc/rtc.h" #include "soc/reset_reasons.h" -#include "soc/soc_caps.h" #include "hal/clk_gate_ll.h" #include "hal/clk_tree_hal.h" #include "hal/clk_tree_ll.h" #include "esp_private/esp_clk_tree_common.h" #include "esp_private/esp_clk_tree_derived.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/critical_section.h" ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree"); +/* -------------------------------------------------------------------------- */ +/* Derived clocks: configurable divider and/or upstream mux + multi-user lock */ +/* -------------------------------------------------------------------------- */ + +enum { + ESP_CLK_TREE_DERIVED_PLL_F25M = 0, + ESP_CLK_TREE_DERIVED_PLL_F50M, + ESP_CLK_TREE_DERIVED_REF_F80M, + ESP_CLK_TREE_DERIVED_PLL_NUM, +}; + +static esp_clk_tree_derived_clk_state_t s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_NUM]; + +static int8_t s_ref_500m_committed_mux = -1; + +/** + * Power ref_25m/ref_50m shared upstream (ref_500m_sel: 0 = CPLL, 1 = MPLL). + * @param mux_sel 0 or 1; values < 0 are ignored. + */ +static esp_err_t esp_clk_tree_ref_500m_parent_power(int8_t mux_sel, bool enable) +{ + if (mux_sel < 0) { + return ESP_OK; + } + if (mux_sel == 0) { + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_CPLL, enable); + return ESP_OK; + } + if (enable) { + return esp_clk_tree_mpll_acquire(); + } + esp_clk_tree_mpll_release(); + return ESP_OK; +} + +/** + * Shared ref_500m_sel: PLL_F25M and PLL_F50M must use the same upstream when both are on. + */ +static void esp_clk_tree_ref_500m_set_src(uint8_t mux_sel) +{ + if (s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F25M].ref_cnt > 0 + && s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F50M].ref_cnt > 0 + && s_ref_500m_committed_mux >= 0) { + assert(mux_sel == (uint8_t)s_ref_500m_committed_mux); + } + clk_ll_ref_500m_set_src(mux_sel); +} + +static esp_err_t esp_clk_tree_ref_500m_derived_acquire_parent(void) +{ + int8_t mux = (int8_t)clk_ll_ref_500m_get_src(); + if (mux == s_ref_500m_committed_mux) { + return ESP_OK; + } + if (s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F25M].ref_cnt > 0 + && s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F50M].ref_cnt > 0 + && s_ref_500m_committed_mux >= 0) { + assert(mux == s_ref_500m_committed_mux); + } + esp_clk_tree_ref_500m_parent_power(s_ref_500m_committed_mux, false); + esp_err_t ret = esp_clk_tree_ref_500m_parent_power(mux, true); + if (ret != ESP_OK) { + esp_clk_tree_ref_500m_parent_power(s_ref_500m_committed_mux, true); + return ret; + } + s_ref_500m_committed_mux = mux; + return ESP_OK; +} + +static esp_err_t esp_clk_tree_ref_500m_derived_release_parent(void) +{ + if (s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F25M].ref_cnt > 0 + || s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F50M].ref_cnt > 0) { + return ESP_OK; + } + esp_clk_tree_ref_500m_parent_power(s_ref_500m_committed_mux, false); + s_ref_500m_committed_mux = -1; + return ESP_OK; +} + +/** F80M parent path committed at first enable: 0 = BBPLL, 1 = XTALx2 (-1 = none). */ +static int8_t s_ref_80m_committed_sel = -1; + +/** + * REF_F80M enable-time source policy: + * 1) If BBPLL is already on → BBPLL/6 path + one more BBPLL power user. + * 2) Else → power XTALx2 and select ref_80m via clk_ll_ref_80m_set_src(1). + */ +static esp_err_t esp_clk_tree_ref_80m_derived_acquire_parent(void) +{ + if (s_ref_80m_committed_sel >= 0) { + return ESP_OK; + } + + _clk_gate_ll_ref_80m_mux_clk_en(true); + if (esp_clk_tree_port_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL)) { + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, true); + clk_ll_ref_80m_set_src(0); + s_ref_80m_committed_sel = 0; + } else { + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, true); + clk_ll_ref_80m_set_src(1); + s_ref_80m_committed_sel = 1; + } + return ESP_OK; +} + +static esp_err_t esp_clk_tree_ref_80m_derived_release_parent(void) +{ + if (s_derived_pll_states[ESP_CLK_TREE_DERIVED_REF_F80M].ref_cnt > 0) { + return ESP_OK; + } + if (s_ref_80m_committed_sel == 0) { + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, false); + } else if (s_ref_80m_committed_sel == 1) { + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, false); + } + _clk_gate_ll_ref_80m_mux_clk_en(false); + s_ref_80m_committed_sel = -1; + return ESP_OK; +} + // Allowed upstreams for PLL_F50M, in preference order (used by both auto-pick // and explicit-upstream paths). Mux selectors match the HP_SYS_CLKRST -// `reg_ref_500m_sel` field: 0 = CPLL, 1 = MPLL. -static const esp_clk_tree_derived_upstream_t s_pll_f50m_upstreams[] = { +// `reg_ref_500m_sel` field: 0 = CPLL, 1 = MPLL. (shared by PLL_F25M and PLL_F50M). +static const esp_clk_tree_derived_upstream_t s_ref_500m_upstreams[] = { { SOC_MOD_CLK_CPLL, 0 }, { SOC_MOD_CLK_MPLL, 1 }, }; -static esp_clk_tree_derived_clk_state_t s_pll_f50m_state = { - .ref_cnt = 0, - .cur_upstream = SOC_MOD_CLK_INVALID, - .cur_divider = 0, -}; - -static const esp_clk_tree_derived_clk_desc_t s_pll_f50m_desc = { - .clk_id = SOC_MOD_CLK_PLL_F50M, - .set_src = clk_ll_ref_500m_set_src, - .set_divider = clk_ll_pll_f50m_set_divider, - .set_gate = _clk_gate_ll_ref_50m_clk_en, // using RCC_ATOMIC lock free function version to avoid nesting critical sections - .upstreams = s_pll_f50m_upstreams, - .upstream_count = sizeof(s_pll_f50m_upstreams) / sizeof(s_pll_f50m_upstreams[0]), - .state = &s_pll_f50m_state, +static const esp_clk_tree_derived_clk_desc_t s_derived_pll_descs[ESP_CLK_TREE_DERIVED_PLL_NUM] = { + [ESP_CLK_TREE_DERIVED_PLL_F25M] = { + .clk_id = SOC_MOD_CLK_PLL_F25M, + .set_src = esp_clk_tree_ref_500m_set_src, + .set_divider = clk_ll_pll_f25m_set_divider, + .set_gate = _clk_gate_ll_ref_25m_clk_en, + .upstreams = s_ref_500m_upstreams, + .upstream_count = sizeof(s_ref_500m_upstreams) / sizeof(s_ref_500m_upstreams[0]), + .state = &s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F25M], + .acquire_parent = esp_clk_tree_ref_500m_derived_acquire_parent, + .release_parent = esp_clk_tree_ref_500m_derived_release_parent, + }, + [ESP_CLK_TREE_DERIVED_PLL_F50M] = { + .clk_id = SOC_MOD_CLK_PLL_F50M, + .set_src = esp_clk_tree_ref_500m_set_src, + .set_divider = clk_ll_pll_f50m_set_divider, + .set_gate = _clk_gate_ll_ref_50m_clk_en, + .upstreams = s_ref_500m_upstreams, + .upstream_count = sizeof(s_ref_500m_upstreams) / sizeof(s_ref_500m_upstreams[0]), + .state = &s_derived_pll_states[ESP_CLK_TREE_DERIVED_PLL_F50M], + .acquire_parent = esp_clk_tree_ref_500m_derived_acquire_parent, + .release_parent = esp_clk_tree_ref_500m_derived_release_parent, + }, + [ESP_CLK_TREE_DERIVED_REF_F80M] = { + .clk_id = SOC_MOD_CLK_REF_F80M, + .set_src = NULL, + .set_divider = NULL, + .set_gate = _clk_gate_ll_ref_80m_clk_en, + .upstreams = NULL, + .upstream_count = 0, + .state = &s_derived_pll_states[ESP_CLK_TREE_DERIVED_REF_F80M], + .acquire_parent = esp_clk_tree_ref_80m_derived_acquire_parent, + .release_parent = esp_clk_tree_ref_80m_derived_release_parent, + }, }; const esp_clk_tree_derived_clk_desc_t *esp_clk_tree_get_derived_clk_desc(soc_module_clk_t clk_src) { switch (clk_src) { + case SOC_MOD_CLK_PLL_F25M: + return &s_derived_pll_descs[ESP_CLK_TREE_DERIVED_PLL_F25M]; case SOC_MOD_CLK_PLL_F50M: - return &s_pll_f50m_desc; + return &s_derived_pll_descs[ESP_CLK_TREE_DERIVED_PLL_F50M]; + case SOC_MOD_CLK_REF_F80M: + return &s_derived_pll_descs[ESP_CLK_TREE_DERIVED_REF_F80M]; default: return NULL; } } +/* -------------------------------------------------------------------------- */ +/* Fixed ref clocks: gate + static BBPLL parent only */ +/* -------------------------------------------------------------------------- */ + +typedef void (*esp_clk_tree_gate_fn_t)(bool enable); +typedef void (*esp_clk_tree_parent_fn_t)(bool enable); + +typedef struct { + soc_module_clk_t clk_id; + esp_clk_tree_gate_fn_t set_gate; + esp_clk_tree_parent_fn_t parent_power; +} esp_clk_tree_gated_clk_t; + +static void esp_clk_tree_parent_bbpll(bool enable) +{ + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, enable); +} + +static void esp_clk_tree_parent_rc_fast(bool enable) +{ + if (enable) { + rtc_dig_clk8m_enable(); + } else { + rtc_dig_clk8m_disable(); + } +} + +DEFINE_CRIT_SECTION_LOCK_STATIC(s_clk_tree_spinlock); + +/** Per soc_module_clk_t: record clock gate consumers */ +static int16_t s_mod_clk_gate_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; + +/** Per soc_root_clk_circuit_t: record clock power consumers */ +static int16_t s_root_pll_power_ref_cnt[SOC_ROOT_CIRCUIT_CLK_MAX] = { 0 }; + +static bool s_clk_tree_initialized = false; + +static int16_t esp_clk_tree_root_pll_power_acquire(soc_root_clk_circuit_t clk_circuit) +{ + int16_t prev; + + assert(clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL || clk_circuit == SOC_ROOT_CIRCUIT_CLK_CPLL + || clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2); + + esp_os_enter_critical(&s_clk_tree_spinlock); + prev = s_root_pll_power_ref_cnt[clk_circuit]++; + if (prev == 0) { + switch (clk_circuit) { + case SOC_ROOT_CIRCUIT_CLK_BBPLL: + clk_ll_bbpll_enable(); + break; + case SOC_ROOT_CIRCUIT_CLK_CPLL: + clk_ll_cpll_enable(); + break; + case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: + clk_ll_xtalx2_enable(); + break; + default: + break; + } + } + esp_os_exit_critical(&s_clk_tree_spinlock); + return prev; +} + +static int16_t esp_clk_tree_root_pll_power_release(soc_root_clk_circuit_t clk_circuit) +{ + int16_t prev; + + assert(clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL || clk_circuit == SOC_ROOT_CIRCUIT_CLK_CPLL + || clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2); + + esp_os_enter_critical(&s_clk_tree_spinlock); + prev = s_root_pll_power_ref_cnt[clk_circuit]; + if (prev <= 0) { + esp_os_exit_critical(&s_clk_tree_spinlock); + ESP_EARLY_LOGW(TAG, "soc_root_clk_circuit_t %d disabled multiple times!!", clk_circuit); + return prev; + } + s_root_pll_power_ref_cnt[clk_circuit] = prev - 1; + if (prev == 1) { + switch (clk_circuit) { + case SOC_ROOT_CIRCUIT_CLK_BBPLL: + clk_ll_bbpll_disable(); + break; + case SOC_ROOT_CIRCUIT_CLK_CPLL: + clk_ll_cpll_disable(); + break; + case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: + clk_ll_xtalx2_disable(); + break; + default: + break; + } + } + esp_os_exit_critical(&s_clk_tree_spinlock); + return prev; +} + +static uint32_t esp_clk_tree_ref_500m_pll_get_freq_hz(uint32_t div_num) +{ + uint32_t up_hz; + + if (clk_ll_ref_500m_get_src() == 0) { + up_hz = clk_ll_cpll_get_freq_mhz(clk_hal_xtal_get_freq_mhz()) * MHZ; + } else { + up_hz = clk_ll_mpll_get_freq_mhz(clk_hal_xtal_get_freq_mhz()) * MHZ; + } + return up_hz / div_num; +} + esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision, uint32_t *freq_value) { @@ -79,9 +336,21 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr case SOC_MOD_CLK_PLL_F20M: clk_src_freq = CLK_LL_PLL_480M_FREQ_MHZ / clk_ll_pll_f20m_get_divider() * MHZ; break; - case SOC_MOD_CLK_PLL_F80M: + case SOC_MOD_CLK_PLL_F25M: + clk_src_freq = esp_clk_tree_ref_500m_pll_get_freq_hz(clk_ll_pll_f25m_get_divider()); + break; + case SOC_MOD_CLK_PLL_F50M: + clk_src_freq = esp_clk_tree_ref_500m_pll_get_freq_hz(clk_ll_pll_f50m_get_divider()); + break; + case SOC_MOD_CLK_PLL_F60M: + clk_src_freq = CLK_LL_PLL_60M_FREQ_MHZ * MHZ; + break; + case SOC_MOD_CLK_REF_F80M: clk_src_freq = CLK_LL_PLL_80M_FREQ_MHZ * MHZ; break; + case SOC_MOD_CLK_PLL_F120M: + clk_src_freq = CLK_LL_PLL_120M_FREQ_MHZ * MHZ; + break; case SOC_MOD_CLK_PLL_F160M: clk_src_freq = CLK_LL_PLL_160M_FREQ_MHZ * MHZ; break; @@ -159,81 +428,159 @@ esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_f return ret; } -static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; -static bool s_clk_tree_initialized = false; -static int16_t s_cpll_ref_cnt = 0; - void esp_clk_tree_initialize(void) { - // TODO: IDF-15502 - /*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)) { + 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; - }*/ - - // Power - soc_cpu_clk_src_t cpu_clk_src_btld = clk_ll_cpu_get_src(); - if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_CPLL) { - s_cpll_ref_cnt++; - } else if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_PLL_F240M) { - // TODO: IDF-15502 - s_pll_src_cg_ref_cnt[SOC_MOD_CLK_PLL_F240M] = 1; } - // flash clock source is set to BBPLL in bootloader - s_pll_src_cg_ref_cnt[SOC_MOD_CLK_BBPLL] = 1; + // Cold boot only + 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; + } + + 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; - // Gating: disable all PLL-derived reference clocks; they will be re-enabled on demand via esp_clk_tree_enable_src - // TODO: IDF-15502 - //_clk_gate_ll_ref_20m_clk_en(false); - //_clk_gate_ll_ref_25m_clk_en(false); - //_clk_gate_ll_ref_50m_clk_en(false); - //_clk_gate_ll_ref_80m_clk_en(false); - //_clk_gate_ll_ref_160m_clk_en(false); - //if (s_pll_src_cg_ref_cnt[SOC_MOD_CLK_PLL_F240M] == 0) _clk_gate_ll_ref_240m_clk_en(false); s_clk_tree_initialized = true; } bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable) { + if (clk_circuit >= SOC_ROOT_CIRCUIT_CLK_MAX) { + return false; + } + bool toggled = false; switch (clk_circuit) { case SOC_ROOT_CIRCUIT_CLK_CPLL: + case SOC_ROOT_CIRCUIT_CLK_BBPLL: + case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: { if (enable) { - s_cpll_ref_cnt++; + toggled = (esp_clk_tree_root_pll_power_acquire(clk_circuit) == 0); } else { - s_cpll_ref_cnt--; + toggled = (esp_clk_tree_root_pll_power_release(clk_circuit) == 1); } - - // Note that a calibration is usually needed after enabling CPLL - if (s_cpll_ref_cnt == 1) { - clk_ll_cpll_enable(); - toggled = true; - } else if (s_cpll_ref_cnt == 0) { - clk_ll_cpll_disable(); - toggled = true; - } - - assert(s_cpll_ref_cnt >= 0); break; + } default: break; } return toggled; } -#define ENABLE_CLK_GATE(clk_src_en_func, enable) \ - PERIPH_RCC_ATOMIC() { \ - clk_src_en_func(enable); \ +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) +{ + if (clk_circuit >= SOC_ROOT_CIRCUIT_CLK_MAX) { + return false; } + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL || clk_circuit == SOC_ROOT_CIRCUIT_CLK_CPLL + || clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2) { + int16_t cnt; + + esp_os_enter_critical(&s_clk_tree_spinlock); + cnt = s_root_pll_power_ref_cnt[clk_circuit]; + esp_os_exit_critical(&s_clk_tree_spinlock); + return cnt > 0; + } + return false; +} + +typedef enum { + ESP_CLK_TREE_GATED_CLK_RC_FAST, + ESP_CLK_TREE_GATED_CLK_PLL_F20M, + ESP_CLK_TREE_GATED_CLK_PLL_F60M, + ESP_CLK_TREE_GATED_CLK_PLL_F120M, + ESP_CLK_TREE_GATED_CLK_PLL_F160M, + ESP_CLK_TREE_GATED_CLK_PLL_F240M, + ESP_CLK_TREE_GATED_CLK_NUM, +} esp_clk_tree_gated_clk_id_t; + +static const esp_clk_tree_gated_clk_t s_gated_ref_clks[] = { + [ESP_CLK_TREE_GATED_CLK_RC_FAST] = { SOC_MOD_CLK_RC_FAST, NULL, esp_clk_tree_parent_rc_fast }, + [ESP_CLK_TREE_GATED_CLK_PLL_F20M] = { SOC_MOD_CLK_PLL_F20M, _clk_gate_ll_ref_20m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_PLL_F60M] = { SOC_MOD_CLK_PLL_F60M, _clk_gate_ll_ref_60m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_PLL_F120M] = { SOC_MOD_CLK_PLL_F120M, _clk_gate_ll_ref_120m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_PLL_F160M] = { SOC_MOD_CLK_PLL_F160M, _clk_gate_ll_ref_160m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_PLL_F240M] = { SOC_MOD_CLK_PLL_F240M, _clk_gate_ll_ref_240m_clk_en, esp_clk_tree_parent_bbpll }, +}; + +#define ENABLE_CLK_GATE(clk_src_en_func, enable) \ + do { \ + if ((clk_src_en_func) != NULL) { \ + PERIPH_RCC_ATOMIC() { \ + (clk_src_en_func)(enable); \ + }; \ + } \ + } while (0) + +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; + + esp_os_enter_critical(&s_clk_tree_spinlock); + if (enable) { + prev_ref_cnt = s_mod_clk_gate_ref_cnt[entry->clk_id]++; + } 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; + } + } + 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); + } + } + return ESP_OK; +} esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) { - if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) { - // some conditions is legal, e.g. -1 means external clock source + if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID || clk_src == SOC_MOD_CLK_XTAL) { + /* Not managed by esp_clk_tree*/ return ESP_OK; } @@ -241,59 +588,36 @@ esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) return ESP_OK; } - int16_t prev_ref_cnt = 0; - - // Derived PLL clocks (PLL_F50M, ...) that participate in the shared - // refcount/lock engine route through that engine instead of the - // global s_pll_src_cg_ref_cnt array below. - if (esp_clk_tree_get_derived_clk_desc(clk_src) != NULL) { - return enable ? esp_clk_tree_derived_clk_acquire(clk_src) - : esp_clk_tree_derived_clk_release(clk_src); - } - + esp_clk_tree_gated_clk_id_t gated_clk_id; // these clock sources have their own reference counting switch (clk_src) { - case SOC_MOD_CLK_APLL: - if (enable) { - esp_clk_tree_apll_acquire(); - } else { - esp_clk_tree_apll_release(); - } - return ESP_OK; - case SOC_MOD_CLK_MPLL: - if (enable) { - return esp_clk_tree_mpll_acquire(); - } else { - esp_clk_tree_mpll_release(); - } - return ESP_OK; - default: - break; - } - - // other clock sources use the global reference counting - if (enable) { - prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1); - } else { - prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1); - if (prev_ref_cnt <= 0) { - ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src); - atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0); + case SOC_MOD_CLK_APLL: + if (enable) { + esp_clk_tree_apll_acquire(); + } else { + esp_clk_tree_apll_release(); + } + return ESP_OK; + case SOC_MOD_CLK_MPLL: + if (enable) { + return esp_clk_tree_mpll_acquire(); + } else { + esp_clk_tree_mpll_release(); 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; + case SOC_MOD_CLK_PLL_F120M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F120M; break; + case SOC_MOD_CLK_PLL_F160M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F160M; break; + case SOC_MOD_CLK_PLL_F240M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F240M; break; + default: + // Derived PLL clocks (PLL_F25M/F50M/F80M) use the shared derived-clk engine. + if (esp_clk_tree_get_derived_clk_desc(clk_src) != NULL) { + return enable ? esp_clk_tree_derived_clk_acquire(clk_src) + : esp_clk_tree_derived_clk_release(clk_src); + } + return ESP_OK; } - // TODO: IDF-15502 - //if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) { - // switch (clk_src) { - // case SOC_MOD_CLK_RC_FAST: enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable(); break; - // case SOC_MOD_CLK_PLL_F20M: ENABLE_CLK_GATE(clk_gate_ll_ref_20m_clk_en, enable); break; - // case SOC_MOD_CLK_PLL_F25M: ENABLE_CLK_GATE(clk_gate_ll_ref_25m_clk_en, enable); break; - // case SOC_MOD_CLK_PLL_F80M: ENABLE_CLK_GATE(clk_gate_ll_ref_80m_clk_en, enable); break; - // case SOC_MOD_CLK_PLL_F160M: ENABLE_CLK_GATE(clk_gate_ll_ref_160m_clk_en, enable); break; - // case SOC_MOD_CLK_PLL_F240M: ENABLE_CLK_GATE(clk_gate_ll_ref_240m_clk_en, enable); break; - // default: break; - // } - //} - - return ESP_OK; + return esp_clk_tree_enable_gated_clk(&s_gated_ref_clks[gated_clk_id], enable); } diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk.c b/components/esp_hw_support/port/esp32s31/rtc_clk.c index def964eae25..9476b24a774 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk.c @@ -357,7 +357,9 @@ static void rtc_clk_cpu_src_clk_enable(soc_cpu_clk_src_t new_src, uint32_t new_s 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 +#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; @@ -380,7 +382,9 @@ static void rtc_clk_cpu_src_clk_disable(soc_cpu_clk_src_t old_src) } #endif } else if (old_src == SOC_CPU_CLK_SRC_PLL_F240M) { -#if !BOOTLOADER_BUILD +#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); diff --git a/components/esp_hw_support/port/esp_clk_tree_common.c b/components/esp_hw_support/port/esp_clk_tree_common.c index 4c6378bbfd5..c42bbb6e66b 100644 --- a/components/esp_hw_support/port/esp_clk_tree_common.c +++ b/components/esp_hw_support/port/esp_clk_tree_common.c @@ -409,8 +409,8 @@ end: * dispatchers route into. * * Semantics: - * - acquire: ref_cnt++; on first acquire enable the gate. - * - release: ref_cnt--; on last release disable the gate. + * - acquire: ref_cnt++; on first acquire acquire_parent then enable the gate. + * - release: ref_cnt--; on last release disable the gate and release_parent. * - select_upstream: program the mux to source from `upstream`. * - freq_set: pick a divider for `state->cur_upstream` (if `select_upstream` * was called) or auto-pick an upstream that divides cleanly @@ -436,14 +436,21 @@ esp_err_t esp_clk_tree_derived_clk_acquire(soc_module_clk_t clk_src) return ESP_ERR_NOT_SUPPORTED; } esp_clk_tree_derived_clk_state_t *state = desc->state; - + esp_err_t ret = ESP_OK; esp_os_enter_critical(&s_derived_clk_spinlock); state->ref_cnt++; if (state->ref_cnt == 1) { - desc->set_gate(true); + if (desc->acquire_parent != NULL) { + ret = desc->acquire_parent(); + } + if (ret == ESP_OK) { + desc->set_gate(true); + } else { + state->ref_cnt--; + } } esp_os_exit_critical(&s_derived_clk_spinlock); - return ESP_OK; + return ret; } esp_err_t esp_clk_tree_derived_clk_release(soc_module_clk_t clk_src) @@ -455,6 +462,7 @@ esp_err_t esp_clk_tree_derived_clk_release(soc_module_clk_t clk_src) esp_clk_tree_derived_clk_state_t *state = desc->state; bool released_too_many = false; + esp_err_t ret = ESP_OK; esp_os_enter_critical(&s_derived_clk_spinlock); if (state->ref_cnt <= 0) { state->ref_cnt = 0; @@ -465,13 +473,17 @@ esp_err_t esp_clk_tree_derived_clk_release(soc_module_clk_t clk_src) desc->set_gate(false); state->cur_upstream = SOC_MOD_CLK_INVALID; state->cur_divider = 0; + if (desc->release_parent != NULL) { + ret = desc->release_parent(); + } } } esp_os_exit_critical(&s_derived_clk_spinlock); if (released_too_many) { ESP_HW_LOGW(TAG, "derived clk %d released without matching acquire", (int)clk_src); + return ESP_OK; } - return ESP_OK; + return ret; } /** @@ -521,6 +533,7 @@ esp_err_t esp_clk_tree_derived_clk_freq_set(soc_module_clk_t clk_src, if (desc == NULL || desc->state == NULL || desc->upstreams == NULL) { return ESP_ERR_NOT_SUPPORTED; } + esp_clk_tree_derived_clk_state_t *state = desc->state; ESP_RETURN_ON_FALSE(expt_freq_hz > 0, ESP_ERR_INVALID_ARG, TAG, "freq must be > 0"); @@ -551,32 +564,49 @@ esp_err_t esp_clk_tree_derived_clk_freq_set(soc_module_clk_t clk_src, // (e.g. another peer ran enable_src already but hasn't called freq_set // yet). Mirrors MPLL's `cur == 0 || ref_cnt < 2` check. bool first_commit = (state->cur_divider == 0); + bool upstream_changed = false; if (state->ref_cnt < 2 || same_config || first_commit) { // First-time configuration: also program the mux. When the caller // already invoked `select_upstream`, `state->cur_upstream` already // matches `upstream` so the mux is left untouched. - if (state->cur_upstream != upstream && desc->set_src != NULL) { - desc->set_src(mux_sel); + if (state->cur_upstream != upstream) { + upstream_changed = true; + if (desc->set_src != NULL) { + desc->set_src(mux_sel); + } + } + if (desc->set_divider != NULL) { + desc->set_divider(divider); } - desc->set_divider(divider); state->cur_upstream = upstream; state->cur_divider = divider; } else { ret = ESP_ERR_INVALID_STATE; } + if (ret == ESP_OK && upstream_changed && desc->acquire_parent != NULL) { + ret = desc->acquire_parent(); + } esp_os_exit_critical(&s_derived_clk_spinlock); reported_upstream = state->cur_upstream; reported_divider = state->cur_divider; if (real_freq_hz != NULL) { - uint32_t up_hz = 0; - if (reported_upstream != SOC_MOD_CLK_INVALID && reported_divider != 0 && - esp_clk_tree_src_get_freq_hz(reported_upstream, - ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, - &up_hz) == ESP_OK) { - *real_freq_hz = up_hz / reported_divider; + if (desc->set_divider == NULL) { + if (esp_clk_tree_src_get_freq_hz(clk_src, + ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, + real_freq_hz) != ESP_OK) { + *real_freq_hz = 0; + } } else { - *real_freq_hz = 0; + uint32_t up_hz = 0; + if (reported_upstream != SOC_MOD_CLK_INVALID && reported_divider != 0 && + esp_clk_tree_src_get_freq_hz(reported_upstream, + ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, + &up_hz) == ESP_OK) { + *real_freq_hz = up_hz / reported_divider; + } else { + *real_freq_hz = 0; + } } } return ret; @@ -626,7 +656,33 @@ esp_err_t esp_clk_tree_src_select_upstream(soc_module_clk_t clk_src, // Divider for the previous upstream is no longer meaningful; the next // `set_freq_hz` call will program a fresh divider for `upstream`. state->cur_divider = 0; + if (desc->acquire_parent != NULL) { + ret = desc->acquire_parent(); + } } esp_os_exit_critical(&s_derived_clk_spinlock); return ret; } + +bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit) +{ +#if SOC_CLK_MPLL_SUPPORTED + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_MPLL) { + bool on; + esp_os_enter_critical(&s_periph_mpll_spinlock); + on = s_mpll_ref_cnt > 0; + esp_os_exit_critical(&s_periph_mpll_spinlock); + return on; + } +#endif +#if SOC_CLK_APLL_SUPPORTED + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_APLL) { + bool on; + esp_os_enter_critical(&s_periph_apll_spinlock); + on = s_apll_ref_cnt > 0; + esp_os_exit_critical(&s_periph_apll_spinlock); + return on; + } +#endif + return esp_clk_tree_port_is_power_on(clk_circuit); +} diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index 6168f2d30f5..4d13caf6b7d 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -77,6 +77,8 @@ typedef enum { SOC_ROOT_CIRCUIT_CLK_CPLL, /*!< CPLL_CLK is the output of the CPLL generator circuit */ SOC_ROOT_CIRCUIT_CLK_MPLL, /*!< MPLL_CLK is the output of the MPLL generator circuit */ SOC_ROOT_CIRCUIT_CLK_APLL, /*!< APLL_CLK is the output of the APLL generator circuit */ + SOC_ROOT_CIRCUIT_CLK_XTAL_X2, /*!< XTALx2 80MHz; ref_80m mux alternate source (see clk_ll_xtalx2_enable) */ + SOC_ROOT_CIRCUIT_CLK_MAX, } soc_root_clk_circuit_t; /** @@ -141,9 +143,12 @@ typedef enum { // For digital domain: peripherals SOC_MOD_CLK_SYS, /*!< SYS_CLK is the system clock, derived from SOC_CLK clock source */ SOC_MOD_CLK_PLL_F20M, /*!< PLL_F20M_CLK is derived from BBPLL (clock gating + default divider 24), its default frequency is 20MHz */ - SOC_MOD_CLK_PLL_F25M, /*!< PLL_F25M_CLK is derived from MPLL (clock gating + configurable divider), it will have a frequency of 25MHz */ - SOC_MOD_CLK_PLL_F50M, /*!< PLL_F50M_CLK is derived from C/MPLL (clock gating + configurable divider 10), it will have a frequency of 50MHz */ + SOC_MOD_CLK_PLL_F25M, /*!< PLL_F25M_CLK is from ref_25m (clock gating + configurable divider). Shares HP_SYS `ref_500m_sel` with PLL_F50M (0=CPLL, 1=MPLL); if both are used, they must select the same upstream. */ + SOC_MOD_CLK_PLL_F50M, /*!< PLL_F50M_CLK is from ref_50m (clock gating + configurable divider). Shares `ref_500m_sel` with PLL_F25M; frequency via esp_clk_tree_src_set_freq_hz (CPLL or MPLL upstream). */ + SOC_MOD_CLK_PLL_F60M, /*!< PLL_F60M_CLK is derived from BBPLL (clock gating + default divider 8), its default frequency is 60MHz */ + SOC_MOD_CLK_REF_F80M, /*!< REF_F80M_CLK from ref_80m (gate). Mux: BBPLL/6 (default) or XTALx2 80MHz (`reg_ref_80m_sel`). Frequency 80MHz either path. */ SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from BBPLL (clock gating + default divider 6), its default frequency is 80MHz */ + SOC_MOD_CLK_PLL_F120M, /*!< PLL_F120M_CLK is derived from BBPLL (clock gating + default divider 4), its default frequency is 120MHz */ SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from BBPLL (clock gating + default divider 3), its default frequency is 160MHz */ SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from BBPLL (clock gating + default divider 2), its default frequency is 240MHz */ SOC_MOD_CLK_CPLL, /*!< CPLL is from 40MHz XTAL oscillator frequency multipliers */ From 0b7f047e9e927357efe1936c5b467ddafd92b48a Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 27 May 2026 14:18:21 +0800 Subject: [PATCH 2/8] fix(driver): fix drivers clock management --- .../dvp/src/esp_cam_ctlr_dvp_cam.c | 16 ++++++++++++++++ .../gptimer/main/test_gptimer_sleep.c | 10 ++++++++-- components/esp_hw_support/etm/esp_etm.c | 18 +++++++++++++++++- .../modem/port/esp32s31/modem_clock_impl.c | 8 ++++++++ .../esp_hw_support/port/esp32s31/rtc_time.c | 3 +++ components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 16 ++++++++++++++++ components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 14 ++++++++++++++ 7 files changed, 82 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index a64df57d63e..2b2bcd5735e 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -66,6 +66,7 @@ typedef struct dvp_platform { static dvp_platform_t s_platform; static const char *TAG = "dvp_cam"; +static soc_module_clk_t s_dvp_clk_src[CAP_DVP_PERIPH_NUM]; /** * @brief Claim DVP controller @@ -346,6 +347,11 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e esp_rom_gpio_connect_out_signal(pin->xclk_io, cam_periph_signals.buses[ctlr_id].clk_sig, false, false); } +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true)); +#endif + PERIPH_RCC_ACQUIRE_ATOMIC(cam_periph_signals.buses[ctlr_id].module, ref_count) { if (ref_count == 0) { cam_ll_enable_bus_clock(ctlr_id, true); @@ -354,6 +360,7 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e } ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true)); + s_dvp_clk_src[ctlr_id] = (soc_module_clk_t)clk_src; PERIPH_RCC_ATOMIC() { cam_ll_enable_clk(ctlr_id, true); cam_ll_select_clk_src(ctlr_id, clk_src); @@ -458,6 +465,15 @@ esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id) } } + if (s_dvp_clk_src[ctlr_id]) { + esp_clk_tree_enable_src(s_dvp_clk_src[ctlr_id], false); + s_dvp_clk_src[ctlr_id] = 0; + } + +#if CONFIG_IDF_TARGET_ESP32S31 + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); +#endif + return ESP_OK; } diff --git a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c index 49f7637cb1c..788ef809946 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c +++ b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,7 +18,13 @@ #include "esp_private/esp_sleep_internal.h" #include "esp_private/esp_pmu.h" -static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +#if CONFIG_GPTIMER_ISR_CACHE_SAFE +#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR +#else +#define TEST_ALARM_CALLBACK_ATTR +#endif // CONFIG_GPTIMER_ISR_CACHE_SAFE + +TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { TaskHandle_t task_handle = (TaskHandle_t)user_data; BaseType_t high_task_wakeup; diff --git a/components/esp_hw_support/etm/esp_etm.c b/components/esp_hw_support/etm/esp_etm.c index 8bb34071ae2..0b3d65952c2 100644 --- a/components/esp_hw_support/etm/esp_etm.c +++ b/components/esp_hw_support/etm/esp_etm.c @@ -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 */ @@ -27,6 +27,7 @@ #include "esp_private/etm_interface.h" #include "esp_private/sleep_retention.h" #include "esp_private/critical_section.h" +#include "esp_private/esp_clk_tree_common.h" #define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT @@ -63,6 +64,9 @@ struct esp_etm_channel_t { _Atomic etm_chan_fsm_t fsm; // record ETM channel's driver state esp_etm_event_handle_t event; // which event is connect to the channel esp_etm_task_handle_t task; // which task is connect to the channel +#if ETM_LL_SUPPORT(CLOCK_SRC) + etm_clock_source_t clk_src; // function clock source enabled for this channel +#endif }; // ETM driver platform, it's always a singleton @@ -272,6 +276,8 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch if (clk_src == 0) { clk_src = ETM_CLK_SRC_DEFAULT; } + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), err, TAG, "clock source enable failed"); + chan->clk_src = clk_src; etm_ll_set_clock_source(group_id, clk_src); #endif @@ -290,6 +296,11 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch err: if (chan) { +#if ETM_LL_SUPPORT(CLOCK_SRC) + if (chan->clk_src != 0) { + esp_clk_tree_enable_src((soc_module_clk_t)chan->clk_src, false); + } +#endif etm_chan_destroy(chan); } return ret; @@ -310,6 +321,11 @@ esp_err_t esp_etm_del_channel(esp_etm_channel_handle_t chan) etm_ll_channel_set_task(group->hal.regs, chan_id, 0); ESP_LOGD(TAG, "del etm channel (%d,%d)", group_id, chan_id); +#if ETM_LL_SUPPORT(CLOCK_SRC) + // Back to hardware default clock selection, otherwise it might get stuck when stopping the bus during sleep process. + etm_ll_set_clock_source(group_id, ETM_CLK_SRC_XTAL); + ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)chan->clk_src, false), TAG, "clock source disable failed"); +#endif // recycle memory resource ESP_RETURN_ON_ERROR(etm_chan_destroy(chan), TAG, "destroy etm channel failed"); return ESP_OK; diff --git a/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c b/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c index f927d61b208..1cfe9aa83ea 100644 --- a/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c +++ b/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c @@ -6,6 +6,8 @@ #include "sdkconfig.h" #include "esp_attr.h" +#include "esp_check.h" +#include "esp_clk_tree.h" #include "soc/soc_caps.h" #include "modem/modem_clock_impl.h" #include "esp_private/regi2c_ctrl.h" @@ -212,7 +214,13 @@ static void IRAM_ATTR modem_clock_coex_configure(modem_clock_context_t *ctx, boo #if SOC_MODEM_CLOCK_SOC_PLL_SOURCE_CG_SUPPORTED static void IRAM_ATTR modem_clock_soc_pll_source_cg_configure(modem_clock_context_t *ctx, bool enable) { + if (enable) { + ESP_ERROR_CHECK(esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F160M, true)); + } modem_clock_hal_enable_soc_pll_source_cg(ctx->hal, enable); + if (!enable) { + ESP_ERROR_CHECK(esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F160M, false)); + } } #endif diff --git a/components/esp_hw_support/port/esp32s31/rtc_time.c b/components/esp_hw_support/port/esp32s31/rtc_time.c index 6c60a93f95a..004a143e62d 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_time.c +++ b/components/esp_hw_support/port/esp32s31/rtc_time.c @@ -144,6 +144,9 @@ uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32 } CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); clk_ll_freq_calculation_set_divider(1); + // Back to always on clock source, Otherwise, if the source for this calibration is subsequently turned off, + // the next calibration will not be able to switch to the new calibration source. + clk_ll_freq_calulation_set_target(CLK_CAL_RC_SLOW); /* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */ if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) { diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index d4ccb44585a..ca17ae55e3d 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -123,6 +123,9 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc { esp_err_t ret = ESP_OK; esp_lcd_i80_bus_t *bus = NULL; +#if CONFIG_IDF_TARGET_ESP32S31 + bool pll_f120m_enabled = false; +#endif ESP_RETURN_ON_FALSE(bus_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); // although LCD_CAM can support up to 24 data lines, we restrict users to only use 8 or 16 bit width ESP_RETURN_ON_FALSE(bus_config->bus_width == 8 || bus_config->bus_width == 16, ESP_ERR_INVALID_ARG, @@ -181,6 +184,11 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc #endif // I80_USE_RETENTION_LINK // initialize HAL layer, so we can call LL APIs later lcd_hal_init(&bus->hal, bus_id); +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true), err, TAG, "clock source enable failed"); + pll_f120m_enabled = true; +#endif PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(bus->hal.dev, true); } @@ -264,6 +272,11 @@ err: esp_clk_tree_enable_src(bus->clk_src, false); bus->clk_src = SOC_MOD_CLK_INVALID; } +#if CONFIG_IDF_TARGET_ESP32S31 + if (pll_f120m_enabled) { + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); + } +#endif #if CONFIG_PM_ENABLE if (bus->pm_lock) { esp_pm_lock_delete(bus->pm_lock); @@ -287,6 +300,9 @@ esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus) esp_clk_tree_enable_src(bus->clk_src, false); bus->clk_src = SOC_MOD_CLK_INVALID; } +#if CONFIG_IDF_TARGET_ESP32S31 + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false), err, TAG, "clock source disable failed"); +#endif #if I80_USE_RETENTION_LINK const periph_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module; sleep_retention_module_detach(module_id); diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 8a5a73d5e6a..ec9bc5725e5 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -173,6 +173,9 @@ struct esp_rgb_panel_t { uint32_t fb_behind_cache: 1; // Whether the frame buffer is behind the cache uint32_t bb_behind_cache: 1; // Whether the bounce buffer is behind the cache uint32_t user_fb: 1; // Whether the frame buffer is provided by user +#if CONFIG_IDF_TARGET_ESP32S31 + uint32_t pll_f120m_enabled: 1; // Whether PLL_F120M was enabled for this panel instance +#endif } flags; // hook fields esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function @@ -265,6 +268,12 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel) PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(rgb_panel->hal.dev, false); } +#if CONFIG_IDF_TARGET_ESP32S31 + if (rgb_panel->flags.pll_f120m_enabled) { + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); + rgb_panel->flags.pll_f120m_enabled = 0; + } +#endif if (rgb_panel->clk_src) { esp_clk_tree_enable_src(rgb_panel->clk_src, false); } @@ -419,6 +428,11 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf lcd_hal_init(&rgb_panel->hal, panel_id); lcd_hal_context_t *hal = &rgb_panel->hal; // enable clock +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true), err, TAG, "clock source enable failed"); + rgb_panel->flags.pll_f120m_enabled = 1; +#endif PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(hal->dev, true); } From 3641d243e095f06862348aba324d15c2a740e285 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 31 Aug 2026 12:01:03 +0800 Subject: [PATCH 3/8] feat(esp_hw_support): disable all unused pll source in rtc_clk_init to save power --- .../src/bootloader_flash_config_esp32s31.c | 2 ++ .../port/esp32s31/include/soc/rtc.h | 8 +++++++ .../port/esp32s31/rtc_clk_init.c | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c index a71f8acdb72..f602074bb63 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c @@ -23,6 +23,7 @@ #include "hal/mspi_ll.h" #include "hal/cache_hal.h" #include "hal/cache_ll.h" +#include "hal/clk_tree_ll.h" #include "esp_private/bootloader_flash_internal.h" void IRAM_ATTR bootloader_flash_update_id(void) @@ -46,6 +47,7 @@ void IRAM_ATTR bootloader_flash_cs_timing_config(void) void IRAM_ATTR bootloader_init_mspi_clock(void) { cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); + clk_ll_bbpll_enable(); _mspi_timing_ll_set_flash_core_clock(0, 80); _mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_BBPLL); cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); 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 7d0dadb89f0..44c5ee342e3 100644 --- a/components/esp_hw_support/port/esp32s31/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32s31/include/soc/rtc.h @@ -88,6 +88,10 @@ typedef struct { uint32_t slow_clk_dcap : 8; //!< RC_SLOW clock adjustment parameter (higher value leads to lower frequency) uint32_t clk_8m_dfreq : 8; //!< RC_FAST clock adjustment parameter (higher value leads to higher frequency) uint32_t rc32k_dfreq : 10; //!< Internal RC32K clock adjustment parameter (higher value leads to higher frequency) + uint32_t disable_apll : 1; //!< Whether to disable APLL in rtc_clk_init + uint32_t disable_mpll : 1; //!< Whether to disable MPLL in rtc_clk_init + uint32_t disable_cpll : 1; //!< Whether to disable CPLL in rtc_clk_init + uint32_t disable_bbpll : 1; //!< Whether to disable BBPLL in rtc_clk_init } rtc_clk_config_t; /** @@ -103,6 +107,10 @@ typedef struct { .slow_clk_dcap = RTC_CNTL_SCK_DCAP_DEFAULT, \ .clk_8m_dfreq = RTC_CNTL_CK8M_DFREQ_DEFAULT, \ .rc32k_dfreq = RTC_CNTL_RC32K_DFREQ_DEFAULT, \ + .disable_apll = 1, \ + .disable_mpll = 1, \ + .disable_cpll = 0, \ + .disable_bbpll = 1, \ } /** diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk_init.c b/components/esp_hw_support/port/esp32s31/rtc_clk_init.c index 0e14f89fbf0..75ffc533bbb 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk_init.c @@ -8,6 +8,7 @@ #include #include #include +#include "sdkconfig.h" #include "esp32s31/rom/ets_sys.h" #include "esp32s31/rom/rtc.h" #include "soc/rtc.h" @@ -27,6 +28,25 @@ ESP_HW_LOG_ATTR_TAG(TAG, "rtc_clk_init"); +static inline void rtc_clk_pll_disable(rtc_clk_config_t cfg) +{ + if (cfg.disable_apll) { + clk_ll_apll_disable(); + } + if (cfg.disable_mpll) { + clk_ll_mpll_disable(); + } + if (cfg.disable_cpll) { + clk_ll_cpll_disable(); + } +#if !CONFIG_USJ_ENABLE_USB_SERIAL_JTAG && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + // USB-Serial-JTAG depends on bbpll480M, bypass disable bbpll if USB console is used. + if (cfg.disable_bbpll) { + clk_ll_bbpll_disable(); + } +#endif +} + void rtc_clk_init(rtc_clk_config_t cfg) { rtc_cpu_freq_config_t old_config, new_config; @@ -50,6 +70,9 @@ void rtc_clk_init(rtc_clk_config_t cfg) // No need to wait UART0 TX idle since its default clock source is XTAL, should not be affected by system clock configuration + /* Disable PLLs to save power, the PLLs will be enabled by the user in application code */ + rtc_clk_pll_disable(cfg); + /* Set CPU frequency */ rtc_clk_cpu_freq_get_config(&old_config); uint32_t freq_before = old_config.freq_mhz; From 5f23a5646e8ec25af141b5d611734b2e0dc37f91 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 7 Jul 2026 22:02:20 +0800 Subject: [PATCH 4/8] change(hal): rename PLL_F80M to REF_80M for esp32s31 peripherals clock defination --- .../esp32s31/include/hal/ana_cmpr_ll.h | 2 +- .../esp32s31/include/hal/emac_ll.h | 2 +- .../esp_hal_rmt/esp32s31/include/hal/rmt_ll.h | 2 +- .../esp32s31/include/hal/timer_ll.h | 2 +- .../esp32s31/include/hal/twai_ll.h | 2 +- .../esp32s31/include/hal/uart_ll.h | 4 +- components/hal/esp32s31/include/hal/etm_ll.h | 2 +- .../soc/esp32s31/include/soc/clk_tree_defs.h | 55 +++++++++---------- 8 files changed, 35 insertions(+), 36 deletions(-) diff --git a/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h b/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h index a57fbd83733..aee64445668 100644 --- a/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h +++ b/components/esp_hal_ana_cmpr/esp32s31/include/hal/ana_cmpr_ll.h @@ -105,7 +105,7 @@ static inline void analog_cmpr_ll_set_clk_src(int unit_id, ana_cmpr_clk_src_t cl case ANA_CMPR_CLK_SRC_RC_FAST: HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_src_sel = 1; break; - case ANA_CMPR_CLK_SRC_PLL_F80M: + case ANA_CMPR_CLK_SRC_REF_F80M: HP_SYS_CLKRST.zero_det_ctrl0.reg_zero_det_clk_src_sel = 2; break; default: diff --git a/components/esp_hal_emac/esp32s31/include/hal/emac_ll.h b/components/esp_hal_emac/esp32s31/include/hal/emac_ll.h index f2c798d6520..24a2220ee7a 100644 --- a/components/esp_hal_emac/esp32s31/include/hal/emac_ll.h +++ b/components/esp_hal_emac/esp32s31/include/hal/emac_ll.h @@ -1086,7 +1086,7 @@ static inline void emac_ll_clock_enable_ptp(void *ext_regs, soc_periph_emac_ptp_ case EMAC_PTP_CLK_SRC_XTAL: clk_src_val = 0; break; - case EMAC_PTP_CLK_SRC_PLL_F80M: + case EMAC_PTP_CLK_SRC_REF_F80M: clk_src_val = 1; break; default: diff --git a/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h index 49b1d2fa949..cf3b484bf9f 100644 --- a/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h @@ -173,7 +173,7 @@ static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.rmt_ctrl0, reg_rmt_clk_div_numerator, divider_numerator); HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.rmt_ctrl0, reg_rmt_clk_div_denominator, divider_denominator); switch (src) { - case RMT_CLK_SRC_PLL_F80M: + case RMT_CLK_SRC_REF_F80M: HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_clk_src_sel = 2; break; case RMT_CLK_SRC_RC_FAST: diff --git a/components/esp_hal_timg/esp32s31/include/hal/timer_ll.h b/components/esp_hal_timg/esp32s31/include/hal/timer_ll.h index 54b07254130..010417360b8 100644 --- a/components/esp_hal_timg/esp32s31/include/hal/timer_ll.h +++ b/components/esp_hal_timg/esp32s31/include/hal/timer_ll.h @@ -104,7 +104,7 @@ static inline void _timer_ll_set_clock_source(int group_id, uint32_t timer_num, case GPTIMER_CLK_SRC_XTAL: clk_id = 0; break; - case GPTIMER_CLK_SRC_PLL_F80M: + case GPTIMER_CLK_SRC_REF_F80M: clk_id = 2; break; case GPTIMER_CLK_SRC_RC_FAST: diff --git a/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h b/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h index 541f75a3d19..5c77f76551b 100644 --- a/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h +++ b/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h @@ -167,7 +167,7 @@ static inline void twai_ll_set_clock_source(uint8_t twai_id, twai_clock_source_t case TWAI_CLK_SRC_XTAL: clk_sel = 0; break; - case TWAI_CLK_SRC_PLL_F80M: + case TWAI_CLK_SRC_REF_F80M: clk_sel = 2; break; default: diff --git a/components/esp_hal_uart/esp32s31/include/hal/uart_ll.h b/components/esp_hal_uart/esp32s31/include/hal/uart_ll.h index 381fb94f5d7..9a3ba9f486d 100644 --- a/components/esp_hal_uart/esp32s31/include/hal/uart_ll.h +++ b/components/esp_hal_uart/esp32s31/include/hal/uart_ll.h @@ -433,7 +433,7 @@ FORCE_INLINE_ATTR void uart_ll_set_sclk(uart_dev_t *hw, soc_module_clk_t source_ case UART_SCLK_RTC: sel_value = 1; break; - case UART_SCLK_PLL_F80M: + case UART_SCLK_REF_F80M: sel_value = 2; break; default: @@ -484,7 +484,7 @@ FORCE_INLINE_ATTR void uart_ll_get_sclk(uart_dev_t *hw, soc_module_clk_t *source *source_clk = (soc_module_clk_t)UART_SCLK_XTAL; break; case 2: - *source_clk = (soc_module_clk_t)UART_SCLK_PLL_F80M; + *source_clk = (soc_module_clk_t)UART_SCLK_REF_F80M; break; } } else { diff --git a/components/hal/esp32s31/include/hal/etm_ll.h b/components/hal/esp32s31/include/hal/etm_ll.h index a793e5bafbe..7d4376e95a6 100644 --- a/components/hal/esp32s31/include/hal/etm_ll.h +++ b/components/hal/esp32s31/include/hal/etm_ll.h @@ -74,7 +74,7 @@ static inline void etm_ll_set_clock_source(int group_id, etm_clock_source_t clk_ case ETM_CLK_SRC_RC_FAST: HP_SYS_CLKRST.etm_ctrl0.reg_soc_etm_clk_sel = 1; break; - case ETM_CLK_SRC_PLL_F80M: + case ETM_CLK_SRC_REF_F80M: HP_SYS_CLKRST.etm_ctrl0.reg_soc_etm_clk_sel = 2; break; default: diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index 4d13caf6b7d..4504a342eef 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -147,7 +147,6 @@ typedef enum { SOC_MOD_CLK_PLL_F50M, /*!< PLL_F50M_CLK is from ref_50m (clock gating + configurable divider). Shares `ref_500m_sel` with PLL_F25M; frequency via esp_clk_tree_src_set_freq_hz (CPLL or MPLL upstream). */ SOC_MOD_CLK_PLL_F60M, /*!< PLL_F60M_CLK is derived from BBPLL (clock gating + default divider 8), its default frequency is 60MHz */ SOC_MOD_CLK_REF_F80M, /*!< REF_F80M_CLK from ref_80m (gate). Mux: BBPLL/6 (default) or XTALx2 80MHz (`reg_ref_80m_sel`). Frequency 80MHz either path. */ - SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from BBPLL (clock gating + default divider 6), its default frequency is 80MHz */ SOC_MOD_CLK_PLL_F120M, /*!< PLL_F120M_CLK is derived from BBPLL (clock gating + default divider 4), its default frequency is 120MHz */ SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from BBPLL (clock gating + default divider 3), its default frequency is 160MHz */ SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from BBPLL (clock gating + default divider 2), its default frequency is 240MHz */ @@ -227,25 +226,25 @@ typedef enum { * } * @endcode */ -#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} +#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_REF_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of GPTimer clock source */ typedef enum { - GPTIMER_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + GPTIMER_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the source clock */ GPTIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ GPTIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ + GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the default choice */ } soc_periph_gptimer_clk_src_t; //////////////////////////////////////////////////ETM/////////////////////////////////////////////////////////////////// typedef enum { - ETM_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + ETM_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the source clock */ ETM_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ ETM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - ETM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ + ETM_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the default choice */ } soc_periph_etm_clk_src_t; //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// @@ -253,16 +252,16 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of RMT */ -#define SOC_RMT_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} +#define SOC_RMT_CLKS {SOC_MOD_CLK_REF_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of RMT clock source */ typedef enum { - RMT_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + RMT_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the source clock */ RMT_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ RMT_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ + RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the default choice */ } soc_periph_rmt_clk_src_t; ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// @@ -270,16 +269,16 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of UART */ -#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} +#define SOC_UART_CLKS {SOC_MOD_CLK_REF_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} /** * @brief Type of UART clock source, reserved for the legacy UART driver */ typedef enum { - UART_SCLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock is PLL_F80M */ + UART_SCLK_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< UART source clock is REF_F80M */ UART_SCLK_RTC = SOC_MOD_CLK_RC_FAST, /*!< UART source clock is RC_FAST */ UART_SCLK_XTAL = SOC_MOD_CLK_XTAL, /*!< UART source clock is XTAL */ - UART_SCLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock default choice is PLL_F80M */ + UART_SCLK_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< UART source clock default choice is REF_F80M */ } soc_periph_uart_clk_src_legacy_t; /** @@ -301,7 +300,7 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of LEDC */ -#define SOC_LEDC_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST} +#define SOC_LEDC_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_REF_F80M, SOC_MOD_CLK_RC_FAST} #define SOC_LEDC_CLK_STRS {"LEDC_USE_XTAL_CLK", "LEDC_USE_PLL_DIV_CLK", "LEDC_USE_RC_FAST_CLK"} /** @@ -309,7 +308,7 @@ typedef enum { */ typedef enum { LEDC_AUTO_CLK = 0, /*!< LEDC source clock will be automatically selected based on the giving resolution and duty parameter when init the timer*/ - LEDC_USE_PLL_DIV_CLK = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the source clock */ + LEDC_USE_PLL_DIV_CLK = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M clock as the source clock */ LEDC_USE_RC_FAST_CLK = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ LEDC_USE_XTAL_CLK = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ } soc_periph_ledc_clk_src_legacy_t; @@ -417,14 +416,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MWDT */ -#define SOC_MWDT_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST} +#define SOC_MWDT_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_REF_F80M, SOC_MOD_CLK_RC_FAST} /** * @brief MWDT clock source */ typedef enum { MWDT_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - MWDT_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL fixed 80 MHz as the source clock */ + MWDT_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select PLL fixed 80 MHz as the source clock */ MWDT_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RTC fast as the source clock */ MWDT_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL 40 MHz as the default clock choice */ } soc_periph_mwdt_clk_src_t; @@ -436,8 +435,8 @@ typedef enum { */ typedef enum { SDM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ - SDM_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the source clock */ - SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the default clock choice */ + SDM_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M clock as the source clock */ + SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M clock as the default clock choice */ } soc_periph_sdm_clk_src_t; //////////////////////////////////////////////////GPIO Glitch Filter//////////////////////////////////////////////////// @@ -448,8 +447,8 @@ typedef enum { typedef enum { GLITCH_FILTER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ - GLITCH_FILTER_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the source clock */ - GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the default clock choice */ + GLITCH_FILTER_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M clock as the source clock */ + GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M clock as the default clock choice */ } soc_periph_glitch_filter_clk_src_t; ////////////////////////////////////////////////ANA_CMPR//////////////////////////////////////////////////// @@ -457,7 +456,7 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of Analog Comparator */ -#define SOC_ANA_CMPR_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F80M} +#define SOC_ANA_CMPR_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_REF_F80M} /** * @brief Type of Analog Comparator clock source @@ -465,8 +464,8 @@ typedef enum { typedef enum { ANA_CMPR_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ ANA_CMPR_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ - ANA_CMPR_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ - ANA_CMPR_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default clock choice */ + ANA_CMPR_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the source clock */ + ANA_CMPR_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the default clock choice */ } soc_periph_ana_cmpr_clk_src_t; //////////////////////////////////////////////////TWAI////////////////////////////////////////////////////////////////// @@ -474,15 +473,15 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of TWAI */ -#define SOC_TWAI_CLKS {(soc_periph_twai_clk_src_t)SOC_MOD_CLK_XTAL, (soc_periph_twai_clk_src_t)SOC_MOD_CLK_PLL_F80M} +#define SOC_TWAI_CLKS {(soc_periph_twai_clk_src_t)SOC_MOD_CLK_XTAL, (soc_periph_twai_clk_src_t)SOC_MOD_CLK_REF_F80M} /** * @brief TWAI clock source */ typedef enum { TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - TWAI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ - TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default clock choice */ + TWAI_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the source clock */ + TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_REF_F80M, /*!< Select REF_F80M as the default clock choice */ } soc_periph_twai_clk_src_t; //////////////////////////////////////////////////MCPWM///////////////////////////////////////////////////////////////// @@ -791,11 +790,11 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of EMAC PTP */ -#define SOC_EMAC_PTP_CLK {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F80M} +#define SOC_EMAC_PTP_CLK {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_REF_F80M} typedef enum { EMAC_PTP_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, - EMAC_PTP_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, + EMAC_PTP_CLK_SRC_REF_F80M = SOC_MOD_CLK_REF_F80M, EMAC_PTP_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, } soc_periph_emac_ptp_clk_src_t; From 0f5ec4d26199859e9f6e82b10a1643517257f6ca Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 26 May 2026 21:10:27 +0800 Subject: [PATCH 5/8] feat(esp_security): support s31 security clock management --- .../esp32/include/hal/sec_ll.h | 26 +++++++++++ .../esp32c2/include/hal/sec_ll.h | 26 +++++++++++ .../esp32c3/include/hal/sec_ll.h | 26 +++++++++++ .../esp32c5/include/hal/sec_ll.h | 39 ++++++++++++++++ .../esp32c6/include/hal/sec_ll.h | 26 +++++++++++ .../esp32c61/include/hal/sec_ll.h | 39 ++++++++++++++++ .../esp32h2/include/hal/sec_ll.h | 41 +++++++++++++++++ .../esp32h21/include/hal/sec_ll.h | 41 +++++++++++++++++ .../esp32h4/include/hal/sec_ll.h | 41 +++++++++++++++++ .../esp32p4/include/hal/sec_ll.h | 41 +++++++++++++++++ .../esp32s2/include/hal/sec_ll.h | 26 +++++++++++ .../esp32s3/include/hal/sec_ll.h | 26 +++++++++++ .../esp32s31/include/hal/sec_ll.h | 39 ++++++++++++++++ components/esp_security/CMakeLists.txt | 2 +- .../esp_security/src/esp32c5/esp_crypto_clk.h | 9 ++-- .../src/esp32c61/esp_crypto_clk.h | 9 ++-- .../esp_security/src/esp32h2/esp_crypto_clk.h | 9 ++-- .../src/esp32h21/esp_crypto_clk.h | 5 +- .../esp_security/src/esp32h4/esp_crypto_clk.h | 5 +- .../esp_security/src/esp32p4/esp_crypto_clk.h | 11 +++-- .../src/esp32s31/esp_crypto_clk.c | 46 +++++++++++++------ .../src/esp32s31/esp_crypto_clk.h | 7 ++- components/esp_system/CMakeLists.txt | 2 +- .../port/soc/esp32s31/system_internal.c | 4 ++ components/espcoredump/src/core_dump_sha.c | 7 ++- 25 files changed, 509 insertions(+), 44 deletions(-) create mode 100644 components/esp_hal_security/esp32/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32c2/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32c3/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32c5/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32c6/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32c61/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32h2/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32h21/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32h4/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32p4/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32s2/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32s3/include/hal/sec_ll.h create mode 100644 components/esp_hal_security/esp32s31/include/hal/sec_ll.h diff --git a/components/esp_hal_security/esp32/include/hal/sec_ll.h b/components/esp_hal_security/esp32/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32c2/include/hal/sec_ll.h b/components/esp_hal_security/esp32c2/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32c2/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32c3/include/hal/sec_ll.h b/components/esp_hal_security/esp32c3/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32c3/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32c5/include/hal/sec_ll.h b/components/esp_hal_security/esp32c5/include/hal/sec_ll.h new file mode 100644 index 00000000000..343bf94582b --- /dev/null +++ b/components/esp_hal_security/esp32c5/include/hal/sec_ll.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, or SOC_MOD_CLK_SPLL) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_SPLL) { + reg_val = 2; + } else { + HAL_ASSERT(false); + } + PCR.sec_conf.sec_clk_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32c6/include/hal/sec_ll.h b/components/esp_hal_security/esp32c6/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32c6/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32c61/include/hal/sec_ll.h b/components/esp_hal_security/esp32c61/include/hal/sec_ll.h new file mode 100644 index 00000000000..343bf94582b --- /dev/null +++ b/components/esp_hal_security/esp32c61/include/hal/sec_ll.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, or SOC_MOD_CLK_SPLL) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_SPLL) { + reg_val = 2; + } else { + HAL_ASSERT(false); + } + PCR.sec_conf.sec_clk_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32h2/include/hal/sec_ll.h b/components/esp_hal_security/esp32h2/include/hal/sec_ll.h new file mode 100644 index 00000000000..bc91058af56 --- /dev/null +++ b/components/esp_hal_security/esp32h2/include/hal/sec_ll.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F64M, or SOC_MOD_CLK_PLL_F96M) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_PLL_F64M) { + reg_val = 2; + } else if (src == SOC_MOD_CLK_PLL_F96M) { + reg_val = 3; + } else { + HAL_ASSERT(false); + } + PCR.sec_conf.sec_clk_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32h21/include/hal/sec_ll.h b/components/esp_hal_security/esp32h21/include/hal/sec_ll.h new file mode 100644 index 00000000000..6d6512bada3 --- /dev/null +++ b/components/esp_hal_security/esp32h21/include/hal/sec_ll.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_X2_F64M, or SOC_MOD_CLK_PLL_F96M) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_XTAL_X2_F64M) { + reg_val = 2; + } else if (src == SOC_MOD_CLK_PLL_F96M) { + reg_val = 3; + } else { + HAL_ASSERT(false); + } + PCR.sec_conf.sec_clk_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32h4/include/hal/sec_ll.h b/components/esp_hal_security/esp32h4/include/hal/sec_ll.h new file mode 100644 index 00000000000..6d6512bada3 --- /dev/null +++ b/components/esp_hal_security/esp32h4/include/hal/sec_ll.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_X2_F64M, or SOC_MOD_CLK_PLL_F96M) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_XTAL_X2_F64M) { + reg_val = 2; + } else if (src == SOC_MOD_CLK_PLL_F96M) { + reg_val = 3; + } else { + HAL_ASSERT(false); + } + PCR.sec_conf.sec_clk_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32p4/include/hal/sec_ll.h b/components/esp_hal_security/esp32p4/include/hal/sec_ll.h new file mode 100644 index 00000000000..a48e5a2d4c7 --- /dev/null +++ b/components/esp_hal_security/esp32p4/include/hal/sec_ll.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F240M, or SOC_MOD_CLK_PLL_F160M) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_PLL_F240M) { + reg_val = 2; + } else if (src == SOC_MOD_CLK_PLL_F160M) { + reg_val = 3; + } else { + HAL_ASSERT(false); + } + HP_SYS_CLKRST.peri_clk_ctrl25.reg_crypto_clk_src_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32s2/include/hal/sec_ll.h b/components/esp_hal_security/esp32s2/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32s2/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32s3/include/hal/sec_ll.h b/components/esp_hal_security/esp32s3/include/hal/sec_ll.h new file mode 100644 index 00000000000..626e6ecefac --- /dev/null +++ b/components/esp_hal_security/esp32s3/include/hal/sec_ll.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "soc/clk_tree_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source + * + * @note Not supported. No-op. + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + (void)src; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_security/esp32s31/include/hal/sec_ll.h b/components/esp_hal_security/esp32s31/include/hal/sec_ll.h new file mode 100644 index 00000000000..dcbc400fe34 --- /dev/null +++ b/components/esp_hal_security/esp32s31/include/hal/sec_ll.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select crypto clock source. + * + * @param src Clock source (SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, or SOC_MOD_CLK_PLL_F240M) + */ +static inline __attribute__((always_inline)) void sec_ll_crypto_clk_src_sel(soc_module_clk_t src) +{ + uint32_t reg_val = 3; + if (src == SOC_MOD_CLK_XTAL) { + reg_val = 0; + } else if (src == SOC_MOD_CLK_RC_FAST) { + reg_val = 1; + } else if (src == SOC_MOD_CLK_PLL_F240M) { + reg_val = 2; + } else { + HAL_ASSERT(false); + } + HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_clk_src_sel = reg_val; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_security/CMakeLists.txt b/components/esp_security/CMakeLists.txt index 9831436a841..fd96e914e4c 100644 --- a/components/esp_security/CMakeLists.txt +++ b/components/esp_security/CMakeLists.txt @@ -9,7 +9,7 @@ endif() set(srcs "") set(requires esp_hal_security) -set(priv_requires esp_hw_support hal efuse) +set(priv_requires esp_hw_support hal efuse esp_hal_clock) set(priv_includes "src/${IDF_TARGET}") if(NOT non_os_build) diff --git a/components/esp_security/src/esp32c5/esp_crypto_clk.h b/components/esp_security/src/esp32c5/esp_crypto_clk.h index caca106b28f..d6d22b90130 100644 --- a/components/esp_security/src/esp32c5/esp_crypto_clk.h +++ b/components/esp_security/src/esp32c5/esp_crypto_clk.h @@ -1,20 +1,19 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/pcr_reg.h" - #pragma once #include +#include "hal/sec_ll.h" +#include "soc/clk_tree_defs.h" void esp_crypto_common_clk_enable(bool enable); static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 480M SPLL clock - REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x2); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_SPLL); } diff --git a/components/esp_security/src/esp32c61/esp_crypto_clk.h b/components/esp_security/src/esp32c61/esp_crypto_clk.h index caca106b28f..d6d22b90130 100644 --- a/components/esp_security/src/esp32c61/esp_crypto_clk.h +++ b/components/esp_security/src/esp32c61/esp_crypto_clk.h @@ -1,20 +1,19 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/pcr_reg.h" - #pragma once #include +#include "hal/sec_ll.h" +#include "soc/clk_tree_defs.h" void esp_crypto_common_clk_enable(bool enable); static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 480M SPLL clock - REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x2); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_SPLL); } diff --git a/components/esp_security/src/esp32h2/esp_crypto_clk.h b/components/esp_security/src/esp32h2/esp_crypto_clk.h index 74f36a220b4..290da917979 100644 --- a/components/esp_security/src/esp32h2/esp_crypto_clk.h +++ b/components/esp_security/src/esp32h2/esp_crypto_clk.h @@ -1,20 +1,19 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/pcr_reg.h" - #pragma once #include +#include "hal/sec_ll.h" +#include "soc/clk_tree_defs.h" void esp_crypto_common_clk_enable(bool enable); static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 96M PLL clock - REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x3); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F96M); } diff --git a/components/esp_security/src/esp32h21/esp_crypto_clk.h b/components/esp_security/src/esp32h21/esp_crypto_clk.h index 14865e0f7c7..1be3fc08d62 100644 --- a/components/esp_security/src/esp32h21/esp_crypto_clk.h +++ b/components/esp_security/src/esp32h21/esp_crypto_clk.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include "soc/soc.h" #include "soc/pcr_reg.h" #include "esp_private/esp_clk_tree_common.h" +#include "hal/sec_ll.h" #pragma once @@ -18,5 +19,5 @@ static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 96M PLL clock esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, true); - REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x3); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F96M); } diff --git a/components/esp_security/src/esp32h4/esp_crypto_clk.h b/components/esp_security/src/esp32h4/esp_crypto_clk.h index cf0a043509f..a39fdfabf09 100644 --- a/components/esp_security/src/esp32h4/esp_crypto_clk.h +++ b/components/esp_security/src/esp32h4/esp_crypto_clk.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include "soc/soc.h" #include "soc/pcr_reg.h" #include "esp_private/esp_clk_tree_common.h" +#include "hal/sec_ll.h" #pragma once @@ -18,5 +19,5 @@ static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 96M PLL clock esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, true); - REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x3); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F96M); } diff --git a/components/esp_security/src/esp32p4/esp_crypto_clk.h b/components/esp_security/src/esp32p4/esp_crypto_clk.h index 694dfa496cd..9c07db3c080 100644 --- a/components/esp_security/src/esp32p4/esp_crypto_clk.h +++ b/components/esp_security/src/esp32p4/esp_crypto_clk.h @@ -1,14 +1,15 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/hp_sys_clkrst_reg.h" -#include "esp_private/esp_clk_tree_common.h" + #pragma once #include +#include "hal/sec_ll.h" +#include "soc/clk_tree_defs.h" +#include "esp_private/esp_clk_tree_common.h" void esp_crypto_common_clk_enable(bool enable); @@ -16,5 +17,5 @@ static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 240M PLL clock esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F240M, true); - REG_SET_FIELD(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_CRYPTO_CLK_SRC_SEL, 0x2); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F240M); } diff --git a/components/esp_security/src/esp32s31/esp_crypto_clk.c b/components/esp_security/src/esp32s31/esp_crypto_clk.c index 172f291e2ae..d54eb26627a 100644 --- a/components/esp_security/src/esp32s31/esp_crypto_clk.c +++ b/components/esp_security/src/esp32s31/esp_crypto_clk.c @@ -4,35 +4,55 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_attr.h" #include "esp_crypto_clk.h" #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_struct.h" +#include "hal/clk_gate_ll.h" +#include "esp_private/esp_clk_tree_common.h" #if !NON_OS_BUILD #include "esp_private/critical_section.h" #endif #if !NON_OS_BUILD DEFINE_CRIT_SECTION_LOCK_STATIC(s_crypto_common_clk_mux); +#define CRYPTO_CLK_LOCK() esp_os_enter_critical_safe(&s_crypto_common_clk_mux) +#define CRYPTO_CLK_UNLOCK() esp_os_exit_critical_safe(&s_crypto_common_clk_mux) +#else +#define CRYPTO_CLK_LOCK() +#define CRYPTO_CLK_UNLOCK() #endif + static int s_crypto_common_clk_ref_cnt; +static void esp_crypto_pll_f240m_enable(bool enable) +{ +#if !NON_OS_BUILD + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F240M, enable); +#else + /* Bootloader: BBPLL is already on; no esp_clk_tree in NON_OS. */ + _clk_gate_ll_ref_240m_clk_en(enable); +#endif +} + +FORCE_INLINE_ATTR void esp_crypto_periph_clk_enable(bool enable) +{ + HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sys_clk_en = enable; + HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sec_clk_en = enable; +} + void esp_crypto_common_clk_enable(bool enable) { -#if !NON_OS_BUILD - esp_os_enter_critical_safe(&s_crypto_common_clk_mux); -#endif + CRYPTO_CLK_LOCK(); if (enable) { if (s_crypto_common_clk_ref_cnt++ == 0) { - HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sys_clk_en = 1; - HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sec_clk_en = 1; - } - } else { - if (s_crypto_common_clk_ref_cnt > 0 && --s_crypto_common_clk_ref_cnt == 0) { - HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sec_clk_en = 0; - HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sys_clk_en = 0; + /* Parent: PLL_F240M (see esp_crypto_clk_init() REG_CRYPTO_CLK_SRC_SEL). */ + esp_crypto_pll_f240m_enable(true); + esp_crypto_periph_clk_enable(true); } + } else if (s_crypto_common_clk_ref_cnt > 0 && --s_crypto_common_clk_ref_cnt == 0) { + esp_crypto_periph_clk_enable(false); + esp_crypto_pll_f240m_enable(false); } -#if !NON_OS_BUILD - esp_os_exit_critical_safe(&s_crypto_common_clk_mux); -#endif + CRYPTO_CLK_UNLOCK(); } diff --git a/components/esp_security/src/esp32s31/esp_crypto_clk.h b/components/esp_security/src/esp32s31/esp_crypto_clk.h index 094e8c7f6da..89a44dbf4e4 100644 --- a/components/esp_security/src/esp32s31/esp_crypto_clk.h +++ b/components/esp_security/src/esp32s31/esp_crypto_clk.h @@ -7,14 +7,13 @@ #pragma once #include -#include "soc/soc.h" -#include "soc/hp_sys_clkrst_reg.h" -#include "soc/hp_sys_clkrst_struct.h" +#include "hal/sec_ll.h" +#include "soc/clk_tree_defs.h" static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 240M PLL clock - REG_SET_FIELD(HP_SYS_CLKRST_CRYPTO_CTRL0_REG, HP_SYS_CLKRST_REG_CRYPTO_CLK_SRC_SEL, 0x2); + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F240M); } void esp_crypto_common_clk_enable(bool enable); diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index cc435662c90..12aa8ff7034 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -89,7 +89,7 @@ else() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include - PRIV_REQUIRES spi_flash esp_timer esp_mm + PRIV_REQUIRES spi_flash esp_timer esp_mm esp_hal_security esp_hal_mspi esp_hal_wdt esp_hal_uart esp_hal_clock esp_hal_dma # [refactor-todo] requirements due to init code, # should be removable once using component init functions diff --git a/components/esp_system/port/soc/esp32s31/system_internal.c b/components/esp_system/port/soc/esp32s31/system_internal.c index 2da0d2b1275..756b1538821 100644 --- a/components/esp_system/port/soc/esp32s31/system_internal.c +++ b/components/esp_system/port/soc/esp32s31/system_internal.c @@ -26,6 +26,7 @@ #endif #include "esp_private/cache_err_int.h" #include "hal/uart_ll.h" +#include "hal/sec_ll.h" #include "esp_memory_utils.h" #define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) @@ -51,6 +52,9 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_EN); SET_PERI_REG_MASK(HP_SYSTEM_ECC_MEM_LP_CTRL_REG, HP_SYSTEM_ECC_MEM_LP_FORCE_CTRL); + // Reset the clock source selection to an always-on source (XTAL), otherwise if the clock source + // is disabled, will get stuck in ROM encryption related ops. + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_XTAL); } static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) diff --git a/components/espcoredump/src/core_dump_sha.c b/components/espcoredump/src/core_dump_sha.c index fd41dfa7a78..3e68870847d 100644 --- a/components/espcoredump/src/core_dump_sha.c +++ b/components/espcoredump/src/core_dump_sha.c @@ -1,12 +1,14 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "sdkconfig.h" #include +#include "hal/sec_ll.h" #include "esp_core_dump_types.h" +#include "esp_crypto_periph_clk.h" const static char TAG[] __attribute__((unused)) = "esp_core_dump_sha"; @@ -40,6 +42,9 @@ static void core_dump_sha256_finish(core_dump_sha_ctx_t *sha_ctx) static void core_dump_sha256_start(core_dump_sha_ctx_t *sha_ctx) { + /* Back to always on clock source since the crypto clock source selected in + esp_crypto_clk_init may be disabled */ + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_XTAL); /* Enable SHA hardware */ ets_sha_enable(); ets_sha_init(&sha_ctx->ctx, SHA2_256); From d25d49d307ff04ec88bcf68e3ddd915e17984c47 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 21 Jul 2026 21:29:36 +0800 Subject: [PATCH 6/8] feat(esp_security): make esp32s31 on-demand crypto clock management optional --- components/esp_security/Kconfig | 17 ++++++++++ .../src/esp32s31/esp_crypto_clk.c | 32 +++++++++++++++++-- .../src/esp32s31/esp_crypto_clk.h | 9 ++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/components/esp_security/Kconfig b/components/esp_security/Kconfig index feadfe56a2f..c9784ffdf41 100644 --- a/components/esp_security/Kconfig +++ b/components/esp_security/Kconfig @@ -1,5 +1,22 @@ menu "ESP Security Specific" + config ESP_CRYPTO_CLK_ON_DEMAND + bool "Enable on-demand crypto clock management" + depends on IDF_TARGET_ESP32S31 + default y if PM_ENABLE + default n + help + When enabled, crypto/security peripheral clocks and their parent + (PLL_F240M) are enabled only while crypto operations are in + progress and disabled afterwards, reducing power consumption. + + Enabling and disabling these clocks has a noticeable performance + cost for crypto operations. When this option is disabled (default), + crypto clocks remain always on after initialization for better + crypto performance. + + Defaults to enabled when Power Management (CONFIG_PM_ENABLE) is on. + menu "Crypto DPA Protection" depends on SOC_CRYPTO_DPA_PROTECTION_SUPPORTED config ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP diff --git a/components/esp_security/src/esp32s31/esp_crypto_clk.c b/components/esp_security/src/esp32s31/esp_crypto_clk.c index d54eb26627a..a12cb869886 100644 --- a/components/esp_security/src/esp32s31/esp_crypto_clk.c +++ b/components/esp_security/src/esp32s31/esp_crypto_clk.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "sdkconfig.h" #include "esp_attr.h" #include "esp_crypto_clk.h" #include "soc/clk_tree_defs.h" @@ -23,8 +24,6 @@ DEFINE_CRIT_SECTION_LOCK_STATIC(s_crypto_common_clk_mux); #define CRYPTO_CLK_UNLOCK() #endif -static int s_crypto_common_clk_ref_cnt; - static void esp_crypto_pll_f240m_enable(bool enable) { #if !NON_OS_BUILD @@ -41,6 +40,10 @@ FORCE_INLINE_ATTR void esp_crypto_periph_clk_enable(bool enable) HP_SYS_CLKRST.crypto_ctrl0.reg_crypto_sec_clk_en = enable; } +#if CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + +static int s_crypto_common_clk_ref_cnt; + void esp_crypto_common_clk_enable(bool enable) { CRYPTO_CLK_LOCK(); @@ -56,3 +59,28 @@ void esp_crypto_common_clk_enable(bool enable) } CRYPTO_CLK_UNLOCK(); } + +#else /* !CONFIG_ESP_CRYPTO_CLK_ON_DEMAND */ + +static bool s_crypto_clk_always_on_done; + +static void esp_crypto_clk_always_on(void) +{ + CRYPTO_CLK_LOCK(); + if (!s_crypto_clk_always_on_done) { + esp_crypto_pll_f240m_enable(true); + esp_crypto_periph_clk_enable(true); + s_crypto_clk_always_on_done = true; + } + CRYPTO_CLK_UNLOCK(); +} + +void esp_crypto_common_clk_enable(bool enable) +{ + /* Keep clocks always on: enable once, ignore disable. */ + if (enable) { + esp_crypto_clk_always_on(); + } +} + +#endif /* CONFIG_ESP_CRYPTO_CLK_ON_DEMAND */ diff --git a/components/esp_security/src/esp32s31/esp_crypto_clk.h b/components/esp_security/src/esp32s31/esp_crypto_clk.h index 89a44dbf4e4..25c3b3f80c2 100644 --- a/components/esp_security/src/esp32s31/esp_crypto_clk.h +++ b/components/esp_security/src/esp32s31/esp_crypto_clk.h @@ -7,13 +7,18 @@ #pragma once #include +#include "sdkconfig.h" #include "hal/sec_ll.h" #include "soc/clk_tree_defs.h" +void esp_crypto_common_clk_enable(bool enable); + static inline void esp_crypto_clk_init(void) { // Set crypto clock (`clk_sec`) to use 240M PLL clock sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F240M); +#if !CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + /* Keep crypto clocks always on for better crypto performance. */ + esp_crypto_common_clk_enable(true); +#endif } - -void esp_crypto_common_clk_enable(bool enable); From 175cf9a521ea2068a897097c8c7beb67e06a317c Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 3 Aug 2026 20:00:14 +0800 Subject: [PATCH 7/8] feat(bootloader): use CPLL/4 as flash default 80M clock source --- .../bootloader_flash/src/bootloader_flash_config_esp32s31.c | 4 ++-- components/esp_hal_mspi/esp32s31/include/hal/mspi_ll.h | 2 +- components/soc/esp32s31/include/soc/clk_tree_defs.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c index f602074bb63..f9ac78c2b1a 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32s31.c @@ -47,9 +47,9 @@ void IRAM_ATTR bootloader_flash_cs_timing_config(void) void IRAM_ATTR bootloader_init_mspi_clock(void) { cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); - clk_ll_bbpll_enable(); + clk_ll_cpll_enable(); _mspi_timing_ll_set_flash_core_clock(0, 80); - _mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_BBPLL); + _mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_CPLL); cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); } 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 d58f5f8fad5..dabe3a8868f 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 6 +#define MSPI_TIMING_LL_FLASH_CORE_80M_CLK_DIV 4 // PSRAM frequency should be constrained by AXI frequency to avoid FIFO underflow. #define MSPI_TIMING_LL_PSRAM_FREQ_AXI_CONSTRAINED 1 diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index 4504a342eef..6c5119db2fc 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -405,7 +405,7 @@ typedef enum { * @brief Type of FLASH clock source. */ typedef enum { - FLASH_CLK_SRC_DEFAULT = SOC_MOD_CLK_BBPLL, /*!< Select SOC_MOD_CLK_BBPLL as FLASH source clock */ + FLASH_CLK_SRC_DEFAULT = SOC_MOD_CLK_CPLL, /*!< Select SOC_MOD_CLK_CPLL as FLASH source clock */ FLASH_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select SOC_MOD_CLK_XTAL as FLASH source clock */ FLASH_CLK_SRC_CPLL = SOC_MOD_CLK_CPLL, /*!< Select SOC_MOD_CLK_CPLL as FLASH source clock */ FLASH_CLK_SRC_BBPLL = SOC_MOD_CLK_BBPLL, /*!< Select SOC_MOD_CLK_BBPLL as FLASH source clock */ From 4ffb72cbc14df8f52895a6c0260662229a7fa370 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 10 Aug 2026 16:56:53 +0800 Subject: [PATCH 8/8] 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 | 188 +++++++++--------- 13 files changed, 237 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 7e386382b70..1cf9202c35f 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 28eb74ad292..4a85d745edf 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 5cbaf821e74..b08f493c1bb 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_init.c +++ b/components/esp_hw_support/port/esp32s31/pmu_init.c @@ -67,7 +67,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 9476b24a774..aa3bdceb3ac 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,56 @@ 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); +#ifndef BOOTLOADER_BUILD + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); +#endif +} + +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) { @@ -667,3 +674,4 @@ IRAM_ATTR uint32_t rtc_clk_mpll_get_freq(void) { return s_cur_mpll_freq; } +#endif