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_hal_clock/esp32h21/include/hal/clk_tree_ll.h b/components/esp_hal_clock/esp32h21/include/hal/clk_tree_ll.h index 76bcab352b4..83e6249797d 100644 --- a/components/esp_hal_clock/esp32h21/include/hal/clk_tree_ll.h +++ b/components/esp_hal_clock/esp32h21/include/hal/clk_tree_ll.h @@ -68,6 +68,8 @@ typedef struct { static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void) { SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C); + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_BBPLL_ICG); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -77,6 +79,7 @@ static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void) { SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_BBPLL_ICG) ; SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_BBPLL | PMU_TIE_LOW_XPD_BBPLL_I2C); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -88,6 +91,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtal_x2_enable(void) CLEAR_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_XTALX2_ICG); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_XTAL_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** @@ -98,6 +102,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtal_x2_disable(void) CLEAR_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_XTALX2); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_XTALX2_ICG); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_XTAL_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** diff --git a/components/esp_hal_clock/esp32h4/include/hal/clk_tree_ll.h b/components/esp_hal_clock/esp32h4/include/hal/clk_tree_ll.h index f89b1bd89bb..b12ec8afcfc 100644 --- a/components/esp_hal_clock/esp32h4/include/hal/clk_tree_ll.h +++ b/components/esp_hal_clock/esp32h4/include/hal/clk_tree_ll.h @@ -66,6 +66,8 @@ typedef struct { static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void) { SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C); + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_BBPLL_ICG); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -75,6 +77,7 @@ static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void) { SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_BBPLL_ICG) ; SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_BBPLL | PMU_TIE_LOW_XPD_BBPLL_I2C); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_CK_POWER_REG, PMU_HP_ACTIVE_XPD_BBPLL_I2C | PMU_HP_ACTIVE_XPD_BBPLL); } /** @@ -94,6 +97,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtal_x2_enable(void) CLEAR_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_XTALX2_ICG); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_XTAL_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** @@ -104,6 +108,7 @@ static inline __attribute__((always_inline)) void clk_ll_xtal_x2_disable(void) CLEAR_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_XTALX2); SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_XTALX2_ICG); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_XTAL_REG, PMU_HP_ACTIVE_XPD_XTALX2); } /** diff --git a/components/esp_hal_pmu/esp32h21/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32h21/include/hal/pmu_ll.h index e2b65687321..507f7a3f8b5 100644 --- a/components/esp_hal_pmu/esp32h21/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32h21/include/hal/pmu_ll.h @@ -94,6 +94,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_dcdc_ccm_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool enable) { hw->hp_sys[mode].bias.dcdc_ccm_enb = enable; diff --git a/components/esp_hal_pmu/esp32h4/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32h4/include/hal/pmu_ll.h index 2c46c18518f..1cf6285ec35 100644 --- a/components/esp_hal_pmu/esp32h4/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32h4/include/hal/pmu_ll.h @@ -95,6 +95,29 @@ 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; } +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode) +{ + return hw->hp_sys[mode].clk_power.val; +} + +/** + * @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; @@ -105,6 +128,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_xtalx2_xpd(pmu_dev_t *hw, pmu_hp_mode_t mod hw->hp_sys[mode].xtal.xpd_xtalx2 = xpd_xtalx2; } +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_xtalx2_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode) +{ + return hw->hp_sys[mode].xtal.xpd_xtalx2; +} + FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_bias) { hw->hp_sys[mode].bias.xpd_bias = xpd_bias; diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index 372523ca4d7..8f3a3accf14 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -56,8 +56,9 @@ entries: pmu_sleep:pmu_sleep_get_wakup_retention_cost (noflash) if PM_SLEEP_CLK_ICG_ENABLE = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP != y: pmu_sleep_clock_icg:pmu_sleep_clock_icg_config (noflash) - if IDF_TARGET_ESP32H4 = y && BT_LE_MODEM_STATE_ENABLED = y: + if IDF_TARGET_ESP32H4 = y && PM_MODEM_STATE_ENABLED = y: pmu_sleep_power:pmu_sleep_power_analog_wait_config (noflash) + pmu_sleep_power:pmu_sleep_power_clock_config (noflash) sleep_mspi (noflash) if PM_SLP_IRAM_OPT = y && IDF_TARGET_ESP32S31 != y: pmu_param:get_act_lp_dbias (noflash) 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/esp32h21/include/soc/rtc.h b/components/esp_hw_support/port/esp32h21/include/soc/rtc.h index 5da854b0e48..5499bd6508b 100644 --- a/components/esp_hw_support/port/esp32h21/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32h21/include/soc/rtc.h @@ -262,7 +262,9 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config); * * @param config CPU frequency configuration structure */ +#ifndef BOOTLOADER_BUILD void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config); +#endif /** * @brief Get the currently used CPU frequency configuration @@ -270,6 +272,7 @@ 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 * @@ -277,11 +280,10 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config); * 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 This function always disables BBPLL after switching the CPU clock source to XTAL for power saving purpose. - * If this is unwanted, please use rtc_clk_cpu_freq_set_config. It helps to check whether USB Serial JTAG is in use, - * if so, then BBPLL will not be turned off. + * Releases the CPU clk_tree hold on the previous root clock (BBPLL / XTAL_X2). */ void rtc_clk_cpu_freq_set_xtal(void); +#endif /** * @brief Get the current APB frequency. diff --git a/components/esp_hw_support/port/esp32h21/pmu_init.c b/components/esp_hw_support/port/esp32h21/pmu_init.c index 4108e24cd05..02748dcaea5 100644 --- a/components/esp_hw_support/port/esp32h21/pmu_init.c +++ b/components/esp_hw_support/port/esp32h21/pmu_init.c @@ -64,9 +64,15 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, const pmu_hp_sys 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_xtalx2_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtalx2); + } pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal); - pmu_ll_hp_set_xtalx2_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtalx2); /* Default configuration of hp-system clock in active, modem and sleep modes */ pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func); diff --git a/components/esp_hw_support/port/esp32h21/rtc_clk.c b/components/esp_hw_support/port/esp32h21/rtc_clk.c index 3acace5c407..f06736a90dd 100644 --- a/components/esp_hw_support/port/esp32h21/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h21/rtc_clk.c @@ -25,16 +25,19 @@ ESP_HW_LOG_ATTR_TAG(TAG, "rtc_clk"); -// Current PLL frequency, in 96MHz. Zero if PLL is not enabled. -static int s_cur_pll_freq; +#ifndef BOOTLOADER_BUILD +// BBPLL frequency option, in 96MHz. Zero if BBPLL is not enabled / needs recalibration. +static int s_cur_pll_freq = 0; static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it only tracks whether the 48MHz PHY clock is in-use by USB Serial/JTAG -#if !BOOTLOADER_BUILD -// Indicate whether the specific cpu clock source is acquired by the hp root clock (i.e. whether ref_cnt in esp_clk_tree.c is incremented by the hp root clock) +/** + * Whether CPU currently holds a clk_tree ref on BBPLL / XTAL_X2. + * 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_pll_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 96 || CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 48); static bool s_is_xtal_x2_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 64); -#endif void rtc_clk_bbpll_add_consumer(void) { @@ -45,6 +48,7 @@ void rtc_clk_bbpll_remove_consumer(void) { s_bbpll_digi_consumers_ref_count -= 1; } +#endif void rtc_clk_32k_enable(bool enable) { @@ -137,19 +141,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_bbpll_disable(void) -{ - clk_ll_bbpll_disable(); - s_cur_pll_freq = 0; -} - -static void rtc_clk_bbpll_enable(void) -{ - clk_ll_bbpll_enable(); -} -#endif - static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) { /* Digital part */ @@ -167,7 +158,9 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_calibration_stop(); ANALOG_CLOCK_DISABLE(); +#ifndef BOOTLOADER_BUILD s_cur_pll_freq = pll_freq; +#endif } /** @@ -281,64 +274,62 @@ __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_PLL) { - bool truly_enabled = false; -#if BOOTLOADER_BUILD - rtc_clk_bbpll_enable(); - truly_enabled = true; + clk_ll_bbpll_enable(); + rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); + } else if (new_src == SOC_CPU_CLK_SRC_XTAL_X2) { + clk_ll_xtal_x2_enable(); + } #else + if (new_src == SOC_CPU_CLK_SRC_PLL) { + bool need_configure = false; if (!s_is_pll_acquired) { - truly_enabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, true); + need_configure = !esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL); + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); s_is_pll_acquired = true; } -#endif - if (truly_enabled || (s_cur_pll_freq != new_src_freq_mhz)) { + if (need_configure || (s_cur_pll_freq != (int)new_src_freq_mhz)) { rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); } } else if (new_src == SOC_CPU_CLK_SRC_XTAL_X2) { -#if BOOTLOADER_BUILD - clk_ll_xtal_x2_enable(); -#else if (!s_is_xtal_x2_acquired) { - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, true); + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, true); s_is_xtal_x2_acquired = true; } -#endif } +#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_PLL) && !s_bbpll_digi_consumers_ref_count) { -#if BOOTLOADER_BUILD - rtc_clk_bbpll_disable(); -#else assert(s_is_pll_acquired); - bool truly_disabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, false); + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, false); s_is_pll_acquired = false; - if (truly_disabled) { + if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL)) { s_cur_pll_freq = 0; } -#endif } else if (old_src == SOC_CPU_CLK_SRC_XTAL_X2) { -#if BOOTLOADER_BUILD - clk_ll_xtal_x2_disable(); -#else assert(s_is_xtal_x2_acquired); - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, false); + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, false); s_is_xtal_x2_acquired = false; -#endif } } +#endif void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) { - 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); + __attribute__((unused)) soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); +#ifndef BOOTLOADER_BUILD + bool src_changed = (old_cpu_clk_src != config->source); + if (src_changed) +#endif + { + rtc_clk_update_pll_state_on_cpu_src_switching_start(config->source, config->source_freq_mhz); } if (config->source == SOC_CPU_CLK_SRC_XTAL) { @@ -353,9 +344,11 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) rtc_clk_cpu_freq_to_xtal_x2(config->freq_mhz, config->div); } - 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 } void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) @@ -391,20 +384,21 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) }; } +#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/XTALx2 must be reacquired or recalibrated + * (s_cur_pll_freq == 0 after sleep). */ if (config->source == SOC_CPU_CLK_SRC_XTAL) { rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); } else if (config->source == SOC_CPU_CLK_SRC_PLL && - s_cur_pll_freq == config->source_freq_mhz) { + s_is_pll_acquired && + s_cur_pll_freq == (int)config->source_freq_mhz) { rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz); } 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_XTAL_X2 -#if !BOOTLOADER_BUILD - && s_is_xtal_x2_acquired -#endif - ) { + } else if (config->source == SOC_CPU_CLK_SRC_XTAL_X2 && + s_is_xtal_x2_acquired) { rtc_clk_cpu_freq_to_xtal_x2(config->freq_mhz, config->div); } else { /* fallback */ @@ -419,22 +413,29 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) { - rtc_clk_cpu_src_clk_disable(old_cpu_clk_src); + 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); - s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep } +#ifndef BOOTLOADER_BUILD void rtc_clk_cpu_freq_set_xtal_for_sleep(void) { - rtc_clk_cpu_set_to_default_config(); + 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_pll_freq forces recalibration via set_config fallback. */ + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); + s_cur_pll_freq = 0; } +#endif FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { diff --git a/components/esp_hw_support/port/esp32h4/CMakeLists.txt b/components/esp_hw_support/port/esp32h4/CMakeLists.txt index 8943bdfc0c3..340b509dd46 100644 --- a/components/esp_hw_support/port/esp32h4/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32h4/CMakeLists.txt @@ -14,11 +14,9 @@ endif() if(NOT BOOTLOADER_BUILD) list(APPEND srcs "sar_periph_ctrl.c") - -if(CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT) - list(APPEND srcs "pmu_sleep_power.c") -endif() - + if(CONFIG_PM_MODEM_STATE_ENABLED) + list(APPEND srcs "pmu_sleep_power.c") + endif() endif() add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") 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/esp_hw_support/port/esp32h4/include/soc/rtc.h b/components/esp_hw_support/port/esp32h4/include/soc/rtc.h index fd1ac2f3b37..1d3bbeca0e0 100644 --- a/components/esp_hw_support/port/esp32h4/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32h4/include/soc/rtc.h @@ -261,7 +261,9 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config); * * @param config CPU frequency configuration structure */ +#ifndef BOOTLOADER_BUILD void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config); +#endif /** * @brief Get the currently used CPU frequency configuration @@ -269,6 +271,7 @@ 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 * @@ -276,11 +279,10 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config); * 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 This function always disables BBPLL after switching the CPU clock source to XTAL for power saving purpose. - * If this is unwanted, please use rtc_clk_cpu_freq_set_config. It helps to check whether USB Serial JTAG is in use, - * if so, then BBPLL will not be turned off. + * Releases the CPU clk_tree hold on the previous root clock (BBPLL / XTAL_X2). */ void rtc_clk_cpu_freq_set_xtal(void); +#endif /** * @brief Switch root clock source to PLL (only used by sleep) release root clock source locked by PMU diff --git a/components/esp_hw_support/port/esp32h4/pmu_init.c b/components/esp_hw_support/port/esp32h4/pmu_init.c index 625b549c00b..9180baa9c3c 100644 --- a/components/esp_hw_support/port/esp32h4/pmu_init.c +++ b/components/esp_hw_support/port/esp32h4/pmu_init.c @@ -68,9 +68,15 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, const pmu_hp_sys 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_xtalx2_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtalx2); + } pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal); - pmu_ll_hp_set_xtalx2_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtalx2); /* Default configuration of hp-system clock in active, modem and sleep modes */ pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func); diff --git a/components/esp_hw_support/port/esp32h4/pmu_sleep.c b/components/esp_hw_support/port/esp32h4/pmu_sleep.c index 6b8127e247d..21f207244f8 100644 --- a/components/esp_hw_support/port/esp32h4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h4/pmu_sleep.c @@ -250,14 +250,27 @@ static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_confi pmu_ll_set_xtal_stable_wait_cycle(ctx->hal->dev, param->hp_lp.xtal_stable_wait_slow_clk_cycle); pmu_ll_set_pll_stable_wait_cycle(ctx->hal->dev, param->hp_sys.pll_stable_wait_cycle); -#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT +#if CONFIG_PM_MODEM_STATE_ENABLED uint16_t ana_wait[ANALOG_WAIT_CTRL_NUM] = { 0x20, // about 1.6us param->hp_sys.analog_wait_target_cycle, param->hp_sys.analog_wait_target_cycle, }; pmu_sleep_power_analog_wait_config(ctx->priv, ana_wait); -#endif +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND + pmu_hp_clk_power_reg_t hp_ck = { .val = pmu_ll_hp_get_clk_power(ctx->hal->dev, HP(ACTIVE)) }; + uint32_t xtalx2_xpd = pmu_ll_hp_get_xtalx2_xpd(ctx->hal->dev, HP(ACTIVE)); + pmu_imm_hp_clk_power_reg_t imm = { + .tie_high_xpd_bbpll = hp_ck.xpd_bbpll, + .tie_high_xpd_bbpll_i2c = hp_ck.xpd_bbpll_i2c, + .tie_high_global_bbpll_icg = hp_ck.xpd_bbpll || hp_ck.xpd_bbpll_i2c, + .tie_high_xtalx2 = xtalx2_xpd, + .tie_high_global_xtalx2_icg = xtalx2_xpd, + }; + pmu_sleep_power_clock_config(ctx->priv, imm.val); +#endif // SOC_PM_MODEM_LOCK_CLK_WORKAROUND + +#endif // CONFIG_PM_MODEM_STATE_ENABLED } bool pmu_sleep_pll_already_enabled(void) diff --git a/components/esp_hw_support/port/esp32h4/pmu_sleep_power.c b/components/esp_hw_support/port/esp32h4/pmu_sleep_power.c index 123dd01b9ba..e3945bb29d3 100644 --- a/components/esp_hw_support/port/esp32h4/pmu_sleep_power.c +++ b/components/esp_hw_support/port/esp32h4/pmu_sleep_power.c @@ -20,17 +20,37 @@ ESP_LOG_ATTR_TAG(TAG, "sleep_power"); #if SOC_PM_MODEM_LOCK_CLK_WORKAROUND +#define XTALX2_TIE_HIGH_MASK (PMU_TIE_HIGH_XTALX2_M | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG_M) +#define XTALX2_TIE_HIGH_ON (PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG) +#define BBPLL_TIE_HIGH_MASK (PMU_TIE_HIGH_XPD_BBPLL_M | PMU_TIE_HIGH_XPD_BBPLL_I2C_M | PMU_TIE_HIGH_GLOBAL_BBPLL_ICG_M) +#define BBPLL_TIE_HIGH_ON (PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C | PMU_TIE_HIGH_GLOBAL_BBPLL_ICG) + +typedef struct { + void *regdma_desc[2]; +} pmu_sleep_power_clock_context_t; + static esp_err_t sleep_power_system_retention_init(void *arg) { const static sleep_retention_entries_config_t power_regs_retention[] = { /* During the modem-to-active transition, the MODEM lock keeps the xtalx2, bbpll xpd status unchanged. - * Therefore, if xtalx2, bbpll is disabled in modem state, we need to set xtalx2, bbpll tie-high to enable it in active state. */ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(0), PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XTALX2 | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG, PMU_TIE_HIGH_XTALX2_M | PMU_TIE_HIGH_GLOBAL_XTALX2_ICG_M, 1, 0), .owner = ENTRY(2) }, - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(1), PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_BBPLL | PMU_TIE_HIGH_XPD_BBPLL_I2C, PMU_TIE_HIGH_XPD_BBPLL_M | PMU_TIE_HIGH_XPD_BBPLL_I2C_M, 1, 0), .owner = ENTRY(2) }, + * Therefore, if xtalx2, bbpll is disabled in modem state, we need to set xtalx2, bbpll tie-high to enable it in active state. + * + * XTALX2 and BBPLL write values are back-filled before sleep by pmu_sleep_power_clock_config(). */ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(0), PMU_IMM_HP_CK_POWER_REG, XTALX2_TIE_HIGH_ON, XTALX2_TIE_HIGH_MASK, 1, 0), .owner = ENTRY(2) }, + [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_POWER_LINK(1), PMU_IMM_HP_CK_POWER_REG, BBPLL_TIE_HIGH_ON, BBPLL_TIE_HIGH_MASK, 1, 0), .owner = ENTRY(2) }, }; esp_err_t err = sleep_retention_entries_create(power_regs_retention, ARRAY_SIZE(power_regs_retention), REGDMA_LINK_PRI_POWER, SLEEP_RETENTION_MODULE_POWER); + + pmu_sleep_power_clock_context_t *clk = (pmu_sleep_power_clock_context_t *)arg; + int id_array[ARRAY_SIZE(clk->regdma_desc)] = { REGDMA_POWER_LINK(0), REGDMA_POWER_LINK(1) }; + for (int i = 0; i < ARRAY_SIZE(id_array); i++) { + void *head = sleep_retention_find_link_by_id(id_array[i]); + if (head) { + clk->regdma_desc[i] = head; + } + } + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for clock power retention"); - ESP_LOGI(TAG, "Clock power sleep retention initialization"); return ESP_OK; } @@ -67,32 +87,45 @@ static esp_err_t sleep_power_analog_wait_ctrl_init(void *arg) return ESP_OK; } +typedef struct { +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND + pmu_sleep_power_clock_context_t clock; +#endif + pmu_sleep_power_ana_wait_context_t ana_wait; +} pmu_sleep_power_context_t; + static esp_err_t sleep_power_retention_init(void *arg) { + pmu_sleep_power_context_t *ctx = (pmu_sleep_power_context_t *)arg; #if SOC_PM_MODEM_LOCK_CLK_WORKAROUND - ESP_RETURN_ON_ERROR(sleep_power_system_retention_init(arg), TAG, "system retention init failed"); + ESP_RETURN_ON_ERROR(sleep_power_system_retention_init(&ctx->clock), TAG, "system retention init failed"); #endif - ESP_RETURN_ON_ERROR(sleep_power_analog_wait_ctrl_init(arg), TAG, "analog wait ctrl retention init failed"); + ESP_RETURN_ON_ERROR(sleep_power_analog_wait_ctrl_init(&ctx->ana_wait), TAG, "analog wait ctrl retention init failed"); return ESP_OK; } static esp_err_t sleep_power_retention_deinit(void *arg) { - pmu_sleep_power_ana_wait_context_t *ana_wait_ctx = (pmu_sleep_power_ana_wait_context_t *)arg; + pmu_sleep_power_context_t *ctx = (pmu_sleep_power_context_t *)arg; +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND + for (int i = 0; i < ARRAY_SIZE(ctx->clock.regdma_desc); i++) { + ctx->clock.regdma_desc[i] = NULL; + } +#endif for (int i = 0; i < ANALOG_WAIT_CTRL_NUM; i++) { - ana_wait_ctx->regdma_desc[i] = NULL; + ctx->ana_wait.regdma_desc[i] = NULL; } return ESP_OK; } ESP_SYSTEM_INIT_FN(sleep_power_startup_init, SECONDARY, BIT(0), 108) { - static DRAM_ATTR pmu_sleep_power_ana_wait_context_t ana_wait_ctx; + static DRAM_ATTR pmu_sleep_power_context_t power_context = { 0 }; sleep_retention_module_init_param_t init_param = { .cbs = { - .create = { .handle = sleep_power_retention_init, .arg = &ana_wait_ctx }, - .destroy = { .handle = sleep_power_retention_deinit, .arg = &ana_wait_ctx }, + .create = { .handle = sleep_power_retention_init, .arg = &power_context }, + .destroy = { .handle = sleep_power_retention_deinit, .arg = &power_context }, }, .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE | SLEEP_RETENTION_MODULE_ATTR_ATTACH }; @@ -101,8 +134,13 @@ ESP_SYSTEM_INIT_FN(sleep_power_startup_init, SECONDARY, BIT(0), 108) if (err != ESP_OK) { ESP_LOGW(TAG, "failed to init power retention module, err=%d", err); } else { +#if PMU_SLEEP_PRIV_ENABLED pmu_sleep_data_t *data = (pmu_sleep_data_t *)PMU_instance()->priv; - data->func[PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT] = &ana_wait_ctx; + data->func[PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT] = &power_context.ana_wait; +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND + data->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER] = &power_context.clock; +#endif +#endif } return ESP_OK; @@ -123,3 +161,21 @@ void pmu_sleep_power_analog_wait_config(void *data, const uint16_t analog_wait[A regdma_link_set_write_wait_content(ana_wait_ctx->regdma_desc[i], (uint32_t)analog_wait[i] << PMU_ANA_WAIT_TARGET_S, PMU_ANA_WAIT_TARGET_M); } } + +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND +void pmu_sleep_power_clock_config(void *data, const uint32_t config) +{ + pmu_sleep_data_t *datap = (pmu_sleep_data_t *)data; + if (!datap || !datap->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER]) { + return; + } + + pmu_sleep_power_clock_context_t *clk = (pmu_sleep_power_clock_context_t *)datap->func[PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER]; + if (clk->regdma_desc[0]) { + regdma_link_set_write_wait_content(clk->regdma_desc[0], config & XTALX2_TIE_HIGH_MASK, XTALX2_TIE_HIGH_MASK); + } + if (clk->regdma_desc[1]) { + regdma_link_set_write_wait_content(clk->regdma_desc[1], config & BBPLL_TIE_HIGH_MASK, BBPLL_TIE_HIGH_MASK); + } +} +#endif diff --git a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h index ed749b6c43e..85a40c43f7e 100644 --- a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h @@ -112,7 +112,7 @@ typedef struct { const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mode_t mode); -#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT +#if CONFIG_PM_MODEM_STATE_ENABLED #define ANALOG_WAIT_CTRL_NUM 3 // S2M, M2S, M2A /** * @brief Update content of selected analog wait ctrl REGDMA links. @@ -121,15 +121,29 @@ const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mo * @param analog_wait Update analog wait values at S2M, M2S, M2A retention links. */ void pmu_sleep_power_analog_wait_config(void *data, const uint16_t analog_wait[ANALOG_WAIT_CTRL_NUM]); -#endif + +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND +/** + * @brief Back-fill M2A clk power REGDMA write values before sleep. + * + * @param data PMU sleep data context. + * @param config IMM TIE_HIGH bits to write. + */ +void pmu_sleep_power_clock_config(void *data, const uint32_t config); +#endif // SOC_PM_MODEM_LOCK_CLK_WORKAROUND + +#endif // CONFIG_PM_MODEM_STATE_ENABLED /* Enabled when this chip needs any pmu_sleep_data_t priv slot; conditions differ per chip. */ -#define PMU_SLEEP_PRIV_ENABLED (CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT || SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG) +#define PMU_SLEEP_PRIV_ENABLED (CONFIG_PM_MODEM_STATE_ENABLED || SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG || SOC_PM_MODEM_LOCK_CLK_WORKAROUND) #if PMU_SLEEP_PRIV_ENABLED enum { -#if CONFIG_PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT +#if CONFIG_PM_MODEM_STATE_ENABLED PMU_SLEEP_PRIV_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT, -#endif +#if SOC_PM_MODEM_LOCK_CLK_WORKAROUND + PMU_SLEEP_PRIV_MODEM_LOCK_CLK_POWER, +#endif // SOC_PM_MODEM_LOCK_CLK_WORKAROUND +#endif // CONFIG_PM_MODEM_STATE_ENABLED #if SOC_PM_SUPPORT_PMU_RETENTION_CLK_ICG PMU_SLEEP_PRIV_HW_RETENTION_ICG_CLK, #endif diff --git a/components/esp_hw_support/port/esp32h4/rtc_clk.c b/components/esp_hw_support/port/esp32h4/rtc_clk.c index cd6083e4eb5..efae5d5728e 100644 --- a/components/esp_hw_support/port/esp32h4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h4/rtc_clk.c @@ -25,16 +25,19 @@ ESP_HW_LOG_ATTR_TAG(TAG, "rtc_clk"); -// Current PLL frequency, in 96MHz. Zero if PLL is not enabled. -static int s_cur_pll_freq; +#ifndef BOOTLOADER_BUILD +// BBPLL frequency option, in 96MHz. Zero if BBPLL is not enabled / needs recalibration. +static int s_cur_pll_freq = 0; static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it only tracks whether the 48MHz PHY clock is in-use by USB Serial/JTAG -#if !BOOTLOADER_BUILD -// Indicate whether the specific cpu clock source is acquired by the hp root clock (i.e. whether ref_cnt in esp_clk_tree.c is incremented by the hp root clock) +/** + * Whether CPU currently holds a clk_tree ref on BBPLL / XTAL_X2. + * 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_pll_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 96 || CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 48); static bool s_is_xtal_x2_acquired = (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ == 64); -#endif void rtc_clk_bbpll_add_consumer(void) { @@ -45,6 +48,7 @@ void rtc_clk_bbpll_remove_consumer(void) { s_bbpll_digi_consumers_ref_count -= 1; } +#endif void rtc_clk_32k_enable(bool enable) { @@ -137,19 +141,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_bbpll_disable(void) -{ - clk_ll_bbpll_disable(); - s_cur_pll_freq = 0; -} - -static void rtc_clk_bbpll_enable(void) -{ - clk_ll_bbpll_enable(); -} -#endif - static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) { /* Digital part */ @@ -167,7 +158,9 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) clk_ll_bbpll_calibration_stop(); ANALOG_CLOCK_DISABLE(); +#ifndef BOOTLOADER_BUILD s_cur_pll_freq = pll_freq; +#endif } /** @@ -281,64 +274,62 @@ __attribute__((weak)) void rtc_clk_set_cpu_switch_to_bbpll(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_PLL) { - bool truly_enabled = false; -#if BOOTLOADER_BUILD - rtc_clk_bbpll_enable(); - truly_enabled = true; + clk_ll_bbpll_enable(); + rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); + } else if (new_src == SOC_CPU_CLK_SRC_XTAL_X2) { + clk_ll_xtal_x2_enable(); + } #else + if (new_src == SOC_CPU_CLK_SRC_PLL) { + bool need_configure = false; if (!s_is_pll_acquired) { - truly_enabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, true); + need_configure = !esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL); + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); s_is_pll_acquired = true; } -#endif - if (truly_enabled || (s_cur_pll_freq != new_src_freq_mhz)) { + if (need_configure || (s_cur_pll_freq != (int)new_src_freq_mhz)) { rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), new_src_freq_mhz); } } else if (new_src == SOC_CPU_CLK_SRC_XTAL_X2) { -#if BOOTLOADER_BUILD - clk_ll_xtal_x2_enable(); -#else if (!s_is_xtal_x2_acquired) { - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, true); + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, true); s_is_xtal_x2_acquired = true; } -#endif } +#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_PLL) && !s_bbpll_digi_consumers_ref_count) { -#if BOOTLOADER_BUILD - rtc_clk_bbpll_disable(); -#else assert(s_is_pll_acquired); - bool truly_disabled = esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_BBPLL, false); + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, false); s_is_pll_acquired = false; - if (truly_disabled) { + if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL)) { s_cur_pll_freq = 0; } -#endif } else if (old_src == SOC_CPU_CLK_SRC_XTAL_X2) { -#if BOOTLOADER_BUILD - clk_ll_xtal_x2_disable(); -#else assert(s_is_xtal_x2_acquired); - esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, false); + esp_clk_tree_enable_src(SOC_MOD_CLK_XTAL_X2, false); s_is_xtal_x2_acquired = false; -#endif } } +#endif void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) { - 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); + __attribute__((unused)) soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); +#ifndef BOOTLOADER_BUILD + bool src_changed = (old_cpu_clk_src != config->source); + if (src_changed) +#endif + { + rtc_clk_update_pll_state_on_cpu_src_switching_start(config->source, config->source_freq_mhz); } if (config->source == SOC_CPU_CLK_SRC_XTAL) { @@ -353,9 +344,11 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) rtc_clk_cpu_freq_to_xtal_x2(config->freq_mhz, config->div); } - 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 } void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) @@ -391,20 +384,21 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) }; } +#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/XTALx2 must be reacquired or recalibrated + * (s_cur_pll_freq == 0 after sleep). */ if (config->source == SOC_CPU_CLK_SRC_XTAL) { rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); } else if (config->source == SOC_CPU_CLK_SRC_PLL && - s_cur_pll_freq == config->source_freq_mhz) { + s_is_pll_acquired && + s_cur_pll_freq == (int)config->source_freq_mhz) { rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz); } 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_XTAL_X2 -#if !BOOTLOADER_BUILD - && s_is_xtal_x2_acquired -#endif - ) { + } else if (config->source == SOC_CPU_CLK_SRC_XTAL_X2 && + s_is_xtal_x2_acquired) { rtc_clk_cpu_freq_to_xtal_x2(config->freq_mhz, config->div); } else { /* fallback */ @@ -419,22 +413,29 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) { - rtc_clk_cpu_src_clk_disable(old_cpu_clk_src); + 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); - s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep } +#ifndef BOOTLOADER_BUILD void rtc_clk_cpu_freq_set_xtal_for_sleep(void) { - rtc_clk_cpu_set_to_default_config(); + 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_pll_freq forces recalibration via set_config fallback. */ + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); + s_cur_pll_freq = 0; } +#endif void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) { diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk.c b/components/esp_hw_support/port/esp32s31/rtc_clk.c index ab6f32616e8..b057b9c8b95 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk.c @@ -516,7 +516,9 @@ void rtc_clk_cpu_freq_set_xtal(void) int freq_mhz = (int)rtc_clk_xtal_freq_get(); rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); - rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); + if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) { + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); + } } FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 991245da5c1..6e88171f0c0 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -345,12 +345,11 @@ menu "Power Management" keeping all other peripheral clocks gated to minimize sleep power consumption. - config PM_SKIP_MODEM_TO_ACTIVE_ANALOG_WAIT + config PM_MODEM_STATE_ENABLED bool - depends on SOC_PM_SUPPORT_PMU_MODEM_STATE + depends on SOC_PM_SUPPORT_PMU_MODEM_STATE && IDF_TARGET_ESP32H4 default n help - If enabled, the analog wait time when waking up from modem to active state will be skipped. - This will reduce the wakeup time. + If enabled, the modem state is supported. Note: This option is only supported on ESP32H4. endmenu # "Power Management" diff --git a/components/esp_security/Kconfig b/components/esp_security/Kconfig index c9784ffdf41..01b0bc87ded 100644 --- a/components/esp_security/Kconfig +++ b/components/esp_security/Kconfig @@ -2,7 +2,7 @@ menu "ESP Security Specific" config ESP_CRYPTO_CLK_ON_DEMAND bool "Enable on-demand crypto clock management" - depends on IDF_TARGET_ESP32S31 + depends on IDF_TARGET_ESP32S31 || IDF_TARGET_ESP32H4 || IDF_TARGET_ESP32H21 default y if PM_ENABLE default n help diff --git a/components/esp_security/src/esp32h21/esp_crypto_clk.c b/components/esp_security/src/esp32h21/esp_crypto_clk.c index 8233631cfdf..3d44c099fba 100644 --- a/components/esp_security/src/esp32h21/esp_crypto_clk.c +++ b/components/esp_security/src/esp32h21/esp_crypto_clk.c @@ -4,10 +4,72 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "sdkconfig.h" #include "esp_crypto_clk.h" +#include "soc/clk_tree_defs.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 void esp_crypto_pll_f96m_enable(bool enable) +{ +#if !NON_OS_BUILD + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, enable); +#else + /* Bootloader: no esp_clk_tree; toggle the ref gate directly. */ + _clk_gate_ll_ref_96m_clk_en(enable); +#endif +} + +#if CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + +static int s_crypto_common_clk_ref_cnt; void esp_crypto_common_clk_enable(bool enable) { - (void)enable; + CRYPTO_CLK_LOCK(); + if (enable) { + if (s_crypto_common_clk_ref_cnt++ == 0) { + /* Parent: PLL_F96M (see esp_crypto_clk_init() sec_clk_sel). */ + esp_crypto_pll_f96m_enable(true); + } + } else if (s_crypto_common_clk_ref_cnt > 0 && --s_crypto_common_clk_ref_cnt == 0) { + esp_crypto_pll_f96m_enable(false); + } + 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_f96m_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/esp32h21/esp_crypto_clk.h b/components/esp_security/src/esp32h21/esp_crypto_clk.h index 1be3fc08d62..ec8af15a9f3 100644 --- a/components/esp_security/src/esp32h21/esp_crypto_clk.h +++ b/components/esp_security/src/esp32h21/esp_crypto_clk.h @@ -4,20 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/pcr_reg.h" -#include "esp_private/esp_clk_tree_common.h" -#include "hal/sec_ll.h" - #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) { +#if !CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + /* Keep crypto clocks always on for better crypto performance. */ + esp_crypto_common_clk_enable(true); +#endif // Set crypto clock (`clk_sec`) to use 96M PLL clock - esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, true); sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F96M); } diff --git a/components/esp_security/src/esp32h4/esp_crypto_clk.c b/components/esp_security/src/esp32h4/esp_crypto_clk.c index 8233631cfdf..3d44c099fba 100644 --- a/components/esp_security/src/esp32h4/esp_crypto_clk.c +++ b/components/esp_security/src/esp32h4/esp_crypto_clk.c @@ -4,10 +4,72 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "sdkconfig.h" #include "esp_crypto_clk.h" +#include "soc/clk_tree_defs.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 void esp_crypto_pll_f96m_enable(bool enable) +{ +#if !NON_OS_BUILD + esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, enable); +#else + /* Bootloader: no esp_clk_tree; toggle the ref gate directly. */ + _clk_gate_ll_ref_96m_clk_en(enable); +#endif +} + +#if CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + +static int s_crypto_common_clk_ref_cnt; void esp_crypto_common_clk_enable(bool enable) { - (void)enable; + CRYPTO_CLK_LOCK(); + if (enable) { + if (s_crypto_common_clk_ref_cnt++ == 0) { + /* Parent: PLL_F96M (see esp_crypto_clk_init() sec_clk_sel). */ + esp_crypto_pll_f96m_enable(true); + } + } else if (s_crypto_common_clk_ref_cnt > 0 && --s_crypto_common_clk_ref_cnt == 0) { + esp_crypto_pll_f96m_enable(false); + } + 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_f96m_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/esp32h4/esp_crypto_clk.h b/components/esp_security/src/esp32h4/esp_crypto_clk.h index a39fdfabf09..b16277ba3e7 100644 --- a/components/esp_security/src/esp32h4/esp_crypto_clk.h +++ b/components/esp_security/src/esp32h4/esp_crypto_clk.h @@ -4,20 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc.h" -#include "soc/pcr_reg.h" -#include "esp_private/esp_clk_tree_common.h" -#include "hal/sec_ll.h" - #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) { +#if !CONFIG_ESP_CRYPTO_CLK_ON_DEMAND + /* Keep crypto clocks always on for better crypto performance. */ + esp_crypto_common_clk_enable(true); +#endif // Set crypto clock (`clk_sec`) to use 96M PLL clock - esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F96M, true); sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F96M); } diff --git a/components/esp_security/src/esp32s31/esp_crypto_clk.h b/components/esp_security/src/esp32s31/esp_crypto_clk.h index 25c3b3f80c2..aaa01a9b3db 100644 --- a/components/esp_security/src/esp32s31/esp_crypto_clk.h +++ b/components/esp_security/src/esp32s31/esp_crypto_clk.h @@ -15,10 +15,10 @@ 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 + // Set crypto clock (`clk_sec`) to use 240M PLL clock + sec_ll_crypto_clk_src_sel(SOC_MOD_CLK_PLL_F240M); } 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;