feat(esp_hw_support): support gate PLL div clock source by reference count

This commit is contained in:
wuzhenghui
2025-01-15 21:41:34 +08:00
parent 34f249a28b
commit 113f40a3e0
12 changed files with 154 additions and 69 deletions

View File

@ -78,6 +78,9 @@ uint32_t esp_clk_tree_lp_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t prec
/**
* @brief Enable / Disable the clock gate of the clock source
*
* @note The clock enable status is maintained by reference counter and
* its status is not reset after software restart.
*
* @param[in] clk_src Clock source available to modules, in soc_module_clk_t
* @param[in] enable Enable / Disable the clock gate
*
@ -92,6 +95,13 @@ uint32_t esp_clk_tree_lp_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t prec
*/
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable);
#if SOC_CLOCK_TREE_MANAGEMENT_SUPPORTED
/**
* @brief Set the clock source not in use on the clock tree to the gated state.
*/
void esp_clk_tree_initialize(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -7,12 +7,17 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_rom_regi2c.h"
#include "soc/soc_caps.h"
#include "esp_private/periph_ctrl.h"
#include "hal/regi2c_ctrl_ll.h"
#ifndef BOOTLOADER_BUILD
#include "esp_private/esp_clk_tree_common.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -25,22 +30,32 @@ extern "C" {
#else // !BOOTLOADER_BUILD
static inline __attribute__((always_inline)) void ANA_I2C_SRC_CLOCK_ENABLE(bool enable) {
#if SOC_CLK_ANA_I2C_MST_DEPENDS_ON_MODEM_APB
esp_clk_tree_enable_src(SOC_MOD_CLK_MODEM_APB, enable);
#endif
}
#if ANA_I2C_MST_CLK_HAS_ROOT_GATING
// This clock needs to be enabled for regi2c write/read, pll calibaration, PHY, RNG, ADC, etc.
// Use reference count to manage the analog i2c master clock
#define ANALOG_CLOCK_ENABLE() \
#define ANALOG_CLOCK_ENABLE() { \
ANA_I2C_SRC_CLOCK_ENABLE(true); \
PERIPH_RCC_ACQUIRE_ATOMIC(PERIPH_ANA_I2C_MASTER_MODULE, ref_count) { \
if (ref_count == 0) { \
regi2c_ctrl_ll_master_enable_clock(true); \
} \
}
} \
}
#define ANALOG_CLOCK_DISABLE() \
#define ANALOG_CLOCK_DISABLE() { \
PERIPH_RCC_RELEASE_ATOMIC(PERIPH_ANA_I2C_MASTER_MODULE, ref_count) { \
if (ref_count == 0) { \
regi2c_ctrl_ll_master_enable_clock(false); \
} \
}
} \
ANA_I2C_SRC_CLOCK_ENABLE(false); \
}
#else
#define ANALOG_CLOCK_ENABLE()

View File

@ -16,6 +16,7 @@ entries:
if PM_SLP_IRAM_OPT = y:
rtc_clk (noflash)
rtc_time (noflash_text)
esp_clk_tree: esp_clk_tree_enable_src (noflash)
if IDF_TARGET_ESP32 = y:
rtc_clk:rtc_clk_cpu_freq_to_pll_mhz (noflash)
rtc_clk:rtc_clk_cpu_freq_to_xtal (noflash)

View File

@ -141,7 +141,7 @@ static void IRAM_ATTR modem_clock_data_dump_configure(modem_clock_context_t *ctx
modem_clock_context_t * __attribute__((weak)) IRAM_ATTR MODEM_CLOCK_instance(void)
{
/* It should be explicitly defined in the internal RAM */
static DRAM_ATTR modem_clock_hal_context_t modem_clock_hal = { .syscon_dev = &MODEM_SYSCON, .lpcon_dev = &MODEM_LPCON };
static DRAM_ATTR modem_clock_hal_context_t modem_clock_hal = { .syscon_dev = NULL, .lpcon_dev = NULL };
static DRAM_ATTR modem_clock_context_t modem_clock_context = {
.hal = &modem_clock_hal, .lock = portMUX_INITIALIZER_UNLOCKED,
.dev = {
@ -167,6 +167,13 @@ modem_clock_context_t * __attribute__((weak)) IRAM_ATTR MODEM_CLOCK_instance(voi
},
.lpclk_src = { [0 ... PERIPH_MODEM_MODULE_NUM - 1] = MODEM_CLOCK_LPCLK_SRC_INVALID }
};
if (modem_clock_hal.syscon_dev == NULL || modem_clock_hal.lpcon_dev == NULL) {
modem_clock_hal.syscon_dev = &MODEM_SYSCON;
modem_clock_hal.lpcon_dev = &MODEM_LPCON;
#if SOC_CLOCK_TREE_MANAGEMENT_SUPPORTED
esp_clk_tree_enable_src(SOC_MOD_CLK_MODEM_APB, true);
#endif
}
return &modem_clock_context;
}

View File

@ -5,6 +5,7 @@
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_clk_tree.h"
#include "esp_err.h"
#include "esp_check.h"
@ -68,40 +69,72 @@ uint32_t *freq_value)
return ESP_OK;
}
#define ENUM2ARRAY(clk_src) (clk_src - SOC_MOD_CLK_PLL_F12M)
static __NOINIT_ATTR int16_t s_pll_src_cg_ref_cnt[9] = { 0 };
static bool esp_clk_tree_initialized = false;
void esp_clk_tree_initialize(void)
{
soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0);
if ((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_CPU0_LOCKUP)) {
esp_clk_tree_initialized = true;
return;
} else {
bzero(s_pll_src_cg_ref_cnt, sizeof(s_pll_src_cg_ref_cnt));
}
soc_cpu_clk_src_t current_cpu_clk_src = clk_ll_cpu_get_src();
if (current_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160M) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(SOC_MOD_CLK_PLL_F160M)] = 1;
_clk_gate_ll_ref_240m_clk_en(false);
} else if (current_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240M) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(SOC_MOD_CLK_PLL_F240M)] = 1;
_clk_gate_ll_ref_160m_clk_en(false);
}
_clk_gate_ll_ref_120m_clk_en(false);
_clk_gate_ll_ref_80m_clk_en(false);
_clk_gate_ll_ref_60m_clk_en(false);
#if !CONFIG_USJ_ENABLE_USB_SERIAL_JTAG && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
_clk_gate_ll_ref_48m_clk_en(false);
#endif
_clk_gate_ll_ref_40m_clk_en(false);
_clk_gate_ll_ref_20m_clk_en(false);
_clk_gate_ll_ref_12m_clk_en(false);
esp_clk_tree_initialized = true;
}
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
{
if (!esp_clk_tree_initialized || (clk_src < SOC_MOD_CLK_PLL_F12M) || (clk_src > SOC_MOD_CLK_PLL_F240M)) {
return ESP_OK;
}
PERIPH_RCC_ATOMIC() {
switch (clk_src) {
case SOC_MOD_CLK_PLL_F12M:
clk_gate_ll_ref_12m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F20M:
clk_gate_ll_ref_20m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F40M:
clk_gate_ll_ref_40m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F48M:
clk_gate_ll_ref_48m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F60M:
clk_gate_ll_ref_60m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F80M:
clk_gate_ll_ref_80m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F120M:
clk_gate_ll_ref_120m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F160M:
clk_gate_ll_ref_160m_clk_en(enable);
break;
case SOC_MOD_CLK_PLL_F240M:
clk_gate_ll_ref_240m_clk_en(enable);
break;
default:
break;
if (enable) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]++;
}
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] == 1) {
switch (clk_src) {
case SOC_MOD_CLK_PLL_F12M: clk_gate_ll_ref_12m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F20M: clk_gate_ll_ref_20m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F40M: clk_gate_ll_ref_40m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F48M: clk_gate_ll_ref_48m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F60M: clk_gate_ll_ref_60m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F80M: clk_gate_ll_ref_80m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F120M: clk_gate_ll_ref_120m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F160M: clk_gate_ll_ref_160m_clk_en(enable); break;
case SOC_MOD_CLK_PLL_F240M: clk_gate_ll_ref_240m_clk_en(enable); break;
default: break;
}
}
if (!enable) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]--;
}
assert(s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] >= 0);
}
return ESP_OK;
}
#undef ENUM2ARRAY

View File

@ -286,37 +286,53 @@ __attribute__((weak)) void rtc_clk_set_cpu_switch_to_pll(int event_id)
{
}
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
static void rtc_clk_update_pll_state_on_cpu_src_switching_start(soc_cpu_clk_src_t old_src, soc_cpu_clk_src_t new_src)
{
soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
if (((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160M) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240M)) && !s_bbpll_digi_consumers_ref_count) {
if ((new_src == SOC_CPU_CLK_SRC_PLL_F160M) || (new_src == SOC_CPU_CLK_SRC_PLL_F240M)) {
if (s_cur_pll_freq != CLK_LL_PLL_480M_FREQ_MHZ) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_480M_FREQ_MHZ);
}
#ifndef BOOTLOADER_BUILD
esp_clk_tree_enable_src((new_src == SOC_CPU_CLK_SRC_PLL_F240M) ? SOC_MOD_CLK_PLL_F240M : SOC_MOD_CLK_PLL_F160M, true);
#endif
}
}
static void rtc_clk_update_pll_state_on_cpu_switching_end(soc_cpu_clk_src_t old_src, soc_cpu_clk_src_t new_src)
{
if ((old_src == SOC_CPU_CLK_SRC_PLL_F160M) || (old_src == SOC_CPU_CLK_SRC_PLL_F240M)) {
#ifndef BOOTLOADER_BUILD
esp_clk_tree_enable_src((old_src == SOC_CPU_CLK_SRC_PLL_F240M) ? SOC_MOD_CLK_PLL_F240M : SOC_MOD_CLK_PLL_F160M, false);
#endif
if ((new_src != SOC_CPU_CLK_SRC_PLL_F160M) && (new_src != SOC_CPU_CLK_SRC_PLL_F240M) && !s_bbpll_digi_consumers_ref_count) {
// We don't turn off the bbpll if some consumers depend on bbpll
rtc_clk_bbpll_disable();
}
}
}
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_update_pll_state_on_cpu_src_switching_start(old_cpu_clk_src, config->source);
}
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_F240M) {
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F240M && old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F160M) {
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_START);
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_480M_FREQ_MHZ);
}
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_START);
rtc_clk_cpu_freq_to_pll_240_mhz(config->freq_mhz);
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_STOP);
} else if (config->source == SOC_CPU_CLK_SRC_PLL_F160M) {
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F240M && old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F160M) {
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_START);
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_480M_FREQ_MHZ);
}
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_START);
rtc_clk_cpu_freq_to_pll_160_mhz(config->freq_mhz);
rtc_clk_set_cpu_switch_to_pll(SLEEP_EVENT_HW_PLL_EN_STOP);
} else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
rtc_clk_cpu_freq_to_8m();
if (((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160M) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240M)) && !s_bbpll_digi_consumers_ref_count) {
// We don't turn off the bbpll if some consumers depend on bbpll
rtc_clk_bbpll_disable();
}
}
if (old_cpu_clk_src != config->source) {
rtc_clk_update_pll_state_on_cpu_switching_end(old_cpu_clk_src, config->source);
}
}

View File

@ -54,5 +54,5 @@ uint32_t *freq_value)
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
{
(void)clk_src; (void)enable;
return ESP_ERR_NOT_SUPPORTED;
return ESP_OK;
}

View File

@ -707,6 +707,9 @@ void IRAM_ATTR call_start_cpu0(void)
trax_start_trace(TRAX_DOWNCOUNT_WORDS);
#endif // CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX || CONFIG_ESP32S3_TRAX
#if SOC_CLOCK_TREE_MANAGEMENT_SUPPORTED
esp_clk_tree_initialize();
#endif
esp_clk_init();
esp_perip_clk_init();

View File

@ -239,12 +239,14 @@ __attribute__((weak)) void esp_perip_clk_init(void)
* oscillator (40 MHz) to provide the clock during the sleep process in some
* scenarios), the module needs to switch to the required clock source by
* itself. */
#if CONFIG_ESP_WIFI_ENABLED
soc_rtc_slow_clk_src_t rtc_slow_clk_src = rtc_clk_slow_src_get();
modem_clock_lpclk_src_t modem_lpclk_src = (modem_clock_lpclk_src_t)(
(rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? MODEM_CLOCK_LPCLK_SRC_XTAL32K
: (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) ? MODEM_CLOCK_LPCLK_SRC_EXT32K
: MODEM_CLOCK_LPCLK_SRC_RC_SLOW);
modem_clock_select_lp_clock_source(PERIPH_WIFI_MODULE, modem_lpclk_src, 0);
#endif
/* On ESP32-C5 ECO1, clearing BIT(31) of PCR_FPGA_DEBUG_REG is used to fix
* the issue where the modem module fails to transmit and receive packets
@ -329,19 +331,6 @@ __attribute__((weak)) void esp_perip_clk_init(void)
usb_serial_jtag_ll_enable_mem_clock(false);
usb_serial_jtag_ll_set_mem_pd(true);
#endif
if (clk_ll_cpu_get_src() != SOC_CPU_CLK_SRC_PLL_F240M) {
_clk_gate_ll_ref_240m_clk_en(false);
}
if (clk_ll_cpu_get_src() != SOC_CPU_CLK_SRC_PLL_F160M) {
_clk_gate_ll_ref_160m_clk_en(false);
}
_clk_gate_ll_ref_120m_clk_en(false);
_clk_gate_ll_ref_80m_clk_en(false);
_clk_gate_ll_ref_60m_clk_en(false);
_clk_gate_ll_ref_40m_clk_en(false);
_clk_gate_ll_ref_20m_clk_en(false);
_clk_gate_ll_ref_12m_clk_en(false);
}
if ((rst_reason == RESET_REASON_CHIP_POWER_ON) || (rst_reason == RESET_REASON_CHIP_BROWN_OUT) \

View File

@ -255,6 +255,10 @@ config SOC_PM_SUPPORTED
bool
default y
config SOC_CLOCK_TREE_MANAGEMENT_SUPPORTED
bool
default y
config SOC_SPIRAM_SUPPORTED
bool
default y
@ -1671,6 +1675,10 @@ config SOC_RCC_IS_INDEPENDENT
bool
default y
config SOC_CLK_ANA_I2C_MST_DEPENDS_ON_MODEM_APB
bool
default y
config SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
bool
default y

View File

@ -132,6 +132,7 @@ typedef enum {
SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from SPLL (clock gating + fixed divider of 6), it has a fixed frequency of 80MHz */
SOC_MOD_CLK_PLL_F120M, /*!< PLL_F120M_CLK is derived from SPLL (clock gating + fixed divider of 4), it has a fixed frequency of 120MHz */
SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 160MHz */
SOC_MOD_CLK_MODEM_APB = SOC_MOD_CLK_PLL_F160M, /*!< Modem APB clock comes from the CLK_160M_REF */
SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from SPLL (clock gating + fixed divider of 2), it has a fixed frequency of 240MHz */
SOC_MOD_CLK_SPLL, /*!< SPLL is from the main XTAL oscillator frequency multipliers, it has a "fixed" frequency of 480MHz */
SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */
@ -139,7 +140,6 @@ typedef enum {
SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 48MHz crystal */
// For LP peripherals
SOC_MOD_CLK_XTAL_D2, /*!< XTAL_D2_CLK comes from the external 48MHz crystal, passing a div of 2 to the LP peripherals */
SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */
} soc_module_clk_t;

View File

@ -82,6 +82,7 @@
#define SOC_LIGHT_SLEEP_SUPPORTED 1
#define SOC_DEEP_SLEEP_SUPPORTED 1
#define SOC_PM_SUPPORTED 1
#define SOC_CLOCK_TREE_MANAGEMENT_SUPPORTED 1
#define SOC_SPIRAM_SUPPORTED 1
#define SOC_BT_SUPPORTED 1
@ -658,6 +659,8 @@
#define SOC_RCC_IS_INDEPENDENT 1 /*!< Reset and Clock Control is independent, thanks to the PCR registers */
#define SOC_CLK_ANA_I2C_MST_DEPENDS_ON_MODEM_APB (1) /*!< Analog I2C master clock depends on CLK_160M_REF on clock tree */
/*-------------------------- Temperature Sensor CAPS -------------------------------------*/
#define SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC (1)
#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL (1)