feat(clk): preliminary clock tree support for ESP32C5

This commit is contained in:
Song Ruo Jing
2024-02-07 14:38:15 +08:00
parent a2e5770bce
commit 95133c179f
16 changed files with 512 additions and 242 deletions
-9
View File
@@ -180,15 +180,6 @@ if(NOT BOOTLOADER_BUILD)
"port/esp_clk_tree_common.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
)
endif()
if(CONFIG_IDF_TARGET_ESP32C5)
list(REMOVE_ITEM srcs
"sleep_cpu.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_modes.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_wake_stub.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_gpio.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"port/esp_clk_tree_common.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
)
endif()
else()
# Requires "_esp_error_check_failed()" function
list(APPEND priv_requires "esp_system")
@@ -11,7 +11,8 @@
#include "soc/rtc.h"
#include "hal/clk_tree_hal.h"
#include "hal/clk_tree_ll.h"
#include "esp_private/esp_clk_tree_common.h"
// #include "esp_private/esp_clk_tree_common.h"
#include "sdkconfig.h"
static const char *TAG = "esp_clk_tree";
@@ -19,7 +20,40 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr
uint32_t *freq_value)
{
// TODO: [ESP32C5] IDF-8642
ESP_LOGW(TAG, "esp_clk_tree_src_get_freq_hz() has not implemented yet");
*freq_value = 0;
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");
ESP_RETURN_ON_FALSE(freq_value, ESP_ERR_INVALID_ARG, TAG, "null pointer");
uint32_t clk_src_freq = 0;
switch (clk_src) {
case SOC_MOD_CLK_XTAL:
clk_src_freq = CONFIG_XTAL_FREQ * MHZ;
break;
case SOC_MOD_CLK_PLL_F80M:
clk_src_freq = CLK_LL_PLL_80M_FREQ_MHZ * MHZ;
break;
case SOC_MOD_CLK_PLL_F160M:
clk_src_freq = CLK_LL_PLL_160M_FREQ_MHZ * MHZ;
break;
case SOC_MOD_CLK_PLL_F240M:
clk_src_freq = CLK_LL_PLL_240M_FREQ_MHZ * MHZ;
break;
case SOC_MOD_CLK_SPLL:
clk_src_freq = CLK_LL_PLL_480M_FREQ_MHZ * MHZ;
break;
case SOC_MOD_CLK_RC_FAST:
// C5-beta3 unable to calibrate to get exact RC_FAST frequency
clk_src_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
break;
case SOC_MOD_CLK_XTAL_D2:
clk_src_freq = (CONFIG_XTAL_FREQ * MHZ) >> 1;
break;
default:
break;
}
ESP_RETURN_ON_FALSE(clk_src_freq, ESP_FAIL, TAG,
"freq shouldn't be 0, calibration failed");
*freq_value = clk_src_freq;
return ESP_OK;
}
@@ -134,7 +134,7 @@ typedef enum {
RTC_CAL_RC32K = SOC_RTC_SLOW_CLK_SRC_RC32K, //!< Internal 32kHz RC oscillator, as one type of 32k clock
RTC_CAL_32K_XTAL = SOC_RTC_SLOW_CLK_SRC_XTAL32K, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = SOC_RTC_SLOW_CLK_SRC_OSC_SLOW, //!< External slow clock signal input by lp_pad_gpio0, as one type of 32k clock
RTC_CAL_RC_FAST //!< Internal 20MHz RC oscillator
// RTC_CAL_RC_FAST //!< Internal 20MHz RC oscillator
} rtc_cal_sel_t;
/**
@@ -450,6 +450,10 @@ bool rtc_dig_8m_enabled(void);
*/
uint32_t rtc_clk_freq_cal(uint32_t cal_val);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.
/**
* @brief Possible main XTAL frequency values. TODO: To be removed!
*/
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -159,21 +159,20 @@ static void rtc_clk_enable_i2c_ana_master_clock(bool enable)
static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq)
{
assert((pll_freq == CLK_LL_PLL_160M_FREQ_MHZ) || \
(pll_freq == CLK_LL_PLL_240M_FREQ_MHZ));
/* Digital part */
clk_ll_bbpll_set_freq_mhz(CLK_LL_PLL_480M_FREQ_MHZ);
clk_ll_bbpll_set_freq_mhz(pll_freq);
/* Analog part */
rtc_clk_enable_i2c_ana_master_clock(true);
/* BBPLL CALIBRATION START */
regi2c_ctrl_ll_bbpll_calibration_start();
clk_ll_bbpll_set_config(CLK_LL_PLL_480M_FREQ_MHZ, xtal_freq);
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
/* WAIT CALIBRATION DONE */
while(!regi2c_ctrl_ll_bbpll_calibration_is_done());
esp_rom_delay_us(10); // wait for true stop // TODO: check this
/* BBPLL CALIBRATION STOP */
regi2c_ctrl_ll_bbpll_calibration_stop();
rtc_clk_enable_i2c_ana_master_clock(false);
s_cur_pll_freq = CLK_LL_PLL_480M_FREQ_MHZ;
s_cur_pll_freq = pll_freq;
}
/**
@@ -184,24 +183,26 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div)
{
/* Configure clk mspi fast to XTAL*/
clk_ll_mspi_fast_sel_clk(SOC_MOD_CLK_XTAL);
clk_ll_mspi_fast_set_src(MSPI_CLK_SRC_XTAL);
clk_ll_mspi_fast_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
clk_ll_ahb_set_divider(div);
clk_ll_cpu_set_divider(div);
clk_ll_ahb_set_divider(div);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
clk_ll_bus_update();
esp_rom_set_cpu_ticks_per_us(cpu_freq);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
/* Configure clk mspi fast to XTAL*/
clk_ll_mspi_fast_sel_clk(SOC_MOD_CLK_XTAL);
clk_ll_mspi_fast_set_src(MSPI_CLK_SRC_XTAL);
clk_ll_mspi_fast_set_divider(1);
clk_ll_ahb_set_divider(1);
clk_ll_cpu_set_divider(1);
clk_ll_ahb_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
clk_ll_bus_update();
esp_rom_set_cpu_ticks_per_us(20);
}
@@ -218,11 +219,12 @@ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
clk_ll_ahb_set_divider(cfg.source_freq_mhz / 40);
clk_ll_cpu_set_divider(cfg.div);
clk_ll_cpu_set_src(cfg.source);
clk_ll_bus_update();
esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
/* Configure clk mspi fast to 80m*/
clk_ll_mspi_fast_set_divider(6);
clk_ll_mspi_fast_sel_clk(MSPI_CLK_SRC_SPLL);
clk_ll_mspi_fast_set_src(MSPI_CLK_SRC_SPLL);
}
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
@@ -233,19 +235,34 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
uint32_t real_freq_mhz;
uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (freq_mhz == 48 || freq_mhz == 24 || freq_mhz == 16 || freq_mhz == 12 || freq_mhz == 8) {
#if (CONFIG_XTAL_FREQ == 48)
// To maintain APB_MAX (40MHz) while lowering CPU frequency when using a 48MHz XTAL, have to let CPU frequnecy be
// 40MHz with PLL_F160M or PLL_F240M clock source. This is a special case, has to handle separately.
if (freq_mhz == 40) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL_F160M;
source_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ;
divider = CLK_LL_PLL_160M_FREQ_MHZ / freq_mhz;
} else
#endif
if (freq_mhz <= xtal_freq && freq_mhz != 0) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
if (real_freq_mhz != freq_mhz) {
// no suitable divider
return false;
}
source_freq_mhz = xtal_freq;
source = SOC_CPU_CLK_SRC_XTAL;
} else if (freq_mhz == 240) {
real_freq_mhz = freq_mhz;
} else if (freq_mhz == 240 || freq_mhz == 120) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL_F240;
source = SOC_CPU_CLK_SRC_PLL_F240M;
source_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ;
divider = CLK_LL_PLL_240M_FREQ_MHZ / freq_mhz;
}else if (freq_mhz == 160 || freq_mhz == 80 || freq_mhz == 40) {
} else if (freq_mhz == 160 || freq_mhz == 80) { // TODO: 80MHz can be get from PLL_F240M or PLL_F160M, which is better?
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL_F160;
source = SOC_CPU_CLK_SRC_PLL_F160M;
source_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ;
divider = CLK_LL_PLL_160M_FREQ_MHZ / freq_mhz;
} else {
@@ -271,21 +288,22 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
/* Configure clk mspi fast to 80m*/
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
if (((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240)) && !s_bbpll_digi_consumers_ref_count) {
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();
}
} else if ((config->source == SOC_CPU_CLK_SRC_PLL_F160) || (config->source == SOC_CPU_CLK_SRC_PLL_F240)) {
if ((old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F160) && (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F240)) {
} else if ((config->source == SOC_CPU_CLK_SRC_PLL_F160M) || (config->source == SOC_CPU_CLK_SRC_PLL_F240M)) {
if ((old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F160M) && (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F240M)) {
// PLL_F160M and PLL_F240M both derived from S(BB)PLL (480MHz)
rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_EN_START);
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_480M_FREQ_MHZ);
}
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_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_F160) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240)) && !s_bbpll_digi_consumers_ref_count) {
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();
}
@@ -305,13 +323,13 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
freq_mhz = source_freq_mhz / div;
break;
}
case SOC_CPU_CLK_SRC_PLL_F160: {
case SOC_CPU_CLK_SRC_PLL_F160M: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ;
freq_mhz = source_freq_mhz / div;
break;
}
case SOC_CPU_CLK_SRC_PLL_F240: {
case SOC_CPU_CLK_SRC_PLL_F240M: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ;
freq_mhz = source_freq_mhz / div;
@@ -338,7 +356,7 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
{
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
} else if (((config->source == SOC_CPU_CLK_SRC_PLL_F160) || (config->source == SOC_CPU_CLK_SRC_PLL_F240)) &&
} else if (((config->source == SOC_CPU_CLK_SRC_PLL_F160M) || (config->source == SOC_CPU_CLK_SRC_PLL_F240M)) &&
s_cur_pll_freq == config->source_freq_mhz) {
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
} else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
@@ -391,11 +409,11 @@ static uint32_t rtc_clk_ahb_freq_get(void)
soc_root_freq_mhz = rtc_clk_xtal_freq_get();
divider = clk_ll_ahb_get_divider();
break;
case SOC_CPU_CLK_SRC_PLL_F160:
case SOC_CPU_CLK_SRC_PLL_F160M:
soc_root_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ;
divider = clk_ll_ahb_get_divider();
break;
case SOC_CPU_CLK_SRC_PLL_F240:
case SOC_CPU_CLK_SRC_PLL_F240M:
soc_root_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ;
divider = clk_ll_ahb_get_divider();
break;
@@ -78,7 +78,7 @@ void rtc_clk_init(rtc_clk_config_t cfg)
REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, HP_CALI_DBIAS);
REG_SET_FIELD(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, LP_CALI_DBIAS);
clk_ll_rc_fast_tick_conf();
clk_ll_rc_fast_tick_conf(); // TODO: IDF-8642 Unnecessary or not?
soc_xtal_freq_t xtal_freq = cfg.xtal_freq;
esp_rom_output_tx_wait_idle(0);
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -69,13 +69,13 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
if (cal_clk == RTC_CAL_RTC_MUX) {
cal_clk = (rtc_cal_sel_t)slow_clk_src;
}
if (cal_clk == RTC_CAL_RC_FAST) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
#if !CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8642 Seems RC_SLOW can't be calibrated
} else if (cal_clk == RTC_CAL_RC_SLOW) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
#endif // !CONFIG_IDF_TARGET_ESP32C5
} else {
// TODO: [ESP32C5] IDF-8642 Seems RC_SLOW, RC_FAST can't be calibrated on beta3
// if (cal_clk == RTC_CAL_RC_FAST) {
// cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
// } else if (cal_clk == RTC_CAL_RC_SLOW) {
// cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
// } else
{
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K;
clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk);
}
@@ -90,16 +90,16 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_enable();
}
}
// bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
// bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
// if (cal_clk == RTC_CAL_RC_FAST) {
// if (!rc_fast_enabled) {
// rtc_clk_8m_enable(true);
// }
// if (!dig_rc_fast_enabled) {
// rtc_dig_clk8m_enable();
// }
// }
bool rc32k_enabled = clk_ll_rc32k_is_enabled();
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
@@ -155,14 +155,12 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
/*The Fosc CLK of calibration circuit is divided by 32 for ECO1.
So we need to multiply the frequency of the Fosc for ECO1 and above chips by 32 times.
And ensure that this modification will not affect ECO0.*/
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
if (cal_clk == RTC_CAL_RC_FAST) {
cal_val = cal_val >> 5;
}
}
// TODO: IDF-8642 Check whether this workaround still need for C5
// /*The Fosc CLK of calibration circuit is divided by 32.
// So we need to multiply the frequency of the FOSC by 32 times.*/
// if (cal_clk == RTC_CAL_RC_FAST) {
// cal_val = cal_val >> 5;
// }
break;
}
if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) {
@@ -177,14 +175,14 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
if (!rc_fast_enabled) {
rtc_clk_8m_enable(false);
}
}
// if (cal_clk == RTC_CAL_RC_FAST) {
// if (!dig_rc_fast_enabled) {
// rtc_dig_clk8m_disable();
// }
// if (!rc_fast_enabled) {
// rtc_clk_8m_enable(false);
// }
// }
if (cal_clk == RTC_CAL_RC32K) {
if (!dig_rc32k_enabled) {
@@ -214,14 +212,13 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
/*The Fosc CLK of calibration circuit is divided by 32 for ECO1.
So we need to divide the calibrate cycles of the FOSC for ECO1 and above chips by 32 to
avoid excessive calibration time.*/
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
if (cal_clk == RTC_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> 5;
}
}
// TODO: IDF-8642 Check whether this workaround still need for C5
// /*The Fosc CLK of calibration circuit is divided by 32.
// So we need to divide the calibrate cycles of the FOSC by 32 to
// avoid excessive calibration time.*/
// if (cal_clk == RTC_CAL_RC_FAST) {
// slowclk_cycles = slowclk_cycles >> 5;
// }
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);