mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'feat/esp_idf_h4_clk_tree_management' into 'master'
Feat/esp idf h4 h21 clk tree management Closes PM-858 and PM-653 See merge request espressif/esp-idf!50653
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,23 +5,123 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -5,23 +5,123 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,10 +4,72 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#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 */
|
||||
|
||||
@@ -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 <stdbool.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,72 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#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 */
|
||||
|
||||
@@ -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 <stdbool.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user