From df77b4bd388af5b8a399444aff82e567d82a9f7c Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 13 Jul 2026 10:49:42 +0800 Subject: [PATCH] feat(esp_hw_support): support esp32h4/h21 clk tree management --- .../esp32h21/include/hal/clk_gate_ll.h | 73 ++-- .../port/esp32h21/esp_clk_tree.c | 333 +++++++++++++----- .../port/esp32h4/esp_clk_tree.c | 331 ++++++++++++----- .../soc/esp32h21/include/soc/clk_tree_defs.h | 3 + .../soc/esp32h21/register/soc/pcr_reg.h | 74 ++-- .../soc/esp32h21/register/soc/pcr_struct.h | 26 +- .../soc/esp32h4/include/soc/clk_tree_defs.h | 4 +- 7 files changed, 581 insertions(+), 263 deletions(-) diff --git a/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h index 09076939eed..46fa489cb6e 100644 --- a/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h @@ -24,16 +24,40 @@ extern "C" { #endif /** - * Enable or disable the clock gate for ref_40m. + * Enable or disable the clock gate for ref_8m. * @param enable Enable / disable */ -FORCE_INLINE_ATTR void _clk_gate_ll_ref_40m_clk_en(bool enable) +FORCE_INLINE_ATTR void _clk_gate_ll_ref_8m_clk_en(bool enable) { - PCR.pll_div_clk_en.pll_40m_clk_en = enable; + PCR.pll_div_clk_en.pll_8m_clk_en = enable; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define clk_gate_ll_ref_40m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_40m_clk_en(__VA_ARGS__) +#define clk_gate_ll_ref_8m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_8m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_16m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_16m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_16m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_16m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_16m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_32m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_32m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_32m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_32m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_32m_clk_en(__VA_ARGS__) /** * Enable or disable the clock gate for ref_48m. @@ -48,53 +72,28 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_48m_clk_en(bool enable) #define clk_gate_ll_ref_48m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_48m_clk_en(__VA_ARGS__) /** - * Enable or disable the clock gate for ref_80m. + * Enable or disable the clock gate for ref_64m. * @param enable Enable / disable */ -FORCE_INLINE_ATTR void _clk_gate_ll_ref_80m_clk_en(bool enable) +FORCE_INLINE_ATTR void _clk_gate_ll_ref_64m_clk_en(bool enable) { - PCR.pll_div_clk_en.pll_80m_clk_en = enable; + PCR.pll_div_clk_en.pll_64m_clk_en = enable; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define clk_gate_ll_ref_80m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_80m_clk_en(__VA_ARGS__) +#define clk_gate_ll_ref_64m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_64m_clk_en(__VA_ARGS__) /** - * Enable or disable the clock gate for ref_120m. + * Enable or disable the clock gate for ref_96m. * @param enable Enable / disable */ -FORCE_INLINE_ATTR void _clk_gate_ll_ref_120m_clk_en(bool enable) +FORCE_INLINE_ATTR void _clk_gate_ll_ref_96m_clk_en(bool enable) { - PCR.pll_div_clk_en.pll_120m_clk_en = enable; + PCR.pll_div_clk_en.pll_96m_clk_en = enable; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define clk_gate_ll_ref_120m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_120m_clk_en(__VA_ARGS__) - -/** - * Enable or disable the clock gate for ref_160m. - * @param enable Enable / disable - */ -FORCE_INLINE_ATTR void _clk_gate_ll_ref_160m_clk_en(bool enable) -{ - PCR.pll_div_clk_en.pll_160m_clk_en = enable; -} -/// use a macro to wrap the function, force the caller to use it in a critical section -/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define clk_gate_ll_ref_160m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_160m_clk_en(__VA_ARGS__) - -/** - * Enable or disable the clock gate for ref_240m. - * @param enable Enable / disable - */ -FORCE_INLINE_ATTR void _clk_gate_ll_ref_240m_clk_en(bool enable) -{ - PCR.pll_div_clk_en.pll_240m_clk_en = enable; -} -/// use a macro to wrap the function, force the caller to use it in a critical section -/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define clk_gate_ll_ref_240m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_240m_clk_en(__VA_ARGS__) - +#define clk_gate_ll_ref_96m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_96m_clk_en(__VA_ARGS__) /** * @brief Configuration structure for peripheral clock gate settings */ 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 b06f0bb66db..e57419eb7fb 100644 --- a/components/esp_hw_support/port/esp32h21/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32h21/esp_clk_tree.c @@ -5,23 +5,123 @@ */ #include -#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" +#include "esp_rom_sys.h" #include "soc/rtc.h" +#include "soc/reset_reasons.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/periph_ctrl.h" +#include "esp_private/critical_section.h" ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree"); -static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; +/* -------------------------------------------------------------------------- */ +/* Fixed ref clocks: gate + static parent power */ +/* -------------------------------------------------------------------------- */ + +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_xtal_x2(bool enable) +{ + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, 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_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_XTAL_X2: + clk_ll_xtal_x2_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_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_XTAL_X2: + clk_ll_xtal_x2_disable(); + break; + default: + break; + } + } + esp_os_exit_critical(&s_clk_tree_spinlock); + return prev; +} 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) + uint32_t *freq_value) { ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); ESP_RETURN_ON_FALSE(precision < ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown precision"); @@ -38,9 +138,11 @@ uint32_t *freq_value) case SOC_MOD_CLK_PLL_F48M: clk_src_freq = CLK_LL_PLL_48M_FREQ_MHZ * MHZ; break; + case SOC_MOD_CLK_XTAL_X2: case SOC_MOD_CLK_XTAL_X2_F64M: clk_src_freq = CLK_LL_PLL_64M_FREQ_MHZ * MHZ; break; + case SOC_MOD_CLK_BBPLL: case SOC_MOD_CLK_PLL_F96M: clk_src_freq = CLK_LL_PLL_96M_FREQ_MHZ * MHZ; break; @@ -67,119 +169,174 @@ uint32_t *freq_value) esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value) { - (void)clk_src; (void)expt_freq_value; (void)ret_freq_value; + ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); + ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency"); + + (void)ret_freq_value; return ESP_ERR_NOT_SUPPORTED; } -static int16_t s_xtal_x2_ref_cnt = 0; -static int16_t s_bbpll_ref_cnt = 0; - void esp_clk_tree_initialize(void) { - // Power - // In bootloader, flash clock source will always be switched to use XTAL_X2 clock - s_xtal_x2_ref_cnt++; - soc_cpu_clk_src_t cpu_clk_src_btld = clk_ll_cpu_get_src(); - if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_XTAL_X2) { - s_xtal_x2_ref_cnt++; - } else if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_PLL) { - s_bbpll_ref_cnt++; + soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + soc_cpu_clk_src_t cpu_src = clk_ll_cpu_get_src(); + bool cpu_reset = (rst_reason == RESET_REASON_CPU0_MWDT0) || (rst_reason == RESET_REASON_CPU0_MWDT1) || + (rst_reason == RESET_REASON_CPU0_SW) || (rst_reason == RESET_REASON_CPU0_RTC_WDT) || + (rst_reason == RESET_REASON_CPU0_JTAG); + if (!cpu_reset) { + /* Cold boot only: gate / power-down clocks not in use. + * Flash MSPI defaults to XTAL_X2_F64M — keep that root/gate alive. */ + _clk_gate_ll_ref_8m_clk_en(false); + _clk_gate_ll_ref_16m_clk_en(false); + _clk_gate_ll_ref_32m_clk_en(false); + _clk_gate_ll_ref_96m_clk_en(false); +#if CONFIG_USJ_ENABLE_USB_SERIAL_JTAG || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + /* Keep BBPLL / ref_48m: USJ PHY still uses them after bootloader. */ +#else + _clk_gate_ll_ref_48m_clk_en(false); + if (cpu_src != SOC_CPU_CLK_SRC_PLL) { + clk_ll_bbpll_disable(); + } +#endif } - // Gating - // PLL_F64M ++ for MSPI -} - -bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) -{ - if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2) { - return s_xtal_x2_ref_cnt > 0; + s_clk_tree_initialized = true; +#if CONFIG_USJ_ENABLE_USB_SERIAL_JTAG || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + /* Bootloader / USJ may keep PLL_F48M on; declare a permanent hold. */ + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F48M, true); +#endif + /* Flash + CPU: sync clk_tree refs with HW already selected at boot. + * Flash uses gated F64M; CPU holds the ungated XTAL_X2 / PLL root, not the F64M / F96M gates. */ + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2_F64M, true); + if (cpu_src == SOC_CPU_CLK_SRC_PLL) { + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); + } else if (cpu_src == SOC_CPU_CLK_SRC_XTAL_X2) { + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, true); } - if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL) { - return s_bbpll_ref_cnt > 0; - } - return false; } 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_XTAL_X2: - if (enable) { - s_xtal_x2_ref_cnt++; - } else { - s_xtal_x2_ref_cnt--; - } - - if (s_xtal_x2_ref_cnt == 1) { - clk_ll_xtal_x2_enable(); - toggled = true; - } else if (s_xtal_x2_ref_cnt == 0) { - clk_ll_xtal_x2_disable(); - toggled = true; - } - - assert(s_xtal_x2_ref_cnt >= 0); - break; case SOC_ROOT_CIRCUIT_CLK_BBPLL: + case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: { if (enable) { - s_bbpll_ref_cnt++; + toggled = (esp_clk_tree_root_pll_power_acquire(clk_circuit) == 0); } else { - s_bbpll_ref_cnt--; + toggled = (esp_clk_tree_root_pll_power_release(clk_circuit) == 1); } - - // Note that a calibration is usually needed after enabling BBPLL - if (s_bbpll_ref_cnt == 1) { - clk_ll_bbpll_enable(); - toggled = true; - } else if (s_bbpll_ref_cnt == 0) { - clk_ll_bbpll_disable(); - toggled = true; - } - - assert(s_bbpll_ref_cnt >= 0); break; + } default: break; } - return toggled; // TODO: PM-653 + return toggled; +} + +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_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_F48M, + ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M, + ESP_CLK_TREE_GATED_CLK_PLL_F96M, + 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 }, // TODO: PM-859 + [ESP_CLK_TREE_GATED_CLK_PLL_F48M] = { SOC_MOD_CLK_PLL_F48M, _clk_gate_ll_ref_48m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M] = { SOC_MOD_CLK_XTAL_X2_F64M, _clk_gate_ll_ref_64m_clk_en, esp_clk_tree_parent_xtal_x2 }, + [ESP_CLK_TREE_GATED_CLK_PLL_F96M] = { SOC_MOD_CLK_PLL_F96M, _clk_gate_ll_ref_96m_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; + 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; + 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 (released_too_many) { + ESP_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", entry->clk_id); + } + 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; } - 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); - return ESP_OK; - } + + if (!s_clk_tree_initialized) { + 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_XTAL_X2_F64M: - // later, here should handle ref count for XTAL_X2_F64M clock gating, then also handle XTAL_X2 circuit enable/disable - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable); - break; - // case SOC_MOD_CLK_PLL_FxxM: - // bool truly_toggled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, enable); - // if (enable && truly_toggled) { - // ESP_LOGW(TAG, "BBPLL enabled, a calibration may be needed"); - // } - default: - break; - } + + esp_clk_tree_gated_clk_id_t gated_clk_id; + switch (clk_src) { + case SOC_MOD_CLK_XTAL_X2: + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable); + 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_RC_FAST: gated_clk_id = ESP_CLK_TREE_GATED_CLK_RC_FAST; break; + case SOC_MOD_CLK_PLL_F48M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F48M; break; + case SOC_MOD_CLK_XTAL_X2_F64M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M; break; + case SOC_MOD_CLK_PLL_F96M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F96M; break; + default: + 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/esp32h4/esp_clk_tree.c b/components/esp_hw_support/port/esp32h4/esp_clk_tree.c index c58a183f8b6..c23db583f39 100644 --- a/components/esp_hw_support/port/esp32h4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32h4/esp_clk_tree.c @@ -5,23 +5,123 @@ */ #include -#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" +#include "esp_rom_sys.h" #include "soc/rtc.h" +#include "soc/reset_reasons.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/periph_ctrl.h" +#include "esp_private/critical_section.h" ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree"); -static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; +/* -------------------------------------------------------------------------- */ +/* Fixed ref clocks: gate + static parent power */ +/* -------------------------------------------------------------------------- */ + +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_xtal_x2(bool enable) +{ + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, 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_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_XTAL_X2: + clk_ll_xtal_x2_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_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_XTAL_X2: + clk_ll_xtal_x2_disable(); + break; + default: + break; + } + } + esp_os_exit_critical(&s_clk_tree_spinlock); + return prev; +} 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) + uint32_t *freq_value) { ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); ESP_RETURN_ON_FALSE(precision < ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown precision"); @@ -41,9 +141,11 @@ uint32_t *freq_value) case SOC_MOD_CLK_PLL_F48M: clk_src_freq = CLK_LL_PLL_48M_FREQ_MHZ * MHZ; break; + case SOC_MOD_CLK_XTAL_X2: case SOC_MOD_CLK_XTAL_X2_F64M: clk_src_freq = CLK_LL_PLL_64M_FREQ_MHZ * MHZ; break; + case SOC_MOD_CLK_BBPLL: case SOC_MOD_CLK_PLL_F96M: clk_src_freq = CLK_LL_PLL_96M_FREQ_MHZ * MHZ; break; @@ -70,122 +172,177 @@ uint32_t *freq_value) esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value) { - (void)clk_src; (void)expt_freq_value; (void)ret_freq_value; + ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); + ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency"); + + (void)ret_freq_value; return ESP_ERR_NOT_SUPPORTED; } -static int16_t s_xtal_x2_ref_cnt = 0; -static int16_t s_bbpll_ref_cnt = 0; void esp_clk_tree_initialize(void) { - // Power - // In bootloader, flash clock source will always be switched to use XTAL_X2 clock - s_xtal_x2_ref_cnt++; - soc_cpu_clk_src_t cpu_clk_src_btld = clk_ll_cpu_get_src(); - if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_XTAL_X2) { - s_xtal_x2_ref_cnt++; - } else if (cpu_clk_src_btld == SOC_CPU_CLK_SRC_PLL) { - s_bbpll_ref_cnt++; + soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + soc_cpu_clk_src_t cpu_src = clk_ll_cpu_get_src(); + bool cpu_reset = (rst_reason == RESET_REASON_CPU0_MWDT0) || (rst_reason == RESET_REASON_CPU0_MWDT1) || + (rst_reason == RESET_REASON_CPU0_SW) || (rst_reason == RESET_REASON_CPU0_RTC_WDT) || + (rst_reason == RESET_REASON_CPU0_JTAG) || (rst_reason == RESET_REASON_CPU_LOCKUP); + if (!cpu_reset) { + /* Cold boot only: gate / power-down clocks not in use. + * Flash MSPI defaults to XTAL_X2_F64M — keep that root/gate alive. */ + _clk_gate_ll_ref_8m_clk_en(false); + _clk_gate_ll_ref_16m_clk_en(false); + _clk_gate_ll_ref_32m_clk_en(false); + _clk_gate_ll_ref_96m_clk_en(false); +#if CONFIG_USJ_ENABLE_USB_SERIAL_JTAG || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + /* Keep BBPLL / ref_48m: USJ PHY still uses them after bootloader. */ +#else + _clk_gate_ll_ref_48m_clk_en(false); + if (cpu_src != SOC_CPU_CLK_SRC_PLL) { + clk_ll_bbpll_disable(); + } +#endif } - // Gating - // PLL_F64M ++ for MSPI -} - -bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) -{ - if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_XTAL_X2) { - return s_xtal_x2_ref_cnt > 0; + s_clk_tree_initialized = true; +#if CONFIG_USJ_ENABLE_USB_SERIAL_JTAG || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + /* Bootloader / USJ may keep PLL_F48M on; declare a permanent hold. */ + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F48M, true); +#endif + /* Flash + CPU: sync clk_tree refs with HW already selected at boot. + * Flash uses gated F64M; CPU holds the ungated XTAL_X2 / PLL root, not the F64M / F96M gates. */ + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2_F64M, true); + if (cpu_src == SOC_CPU_CLK_SRC_PLL) { + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); + } else if (cpu_src == SOC_CPU_CLK_SRC_XTAL_X2) { + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, true); } - if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL) { - return s_bbpll_ref_cnt > 0; - } - return false; } 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_XTAL_X2: - if (enable) { - s_xtal_x2_ref_cnt++; - } else { - s_xtal_x2_ref_cnt--; - } - - if (s_xtal_x2_ref_cnt == 1) { - clk_ll_xtal_x2_enable(); - toggled = true; - } else if (s_xtal_x2_ref_cnt == 0) { - clk_ll_xtal_x2_disable(); - toggled = true; - } - - assert(s_xtal_x2_ref_cnt >= 0); - break; case SOC_ROOT_CIRCUIT_CLK_BBPLL: + case SOC_ROOT_CIRCUIT_CLK_XTAL_X2: { if (enable) { - s_bbpll_ref_cnt++; + toggled = (esp_clk_tree_root_pll_power_acquire(clk_circuit) == 0); } else { - s_bbpll_ref_cnt--; + toggled = (esp_clk_tree_root_pll_power_release(clk_circuit) == 1); } - - // Note that a calibration is usually needed after enabling BBPLL - if (s_bbpll_ref_cnt == 1) { - clk_ll_bbpll_enable(); - toggled = true; - } else if (s_bbpll_ref_cnt == 0) { - clk_ll_bbpll_disable(); - toggled = true; - } - - assert(s_bbpll_ref_cnt >= 0); break; + } default: break; } return toggled; } -esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) +bool esp_clk_tree_port_is_power_on(soc_root_clk_circuit_t clk_circuit) { - if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) { - // some conditions is legal, e.g. -1 means external clock source - return ESP_OK; + if (clk_circuit >= SOC_ROOT_CIRCUIT_CLK_MAX) { + return false; } - int16_t prev_ref_cnt = 0; + if (clk_circuit == SOC_ROOT_CIRCUIT_CLK_BBPLL || 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_XTAL_X2_F32M, + ESP_CLK_TREE_GATED_CLK_PLL_F48M, + ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M, + ESP_CLK_TREE_GATED_CLK_PLL_F96M, + 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 }, // TODO: PM-859 + [ESP_CLK_TREE_GATED_CLK_XTAL_X2_F32M] = { SOC_MOD_CLK_XTAL_X2_F32M, _clk_gate_ll_ref_32m_clk_en, esp_clk_tree_parent_xtal_x2 }, + [ESP_CLK_TREE_GATED_CLK_PLL_F48M] = { SOC_MOD_CLK_PLL_F48M, _clk_gate_ll_ref_48m_clk_en, esp_clk_tree_parent_bbpll }, + [ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M] = { SOC_MOD_CLK_XTAL_X2_F64M, _clk_gate_ll_ref_64m_clk_en, esp_clk_tree_parent_xtal_x2 }, + [ESP_CLK_TREE_GATED_CLK_PLL_F96M] = { SOC_MOD_CLK_PLL_F96M, _clk_gate_ll_ref_96m_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; + bool released_too_many = false; + + esp_os_enter_critical(&s_clk_tree_spinlock); if (enable) { - prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1); + 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 = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1); + prev_ref_cnt = s_mod_clk_gate_ref_cnt[entry->clk_id]--; 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); - return ESP_OK; + s_mod_clk_gate_ref_cnt[entry->clk_id] = 0; + 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); + } } } - 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_XTAL_X2_F32M: - // later, here should handle ref count for XTAL_X2_F32M clock gating, then also handle XTAL_X2 circuit enable/disable - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable); - break; - case SOC_MOD_CLK_XTAL_X2_F64M: - // later, here should handle ref count for XTAL_X2_F64M clock gating, then also handle XTAL_X2 circuit enable/disable - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable); - break; - // case SOC_MOD_CLK_PLL_FxxM: - // bool truly_toggled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, enable); - // if (enable && truly_toggled) { - // ESP_LOGW(TAG, "BBPLL enabled, a calibration may be needed"); - // } - default: - break; - } + esp_os_exit_critical(&s_clk_tree_spinlock); + + if (released_too_many) { + ESP_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", entry->clk_id); } 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 || clk_src == SOC_MOD_CLK_XTAL) { + /* Not managed by esp_clk_tree */ + return ESP_OK; + } + + if (!s_clk_tree_initialized) { + return ESP_OK; + } + + esp_clk_tree_gated_clk_id_t gated_clk_id; + switch (clk_src) { + case SOC_MOD_CLK_XTAL_X2: + esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable); + 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_RC_FAST: gated_clk_id = ESP_CLK_TREE_GATED_CLK_RC_FAST; break; + case SOC_MOD_CLK_XTAL_X2_F32M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_XTAL_X2_F32M; break; + case SOC_MOD_CLK_PLL_F48M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F48M; break; + case SOC_MOD_CLK_XTAL_X2_F64M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_XTAL_X2_F64M; break; + case SOC_MOD_CLK_PLL_F96M: gated_clk_id = ESP_CLK_TREE_GATED_CLK_PLL_F96M; break; + default: + return ESP_OK; + } + return esp_clk_tree_enable_gated_clk(&s_gated_ref_clks[gated_clk_id], enable); +} diff --git a/components/soc/esp32h21/include/soc/clk_tree_defs.h b/components/soc/esp32h21/include/soc/clk_tree_defs.h index 49bd843a378..b6f67ecf1dd 100644 --- a/components/soc/esp32h21/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h21/include/soc/clk_tree_defs.h @@ -69,6 +69,7 @@ typedef enum { typedef enum { SOC_ROOT_CIRCUIT_CLK_BBPLL, /*!< BBPLL_CLK is the output of the PLL generator circuit */ SOC_ROOT_CIRCUIT_CLK_XTAL_X2, /*!< XTAL_X2_CLK is the output of the XTAL_X2 generator circuit */ + SOC_ROOT_CIRCUIT_CLK_MAX, } soc_root_clk_circuit_t; /** @@ -140,6 +141,8 @@ typedef enum { SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 32MHz crystal */ + SOC_MOD_CLK_XTAL_X2, /*!< XTAL_X2_CLK is the output of the XTAL_X2 generator circuit (64MHz); CPU clock source, not the gated F64M */ + SOC_MOD_CLK_BBPLL, /*!< BBPLL_CLK is the output of the PLL generator circuit (96MHz); CPU clock source, not the gated F96M */ SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */ } soc_module_clk_t; diff --git a/components/soc/esp32h21/register/soc/pcr_reg.h b/components/soc/esp32h21/register/soc/pcr_reg.h index f0edf36b7df..f26feba92ae 100644 --- a/components/soc/esp32h21/register/soc/pcr_reg.h +++ b/components/soc/esp32h21/register/soc/pcr_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -1947,54 +1947,54 @@ extern "C" { * SPLL DIV clock-gating configuration register */ #define PCR_PLL_DIV_CLK_EN_REG (DR_REG_PCR_BASE + 0x124) -/** PCR_PLL_240M_CLK_EN : R/W; bitpos: [0]; default: 1; +/** PCR_PLL_96M_CLK_EN : R/W; bitpos: [0]; default: 1; * This field is used to open 96 MHz clock (SPLL) driven from SPLL. 0: close, 1: * open(default). Only available when high-speed clock-source SPLL is active. */ -#define PCR_PLL_240M_CLK_EN (BIT(0)) -#define PCR_PLL_240M_CLK_EN_M (PCR_PLL_240M_CLK_EN_V << PCR_PLL_240M_CLK_EN_S) -#define PCR_PLL_240M_CLK_EN_V 0x00000001U -#define PCR_PLL_240M_CLK_EN_S 0 -/** PCR_PLL_160M_CLK_EN : R/W; bitpos: [1]; default: 1; - * This field is used to open 64 MHz clock (div3 of SPLL) driven from SPLL. 0: close, +#define PCR_PLL_96M_CLK_EN (BIT(0)) +#define PCR_PLL_96M_CLK_EN_M (PCR_PLL_96M_CLK_EN_V << PCR_PLL_96M_CLK_EN_S) +#define PCR_PLL_96M_CLK_EN_V 0x00000001U +#define PCR_PLL_96M_CLK_EN_S 0 +/** PCR_PLL_64M_CLK_EN : R/W; bitpos: [1]; default: 1; + * This field is used to open 64 MHz clock (XTALX2) driven from XTALX2. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ -#define PCR_PLL_160M_CLK_EN (BIT(1)) -#define PCR_PLL_160M_CLK_EN_M (PCR_PLL_160M_CLK_EN_V << PCR_PLL_160M_CLK_EN_S) -#define PCR_PLL_160M_CLK_EN_V 0x00000001U -#define PCR_PLL_160M_CLK_EN_S 1 -/** PCR_PLL_120M_CLK_EN : R/W; bitpos: [2]; default: 1; - * This field is used to open 48 MHz clock (div4 of SPLL) driven from SPLL. 0: close, +#define PCR_PLL_64M_CLK_EN (BIT(1)) +#define PCR_PLL_64M_CLK_EN_M (PCR_PLL_64M_CLK_EN_V << PCR_PLL_64M_CLK_EN_S) +#define PCR_PLL_64M_CLK_EN_V 0x00000001U +#define PCR_PLL_64M_CLK_EN_S 1 +/** PCR_PLL_48M_CLK_EN : R/W; bitpos: [2]; default: 1; + * This field is used to open 48 MHz clock (div2 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ -#define PCR_PLL_120M_CLK_EN (BIT(2)) -#define PCR_PLL_120M_CLK_EN_M (PCR_PLL_120M_CLK_EN_V << PCR_PLL_120M_CLK_EN_S) -#define PCR_PLL_120M_CLK_EN_V 0x00000001U -#define PCR_PLL_120M_CLK_EN_S 2 -/** PCR_PLL_80M_CLK_EN : R/W; bitpos: [3]; default: 1; - * This field is used to open 32 MHz clock (div6 of SPLL) driven from SPLL. 0: close, - * 1: open(default). Only available when high-speed clock-source SPLL is active. - */ -#define PCR_PLL_80M_CLK_EN (BIT(3)) -#define PCR_PLL_80M_CLK_EN_M (PCR_PLL_80M_CLK_EN_V << PCR_PLL_80M_CLK_EN_S) -#define PCR_PLL_80M_CLK_EN_V 0x00000001U -#define PCR_PLL_80M_CLK_EN_S 3 -/** PCR_PLL_48M_CLK_EN : R/W; bitpos: [4]; default: 1; - * This field is used to open 16 MHz clock (div10 of SPLL) driven from SPLL. 0: close, - * 1: open(default). Only available when high-speed clock-source SPLL is active. - */ -#define PCR_PLL_48M_CLK_EN (BIT(4)) +#define PCR_PLL_48M_CLK_EN (BIT(2)) #define PCR_PLL_48M_CLK_EN_M (PCR_PLL_48M_CLK_EN_V << PCR_PLL_48M_CLK_EN_S) #define PCR_PLL_48M_CLK_EN_V 0x00000001U -#define PCR_PLL_48M_CLK_EN_S 4 -/** PCR_PLL_40M_CLK_EN : R/W; bitpos: [5]; default: 1; +#define PCR_PLL_48M_CLK_EN_S 2 +/** PCR_PLL_32M_CLK_EN : R/W; bitpos: [3]; default: 1; + * This field is used to open 32 MHz clock (div2 of XTALX2) driven from XTALX2. 0: close, + * 1: open(default). Only available when high-speed clock-source SPLL is active. + */ +#define PCR_PLL_32M_CLK_EN (BIT(3)) +#define PCR_PLL_32M_CLK_EN_M (PCR_PLL_32M_CLK_EN_V << PCR_PLL_32M_CLK_EN_S) +#define PCR_PLL_32M_CLK_EN_V 0x00000001U +#define PCR_PLL_32M_CLK_EN_S 3 +/** PCR_PLL_16M_CLK_EN : R/W; bitpos: [4]; default: 1; + * This field is used to open 16 MHz clock (div6 of SPLL) driven from SPLL. 0: close, + * 1: open(default). Only available when high-speed clock-source SPLL is active. + */ +#define PCR_PLL_16M_CLK_EN (BIT(4)) +#define PCR_PLL_16M_CLK_EN_M (PCR_PLL_16M_CLK_EN_V << PCR_PLL_16M_CLK_EN_S) +#define PCR_PLL_16M_CLK_EN_V 0x00000001U +#define PCR_PLL_16M_CLK_EN_S 4 +/** PCR_PLL_8M_CLK_EN : R/W; bitpos: [5]; default: 1; * This field is used to open 8 MHz clock (div12 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ -#define PCR_PLL_40M_CLK_EN (BIT(5)) -#define PCR_PLL_40M_CLK_EN_M (PCR_PLL_40M_CLK_EN_V << PCR_PLL_40M_CLK_EN_S) -#define PCR_PLL_40M_CLK_EN_V 0x00000001U -#define PCR_PLL_40M_CLK_EN_S 5 +#define PCR_PLL_8M_CLK_EN (BIT(5)) +#define PCR_PLL_8M_CLK_EN_M (PCR_PLL_8M_CLK_EN_V << PCR_PLL_8M_CLK_EN_S) +#define PCR_PLL_8M_CLK_EN_V 0x00000001U +#define PCR_PLL_8M_CLK_EN_S 5 /** PCR_CTRL_CLK_OUT_EN_REG register * CLK_OUT_EN configuration register diff --git a/components/soc/esp32h21/register/soc/pcr_struct.h b/components/soc/esp32h21/register/soc/pcr_struct.h index 1dd1dc9ff4d..b98533f07b3 100644 --- a/components/soc/esp32h21/register/soc/pcr_struct.h +++ b/components/soc/esp32h21/register/soc/pcr_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -1545,36 +1545,36 @@ typedef union { */ typedef union { struct { - /** pll_240m_clk_en : R/W; bitpos: [0]; default: 1; + /** pll_96m_clk_en : R/W; bitpos: [0]; default: 1; * This field is used to open 96 MHz clock (SPLL) driven from SPLL. 0: close, 1: * open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_240m_clk_en:1; - /** pll_160m_clk_en : R/W; bitpos: [1]; default: 1; + uint32_t pll_96m_clk_en:1; + /** pll_64m_clk_en : R/W; bitpos: [1]; default: 1; * This field is used to open 64 MHz clock (div3 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_160m_clk_en:1; - /** pll_120m_clk_en : R/W; bitpos: [2]; default: 1; + uint32_t pll_64m_clk_en:1; + /** pll_48m_clk_en : R/W; bitpos: [2]; default: 1; * This field is used to open 48 MHz clock (div4 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_120m_clk_en:1; - /** pll_80m_clk_en : R/W; bitpos: [3]; default: 1; + uint32_t pll_48m_clk_en:1; + /** pll_32m_clk_en : R/W; bitpos: [3]; default: 1; * This field is used to open 32 MHz clock (div6 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_80m_clk_en:1; - /** pll_48m_clk_en : R/W; bitpos: [4]; default: 1; + uint32_t pll_32m_clk_en:1; + /** pll_16m_clk_en : R/W; bitpos: [4]; default: 1; * This field is used to open 16 MHz clock (div10 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_48m_clk_en:1; - /** pll_40m_clk_en : R/W; bitpos: [5]; default: 1; + uint32_t pll_16m_clk_en:1; + /** pll_8m_clk_en : R/W; bitpos: [5]; default: 1; * This field is used to open 8 MHz clock (div12 of SPLL) driven from SPLL. 0: close, * 1: open(default). Only available when high-speed clock-source SPLL is active. */ - uint32_t pll_40m_clk_en:1; + uint32_t pll_8m_clk_en:1; uint32_t reserved_6:26; }; uint32_t val; diff --git a/components/soc/esp32h4/include/soc/clk_tree_defs.h b/components/soc/esp32h4/include/soc/clk_tree_defs.h index 9f72a3349c1..a57a4e220d8 100644 --- a/components/soc/esp32h4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h4/include/soc/clk_tree_defs.h @@ -69,6 +69,7 @@ typedef enum { typedef enum { SOC_ROOT_CIRCUIT_CLK_BBPLL, /*!< BBPLL_CLK is the output of the PLL generator circuit */ SOC_ROOT_CIRCUIT_CLK_XTAL_X2, /*!< XTAL_X2_CLK is the output of the XTAL_X2 generator circuit */ + SOC_ROOT_CIRCUIT_CLK_MAX, } soc_root_clk_circuit_t; /** @@ -141,7 +142,8 @@ typedef enum { SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 32MHz crystal */ - + SOC_MOD_CLK_XTAL_X2, /*!< XTAL_X2_CLK is the output of the XTAL_X2 generator circuit (64MHz); CPU clock source, not the gated F64M */ + SOC_MOD_CLK_BBPLL, /*!< BBPLL_CLK is the output of the PLL generator circuit (96MHz); CPU clock source, not the gated F96M */ SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */ } soc_module_clk_t;