clk_tree: Refactor rtc_clk.c by adding HAL layer for clock subsystem

This commit is contained in:
songruojing
2022-05-27 02:23:17 +08:00
parent 52769051e2
commit c8752cee6a
64 changed files with 5378 additions and 2048 deletions

View File

@@ -9,7 +9,7 @@
#include "hal/efuse_hal.h"
#include "soc/rtc_cntl_reg.h"
#if CONFIG_IDF_TARGET_ESP32
#include "soc/dport_reg.h"
#include "hal/clk_tree_ll.h"
#endif
#include "esp_rom_sys.h"
#include "esp_rom_uart.h"
@@ -33,22 +33,28 @@ __attribute__((weak)) void bootloader_clock_configure(void)
* previously.
*/
if (efuse_hal_get_chip_revision() == 0 &&
DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL) == DPORT_CPUPERIOD_SEL_240) {
clk_ll_cpu_get_freq_mhz_from_pll() == CLK_LL_PLL_240M_FREQ_MHZ) {
cpu_freq_mhz = 240;
}
#elif CONFIG_IDF_TARGET_ESP32H2
cpu_freq_mhz = 64;
#endif
if (rtc_clk_apb_freq_get() < APB_CLK_FREQ || esp_rom_get_reset_reason(0) != RESET_REASON_CPU0_SW) {
if (esp_rom_get_reset_reason(0) != RESET_REASON_CPU0_SW || rtc_clk_apb_freq_get() < APB_CLK_FREQ) {
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
#if CONFIG_IDF_TARGET_ESP32
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
#endif
/* ESP32-S2 doesn't have XTAL_FREQ choice, always 40MHz */
/* Except ESP32, there is no XTAL_FREQ choice */
clk_cfg.cpu_freq_mhz = cpu_freq_mhz;
clk_cfg.slow_clk_src = rtc_clk_slow_src_get();
if (clk_cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_INVALID) {
clk_cfg.slow_clk_src = SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
}
clk_cfg.fast_clk_src = rtc_clk_fast_src_get();
if (clk_cfg.fast_clk_src == SOC_RTC_FAST_CLK_SRC_INVALID) {
clk_cfg.fast_clk_src = SOC_RTC_FAST_CLK_SRC_XTAL_DIV;
}
rtc_clk_init(clk_cfg);
}

View File

@@ -14,6 +14,7 @@
#include "esp_rom_caps.h"
#include "esp_rom_sys.h"
#include "esp_private/esp_clk.h"
#include "hal/clk_tree_ll.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/rtc.h"
@@ -126,12 +127,12 @@ void esp_clk_slowclk_cal_set(uint32_t new_cal)
*/
esp_rtc_get_time_us();
#endif // CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
REG_WRITE(RTC_SLOW_CLK_CAL_REG, new_cal);
clk_ll_rtc_slow_store_cal(new_cal);
}
uint32_t esp_clk_slowclk_cal_get(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
return clk_ll_rtc_slow_load_cal();
}
uint64_t esp_clk_rtc_time(void)

View File

@@ -47,7 +47,7 @@ void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions
* from regi2c_apll.h/regi2c_bbpll.h header files.
* from regi2c_xxx.h header files.
*/
#define REGI2C_WRITE_MASK(block, reg_add, indata) \
regi2c_ctrl_write_reg_mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata)

View File

@@ -12,92 +12,24 @@
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"
#include "soc/soc_caps.h"
#include "soc/dport_reg.h"
#include "hal/efuse_ll.h"
#include "hal/efuse_hal.h"
#include "soc/syscon_reg.h"
#include "soc/gpio_struct.h"
#include "hal/cpu_hal.h"
#include "hal/gpio_ll.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
#include "esp_rom_gpio.h"
#include "esp32/rom/ets_sys.h" // for ets_update_cpu_frequency
#include "esp32/rom/rtc.h"
#include "hal/clk_tree_ll.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/io_mux_reg.h"
#include "regi2c_ctrl.h"
#include "regi2c_apll.h"
#include "regi2c_bbpll.h"
/* BBPLL configuration values */
#define BBPLL_ENDIV5_VAL_320M 0x43
#define BBPLL_BBADC_DSMP_VAL_320M 0x84
#define BBPLL_ENDIV5_VAL_480M 0xc3
#define BBPLL_BBADC_DSMP_VAL_480M 0x74
#define BBPLL_IR_CAL_DELAY_VAL 0x18
#define BBPLL_IR_CAL_EXT_CAP_VAL 0x20
#define BBPLL_OC_ENB_FCAL_VAL 0x9a
#define BBPLL_OC_ENB_VCON_VAL 0x00
#define BBPLL_BBADC_CAL_7_0_VAL 0x00
#define APLL_SDM_STOP_VAL_1 0x09
#define APLL_SDM_STOP_VAL_2_REV0 0x69
#define APLL_SDM_STOP_VAL_2_REV1 0x49
#define APLL_CAL_DELAY_1 0x0f
#define APLL_CAL_DELAY_2 0x3f
#define APLL_CAL_DELAY_3 0x1f
#define XTAL_32K_DAC_VAL 1
#define XTAL_32K_DRES_VAL 3
#define XTAL_32K_DBIAS_VAL 0
#define XTAL_32K_BOOTSTRAP_DAC_VAL 3
#define XTAL_32K_BOOTSTRAP_DRES_VAL 3
#define XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
#define XTAL_32K_BOOTSTRAP_TIME_US 7
#define XTAL_32K_EXT_DAC_VAL 2
#define XTAL_32K_EXT_DRES_VAL 3
#define XTAL_32K_EXT_DBIAS_VAL 1
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
* TODO: some of these are excessive, and should be reduced.
*/
#define DELAY_PLL_DBIAS_RAISE 3
#define DELAY_PLL_ENABLE_WITH_150K 80
#define DELAY_PLL_ENABLE_WITH_32K 160
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Core voltage needs to be increased in two cases:
* 1. running at 240 MHz
* 2. running with 80MHz Flash frequency
*
* There is a record in efuse which indicates the proper voltage for these two cases.
*/
#define RTC_CNTL_DBIAS_HP_VOLT (RTC_CNTL_DBIAS_1V25 - efuse_ll_get_vol_level_hp_inv())
#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_HP_VOLT
#else
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_1V10
#endif
#define DIG_DBIAS_240M RTC_CNTL_DBIAS_HP_VOLT
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
#define RTC_PLL_FREQ_320M 320
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
static void rtc_clk_cpu_freq_to_8m(void);
static void rtc_clk_bbpll_disable(void);
static void rtc_clk_bbpll_enable(void);
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz);
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
@@ -105,20 +37,12 @@ static uint32_t s_cur_pll_freq;
static const char* TAG = "rtc_clk";
static void rtc_clk_32k_enable_common(int dac, int dres, int dbias)
static void rtc_clk_32k_enable_common(clk_ll_xtal32k_enable_mode_t mode)
{
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE |
RTC_IO_X32N_RDE | RTC_IO_X32N_FUN_IE | RTC_IO_X32P_FUN_IE);
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
/* Set the parameters of xtal
dac --> current
dres --> resistance
dbias --> bais voltage
*/
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, dac);
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, dres);
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias);
#ifdef CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT
uint8_t chip_ver = efuse_hal_get_chip_revision();
@@ -157,17 +81,17 @@ static void rtc_clk_32k_enable_common(int dac, int dres, int dbias)
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_START_M);
}
#endif
/* Power up external xtal */
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
clk_ll_xtal32k_enable(mode);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
rtc_clk_32k_enable_common(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL);
rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
} else {
clk_ll_xtal32k_disable();
/* Disable X32N and X32P pad drive external xtal */
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
#ifdef CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT
@@ -191,7 +115,7 @@ void rtc_clk_32k_enable(bool enable)
void rtc_clk_32k_enable_external(void)
{
rtc_clk_32k_enable_common(XTAL_32K_EXT_DAC_VAL, XTAL_32K_EXT_DRES_VAL, XTAL_32K_EXT_DBIAS_VAL);
rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
}
/* Helping external 32kHz crystal to start up.
@@ -201,88 +125,86 @@ void rtc_clk_32k_enable_external(void)
void rtc_clk_32k_bootstrap(uint32_t cycle)
{
if (cycle){
const uint32_t pin_32 = 32;
const uint32_t pin_33 = 33;
esp_rom_gpio_pad_select_gpio(pin_32);
esp_rom_gpio_pad_select_gpio(pin_33);
gpio_ll_output_enable(&GPIO, pin_32);
gpio_ll_output_enable(&GPIO, pin_33);
gpio_ll_set_level(&GPIO, pin_32, 1);
gpio_ll_set_level(&GPIO, pin_33, 0);
esp_rom_gpio_pad_select_gpio(XTAL32K_P_GPIO_NUM);
esp_rom_gpio_pad_select_gpio(XTAL32K_N_GPIO_NUM);
gpio_ll_output_enable(&GPIO, XTAL32K_P_GPIO_NUM);
gpio_ll_output_enable(&GPIO, XTAL32K_N_GPIO_NUM);
gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 1);
gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 0);
const uint32_t delay_us = (1000000 / SOC_CLK_XTAL32K_FREQ_APPROX / 2);
while(cycle){
gpio_ll_set_level(&GPIO, pin_32, 1);
gpio_ll_set_level(&GPIO, pin_33, 0);
while (cycle) {
gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 1);
gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 0);
esp_rom_delay_us(delay_us);
gpio_ll_set_level(&GPIO, pin_33, 1);
gpio_ll_set_level(&GPIO, pin_32, 0);
gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 1);
gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 0);
esp_rom_delay_us(delay_us);
cycle--;
}
// disable pins
gpio_ll_output_disable(&GPIO, pin_32);
gpio_ll_output_disable(&GPIO, pin_33);
gpio_ll_output_disable(&GPIO, XTAL32K_P_GPIO_NUM);
gpio_ll_output_disable(&GPIO, XTAL32K_N_GPIO_NUM);
}
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
clk_ll_xtal32k_disable();
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE);
esp_rom_delay_us(XTAL_32K_BOOTSTRAP_TIME_US);
rtc_clk_32k_enable_common(XTAL_32K_BOOTSTRAP_DAC_VAL,
XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL);
rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP);
}
bool rtc_clk_32k_enabled(void)
{
return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K) != 0;
return clk_ll_xtal32k_is_enabled();
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
clk_ll_rc_fast_enable();
if (d256_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_enable();
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_disable();
}
esp_rom_delay_us(DELAY_8M_ENABLE);
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
clk_ll_rc_fast_disable();
}
}
bool rtc_clk_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
return clk_ll_rc_fast_is_enabled();
}
bool rtc_clk_8md256_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
return clk_ll_rc_fast_d256_is_enabled();
}
void rtc_clk_apll_enable(bool enable)
{
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1);
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0);
if (!enable &&
REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL) != RTC_CNTL_SOC_CLK_SEL_PLL) {
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
if (enable) {
clk_ll_apll_enable();
} else {
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
clk_ll_apll_disable();
}
if (!enable && (clk_ll_cpu_get_src() != SOC_CPU_CLK_SRC_PLL)) {
// if apll and bbpll are both not in use, then can also power down the internal I2C bus
// this power down affects most of the analog peripherals
clk_ll_i2c_pd();
} else {
clk_ll_i2c_pu();
}
}
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
{
uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (rtc_xtal_freq == 0) {
uint32_t xtal_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
if (xtal_freq_mhz == 0) {
// xtal_freq has not set yet
ESP_HW_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet");
abort();
@@ -316,9 +238,9 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
}
}
// sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
sdm2 = (int)(((o_div + 2) * 2 * freq) / (xtal_freq_mhz * MHZ)) - 4;
// numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2
float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2;
float numrator = (((o_div + 2) * 2 * freq) / ((float)xtal_freq_mhz * MHZ)) - 4 - sdm2;
// If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2
if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) {
sdm2++;
@@ -330,7 +252,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
// Get the closest sdm0
sdm0 = (int)(numrator * 65536.0 + 0.5) % 256;
}
uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
uint32_t real_freq = (uint32_t)(xtal_freq_mhz * MHZ * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
*_o_div = o_div;
*_sdm0 = sdm0;
*_sdm1 = sdm1;
@@ -340,168 +262,90 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1;
uint32_t is_rev0 = (efuse_ll_get_chip_ver_rev1() == 0);
if (is_rev0) {
sdm0 = 0;
sdm1 = 0;
sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0;
}
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
bool is_rev0 = (efuse_ll_get_chip_ver_rev1() == 0);
clk_ll_apll_set_config(is_rev0, o_div, sdm0, sdm1, sdm2);
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
clk_ll_apll_set_calibration();
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
while (!clk_ll_apll_calibration_is_done()) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
}
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
clk_ll_rtc_slow_set_src(clk_src);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
// The logic should be moved to BT driver
if (clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
clk_ll_xtal32k_digi_enable();
} else {
clk_ll_xtal32k_digi_disable();
}
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
{
switch(rtc_clk_slow_src_get()) {
switch (rtc_clk_slow_src_get()) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_disable(void)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t div10_8;
uint8_t lref;
uint8_t dcur;
uint8_t bw;
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
if (pll_freq == RTC_PLL_FREQ_320M) {
/* Raise the voltage, if needed */
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M);
/* Configure 320M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 32;
div10_8 = 0;
lref = 0;
dcur = 6;
bw = 3;
break;
case RTC_XTAL_FREQ_26M:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
case RTC_XTAL_FREQ_24M:
div_ref = 11;
div7_0 = 224;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
default:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 0;
dcur = 0;
bw = 0;
break;
// if apll is under force power down, then can also power down the internal I2C bus
// this power down affects most of the analog peripherals
if (clk_ll_apll_is_fpd()) {
clk_ll_i2c_pd();
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_320M);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, BBPLL_BBADC_DSMP_VAL_320M);
} else {
}
static void rtc_clk_bbpll_enable(void)
{
clk_ll_i2c_pu();
clk_ll_bbpll_enable();
}
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
/* Raise the voltage */
if (pll_freq == CLK_LL_PLL_320M_FREQ_MHZ) {
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M);
} else { // CLK_LL_PLL_480M_FREQ_MHZ
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M);
esp_rom_delay_us(DELAY_PLL_DBIAS_RAISE);
/* Configure 480M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 28;
div10_8 = 0;
lref = 0;
dcur = 6;
bw = 3;
break;
case RTC_XTAL_FREQ_26M:
div_ref = 12;
div7_0 = 144;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
case RTC_XTAL_FREQ_24M:
div_ref = 11;
div7_0 = 144;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
default:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 0;
dcur = 0;
bw = 0;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_480M);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, BBPLL_BBADC_DSMP_VAL_480M);
esp_rom_delay_us(SOC_DELAY_PLL_DBIAS_RAISE);
}
uint8_t i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (bw << 6) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
uint32_t delay_pll_en = (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) ?
DELAY_PLL_ENABLE_WITH_150K : DELAY_PLL_ENABLE_WITH_32K;
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
uint32_t delay_pll_en = (clk_ll_rtc_slow_get_src() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) ?
SOC_DELAY_PLL_ENABLE_WITH_150K : SOC_DELAY_PLL_ENABLE_WITH_32K;
esp_rom_delay_us(delay_pll_en);
s_cur_pll_freq = pll_freq;
}
@@ -513,58 +357,29 @@ void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* set divider from XTAL to APB clock */
REG_SET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT, div - 1);
clk_ll_cpu_set_divider(div);
/* adjust ref_tick */
REG_WRITE(SYSCON_XTAL_TICK_CONF_REG, freq * MHZ / REF_CLK_FREQ - 1);
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_XTAL, freq);
/* switch clock source */
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_XTL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
/* lower the voltage */
if (freq <= 2) {
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M);
} else {
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
}
int dbias = (freq <= 2) ? DIG_DBIAS_2M : DIG_DBIAS_XTAL;
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
REG_SET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT, 0);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_8M);
clk_ll_cpu_set_divider(1);
/* adjust ref_tick */
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_RC_FAST, 8);
/* switch clock source */
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
RTC_CNTL_BBPLL_I2C_FORCE_PD);
s_cur_pll_freq = 0;
/* is APLL under force power down? */
uint32_t apll_fpd = REG_GET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
if (apll_fpd) {
/* then also power down the internal I2C bus */
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
}
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
RTC_CNTL_BIAS_I2C_FORCE_PD | RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
/* reset BBPLL configuration */
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_DELAY, BBPLL_IR_CAL_DELAY_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, BBPLL_IR_CAL_EXT_CAP_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_FCAL, BBPLL_OC_ENB_FCAL_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_VCON, BBPLL_OC_ENB_VCON_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_CAL_7_0, BBPLL_BBADC_CAL_7_0_VAL);
}
/**
* Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
* PLL must already be enabled.
@@ -572,22 +387,13 @@ static void rtc_clk_bbpll_enable(void)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int dbias = DIG_DBIAS_80M_160M;
int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 160) {
per_conf = DPORT_CPUPERIOD_SEL_160;
} else if (cpu_freq_mhz == 240) {
dbias = DIG_DBIAS_240M;
per_conf = DPORT_CPUPERIOD_SEL_240;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
abort();
}
DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, per_conf);
int dbias = (cpu_freq_mhz == 240) ? DIG_DBIAS_240M : DIG_DBIAS_80M_160M;
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_PLL);
/* adjust ref_tick */
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, cpu_freq_mhz);
/* switch clock source */
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
rtc_clk_wait_for_slow_cycle();
@@ -595,7 +401,7 @@ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
rtc_clk_wait_for_slow_cycle();
@@ -623,17 +429,17 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* ou
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_320M;
source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
divider = 4;
} else if (freq_mhz == 160) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_320M;
source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
divider = 2;
} else if (freq_mhz == 240) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 2;
} else {
// unsupported frequency
@@ -651,14 +457,15 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint32_t soc_clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
if (soc_clk_sel != RTC_CNTL_SOC_CLK_SEL_XTL) {
soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(xtal_freq, 1);
rtc_clk_wait_for_slow_cycle();
}
if (soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_disable();
}
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
if (config->div > 1) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
@@ -675,47 +482,40 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
switch (soc_clk_sel) {
case RTC_CNTL_SOC_CLK_SEL_XTL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT) + 1;
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
}
break;
case RTC_CNTL_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
source_freq_mhz = RTC_PLL_FREQ_320M;
case SOC_CPU_CLK_SRC_PLL: {
freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
div = 4;
freq_mhz = 80;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
source_freq_mhz = RTC_PLL_FREQ_320M;
} else if (freq_mhz == CLK_LL_PLL_160M_FREQ_MHZ) {
source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
div = 2;
freq_mhz = 160;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_240) {
source_freq_mhz = RTC_PLL_FREQ_480M;
} else if (freq_mhz == CLK_LL_PLL_240M_FREQ_MHZ) {
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
div = 2;
freq_mhz = 240;
} else {
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
}
break;
}
case RTC_CNTL_SOC_CLK_SEL_8M:
source = SOC_CPU_CLK_SRC_RC_FAST;
case SOC_CPU_CLK_SRC_RC_FAST:
source_freq_mhz = 8;
div = 1;
freq_mhz = source_freq_mhz;
break;
case RTC_CNTL_SOC_CLK_SEL_APLL:
case SOC_CPU_CLK_SRC_APLL:
default:
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
@@ -743,26 +543,21 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config)
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
/* We may have already written XTAL value into RTC_XTAL_FREQ_REG */
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
if (xtal_freq_mhz == 0) {
return RTC_XTAL_FREQ_AUTO;
}
return reg_val_to_clk_val(xtal_freq_reg & ~RTC_DISABLE_ROM_LOG);
return (rtc_xtal_freq_t)xtal_freq_mhz;
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
uint32_t reg = READ_PERI_REG(RTC_XTAL_FREQ_REG) & RTC_DISABLE_ROM_LOG;
if (reg == RTC_DISABLE_ROM_LOG) {
xtal_freq |= 1;
}
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
clk_ll_xtal_store_freq_mhz((uint32_t)xtal_freq);
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
clk_ll_apb_store_freq_hz(apb_freq);
}
uint32_t rtc_clk_apb_freq_get(void)
@@ -770,28 +565,24 @@ uint32_t rtc_clk_apb_freq_get(void)
#if CONFIG_IDF_ENV_FPGA
return CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * MHZ;
#endif // CONFIG_IDF_ENV_FPGA
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
// round to the nearest MHz
freq_hz += MHZ / 2;
uint32_t remainder = freq_hz % MHZ;
return freq_hz - remainder;
return clk_ll_apb_load_freq_hz();
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
return clk_ll_rc_fast_digi_is_enabled();
}
/* Name used in libphy.a:phy_chip_v7.o

View File

@@ -1,40 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define MHZ (1000000)
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val) {
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val) {
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val) {
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -14,12 +14,11 @@
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"
#include "soc/efuse_periph.h"
#include "soc/syscon_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
@@ -27,6 +26,7 @@
#define XTAL_FREQ_EST_CYCLES 10
static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void);
extern void rtc_clk_cpu_freq_to_xtal(int freq, int div);
static const char* TAG = "rtc_clk_init";
@@ -43,7 +43,7 @@ void rtc_clk_init(rtc_clk_config_t cfg)
* PLL is configured for 480M, but it takes less time to switch to 40M and
* run the following code than querying the PLL does.
*/
if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL) == RTC_CNTL_SOC_CLK_SEL_PLL) {
if (clk_ll_cpu_get_src() == SOC_CPU_CLK_SRC_PLL) {
/* We don't know actual XTAL frequency yet, assume 40MHz.
* REF_TICK divider will be corrected below, once XTAL frequency is
* determined.
@@ -63,18 +63,22 @@ void rtc_clk_init(rtc_clk_config_t cfg)
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq);
/* Configure 8M clock division */
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, cfg.clk_8m_div);
clk_ll_rc_fast_set_divider(cfg.clk_8m_div + 1);
/* Reset (disable) i2c internal bus for all regi2c registers */
regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M);
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
regi2c_ctrl_ll_i2c_apll_enable(); // TODO: This should be moved to apll_set_config
/* Estimate XTAL frequency */
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
if (clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
rtc_xtal_freq_t configured_xtal_freq = cfg.xtal_freq;
rtc_xtal_freq_t stored_xtal_freq = rtc_clk_xtal_freq_get(); // read the xtal freq value from RTC storage register
rtc_xtal_freq_t xtal_freq = configured_xtal_freq;
if (configured_xtal_freq == RTC_XTAL_FREQ_AUTO) {
if (stored_xtal_freq != RTC_XTAL_FREQ_AUTO) {
/* XTAL frequency has already been set, use existing value */
xtal_freq = rtc_clk_xtal_freq_get();
xtal_freq = stored_xtal_freq;
} else {
/* Not set yet, estimate XTAL frequency based on RTC_FAST_CLK */
xtal_freq = rtc_clk_xtal_freq_estimate();
@@ -83,16 +87,16 @@ void rtc_clk_init(rtc_clk_config_t cfg)
xtal_freq = RTC_XTAL_FREQ_26M;
}
}
} else if (!clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
} else if (stored_xtal_freq == RTC_XTAL_FREQ_AUTO) {
/* Exact frequency was set in sdkconfig, but still warn if autodetected
* frequency is different. If autodetection failed, worst case we get a
* bit of garbage output.
*/
rtc_xtal_freq_t est_xtal_freq = rtc_clk_xtal_freq_estimate();
if (est_xtal_freq != xtal_freq) {
if (est_xtal_freq != configured_xtal_freq) {
ESP_HW_LOGW(TAG, "Possibly invalid CONFIG_ESP32_XTAL_FREQ setting (%dMHz). Detected %d MHz.",
xtal_freq, est_xtal_freq);
configured_xtal_freq, est_xtal_freq);
}
}
esp_rom_uart_tx_wait_idle(0);
@@ -112,8 +116,10 @@ void rtc_clk_init(rtc_clk_config_t cfg)
rtc_clk_cpu_freq_set_config(&new_config);
/* Configure REF_TICK */
REG_WRITE(SYSCON_XTAL_TICK_CONF_REG, xtal_freq - 1);
REG_WRITE(SYSCON_PLL_TICK_CONF_REG, APB_CLK_FREQ / MHZ - 1); /* Under PLL, APB frequency is always 80MHz */
// Initialize it in the bootloader stage, but it is not a must to do here
// REF_TICK divider value always gets updated when switching cpu clock source
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_XTAL, xtal_freq);
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, new_config.freq_mhz);
/* Re-calculate the ccount to make time calculation correct. */
cpu_hal_set_cycle_count( (uint64_t)cpu_hal_get_cycle_count() * cfg.cpu_freq_mhz / freq_before );

View File

@@ -6,12 +6,11 @@
#include <stdint.h>
#include "esp_rom_sys.h"
#include "hal/clk_tree_ll.h"
#include "soc/rtc.h"
#include "soc/timer_periph.h"
#include "esp_hw_log.h"
#define MHZ (1000000)
static const char* TAG = "rtc_time";
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
@@ -36,13 +35,13 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
{
assert(slowclk_cycles < 32767);
/* Enable requested clock (150k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_enable();
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
@@ -88,10 +87,13 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
esp_rom_delay_us(1);
}
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_disable();
}
if (timeout_us == 0) {
/* timed out waiting for calibration */
@@ -139,7 +141,7 @@ uint64_t rtc_time_get(void)
while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) {
esp_rom_delay_us(1); // might take 1 RTC slowclk period, don't flood RTC bus
if (attempts) {
if (--attempts == 0 && REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN)) {
if (--attempts == 0 && clk_ll_xtal32k_digi_is_enabled()) {
ESP_HW_LOGE(TAG, "rtc_time_get() 32kHz xtal has been stopped");
}
}
@@ -165,7 +167,7 @@ void rtc_clk_wait_for_slow_cycle(void)
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
esp_rom_delay_us(1);
if (attempts) {
if (--attempts == 0 && REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN)) {
if (--attempts == 0 && clk_ll_xtal32k_digi_is_enabled()) {
ESP_HW_LOGE(TAG, "32kHz xtal has been stopped");
}
}

View File

@@ -15,80 +15,75 @@
#include "esp32c2/rom/uart.h"
#include "esp32c2/rom/gpio.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "hal/gpio_ll.h"
#include "soc/io_mux_reg.h"
#include "soc/soc.h"
#include "regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
// Current PLL frequency, in 480MHZ. Zero if PLL is not enabled.
static int s_cur_pll_freq;
static void rtc_clk_cpu_freq_to_xtal(int freq, int div);
static void rtc_clk_cpu_freq_to_8m(void);
void rtc_clk_32k_enable_external(void)
{
REG_SET_BIT(PERIPHS_IO_MUX_XTAL_32K_P_U, FUN_IE);
REG_SET_BIT(RTC_CNTL_PAD_HOLD_REG, RTC_CNTL_GPIO_PIN0_HOLD);
gpio_ll_input_enable(&GPIO, EXT_OSC_SLOW_GPIO_NUM);
gpio_ll_hold_en(&GPIO, EXT_OSC_SLOW_GPIO_NUM);
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
esp_rom_delay_us(DELAY_8M_ENABLE);
clk_ll_rc_fast_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
clk_ll_rc_fast_disable();
}
/* d256 should be independent configured with 8M
* Maybe we can split this function into 8m and dmd256
*/
if (d256_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_enable();
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_disable();
}
}
bool rtc_clk_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
return clk_ll_rc_fast_is_enabled();
}
bool rtc_clk_8md256_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
return clk_ll_rc_fast_d256_is_enabled();
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
clk_ll_rtc_slow_set_src(clk_src);
/* Why we need to connect this clock to digital?
* Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) ? 1 : 0);
if (clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
clk_ll_xtal32k_digi_enable();
} else {
clk_ll_xtal32k_digi_disable();
}
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
@@ -97,60 +92,39 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW: return SOC_CLK_OSC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_enable();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
(void) xtal_freq;
// ESP32-C2 only support 40M XTAL, all the parameters are given as 40M XTAL directly.
uint8_t div_ref = 0;
uint8_t div7_0 = 8;
uint8_t dr1 = 0;
uint8_t dr3 = 0;
uint8_t dchgp = 5;
uint8_t dcur = 3;
uint8_t dbias = 2;
CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
/* Set this register to let the digital part know 480M PLL is used */
SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
/* Digital part */
clk_ll_bbpll_set_freq_mhz(pll_freq);
/* Analog part */
regi2c_ctrl_ll_bbpll_calibration_start();
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
s_cur_pll_freq = pll_freq;
}
@@ -162,18 +136,9 @@ void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 120) {
per_conf = DPORT_CPUPERIOD_SEL_120;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
abort();
}
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(40 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
}
@@ -185,7 +150,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
uint32_t divider;
uint32_t real_freq_mhz;
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (freq_mhz <= xtal_freq && freq_mhz != 0) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
@@ -199,12 +164,12 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 6;
} else if (freq_mhz == 120) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 4;
} else {
// unsupported frequency
@@ -221,21 +186,21 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
{
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
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 (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_disable();
}
} else if (config->source == SOC_CPU_CLK_SRC_PLL) {
if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), 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_8m();
if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_disable();
}
}
@@ -243,38 +208,32 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
}
break;
case DPORT_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
uint32_t cpuperiod_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
source_freq_mhz = RTC_PLL_FREQ_480M; // PLL clock on ESP32-C2 was fixed to 480MHz
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
case SOC_CPU_CLK_SRC_PLL: {
freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ; // PLL clock on ESP32-C2 was fixed to 480MHz
if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
div = 6;
freq_mhz = 80;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_120) {
} else if (freq_mhz == CLK_LL_PLL_120M_FREQ_MHZ) {
div = 4;
freq_mhz = 120;
} else {
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
}
break;
}
case DPORT_SOC_CLK_SEL_8M:
source = SOC_CPU_CLK_SRC_RC_FAST;
source_freq_mhz = 8;
case SOC_CPU_CLK_SRC_RC_FAST:
source_freq_mhz = 20;
div = 1;
freq_mhz = source_freq_mhz;
break;
@@ -305,7 +264,7 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
rtc_clk_bbpll_disable();
@@ -314,84 +273,75 @@ void rtc_clk_cpu_freq_set_xtal(void)
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
/* no need to adjust the REF_TICK */
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_divider(div);
/* switch clock source */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
ets_update_cpu_frequency(20);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
if (xtal_freq_mhz == 0) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 40MHz");
return RTC_XTAL_FREQ_40M;
}
return reg_val_to_clk_val(xtal_freq_reg);
return (rtc_xtal_freq_t)xtal_freq_mhz;
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
clk_ll_xtal_store_freq_mhz(xtal_freq);
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
clk_ll_apb_store_freq_hz(apb_freq);
}
uint32_t rtc_clk_apb_freq_get(void)
{
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
// round to the nearest MHz
freq_hz += MHZ / 2;
uint32_t remainder = freq_hz % MHZ;
return freq_hz - remainder;
return clk_ll_apb_load_freq_hz();
}
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
clk_ll_rc_slow_set_divider(div + 1);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
clk_ll_rc_fast_set_divider(div + 1);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
return clk_ll_rc_fast_digi_is_enabled();
}
/* Name used in libphy.a:phy_chip_v7.o

View File

@@ -1,47 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_120 1
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val)
{
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val)
{
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val)
{
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -15,10 +15,9 @@
#include "soc/rtc_periph.h"
#include "soc/efuse_periph.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
#include "esp_rom_uart.h"
static const char *TAG = "rtc_clk_init";
@@ -44,9 +43,10 @@ void rtc_clk_init(rtc_clk_config_t cfg)
/* Configure 8M clock division */
rtc_clk_8m_divider_set(cfg.clk_8m_clk_div);
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M);
/* Reset (disable) i2c internal bus for all regi2c registers */
regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init
/* Enable the internal bus used to configure BBPLL */
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
esp_rom_uart_tx_wait_idle(0);
@@ -66,7 +66,7 @@ void rtc_clk_init(rtc_clk_config_t cfg)
/* Re-calculate the ccount to make time calculation correct. */
cpu_hal_set_cycle_count( (uint64_t)cpu_hal_get_cycle_count() * cfg.cpu_freq_mhz / freq_before );
/* fast clocks setup */
/* Slow & fast clocks setup */
if (cfg.fast_clk_src == SOC_RTC_FAST_CLK_SRC_RC_FAST) {
bool need_8md256 = cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
rtc_clk_8m_enable(true, need_8md256);

View File

@@ -8,6 +8,7 @@
#include "esp32c2/rom/ets_sys.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/clk_tree_ll.h"
#include "soc/timer_group_reg.h"
#include "esp_rom_sys.h"
@@ -45,13 +46,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
}
/* Enable requested clock (150k clock is always on) */
int dig_ext_clk_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_EXT_CLK && !dig_ext_clk_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
bool dig_ext_clk_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_EXT_CLK && !dig_ext_clk_enabled) {
clk_ll_xtal32k_digi_enable();
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_enable();
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
@@ -99,10 +100,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_ext_clk_state);
/* if dig_ext_clk was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_EXT_CLK && !dig_ext_clk_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_disable();
}
return cal_val;

View File

@@ -12,57 +12,34 @@
#include "sdkconfig.h"
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/rom/rtc.h"
#include "esp32c3/rom/uart.h"
#include "esp32c3/rom/gpio.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
#include "hal/usb_serial_jtag_ll.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_320M 320
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
static int s_cur_pll_freq;
static void rtc_clk_cpu_freq_to_xtal(int freq, int div);
static void rtc_clk_cpu_freq_to_8m(void);
static bool rtc_clk_set_bbpll_always_on(void);
void rtc_clk_32k_enable_internal(x32k_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
} else {
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
clk_ll_xtal32k_disable();
}
}
void rtc_clk_32k_enable_external(void)
{
/* TODO ESP32-C3 IDF-2408: external 32k source may need different settings */
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
}
void rtc_clk_32k_bootstrap(uint32_t cycle)
@@ -70,67 +47,62 @@ void rtc_clk_32k_bootstrap(uint32_t cycle)
/* No special bootstrapping needed for ESP32-C3, 'cycle' argument is to keep the signature
* same as for the ESP32. Just enable the XTAL here.
*/
(void) cycle;
(void)cycle;
rtc_clk_32k_enable(true);
}
bool rtc_clk_32k_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
return !disabled;
return clk_ll_xtal32k_is_enabled();
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
esp_rom_delay_us(DELAY_8M_ENABLE);
clk_ll_rc_fast_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
clk_ll_rc_fast_disable();
}
/* d256 should be independent configured with 8M
* Maybe we can split this function into 8m and dmd256
*/
if (d256_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_enable();
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_disable();
}
}
bool rtc_clk_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
return clk_ll_rc_fast_is_enabled();
}
bool rtc_clk_8md256_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
return clk_ll_rc_fast_d256_is_enabled();
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
clk_ll_rtc_slow_set_src(clk_src);
/* Why we need to connect this clock to digital?
* Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
if (clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
clk_ll_xtal32k_digi_enable();
} else {
clk_ll_xtal32k_digi_disable();
}
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
@@ -139,126 +111,39 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_enable();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
uint8_t dbias;
CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
if (pll_freq == RTC_PLL_FREQ_480M) {
/* Set this register to let the digital part know 480M PLL is used */
SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
/* Configure 480M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 26;
dr1 = 1;
dr3 = 1;
dchgp = 4;
dcur = 0;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Clear this register to let the digital part know 320M PLL is used */
CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
/* Configure 320M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 6;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 2);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
/* Digital part */
clk_ll_bbpll_set_freq_mhz(pll_freq);
/* Analog part */
regi2c_ctrl_ll_bbpll_calibration_start();
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
s_cur_pll_freq = pll_freq;
}
@@ -270,18 +155,9 @@ void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 160) {
per_conf = DPORT_CPUPERIOD_SEL_160;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
abort();
}
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
}
@@ -293,7 +169,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
uint32_t divider;
uint32_t real_freq_mhz;
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (freq_mhz <= xtal_freq && freq_mhz != 0) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
@@ -307,12 +183,12 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 6;
} else if (freq_mhz == 160) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 3;
} else {
// unsupported frequency
@@ -329,22 +205,22 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
{
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
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 ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) && !rtc_clk_set_bbpll_always_on()) {
// We don't turn off the bbpll if some consumers only depends on bbpll
rtc_clk_bbpll_disable();
}
} else if (config->source == SOC_CPU_CLK_SRC_PLL) {
if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), 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_8m();
if ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) && !rtc_clk_set_bbpll_always_on()) {
// We don't turn off the bbpll if some consumers only depends on bbpll
rtc_clk_bbpll_disable();
}
@@ -353,40 +229,32 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
}
break;
case DPORT_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
uint32_t cpuperiod_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
uint32_t pllfreq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M;
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4;
freq_mhz = 80;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2;
div = 3;
freq_mhz = 160;
case SOC_CPU_CLK_SRC_PLL: {
freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
source_freq_mhz = clk_ll_bbpll_get_freq_mhz();
if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 6 : 4;
} else if (freq_mhz == CLK_LL_PLL_160M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 3 : 2;
} else {
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
}
break;
}
case DPORT_SOC_CLK_SEL_8M:
source = SOC_CPU_CLK_SRC_RC_FAST;
source_freq_mhz = 8;
case SOC_CPU_CLK_SRC_RC_FAST:
source_freq_mhz = 20;
div = 1;
freq_mhz = source_freq_mhz;
break;
@@ -417,7 +285,7 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
// We don't turn off the bbpll if some consumers only depends on bbpll
@@ -429,84 +297,75 @@ void rtc_clk_cpu_freq_set_xtal(void)
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
/* no need to adjust the REF_TICK */
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_divider(div);
/* switch clock source */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
ets_update_cpu_frequency(20);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
if (xtal_freq_mhz == 0) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 40MHz");
return RTC_XTAL_FREQ_40M;
}
return reg_val_to_clk_val(xtal_freq_reg);
return (rtc_xtal_freq_t)xtal_freq_mhz;
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
clk_ll_xtal_store_freq_mhz(xtal_freq);
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
clk_ll_apb_store_freq_hz(apb_freq);
}
uint32_t rtc_clk_apb_freq_get(void)
{
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
// round to the nearest MHz
freq_hz += MHZ / 2;
uint32_t remainder = freq_hz % MHZ;
return freq_hz - remainder;
return clk_ll_apb_load_freq_hz();
}
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
clk_ll_rc_slow_set_divider(div + 1);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
clk_ll_rc_fast_set_divider(div + 1);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
return clk_ll_rc_fast_digi_is_enabled();
}
static bool rtc_clk_set_bbpll_always_on(void)

View File

@@ -1,47 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val)
{
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val)
{
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val)
{
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -14,12 +14,10 @@
#include "soc/rtc.h"
#include "soc/rtc_periph.h"
#include "soc/efuse_periph.h"
#include "soc/syscon_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
#include "esp_rom_uart.h"
static const char *TAG = "rtc_clk_init";
@@ -45,9 +43,10 @@ void rtc_clk_init(rtc_clk_config_t cfg)
/* Configure 8M clock division */
rtc_clk_8m_divider_set(cfg.clk_8m_clk_div);
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M);
/* Reset (disable) i2c internal bus for all regi2c registers */
regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init
/* Enable the internal bus used to configure BBPLL */
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
esp_rom_uart_tx_wait_idle(0);

View File

@@ -8,6 +8,7 @@
#include "esp32c3/rom/ets_sys.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/clk_tree_ll.h"
#include "soc/timer_group_reg.h"
#include "esp_rom_sys.h"
@@ -49,13 +50,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
/* Enable requested clock (150k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_enable();
}
/* There may be another calibration process already running during we call this function,
* so we should wait the last process is done.
@@ -108,10 +109,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_disable();
}
return cal_val;

View File

@@ -15,70 +15,48 @@
#include "esp32h2/rom/uart.h"
#include "esp32h2/rom/gpio.h"
#include "soc/rtc.h"
#include "i2c_bbpll.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "regi2c_ctrl.h"
#include "soc/io_mux_reg.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
#include "hal/gpio_ll.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_96M 96
#define RTC_OSC_FREQ_RC8M 8
#define DELAY_RTC_CLK_SWITCH 5
#define RTC_CNTL_ANA_CONF0_CAL_REG 0x6000e040
#define RTC_CNTL_ANA_CONF0_CAL_START BIT(2)
#define RTC_CNTL_ANA_CONF0_CAL_STOP BIT(3)
#define RTC_CNTL_ANA_CONF0_CAL_DONE BIT(24)
// Current PLL frequency, in 96MHZ. Zero if PLL is not enabled.
static int s_cur_pll_freq;
static uint32_t rtc_clk_ahb_freq_get(void);
static void rtc_clk_cpu_freq_to_xtal(int freq, int div);
void rtc_clk_cpu_freq_to_8m(void);
static uint32_t rtc_clk_ahb_freq_set(uint32_t div);
void rtc_clk_32k_enable_internal(x32k_config_t cfg)
static void rtc_gpio_hangup(uint32_t gpio_no)
{
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
gpio_ll_pulldown_dis(&GPIO, gpio_no);
gpio_ll_pullup_dis(&GPIO, gpio_no);
gpio_ll_output_disable(&GPIO, gpio_no);
gpio_ll_input_disable(&GPIO, gpio_no);
gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_no], PIN_FUNC_GPIO);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
/* need to hangup gpio0 & 1 before enable xtal_32k */
rtc_gpio_hangup(0);
rtc_gpio_hangup(1);
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
/* need to hangup 32K_P and 32K_N pins before enable xtal_32k */
rtc_gpio_hangup(XTAL32K_P_GPIO_NUM);
rtc_gpio_hangup(XTAL32K_N_GPIO_NUM);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
} else {
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
clk_ll_xtal32k_disable();
}
}
void rtc_clk_rc32k_dfreq(uint32_t dfreq)
{
REG_SET_FIELD(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_DFREQ, dfreq);
}
void rtc_clk_rc32k_enable(bool enable)
{
rc32k_config_t cfg = RC32K_CONFIG_DEFAULT();
rtc_clk_rc32k_dfreq(cfg.dfreq);
REG_SET_FIELD(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_XPD, enable);
}
void rtc_clk_32k_enable_external(void)
{
rtc_clk_32k_enable(true);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
}
void rtc_clk_32k_bootstrap(uint32_t cycle)
@@ -86,32 +64,35 @@ void rtc_clk_32k_bootstrap(uint32_t cycle)
/* No special bootstrapping needed for ESP32-H2, 'cycle' argument is to keep the signature
* same as for the ESP32. Just enable the XTAL here.
*/
(void) cycle;
(void)cycle;
rtc_clk_32k_enable(true);
}
bool rtc_clk_32k_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
return !disabled;
return clk_ll_xtal32k_is_enabled();
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_rc32k_enable(bool enable)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
rtc_clk_32k_enable((slow_freq == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
rtc_clk_rc32k_enable((slow_freq == SOC_RTC_SLOW_CLK_SRC_RC32K) ? 1 : 0);
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
if (enable) {
clk_ll_rc32k_enable();
} else {
clk_ll_rc32k_disable();
}
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
clk_ll_rtc_slow_set_src(clk_src);
rtc_clk_32k_enable((clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
rtc_clk_rc32k_enable((clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) ? 1 : 0);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
@@ -120,62 +101,86 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC32K: return SOC_CLK_RC32K_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
static void rtc_clk_bbpll_cali_stop(void)
{
while (!REG_GET_BIT(RTC_CNTL_ANA_CONF0_CAL_REG, RTC_CNTL_ANA_CONF0_CAL_DONE));
REG_CLR_BIT(RTC_CNTL_ANA_CONF0_CAL_REG, RTC_CNTL_ANA_CONF0_CAL_STOP);
REG_SET_BIT(RTC_CNTL_ANA_CONF0_CAL_REG, RTC_CNTL_ANA_CONF0_CAL_START);
clk_ll_bbpll_enable();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
uint8_t div_ref;
uint8_t div5_0;
if ((pll_freq == RTC_PLL_FREQ_96M) && (xtal_freq == RTC_XTAL_FREQ_32M)) {
/* Configure 96M PLL */
div_ref = 0;
div5_0 = 1;
} else {
div_ref = 0;
div5_0 = 1;
ESP_HW_LOGE(TAG, "invalid pll frequency");
if (!((pll_freq == CLK_LL_PLL_96M_FREQ_MHZ) && (xtal_freq == RTC_XTAL_FREQ_32M))) {
ESP_HW_LOGE(TAG, "invalid pll or xtal frequency");
}
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, div_ref);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DIV, div5_0); //I2C_BBPLL_OC_DIV_5_0
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 3); // need update to 3 since s2
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
// No digital part needs to be set, pll_freq can only be 96MHz
// Configure analog part
regi2c_ctrl_ll_bbpll_calibration_start();
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
// Wait until calibration finishes
while (!regi2c_ctrl_ll_bbpll_calibration_is_done());
// Prevent BBPLL clock jitter
regi2c_ctrl_ll_bbpll_calibration_stop();
s_cur_pll_freq = pll_freq;
}
uint32_t rtc_clk_select_root_clk(soc_cpu_clk_src_t cpu_clk_src)
{
uint32_t root_clk_freq_mhz;
switch (cpu_clk_src) {
case SOC_CPU_CLK_SRC_XTAL:
root_clk_freq_mhz = RTC_XTAL_FREQ_32M;
rtc_clk_bbpll_disable();
break;
case SOC_CPU_CLK_SRC_PLL:
// SPLL_ENABLE
root_clk_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(RTC_XTAL_FREQ_32M, root_clk_freq_mhz);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
root_clk_freq_mhz = RTC_OSC_FREQ_RC8M;
rtc_dig_clk8m_enable(); // TODO: Do we need to enable digital gating here?
rtc_clk_8m_divider_set(1);
rtc_clk_bbpll_disable();
break;
case SOC_CPU_CLK_SRC_XTAL_D2:
root_clk_freq_mhz = RTC_XTAL_FREQ_32M / 2;
rtc_clk_bbpll_disable();
break;
default:
ESP_HW_LOGE(TAG, "unsupported source clk configuration");
// fallback to XTAL as root clock source
root_clk_freq_mhz = RTC_XTAL_FREQ_32M;
rtc_clk_bbpll_disable();
cpu_clk_src = SOC_CPU_CLK_SRC_XTAL;
break;
}
clk_ll_cpu_set_src(cpu_clk_src);
return root_clk_freq_mhz;
}
/**
* Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
* PLL must already be enabled.
@@ -184,39 +189,40 @@ void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int div = 1;
if (RTC_PLL_FREQ_96M % cpu_freq_mhz == 0) {
div = RTC_PLL_FREQ_96M / cpu_freq_mhz;
if (CLK_LL_PLL_96M_FREQ_MHZ % cpu_freq_mhz == 0) {
div = CLK_LL_PLL_96M_FREQ_MHZ / cpu_freq_mhz;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
abort();
}
rtc_clk_cpu_freq_set(DPORT_SOC_CLK_SEL_PLL, div - 1);
rtc_clk_cpu_freq_set(SOC_CPU_CLK_SRC_PLL, div);
if (cpu_freq_mhz > RTC_XTAL_FREQ_32M) {
rtc_clk_ahb_freq_set(2);
clk_ll_ahb_set_divider(2);
} else {
rtc_clk_ahb_freq_set(1);
clk_ll_ahb_set_divider(1);
}
rtc_clk_apb_freq_update(rtc_clk_apb_freq_get());
ets_update_cpu_frequency(cpu_freq_mhz);
rtc_clk_apb_freq_update(rtc_clk_apb_freq_get());
}
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
{
// TODO: This function supposes to only fill a cpu config, but it is writing to registers, needs to check
uint32_t source_freq_mhz;
soc_cpu_clk_src_t source;
uint32_t divider;
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (freq_mhz > xtal_freq) {
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_96M;
divider = RTC_PLL_FREQ_96M / freq_mhz;
rtc_clk_ahb_freq_set(2);
source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
divider = CLK_LL_PLL_96M_FREQ_MHZ / freq_mhz;
clk_ll_ahb_set_divider(2);
} else if (freq_mhz != 0) {
source = root_clk_get();
source_freq_mhz = root_clk_slt(source);
source = clk_ll_cpu_get_src();
source_freq_mhz = rtc_clk_select_root_clk(source);
divider = source_freq_mhz / freq_mhz;
rtc_clk_ahb_freq_set(1);
clk_ll_ahb_set_divider(1);
} else {
// unsupported frequency
return false;
@@ -232,7 +238,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
{
uint32_t src_freq_mhz = root_clk_slt(config->source);
uint32_t src_freq_mhz = rtc_clk_select_root_clk(config->source);
uint32_t div = src_freq_mhz / (config->freq_mhz);
rtc_clk_cpu_freq_set(config->source, div);
ets_update_cpu_frequency(config->freq_mhz);
@@ -240,37 +246,32 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
break;
}
case DPORT_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
div = REG_GET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = RTC_PLL_FREQ_96M;
case SOC_CPU_CLK_SRC_PLL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
freq_mhz = source_freq_mhz / div;
break;
}
case DPORT_SOC_CLK_SEL_8M: {
source = SOC_CPU_CLK_SRC_RC_FAST;
case SOC_CPU_CLK_SRC_RC_FAST: {
source_freq_mhz = RTC_OSC_FREQ_RC8M;
div = REG_GET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
div = clk_ll_cpu_get_divider();
freq_mhz = source_freq_mhz / div;
break;
}
case DPORT_SOC_CLK_SEL_XTAL_D2: {
source = SOC_CPU_CLK_SRC_XTAL_D2;
div = REG_GET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
case SOC_CPU_CLK_SRC_XTAL_D2: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div / 2;
break;
}
@@ -302,7 +303,8 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
rtc_clk_bbpll_disable();
}
@@ -310,11 +312,11 @@ void rtc_clk_cpu_freq_set_xtal(void)
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
rtc_clk_cpu_freq_set(DPORT_SOC_CLK_SEL_XTAL, div);
rtc_clk_cpu_freq_set(SOC_CPU_CLK_SRC_XTAL, div);
/* no need to adjust the REF_TICK */
/* switch clock source */
rtc_clk_apb_freq_update(rtc_clk_apb_freq_get());
@@ -323,148 +325,75 @@ void rtc_clk_cpu_freq_to_xtal(int freq, int div)
void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(RTC_OSC_FREQ_RC8M);
root_clk_slt(DPORT_SOC_CLK_SEL_8M);
rtc_clk_select_root_clk(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(rtc_clk_apb_freq_get());
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
if (xtal_freq_mhz == 0) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 32MHz");
return RTC_XTAL_FREQ_32M;
}
return reg_val_to_clk_val(xtal_freq_reg);
return (rtc_xtal_freq_t)xtal_freq_mhz;
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
clk_ll_xtal_store_freq_mhz(xtal_freq);
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
clk_ll_apb_store_freq_hz(apb_freq);
}
uint32_t rtc_clk_apb_freq_get(void)
{
uint32_t apb_div = REG_GET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_APB_DIV_NUM) + 1;
return rtc_clk_ahb_freq_get() / apb_div;
return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider();
}
uint32_t rtc_clk_ahb_freq_get()
static uint32_t rtc_clk_ahb_freq_get(void)
{
rtc_cpu_freq_config_t cpu_config;
uint32_t ahb_div = REG_GET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_AHB_DIV_NUM) + 1;
rtc_clk_cpu_freq_get_config(&cpu_config) ;
return cpu_config.freq_mhz * MHZ / ahb_div;
}
uint32_t rtc_clk_ahb_freq_set(uint32_t div)
{
REG_SET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_AHB_DIV_NUM, div - 1);
return rtc_clk_ahb_freq_get();
}
uint32_t rtc_clk_apb_freq_set(uint32_t div)
{
REG_SET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_APB_DIV_NUM, div - 1);
return rtc_clk_apb_freq_get();
rtc_clk_cpu_freq_get_config(&cpu_config);
return cpu_config.freq_mhz * MHZ / clk_ll_ahb_get_divider();
}
void rtc_clk_cpu_freq_set(uint32_t source, uint32_t div)
{
if (root_clk_get() != source) {
root_clk_slt(source);
if ((uint32_t)clk_ll_cpu_get_src() != source) {
rtc_clk_select_root_clk(source);
}
REG_SET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_CPU_DIV_NUM, div - 1);
clk_ll_cpu_set_divider(div);
}
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
clk_ll_rc_slow_set_divider(div);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
clk_ll_rc_fast_set_divider(div);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
uint32_t read_spll_freq(void)
{
return REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SPLL_FREQ);
}
uint32_t read_xtal_freq(void)
{
return REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_CLK_XTAL_FREQ);
}
/* Select clock root source for esp32h2. return source clk freq_mhz
*/
uint32_t root_clk_slt(uint32_t source)
{
uint32_t root_clk_freq_mhz;
switch (source) {
case SOC_CPU_CLK_SRC_XTAL:
root_clk_freq_mhz = RTC_XTAL_FREQ_32M;
rtc_clk_bbpll_disable();
break;
case SOC_CPU_CLK_SRC_PLL:
// SPLL_ENABLE
root_clk_freq_mhz = RTC_PLL_FREQ_96M;
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(RTC_XTAL_FREQ_32M, root_clk_freq_mhz);
rtc_clk_bbpll_cali_stop();
break;
case SOC_CPU_CLK_SRC_RC_FAST:
root_clk_freq_mhz = RTC_OSC_FREQ_RC8M;
rtc_dig_clk8m_enable();
rtc_clk_8m_divider_set(1);
rtc_clk_bbpll_disable();
break;
case SOC_CPU_CLK_SRC_XTAL_D2:
root_clk_freq_mhz = RTC_XTAL_FREQ_32M / 2;
rtc_clk_bbpll_disable();
break;
default:
ESP_HW_LOGE(TAG, "unsupported source clk configuration");
root_clk_freq_mhz = RTC_XTAL_FREQ_32M;
rtc_clk_bbpll_disable();
source = 0;
break;
}
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, source);
return root_clk_freq_mhz;
}
uint32_t root_clk_get()
{
uint32_t src_slt = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
return src_slt;
return clk_ll_rc_fast_digi_is_enabled();
}
/* Name used in libphy.a:phy_chip_v7.o

View File

@@ -1,48 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#define DPORT_SOC_CLK_SEL_XTAL_D2 3
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val)
{
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val)
{
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val)
{
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -17,18 +17,13 @@
#include "soc/rtc_periph.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/efuse_periph.h"
#include "soc/syscon_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
#include "esp_rom_uart.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
static const char *TAG = "rtc_clk_init";
void rtc_clk_init(rtc_clk_config_t cfg)
@@ -68,7 +63,7 @@ void rtc_clk_init(rtc_clk_config_t cfg)
rtc_clk_cpu_freq_get_config(&old_config);
uint32_t freq_before = old_config.freq_mhz;
root_clk_slt(cfg.root_clk_slt);
rtc_clk_select_root_clk(cfg.root_clk_slt);
bool res = rtc_clk_cpu_freq_mhz_to_config(cfg.cpu_freq_mhz, &new_config);
if (!res) {
ESP_HW_LOGE(TAG, "invalid CPU frequency value");

View File

@@ -9,7 +9,6 @@
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/efuse_periph.h"
#include "soc/gpio_reg.h"
#include "soc/spi_mem_reg.h"
@@ -207,41 +206,3 @@ void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
val |= RTC_CNTL_SDIO_PD_EN;
REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val);
}
void dig_gpio_setpd(uint32_t gpio_no, bool pd)
{
SET_PERI_REG_BITS(PERIPHS_IO_MUX_XTAL_32K_P_U + 4 * gpio_no, 0x1, pd, FUN_PD_S);
}
void dig_gpio_setpu(uint32_t gpio_no, bool pu)
{
SET_PERI_REG_BITS(PERIPHS_IO_MUX_XTAL_32K_P_U + 4 * gpio_no, 0x1, pu, FUN_PU_S);
}
void dig_gpio_in_en(uint32_t gpio_no, bool enable)
{
SET_PERI_REG_BITS(PERIPHS_IO_MUX_XTAL_32K_P_U + 4 * gpio_no, 0x1, enable, FUN_IE_S);
}
void dig_gpio_out_en(uint32_t gpio_no, bool enable)
{
if (enable)
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, 1 << gpio_no);
else
SET_PERI_REG_MASK(GPIO_ENABLE_W1TC_REG, 1 << gpio_no);
}
void dig_gpio_mcusel(uint32_t gpio_no, uint32_t mcu_sel)
{
SET_PERI_REG_BITS(PERIPHS_IO_MUX_XTAL_32K_P_U + 4 * gpio_no, MCU_SEL, mcu_sel, MCU_SEL_S);
}
void rtc_gpio_hangup(uint32_t gpio_no)
{
dig_gpio_setpd(gpio_no, 0);
dig_gpio_setpu(gpio_no, 0);
dig_gpio_out_en(gpio_no, 0);
dig_gpio_in_en(gpio_no, 0);
dig_gpio_mcusel(gpio_no, 1);
}

View File

@@ -8,6 +8,7 @@
#include "esp32h2/rom/ets_sys.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/clk_tree_ll.h"
#include "soc/timer_group_reg.h"
#include "esp_rom_sys.h"
@@ -44,15 +45,15 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
cal_clk = RTC_CAL_RC32K;
}
}
/* Enable requested clock (150k clock is always on) */
bool dig_32k_xtal_state = REG_GET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
/* Enable requested clock (150k clock is always on) */
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool dig_rc32k_state = REG_GET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN);
if (cal_clk == RTC_CAL_RC32K && !dig_rc32k_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN, 1);
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
if (cal_clk == RTC_CAL_RC32K && !dig_rc32k_enabled) {
clk_ll_rc32k_digi_enable();
}
/* There may be another calibration process already running during we call this function,
* so we should wait the last process is done.
@@ -104,8 +105,15 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN, dig_rc32k_state);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
/* if dig_rc32k was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_RC32K && !dig_rc32k_enabled) {
clk_ll_rc32k_digi_disable();
}
return cal_val;
}

View File

@@ -16,50 +16,28 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_caps.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "esp_rom_sys.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
#include "sdkconfig.h"
#include "regi2c_ctrl.h"
#include "regi2c_apll.h"
#include "regi2c_bbpll.h"
#include "hal/clk_tree_ll.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_320M 320
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
// On the ESP32-S2, 480MHz PLL is enabled at reset.
static uint32_t s_cur_pll_freq = RTC_PLL_FREQ_480M;
static uint32_t s_cur_pll_freq = CLK_LL_PLL_480M_FREQ_MHZ;
static void rtc_clk_cpu_freq_to_xtal(int freq, int div);
static void rtc_clk_cpu_freq_to_8m(void);
void rtc_clk_32k_enable_internal(x32k_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
} else {
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
clk_ll_xtal32k_disable();
}
}
@@ -67,9 +45,7 @@ void rtc_clk_32k_enable_external(void)
{
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
/* TODO: external 32k source may need different settings */
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
}
void rtc_clk_32k_bootstrap(uint32_t cycle)
@@ -77,55 +53,50 @@ void rtc_clk_32k_bootstrap(uint32_t cycle)
/* No special bootstrapping needed for ESP32-S2, 'cycle' argument is to keep the signature
* same as for the ESP32. Just enable the XTAL here.
*/
(void) cycle;
(void)cycle;
rtc_clk_32k_enable(true);
}
bool rtc_clk_32k_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
return !disabled;
return clk_ll_xtal32k_is_enabled();
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
esp_rom_delay_us(DELAY_8M_ENABLE);
clk_ll_rc_fast_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
clk_ll_rc_fast_disable();
}
/* d256 should be independent configured with 8M
* Maybe we can split this function into 8m and dmd256
*/
if (d256_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_enable();
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_disable();
}
}
bool rtc_clk_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
return clk_ll_rc_fast_is_enabled();
}
bool rtc_clk_8md256_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
return clk_ll_rc_fast_d256_is_enabled();
}
void rtc_clk_apll_enable(bool enable)
{
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1);
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0);
if (enable) {
clk_ll_apll_enable();
} else {
clk_ll_apll_disable();
}
}
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
@@ -165,9 +136,9 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
}
}
// sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * MHZ)) - 4;
// numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2
float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2;
float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * MHZ)) - 4 - sdm2;
// If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2
if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) {
sdm2++;
@@ -179,7 +150,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
// Get the closest sdm0
sdm0 = (int)(numrator * 65536.0 + 0.5) % 256;
}
uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
uint32_t real_freq = (uint32_t)(rtc_xtal_freq * MHZ * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
*_o_div = o_div;
*_sdm0 = sdm0;
*_sdm1 = sdm1;
@@ -189,41 +160,37 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_2_REV1);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
clk_ll_apll_set_config(o_div, sdm0, sdm1, sdm2);
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
clk_ll_apll_set_calibration();
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
while (!clk_ll_apll_calibration_is_done()) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
}
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
clk_ll_rtc_slow_set_src(clk_src);
/* Why we need to connect this clock to digital?
* Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
if (clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
clk_ll_xtal32k_digi_enable();
} else {
clk_ll_xtal32k_digi_disable();
}
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
@@ -232,84 +199,45 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_enable();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
assert(xtal_freq == RTC_XTAL_FREQ_40M);
if (pll_freq == RTC_PLL_FREQ_480M) {
/* Clear this register to let the digital part know 480M PLL is used */
SET_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
/* Configure 480M PLL */
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 4;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Clear this register to let the digital part know 320M PLL is used */
CLEAR_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
/* Configure 320M PLL */
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 5;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
/* Digital part */
clk_ll_bbpll_set_freq_mhz(pll_freq);
/* Analog part */
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
// Enable calibration by software
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_IR_CAL_ENX_CAP, 1);
clk_ll_bbpll_calibration_enable();
for (int ext_cap = 0; ext_cap < 16; ext_cap++) {
uint8_t cal_result;
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, ext_cap);
cal_result = REGI2C_READ_MASK(I2C_BBPLL, I2C_BBPLL_OR_CAL_CAP);
if (cal_result == 0) {
if (clk_ll_bbpll_calibration_is_done(ext_cap)) {
break;
}
if (ext_cap == 15) {
@@ -328,23 +256,11 @@ void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int dbias = DIG_DBIAS_80M_160M;
int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 160) {
per_conf = DPORT_CPUPERIOD_SEL_160;
} else if (cpu_freq_mhz == 240) {
dbias = DIG_DBIAS_240M;
per_conf = DPORT_CPUPERIOD_SEL_240;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
abort();
}
REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, per_conf);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0);
int dbias = (cpu_freq_mhz == 240) ? DIG_DBIAS_240M : DIG_DBIAS_80M_160M;
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
clk_ll_cpu_set_divider(1);
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
}
@@ -356,7 +272,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* ou
uint32_t divider;
uint32_t real_freq_mhz;
uint32_t xtal_freq = RTC_XTAL_FREQ;
uint32_t xtal_freq = CLK_LL_XTAL_FREQ_MHZ;
if (freq_mhz <= xtal_freq && freq_mhz != 0) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
@@ -370,17 +286,17 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* ou
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 6;
} else if (freq_mhz == 160) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 3;
} else if (freq_mhz == 240) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 2;
} else {
// unsupported frequency
@@ -397,20 +313,21 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
{
uint32_t soc_clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL);
if (soc_clk_sel != DPORT_SOC_CLK_SEL_XTAL) {
rtc_clk_cpu_freq_to_xtal(RTC_XTAL_FREQ, 1);
soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(CLK_LL_XTAL_FREQ_MHZ, 1);
}
if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL && config->source_freq_mhz != s_cur_pll_freq) {
if (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL && config->source_freq_mhz != s_cur_pll_freq) {
rtc_clk_bbpll_disable();
}
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
if (config->div > 1) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
}
} else if (config->source == SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(RTC_XTAL_FREQ, config->source_freq_mhz);
rtc_clk_bbpll_configure((rtc_xtal_freq_t)CLK_LL_XTAL_FREQ_MHZ, 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_8m();
@@ -419,47 +336,38 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT) + 1;
source_freq_mhz = RTC_XTAL_FREQ;
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = CLK_LL_XTAL_FREQ_MHZ;
freq_mhz = source_freq_mhz / div;
}
break;
case DPORT_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
uint32_t pllfreq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M;
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4;
freq_mhz = 80;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2;
div = 3;
freq_mhz = 160;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_240) {
case SOC_CPU_CLK_SRC_PLL: {
freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
source_freq_mhz = clk_ll_bbpll_get_freq_mhz();
if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 6 : 4;
} else if (freq_mhz == CLK_LL_PLL_160M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 3 : 2;
} else if (freq_mhz == CLK_LL_PLL_240M_FREQ_MHZ && source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) {
div = 2;
freq_mhz = 240;
} else {
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
}
break;
}
case DPORT_SOC_CLK_SEL_8M:
source = SOC_CPU_CLK_SRC_RC_FAST;
case SOC_CPU_CLK_SRC_RC_FAST:
source_freq_mhz = 8;
div = 1;
freq_mhz = source_freq_mhz;
break;
case DPORT_SOC_CLK_SEL_APLL:
case SOC_CPU_CLK_SRC_APLL:
default:
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
abort();
@@ -488,88 +396,77 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config)
void rtc_clk_cpu_freq_set_xtal(void)
{
/* BBPLL is kept enabled */
rtc_clk_cpu_freq_to_xtal(RTC_XTAL_FREQ, 1);
rtc_clk_cpu_freq_to_xtal(CLK_LL_XTAL_FREQ_MHZ, 1);
}
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, div - 1);
/* no need to adjust the REF_TICK */
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_divider(div);
/* no need to adjust the REF_TICK, default register value already set it to 1MHz with any cpu clock source */
/* switch clock source */
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
/* lower the voltage */
if (freq <= 2) {
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M);
} else {
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
}
int dbias = (freq <= 2) ? DIG_DBIAS_2M : DIG_DBIAS_XTAL;
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
// Note, inside esp32s2-only code it's better to use RTC_XTAL_FREQ constant
return RTC_XTAL_FREQ;
// Note, inside esp32s2-only code it's better to use CLK_LL_XTAL_FREQ_MHZ constant
return (rtc_xtal_freq_t)CLK_LL_XTAL_FREQ_MHZ;
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
clk_ll_apb_store_freq_hz(apb_freq);
}
uint32_t rtc_clk_apb_freq_get(void)
{
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
// round to the nearest MHz
freq_hz += MHZ / 2;
uint32_t remainder = freq_hz % MHZ;
return freq_hz - remainder;
return clk_ll_apb_load_freq_hz();
}
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
clk_ll_rc_slow_set_divider(div + 1);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
clk_ll_rc_fast_set_divider(div + 1);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
return clk_ll_rc_fast_digi_is_enabled();
}
/* Name used in libphy.a:phy_chip_v7.o

View File

@@ -1,49 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_CPUPERIOD_SEL_240 2
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#define DPORT_SOC_CLK_SEL_APLL 3
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val) {
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val) {
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val) {
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -16,10 +16,9 @@
#include "soc/efuse_periph.h"
#include "soc/syscon_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
static const char* TAG = "rtc_clk_init";
@@ -44,9 +43,11 @@ void rtc_clk_init(rtc_clk_config_t cfg)
/* Configure 8M clock division */
rtc_clk_8m_divider_set(cfg.clk_8m_clk_div);
/* Reset (disable) i2c internal bus for all regi2c registers */
regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M);
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
regi2c_ctrl_ll_i2c_apll_enable(); // TODO: This should be moved to apll_set_config
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
esp_rom_uart_tx_wait_idle(0);

View File

@@ -8,6 +8,7 @@
#include "esp_rom_sys.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/clk_tree_ll.h"
#include "soc/timer_group_reg.h"
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
@@ -151,13 +152,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, ui
}
/* Enable requested clock (90k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_enable();
}
uint32_t cal_val;
@@ -169,10 +170,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, ui
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_disable();
}
return cal_val;

View File

@@ -13,55 +13,35 @@
#include "esp32s3/rom/ets_sys.h"
#include "esp32s3/rom/rtc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "esp_rom_sys.h"
#include "regi2c_ctrl.h"
#include "regi2c_dig_reg.h"
#include "regi2c_bbpll.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
#include "hal/usb_serial_jtag_ll.h"
#include "hal/clk_tree_ll.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_dig_reg.h"
#include "sdkconfig.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_320M 320
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
static uint32_t s_cur_pll_freq;
static uint32_t s_apb_freq;
static void rtc_clk_cpu_freq_to_xtal(int freq, int div);
static void rtc_clk_cpu_freq_to_8m(void);
static bool rtc_clk_set_bbpll_always_on(void);
void rtc_clk_32k_enable_internal(x32k_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
} else {
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
clk_ll_xtal32k_disable();
}
}
@@ -69,9 +49,7 @@ void rtc_clk_32k_enable_external(void)
{
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
/* TODO: external 32k source may need different settings */
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
}
void rtc_clk_32k_bootstrap(uint32_t cycle)
@@ -79,49 +57,41 @@ void rtc_clk_32k_bootstrap(uint32_t cycle)
/* No special bootstrapping needed for ESP32-S3, 'cycle' argument is to keep the signature
* same as for the ESP32. Just enable the XTAL here.
*/
(void) cycle;
(void)cycle;
rtc_clk_32k_enable(true);
}
bool rtc_clk_32k_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
return !disabled;
return clk_ll_xtal32k_is_enabled();
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
esp_rom_delay_us(DELAY_8M_ENABLE);
clk_ll_rc_fast_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
clk_ll_rc_fast_disable();
}
/* d256 should be independent configured with 8M
* Maybe we can split this function into 8m and dmd256
*/
if (d256_en) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_enable();
} else {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
clk_ll_rc_fast_d256_disable();
}
}
bool rtc_clk_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
return clk_ll_rc_fast_is_enabled();
}
bool rtc_clk_8md256_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
return clk_ll_rc_fast_d256_is_enabled();
}
static void wait_dig_dbias_valid(uint64_t rtc_cycles)
@@ -136,22 +106,25 @@ static void wait_dig_dbias_valid(uint64_t rtc_cycles)
rtc_clk_cal(cal_clk, rtc_cycles);
}
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq)
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
clk_ll_rtc_slow_set_src(clk_src);
/* Why we need to connect this clock to digital?
* Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? 1 : 0);
if (clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
clk_ll_xtal32k_digi_enable();
} else {
clk_ll_xtal32k_digi_disable();
}
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
}
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
return clk_ll_rtc_slow_get_src();
}
uint32_t rtc_clk_slow_freq_get_hz(void)
@@ -160,132 +133,45 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
default: return 0;
}
return 0;
}
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq)
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
clk_ll_rtc_fast_set_src(clk_src);
esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
}
soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
return clk_ll_rtc_fast_get_src();
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_disable();
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
clk_ll_bbpll_enable();
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
uint8_t dbias;
/* Digital part */
clk_ll_bbpll_set_freq_mhz(pll_freq);
/* Analog part */
/* BBPLL CALIBRATION START */
CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
if (pll_freq == RTC_PLL_FREQ_480M) {
/* Set this register to let the digital part know 480M PLL is used */
SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
/* Configure 480M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 26;
dr1 = 1;
dr3 = 1;
dchgp = 4;
dcur = 0;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Clear this register to let the digital part know 320M PLL is used */
CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
/* Configure 320M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 6;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
regi2c_ctrl_ll_bbpll_calibration_start();
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
/* WAIT CALIBRATION DONE */
while (!GET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE));
while(!regi2c_ctrl_ll_bbpll_calibration_is_done());
/* BBPLL CALIBRATION STOP */
CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
regi2c_ctrl_ll_bbpll_calibration_stop();
s_cur_pll_freq = pll_freq;
}
@@ -296,24 +182,15 @@ void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
int dbias = DIG_DBIAS_80M_160M;
int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 160) {
per_conf = DPORT_CPUPERIOD_SEL_160;
} else if (cpu_freq_mhz == 240) {
dbias = DIG_DBIAS_240M;
per_conf = DPORT_CPUPERIOD_SEL_240;
} else {
ESP_HW_LOGE(TAG, "invalid frequency");
}
int dbias = (cpu_freq_mhz == 240) ? DIG_DBIAS_240M : DIG_DBIAS_80M_160M;
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, dbias);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, dbias);
wait_dig_dbias_valid(2);
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
clk_ll_cpu_set_divider(1);
/* switch clock source */
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
}
@@ -325,7 +202,7 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
uint32_t divider;
uint32_t real_freq_mhz;
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (freq_mhz <= xtal_freq && freq_mhz != 0) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
@@ -339,17 +216,17 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 6;
} else if (freq_mhz == 160) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 3;
} else if (freq_mhz == 240) {
real_freq_mhz = freq_mhz;
source = SOC_CPU_CLK_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
divider = 2;
} else {
// unsupported frequency
@@ -366,22 +243,22 @@ bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *ou
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
{
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
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 ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) && !rtc_clk_set_bbpll_always_on()) {
// We don't turn off the bbpll if some consumers only depends on bbpll
rtc_clk_bbpll_disable();
}
} else if (config->source == SOC_CPU_CLK_SRC_PLL) {
if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) {
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), 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_8m();
if ((soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) && !rtc_clk_set_bbpll_always_on()) {
if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) && !rtc_clk_set_bbpll_always_on()) {
// We don't turn off the bbpll if some consumers only depends on bbpll
rtc_clk_bbpll_disable();
}
@@ -390,43 +267,34 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
{
soc_cpu_clk_src_t source;
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = SOC_CPU_CLK_SRC_XTAL;
div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
switch (source) {
case SOC_CPU_CLK_SRC_XTAL: {
div = clk_ll_cpu_get_divider();
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
}
break;
case DPORT_SOC_CLK_SEL_PLL: {
source = SOC_CPU_CLK_SRC_PLL;
uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
uint32_t pllfreq_sel = DPORT_REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M;
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4;
freq_mhz = 80;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2;
div = 3;
freq_mhz = 160;
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_240) {
case SOC_CPU_CLK_SRC_PLL: {
freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
source_freq_mhz = clk_ll_bbpll_get_freq_mhz();
if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 6 : 4;
} else if (freq_mhz == CLK_LL_PLL_160M_FREQ_MHZ) {
div = (source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) ? 3 : 2;
} else if (freq_mhz == CLK_LL_PLL_240M_FREQ_MHZ && source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) {
div = 2;
freq_mhz = 240;
} else {
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
return;
}
break;
}
case DPORT_SOC_CLK_SEL_8M:
source = SOC_CPU_CLK_SRC_RC_FAST;
source_freq_mhz = 8;
case SOC_CPU_CLK_SRC_RC_FAST:
source_freq_mhz = 20;
div = 1;
freq_mhz = source_freq_mhz;
break;
@@ -457,10 +325,9 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
int freq_mhz = (int)rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
// We don't turn off the bbpll if some consumers only depends on bbpll
if (!rtc_clk_set_bbpll_always_on()) {
rtc_clk_bbpll_disable();
@@ -470,48 +337,44 @@ void rtc_clk_cpu_freq_set_xtal(void)
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* set digital voltage for different cpu freq from xtal */
if (freq <= 2) {
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, DIG_DBIAS_2M);
} else {
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, DIG_DBIAS_XTAL);
}
int dbias = (freq <= 2) ? DIG_DBIAS_2M : DIG_DBIAS_XTAL;
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, dbias);
wait_dig_dbias_valid(2);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
/* no need to adjust the REF_TICK */
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_divider(div);
/* switch clock source */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
ets_update_cpu_frequency(20);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, DIG_DBIAS_XTAL);
wait_dig_dbias_valid(2);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
clk_ll_cpu_set_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
if (xtal_freq_mhz == 0) {
ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 40MHz");
return RTC_XTAL_FREQ_40M;
}
return reg_val_to_clk_val(xtal_freq_reg);
return (rtc_xtal_freq_t)xtal_freq_mhz;
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
clk_ll_xtal_store_freq_mhz(xtal_freq);
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
@@ -526,33 +389,29 @@ uint32_t rtc_clk_apb_freq_get(void)
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
clk_ll_rc_slow_set_divider(div + 1);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
clk_ll_rc_fast_set_divider(div + 1);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_enable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
clk_ll_rc_fast_digi_disable();
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
}
bool rtc_dig_8m_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
return clk_ll_rc_fast_digi_is_enabled();
}
static bool rtc_clk_set_bbpll_always_on(void)

View File

@@ -1,50 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_CPUPERIOD_SEL_240 2
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*/
static inline bool clk_val_is_valid(uint32_t val)
{
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val)
{
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val)
{
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -12,11 +12,9 @@
#include "esp32s3/rom/rtc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/syscon_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "hal/regi2c_ctrl_ll.h"
#include "esp_hw_log.h"
#include "rtc_clk_common.h"
static const char *TAG = "rtc_clk_init";
@@ -41,9 +39,10 @@ void rtc_clk_init(rtc_clk_config_t cfg)
/* Configure 8M clock division */
rtc_clk_8m_divider_set(cfg.clk_8m_clk_div);
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_BBPLL_M);
/* Reset (disable) i2c internal bus for all regi2c registers */
regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init
/* Enable the internal bus used to configure BBPLL */
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
esp_rom_uart_tx_wait_idle(0);

View File

@@ -8,6 +8,7 @@
#include "esp_rom_sys.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/clk_tree_ll.h"
#include "soc/timer_group_reg.h"
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
@@ -47,13 +48,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
/* Enable requested clock (150k clock is always on) */
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
if (cal_clk == RTC_CAL_8MD256) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_enable();
}
/* There may be another calibration process already running during we call this function,
* so we should wait the last process is done.
@@ -106,10 +107,13 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
clk_ll_rc_fast_d256_digi_disable();
}
return cal_val;

View File

@@ -213,7 +213,7 @@ TEST_CASE("light sleep and frequency switching", "[deepsleep]")
rtc_cpu_freq_config_t config_xtal, config_default;
rtc_clk_cpu_freq_get_config(&config_default);
rtc_clk_cpu_freq_mhz_to_config((int) rtc_clk_xtal_freq_get(), &config_xtal);
rtc_clk_cpu_freq_mhz_to_config(esp_clk_xtal_freq() / MHZ, &config_xtal);
esp_sleep_enable_timer_wakeup(1000);
for (int i = 0; i < 1000; ++i) {

View File

@@ -0,0 +1,859 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/dport_reg.h"
#include "soc/syscon_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "regi2c_apll.h"
#include "hal/assert.h"
#include "esp32/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_160M_FREQ_MHZ (160)
#define CLK_LL_PLL_240M_FREQ_MHZ (240)
#define CLK_LL_PLL_320M_FREQ_MHZ (320)
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
/* BBPLL configuration parameters at reset */
#define CLK_LL_BBPLL_IR_CAL_DELAY_VAL 0x18
#define CLK_LL_BBPLL_IR_CAL_EXT_CAP_VAL 0x20
#define CLK_LL_BBPLL_OC_ENB_FCAL_VAL 0x9a
#define CLK_LL_BBPLL_OC_ENB_VCON_VAL 0x00
#define CLK_LL_BBPLL_BBADC_CAL_7_0_VAL 0x00
/* BBPLL configuration parameters */
#define CLK_LL_BBPLL_ENDIV5_VAL_320M 0x43
#define CLK_LL_BBPLL_BBADC_DSMP_VAL_320M 0x84
#define CLK_LL_BBPLL_ENDIV5_VAL_480M 0xc3
#define CLK_LL_BBPLL_BBADC_DSMP_VAL_480M 0x74
/* APLL configuration parameters */
#define CLK_LL_APLL_SDM_STOP_VAL_1 0x09
#define CLK_LL_APLL_SDM_STOP_VAL_2_REV0 0x69
#define CLK_LL_APLL_SDM_STOP_VAL_2_REV1 0x49
/* APLL calibration parameters */
#define CLK_LL_APLL_CAL_DELAY_1 0x0f
#define CLK_LL_APLL_CAL_DELAY_2 0x3f
#define CLK_LL_APLL_CAL_DELAY_3 0x1f
/* XTAL32K configuration parameters for 32kHz crystal */
#define CLK_LL_XTAL_32K_DAC_VAL 1
#define CLK_LL_XTAL_32K_DRES_VAL 3
#define CLK_LL_XTAL_32K_DBIAS_VAL 0
/* XTAL32K configuration parameters for external oscillator clock */
#define CLK_LL_XTAL_32K_EXT_DAC_VAL 2
#define CLK_LL_XTAL_32K_EXT_DRES_VAL 3
#define CLK_LL_XTAL_32K_EXT_DBIAS_VAL 1
/* XTAL32K configuration parameters for fast startup with bootstrap */
#define CLK_LL_XTAL_32K_BOOTSTRAP_DAC_VAL 3
#define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3
#define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief Power up internal I2C bus
*/
static inline __attribute__((always_inline)) void clk_ll_i2c_pu(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
}
/**
* @brief Power down internal I2C bus
*/
static inline __attribute__((always_inline)) void clk_ll_i2c_pd(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
}
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
RTC_CNTL_BBPLL_I2C_FORCE_PD);
// Reset BBPLL configuration
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_DELAY, CLK_LL_BBPLL_IR_CAL_DELAY_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, CLK_LL_BBPLL_IR_CAL_EXT_CAP_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_FCAL, CLK_LL_BBPLL_OC_ENB_FCAL_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_VCON, CLK_LL_BBPLL_OC_ENB_VCON_VAL);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_CAL_7_0, CLK_LL_BBPLL_BBADC_CAL_7_0_VAL);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power up APLL circuit
*/
static inline void clk_ll_apll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
}
/**
* @brief Power down APLL circuit
*/
static inline void clk_ll_apll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
}
/**
* @brief Check whether APLL is under force power down state
*
* @return True if APLL is under force power down; otherwise false
*/
static inline bool clk_ll_apll_is_fpd(void)
{
return REG_GET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
}
/**
* @brief Set APLL configuration
*
* @param is_rev0 True if chip version is rev0
* @param o_div Frequency divider, 0..31
* @param sdm0 Frequency adjustment parameter, 0..255
* @param sdm1 Frequency adjustment parameter, 0..255
* @param sdm2 Frequency adjustment parameter, 0..63
*/
static inline void clk_ll_apll_set_config(bool is_rev0, uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
uint8_t sdm_stop_val_2 = CLK_LL_APLL_SDM_STOP_VAL_2_REV1;
if (is_rev0) {
sdm0 = 0;
sdm1 = 0;
sdm_stop_val_2 = CLK_LL_APLL_SDM_STOP_VAL_2_REV0;
}
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, CLK_LL_APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
}
/**
* @brief Set APLL calibration parameters
*/
static inline void clk_ll_apll_set_calibration(void)
{
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_3);
}
/**
* @brief Check whether APLL calibration is done
*
* @return True if calibration is done; otherwise false
*/
static inline bool clk_ll_apll_calibration_is_done(void)
{
return REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END);
}
/**
* @brief Enable the 32kHz crystal oscillator
*
* @param mode Used to determine the xtal32k configuration parameters
*/
static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
{
// Configure xtal32k
// Default mode as CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL
uint32_t dac = CLK_LL_XTAL_32K_DAC_VAL; // current
uint32_t dres = CLK_LL_XTAL_32K_DRES_VAL; // resistance
uint32_t dbias = CLK_LL_XTAL_32K_DBIAS_VAL; // dbias voltage
if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
dac = CLK_LL_XTAL_32K_EXT_DAC_VAL;
dres = CLK_LL_XTAL_32K_EXT_DRES_VAL;
dbias = CLK_LL_XTAL_32K_EXT_DBIAS_VAL;
} else if (mode == CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP) {
dac = CLK_LL_XTAL_32K_BOOTSTRAP_DAC_VAL;
dres = CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL;
dbias = CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL;
}
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, dac);
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, dres);
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias);
// Enable xtal32k xpd status
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
}
/**
* @brief Disable the 32kHz crystal oscillator
*/
static inline void clk_ll_xtal32k_disable(void)
{
// Disable xtal32k xpd status
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
}
/**
* @brief Get the state of the 32kHz crystal clock
*
* @return True if the 32kHz XTAL is enabled
*/
static inline bool clk_ll_xtal32k_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
}
/**
* @brief Enable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
}
/**
* @brief Disable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/**
* @brief Get the state of the internal oscillator for RC_FAST_CLK
*
* @return True if the oscillator is enabled
*/
static inline bool clk_ll_rc_fast_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
}
/**
* @brief Enable the output from the internal oscillator to be passed into a configurable divider,
* which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Divider values other than 256 may be configured, but this facility is not currently needed,
* so is not exposed in the code.
* The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
*/
static inline void clk_ll_rc_fast_d256_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Disable the output from the internal oscillator to be passed into a configurable divider.
* i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Disabling this divider could reduce power consumption.
*/
static inline void clk_ll_rc_fast_d256_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
*
* @return True if the divided output is enabled
*/
static inline bool clk_ll_rc_fast_d256_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
// ESP32 BBPLL frequency is determined by the cpu freq sel
uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
case 1:
return CLK_LL_PLL_320M_FREQ_MHZ;
case 2:
return CLK_LL_PLL_480M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set BBPLL frequency from XTAL source (digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
(void)pll_freq_mhz;
// No such operation on ESP32
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t div10_8;
uint8_t lref;
uint8_t dcur;
uint8_t bw;
if (pll_freq_mhz == CLK_LL_PLL_320M_FREQ_MHZ) {
/* Configure 320M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 32;
div10_8 = 0;
lref = 0;
dcur = 6;
bw = 3;
break;
case RTC_XTAL_FREQ_26M:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
case RTC_XTAL_FREQ_24M:
div_ref = 11;
div7_0 = 224;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
default:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 0;
dcur = 0;
bw = 0;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, CLK_LL_BBPLL_ENDIV5_VAL_320M);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, CLK_LL_BBPLL_BBADC_DSMP_VAL_320M);
} else {
/* Configure 480M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 28;
div10_8 = 0;
lref = 0;
dcur = 6;
bw = 3;
break;
case RTC_XTAL_FREQ_26M:
div_ref = 12;
div7_0 = 144;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
case RTC_XTAL_FREQ_24M:
div_ref = 11;
div7_0 = 144;
div10_8 = 4;
lref = 1;
dcur = 0;
bw = 1;
break;
default:
div_ref = 12;
div7_0 = 224;
div10_8 = 4;
lref = 0;
dcur = 0;
bw = 0;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, CLK_LL_BBPLL_ENDIV5_VAL_480M);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, CLK_LL_BBPLL_BBADC_DSMP_VAL_480M);
}
uint8_t i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (bw << 6) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 2);
break;
case SOC_CPU_CLK_SRC_APLL:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 3);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
case 3:
return SOC_CPU_CLK_SRC_APLL;
default:
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU frequency from PLL clock
*
* @param cpu_mhz CPU frequency value, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
{
switch (cpu_mhz) {
case CLK_LL_PLL_80M_FREQ_MHZ:
DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 0);
break;
case CLK_LL_PLL_160M_FREQ_MHZ:
DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 1);
break;
case CLK_LL_PLL_240M_FREQ_MHZ:
DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 2);
break;
default:
// Unsupported CPU_CLK freq from PLL
abort();
}
}
/**
* @brief Get CPU_CLK frequency from PLL_CLK source
*
* @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
{
uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
return CLK_LL_PLL_80M_FREQ_MHZ;
case 1:
return CLK_LL_PLL_160M_FREQ_MHZ;
case 2:
return CLK_LL_PLL_240M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT, divider - 1);
}
/**
* @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @return Divider. Divider = (PRE_DIV_CNT + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(SYSCON_SYSCLK_CONF_REG, SYSCON_PRE_DIV_CNT) + 1;
}
/**
* @brief Set REF_TICK divider to make REF_TICK frequency at 1MHz
*
* @param cpu_clk_src Selected CPU clock source (one of soc_cpu_clk_src_t values)
* @param cpu_freq_mhz CPU frequency value, in MHz
*
* Divider = APB_CLK freq in Hz / 1MHz. Value in register = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_ref_tick_set_divider(soc_cpu_clk_src_t cpu_clk_src, uint32_t cpu_freq_mhz)
{
uint32_t apb_freq_mhz;
switch (cpu_clk_src) {
case SOC_CPU_CLK_SRC_XTAL:
apb_freq_mhz = cpu_freq_mhz;
REG_WRITE(SYSCON_XTAL_TICK_CONF_REG, apb_freq_mhz - 1);
break;
case SOC_CPU_CLK_SRC_PLL:
apb_freq_mhz = 80;
REG_WRITE(SYSCON_PLL_TICK_CONF_REG, apb_freq_mhz - 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
apb_freq_mhz = cpu_freq_mhz;
REG_WRITE(SYSCON_CK8M_TICK_CONF_REG, apb_freq_mhz - 1);
break;
case SOC_CPU_CLK_SRC_APLL:
apb_freq_mhz = cpu_freq_mhz >> 1;
REG_WRITE(SYSCON_APLL_TICK_CONF_REG, apb_freq_mhz - 1);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
default:
// Invalid ANA_CLK_RTC_SEL value
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D4:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D4;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store XTAL_CLK frequency in RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param xtal_freq_mhz XTAL frequency, in MHz. The frequency must necessarily be even,
* otherwise there will be a conflict with the low bit, which is used to disable logs
* in the ROM code.
*/
static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
{
// Read the status of whether disabling logging from ROM code
uint32_t reg = READ_PERI_REG(RTC_XTAL_FREQ_REG) & RTC_DISABLE_ROM_LOG;
// If so, need to write back this setting
if (reg == RTC_DISABLE_ROM_LOG) {
xtal_freq_mhz |= 1;
}
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
}
/**
* @brief Load XTAL_CLK frequency from RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return XTAL frequency, in MHz. Returns 0 if format in reg is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
{
// Read from RTC storage register
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) &&
xtal_freq_reg != 0 && xtal_freq_reg != UINT32_MAX) {
return xtal_freq_reg & ~RTC_DISABLE_ROM_LOG & UINT16_MAX;
}
// If the format in reg is invalid or haven't written XTAL value into RTC_XTAL_FREQ_REG
return 0;
}
/**
* @brief Store APB_CLK frequency in RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param apb_freq_hz APB frequency, in Hz
*/
static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
{
uint32_t val = apb_freq_hz >> 12;
WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
}
/**
* @brief Load APB_CLK frequency from RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return The stored APB frequency, in Hz
*/
static inline uint32_t clk_ll_apb_load_freq_hz(void)
{
// Read from RTC storage register
uint32_t apb_freq_hz = (READ_PERI_REG(RTC_APB_FREQ_REG) & UINT16_MAX) << 12;
// Round to the nearest MHz
apb_freq_hz += MHZ / 2;
uint32_t remainder = apb_freq_hz % MHZ;
return apb_freq_hz - remainder;
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_BBPLL_M);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the APLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_apll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,562 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/system_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "esp32c2/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_120M_FREQ_MHZ (120)
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK (i.e. EXT_OSC_CLK)
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Enable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
}
/**
* @brief Disable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/**
* @brief Get the state of the internal oscillator for RC_FAST_CLK
*
* @return True if the oscillator is enabled
*/
static inline bool clk_ll_rc_fast_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
}
/**
* @brief Enable the output from the internal oscillator to be passed into a configurable divider,
* which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Divider values other than 256 may be configured, but this facility is not currently needed,
* so is not exposed in the code.
* The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
*/
static inline void clk_ll_rc_fast_d256_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Disable the output from the internal oscillator to be passed into a configurable divider.
* i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Disabling this divider could reduce power consumption.
*/
static inline void clk_ll_rc_fast_d256_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
*
* @return True if the divided output is enabled
*/
static inline bool clk_ll_rc_fast_d256_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
// ESP32C2 only support 480MHz PLL
uint32_t pll_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
switch (pll_freq_sel) {
case 1: // PLL_480M
return CLK_LL_PLL_480M_FREQ_MHZ;
default:
// Invalid PLL_FREQ_SEL value
return 0;
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
// ESP32C2 only support 480MHz PLL
HAL_ASSERT(pll_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ);
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL, 1);
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
(void)pll_freq_mhz;
(void)xtal_freq_mhz;
// ESP32C2 only support 40M XTAL, all the parameters are given as 40M XTAL directly
uint8_t div_ref = 0;
uint8_t div7_0 = 8;
uint8_t dr1 = 0;
uint8_t dr3 = 0;
uint8_t dchgp = 5;
uint8_t dcur = 3;
uint8_t dbias = 2;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 2);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
default:
// Invalid SOC_CLK_SEL value
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU frequency from PLL clock
*
* @param cpu_mhz CPU frequency value, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
{
switch (cpu_mhz) {
case CLK_LL_PLL_80M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 0);
break;
case CLK_LL_PLL_120M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 1);
break;
default:
// Unsupported CPU_CLK freq from PLL
abort();
}
}
/**
* @brief Get CPU_CLK frequency from PLL_CLK source
*
* @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
{
uint32_t cpu_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
return CLK_LL_PLL_80M_FREQ_MHZ;
case 1:
return CLK_LL_PLL_120M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, divider - 1);
}
/**
* @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @return Divider. Divider = (PRE_DIV_CNT + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_OSC_SLOW;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
default:
// Invalid ANA_CLK_RTC_SEL value
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D2:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D2;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/**
* @brief Set RC_SLOW_CLK divider
*
* @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_slow_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store XTAL_CLK frequency in RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
}
/**
* @brief Load XTAL_CLK frequency from RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
{
// ESP32C2 has a fixed crystal frequency (40MHz), but we will still read from the RTC storage register
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if ((xtal_freq_reg & UINT16_MAX) != RTC_XTAL_FREQ_40M) {
return 0;
}
return (uint32_t)RTC_XTAL_FREQ_40M;
}
/**
* @brief Store APB_CLK frequency in RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param apb_freq_hz APB frequency, in Hz
*/
static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
{
uint32_t val = apb_freq_hz >> 12;
WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
}
/**
* @brief Load APB_CLK frequency from RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return The stored APB frequency, in Hz
*/
static inline uint32_t clk_ll_apb_load_freq_hz(void)
{
// Read from RTC storage register
uint32_t apb_freq_hz = (READ_PERI_REG(RTC_APB_FREQ_REG) & UINT16_MAX) << 12;
// Round to the nearest MHz
apb_freq_hz += MHZ / 2;
uint32_t remainder = apb_freq_hz % MHZ;
return apb_freq_hz - remainder;
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M);
}
/**
* @brief Start BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_start(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,702 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/system_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "esp32c3/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_160M_FREQ_MHZ (160)
#define CLK_LL_PLL_320M_FREQ_MHZ (320)
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief XTAL32K_CLK configuration structure
*/
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} clk_ll_xtal32k_config_t;
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Enable the 32kHz crystal oscillator
*
* @param mode Used to determine the xtal32k configuration parameters
*/
static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
{
// Configure xtal32k
clk_ll_xtal32k_config_t cfg = CLK_LL_XTAL32K_CONFIG_DEFAULT();
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
// Enable xtal32k xpd status
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
/* TODO ESP32-C3 IDF-2408:: external 32k source may need different settings */
;
}
}
/**
* @brief Disable the 32kHz crystal oscillator
*/
static inline void clk_ll_xtal32k_disable(void)
{
// Set xtal32k xpd to be controlled by software
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
// Disable xtal32k xpd status
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
/**
* @brief Get the state of the 32kHz crystal clock
*
* @return True if the 32kHz XTAL is enabled
*/
static inline bool clk_ll_xtal32k_is_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
// disabled = xtal_xpd_sw && !xtal_xpd_st; enabled = !disbaled
bool enabled = !xtal_xpd_sw || xtal_xpd_st;
return enabled;
}
/**
* @brief Enable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
}
/**
* @brief Disable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/**
* @brief Get the state of the internal oscillator for RC_FAST_CLK
*
* @return True if the oscillator is enabled
*/
static inline bool clk_ll_rc_fast_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
}
/**
* @brief Enable the output from the internal oscillator to be passed into a configurable divider,
* which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Divider values other than 256 may be configured, but this facility is not currently needed,
* so is not exposed in the code.
* The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
*/
static inline void clk_ll_rc_fast_d256_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Disable the output from the internal oscillator to be passed into a configurable divider.
* i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Disabling this divider could reduce power consumption.
*/
static inline void clk_ll_rc_fast_d256_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
*
* @return True if the divided output is enabled
*/
static inline bool clk_ll_rc_fast_d256_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
uint32_t pll_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
switch (pll_freq_sel) {
case 0: // PLL_320M
return CLK_LL_PLL_320M_FREQ_MHZ;
case 1: // PLL_480M
return CLK_LL_PLL_480M_FREQ_MHZ;
default:
return 0;
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
switch (pll_freq_mhz) {
case CLK_LL_PLL_320M_FREQ_MHZ: // PLL_320M
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL, 0);
break;
case CLK_LL_PLL_480M_FREQ_MHZ: // PLL_480M
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL, 1);
break;
default:
abort();
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
uint8_t dbias;
if (pll_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) {
/* Configure 480M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 26;
dr1 = 1;
dr3 = 1;
dchgp = 4;
dcur = 0;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Configure 320M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 6;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 2);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 2);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
default:
// Invalid SOC_CLK_SEL value
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU frequency from PLL clock
*
* @param cpu_mhz CPU frequency value, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
{
switch (cpu_mhz) {
case CLK_LL_PLL_80M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 0);
break;
case CLK_LL_PLL_160M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 1);
break;
default:
// Unsupported CPU_CLK freq from PLL
abort();
}
}
/**
* @brief Get CPU_CLK frequency from PLL_CLK source
*
* @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
{
uint32_t cpu_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
return CLK_LL_PLL_80M_FREQ_MHZ;
case 1:
return CLK_LL_PLL_160M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, divider - 1);
}
/**
* @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @return Divider. Divider = (PRE_DIV_CNT + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
default:
// Invalid ANA_CLK_RTC_SEL value
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D2:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D2;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/**
* @brief Set RC_SLOW_CLK divider
*
* @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_slow_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store XTAL_CLK frequency in RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
}
/**
* @brief Load XTAL_CLK frequency from RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
{
// Read from RTC storage register
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) &&
xtal_freq_reg != 0 && xtal_freq_reg != UINT32_MAX) {
return xtal_freq_reg & UINT16_MAX;
}
// If the format in reg is invalid
return 0;
}
/**
* @brief Store APB_CLK frequency in RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param apb_freq_hz APB frequency, in Hz
*/
static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
{
uint32_t val = apb_freq_hz >> 12;
WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
}
/**
* @brief Load APB_CLK frequency from RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return The stored APB frequency, in Hz
*/
static inline uint32_t clk_ll_apb_load_freq_hz(void)
{
// Read from RTC storage register
uint32_t apb_freq_hz = (READ_PERI_REG(RTC_APB_FREQ_REG) & UINT16_MAX) << 12;
// Round to the nearest MHz
apb_freq_hz += MHZ / 2;
uint32_t remainder = apb_freq_hz % MHZ;
return apb_freq_hz - remainder;
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M);
}
/**
* @brief Start BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_start(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,572 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/system_reg.h"
#include "soc/clkrst_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "esp32h2/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_96M_FREQ_MHZ (96)
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
#define CLK_LL_RC32K_DFREQ_DEFAULT 707
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief XTAL32K_CLK configuration structure
*/
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} clk_ll_xtal32k_config_t;
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Enable the 32kHz crystal oscillator
*
* @param mode Used to determine the xtal32k configuration parameters
*/
static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
{
// Configure xtal32k (or only for mode == CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL?)
clk_ll_xtal32k_config_t cfg = CLK_LL_XTAL32K_CONFIG_DEFAULT();
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
// Enable xtal32k xpd status
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
// Not supported yet?
;
}
}
/**
* @brief Disable the 32kHz crystal oscillator
*/
static inline void clk_ll_xtal32k_disable(void)
{
// Set xtal32k xpd to be controlled by software
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
// Disable xtal32k xpd status
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
/**
* @brief Get the state of the 32kHz crystal clock
*
* @return True if the 32kHz XTAL is enabled
*/
static inline bool clk_ll_xtal32k_is_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
// disabled = xtal_xpd_sw && !xtal_xpd_st; enabled = !disbaled
bool enabled = !xtal_xpd_sw || xtal_xpd_st;
return enabled;
}
/**
* @brief Enable the internal oscillator output for RC32K_CLK
*/
static inline void clk_ll_rc32k_enable(void)
{
// Configure rc32k
REG_SET_FIELD(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_DFREQ, CLK_LL_RC32K_DFREQ_DEFAULT);
// Enable rc32k xpd status
SET_PERI_REG_MASK(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_XPD);
}
/**
* @brief Disable the internal oscillator output for RC32k_CLK
*/
static inline void clk_ll_rc32k_disable(void)
{
// Configure rc32k
REG_SET_FIELD(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_DFREQ, CLK_LL_RC32K_DFREQ_DEFAULT);
// Disable rc32k xpd status
CLEAR_PERI_REG_MASK(RTC_CNTL_RC32K_CTRL_REG, RTC_CNTL_RC32K_XPD);
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN_M);
}
/**
* @brief Disable the digital RC32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN_M);
}
/**
* @brief Get the state of the digital RC32K_CLK
*
* @return True if the digital RC32K_CLK is enabled
*/
static inline bool clk_ll_rc32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_RC32K_EN);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
uint32_t bbpll_freq = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SPLL_FREQ);
HAL_ASSERT(bbpll_freq == CLK_LL_PLL_96M_FREQ_MHZ);
return bbpll_freq;
}
/**
* @brief Set BBPLL frequency from XTAL source (Digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
(void)pll_freq_mhz;
// ESP32H2 bbpll frequency cannot be changed, fixed to 96MHz
// Do nothing
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
(void)xtal_freq_mhz;
switch (pll_freq_mhz) {
case CLK_LL_PLL_96M_FREQ_MHZ: // PLL_96M
/* set up PLL by analog control registers */
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, 0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DIV, 1); // I2C_BBPLL_OC_DIV_5_0
break;
default:
break;
}
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 3);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 2);
break;
case SOC_CPU_CLK_SRC_XTAL_D2:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 3);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
case 3:
return SOC_CPU_CLK_SRC_XTAL_D2;
default:
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU_CLK divider. freq of CPU_CLK = freq of CPU clock source / divider
*
* @param divider Divider. CPU_DIV_NUM = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_CPU_DIV_NUM, divider - 1);
}
/**
* @brief Get CPU_CLK divider
*
* @return Divider. Divider = (CPU_DIV_NUM + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_CPUCLK_CONF_REG, SYSTEM_CPU_DIV_NUM) + 1;
}
/**
* @brief Set AHB_CLK divider. freq of AHB_CLK = freq of CPU_CLK / divider
*
* @param divider Divider. AHB_DIV_NUM = divider - 1.
*/
static inline void clk_ll_ahb_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_AHB_DIV_NUM, divider - 1);
}
/**
* @brief Get AHB_CLK divider
*
* @return Divider. Divider = (AHB_DIV_NUM + 1).
*/
static inline uint32_t clk_ll_ahb_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_AHB_DIV_NUM) + 1;
}
/**
* @brief Set APB_CLK divider. freq of APB_CLK = freq of AHB_CLK / divider
*
* @param divider Divider. APB_DIV_NUM = divider - 1.
*/
static inline void clk_ll_apb_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_APB_DIV_NUM, divider - 1);
}
/**
* @brief Get APB_CLK divider
*
* @return Divider. Divider = (APB_DIV_NUM + 1).
*/
static inline uint32_t clk_ll_apb_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_BUSCLK_CONF_REG, SYSTEM_APB_DIV_NUM) + 1;
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC32K;
default:
// Invalid ANA_CLK_RTC_SEL value
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D2:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D2;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/**
* @brief Set RC_SLOW_CLK divider
*
* @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_slow_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store XTAL_CLK frequency in RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
}
/**
* @brief Load XTAL_CLK frequency from RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
{
// ESP32H2 has a fixed crystal frequency (32MHz), but we will still read from the RTC storage register
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if ((xtal_freq_reg & UINT16_MAX) != RTC_XTAL_FREQ_32M) {
return 0;
}
return (uint32_t)RTC_XTAL_FREQ_32M;
}
/**
* @brief Store APB_CLK frequency in RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param apb_freq_hz APB frequency, in Hz
*/
static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
{
uint32_t val = apb_freq_hz >> 12;
WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
// On ESP32-H2, don't need to do anything (indeed do need? not fully supported yet?)
// SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
// On ESP32-H2, don't need to do anything (indeed do need? not fully supported yet?)
// CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M);
}
/**
* @brief Start BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_start(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
}
/**
* @brief Stop BBPLL self-calibration
*
* This helps to prevent BBPLL jitter (phenomenon is significant on ESP32H2)
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_stop(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
}
/**
* @brief Check whether BBPLL calibration is done
*
* @return True if calibration is done; otherwise false
*/
static inline __attribute__((always_inline)) bool regi2c_ctrl_ll_bbpll_calibration_is_done(void)
{
return REG_GET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,749 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/dport_reg.h"
#include "soc/syscon_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "regi2c_apll.h"
#include "hal/assert.h"
#include "esp32s2/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_160M_FREQ_MHZ (160)
#define CLK_LL_PLL_240M_FREQ_MHZ (240)
#define CLK_LL_PLL_320M_FREQ_MHZ (320)
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
// ESP32S2 only supports 40MHz crystal
#define CLK_LL_XTAL_FREQ_MHZ (40)
/* APLL configuration parameters */
#define CLK_LL_APLL_SDM_STOP_VAL_1 0x09
#define CLK_LL_APLL_SDM_STOP_VAL_2_REV0 0x69
#define CLK_LL_APLL_SDM_STOP_VAL_2_REV1 0x49
/* APLL calibration parameters */
#define CLK_LL_APLL_CAL_DELAY_1 0x0f
#define CLK_LL_APLL_CAL_DELAY_2 0x3f
#define CLK_LL_APLL_CAL_DELAY_3 0x1f
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief XTAL32K_CLK configuration structure
*/
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} clk_ll_xtal32k_config_t;
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power up APLL circuit
*/
static inline void clk_ll_apll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
}
/**
* @brief Power down APLL circuit
*/
static inline void clk_ll_apll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
}
/**
* @brief Set APLL configuration
*
* @param o_div Frequency divider, 0..31
* @param sdm0 Frequency adjustment parameter, 0..255
* @param sdm1 Frequency adjustment parameter, 0..255
* @param sdm2 Frequency adjustment parameter, 0..63
*/
static inline void clk_ll_apll_set_config(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, CLK_LL_APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, CLK_LL_APLL_SDM_STOP_VAL_2_REV1);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
}
/**
* @brief Set APLL calibration parameters
*/
static inline void clk_ll_apll_set_calibration(void)
{
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_3);
}
/**
* @brief Check whether APLL calibration is done
*
* @return True if calibration is done; otherwise false
*/
static inline bool clk_ll_apll_calibration_is_done(void)
{
return REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END);
}
/**
* @brief Enable the 32kHz crystal oscillator
*
* @param mode Used to determine the xtal32k configuration parameters
*/
static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
{
// Configure xtal32k
clk_ll_xtal32k_config_t cfg = CLK_LL_XTAL32K_CONFIG_DEFAULT();
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
// Enable xtal32k xpd status
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
/* TODO: external 32k source may need different settings */
;
}
}
/**
* @brief Disable the 32kHz crystal oscillator
*/
static inline void clk_ll_xtal32k_disable(void)
{
// Set xtal32k xpd to be controlled by software
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
// Disable xtal32k xpd status
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
/**
* @brief Get the state of the 32kHz crystal clock
*
* @return True if the 32kHz XTAL is enabled
*/
static inline bool clk_ll_xtal32k_is_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
// disabled = xtal_xpd_sw && !xtal_xpd_st; enabled = !disbaled
bool enabled = !xtal_xpd_sw || xtal_xpd_st;
return enabled;
}
/**
* @brief Enable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
}
/**
* @brief Disable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/**
* @brief Get the state of the internal oscillator for RC_FAST_CLK
*
* @return True if the oscillator is enabled
*/
static inline bool clk_ll_rc_fast_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
}
/**
* @brief Enable the output from the internal oscillator to be passed into a configurable divider,
* which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Divider values other than 256 may be configured, but this facility is not currently needed,
* so is not exposed in the code.
* The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
*/
static inline void clk_ll_rc_fast_d256_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Disable the output from the internal oscillator to be passed into a configurable divider.
* i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Disabling this divider could reduce power consumption.
*/
static inline void clk_ll_rc_fast_d256_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
*
* @return True if the divided output is enabled
*/
static inline bool clk_ll_rc_fast_d256_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
uint32_t pll_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
switch (pll_freq_sel) {
case 0: // PLL_320M
return CLK_LL_PLL_320M_FREQ_MHZ;
case 1: // PLL_480M
return CLK_LL_PLL_480M_FREQ_MHZ;
default:
return 0;
}
}
/**
* @brief Set BBPLL frequency from XTAL source (digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
switch (pll_freq_mhz) {
case CLK_LL_PLL_320M_FREQ_MHZ: // PLL_320M
CLEAR_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
break;
case CLK_LL_PLL_480M_FREQ_MHZ: // PLL_480M
SET_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL);
break;
default:
abort();
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
(void)xtal_freq_mhz;
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
if (pll_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) {
/* Configure 480M PLL */
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 4;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Configure 320M PLL */
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 5;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
}
/**
* @brief Enable BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_calibration_enable(void)
{
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_IR_CAL_ENX_CAP, 1);
}
/**
* @brief Check whether BBPLL calibration is done
*
* @param ext_cap Steps write to I2C_BBPLL_IR_CAL_EXT_CAP
*
* @return True if calibration is done; otherwise false
*/
static inline __attribute__((always_inline)) bool clk_ll_bbpll_calibration_is_done(uint32_t ext_cap)
{
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, ext_cap);
return REGI2C_READ_MASK(I2C_BBPLL, I2C_BBPLL_OR_CAL_CAP) == 0;
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 2);
break;
case SOC_CPU_CLK_SRC_APLL:
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 3);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
case 3:
return SOC_CPU_CLK_SRC_APLL;
default:
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU frequency from PLL clock
*
* @param cpu_mhz CPU frequency value, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
{
switch (cpu_mhz) {
case CLK_LL_PLL_80M_FREQ_MHZ:
REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0);
break;
case CLK_LL_PLL_160M_FREQ_MHZ:
REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 1);
break;
case CLK_LL_PLL_240M_FREQ_MHZ:
REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 2);
break;
default:
// Unsupported CPU_CLK freq from PLL
abort();
}
}
/**
* @brief Get CPU_CLK frequency from PLL_CLK source
*
* @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
{
uint32_t cpu_freq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
return CLK_LL_PLL_80M_FREQ_MHZ;
case 1:
return CLK_LL_PLL_160M_FREQ_MHZ;
case 2:
// When PLL frequency selection is 320MHz but CPU frequency selection is 240MHz, it is an undetermined state.
// It is checked in the upper layer.
return CLK_LL_PLL_240M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, divider - 1);
}
/**
* @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @return Divider. Divider = (PRE_DIV_CNT + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT) + 1;
}
/**
* @brief Set REF_TICK divider to make REF_TICK frequency at 1MHz
*
* @param cpu_clk_src Selected CPU clock source (one of soc_cpu_clk_src_t values)
*
* When PLL, APLL, or XTAL is set as CPU clock source, divider = XTAL_CLK freq in Hz / 1MHz.
* When RC_FAST is set as CPU clock source, divider = RC_FAST_CLK freq in Hz / 1MHz.
* Value in register = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_ref_tick_set_divider(soc_cpu_clk_src_t cpu_clk_src)
{
switch (cpu_clk_src) {
case SOC_CPU_CLK_SRC_XTAL:
case SOC_CPU_CLK_SRC_PLL:
case SOC_CPU_CLK_SRC_APLL:
REG_SET_FIELD(SYSCON_TICK_CONF_REG, SYSCON_XTAL_TICK_NUM, CLK_LL_XTAL_FREQ_MHZ - 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(SYSCON_TICK_CONF_REG, SYSCON_CK8M_TICK_NUM, 8 - 1);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
default:
// Invalid ANA_CLK_RTC_SEL value
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D4:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D4;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/**
* @brief Set RC_SLOW_CLK divider
*
* @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_slow_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store APB_CLK frequency in RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param apb_freq_hz APB frequency, in Hz
*/
static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz)
{
uint32_t val = apb_freq_hz >> 12;
WRITE_PERI_REG(RTC_APB_FREQ_REG, (val & UINT16_MAX) | ((val & UINT16_MAX) << 16));
}
/**
* @brief Load APB_CLK frequency from RTC storage register
*
* Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return The stored APB frequency, in Hz
*/
static inline uint32_t clk_ll_apb_load_freq_hz(void)
{
// Read from RTC storage register
uint32_t apb_freq_hz = (READ_PERI_REG(RTC_APB_FREQ_REG) & UINT16_MAX) << 12;
// Round to the nearest MHz
apb_freq_hz += MHZ / 2;
uint32_t remainder = apb_freq_hz % MHZ;
return apb_freq_hz - remainder;
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_BBPLL_M);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the APLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_apll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,677 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/rtc.h"
#include "soc/system_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_bbpll.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "esp32s3/rom/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MHZ (1000000)
#define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_160M_FREQ_MHZ (160)
#define CLK_LL_PLL_240M_FREQ_MHZ (240)
#define CLK_LL_PLL_320M_FREQ_MHZ (320)
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
/**
* @brief XTAL32K_CLK enable modes
*/
typedef enum {
CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK
CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */
} clk_ll_xtal32k_enable_mode_t;
/**
* @brief XTAL32K_CLK configuration structure
*/
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} clk_ll_xtal32k_config_t;
/**
* @brief Power up BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void)
{
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Power down BBPLL circuit
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void)
{
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
/**
* @brief Enable the 32kHz crystal oscillator
*
* @param mode Used to determine the xtal32k configuration parameters
*/
static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode)
{
// Configure xtal32k
clk_ll_xtal32k_config_t cfg = CLK_LL_XTAL32K_CONFIG_DEFAULT();
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
// Enable xtal32k xpd status
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
if (mode == CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL) {
/* TODO: external 32k oscillator may need different settings */
;
}
}
/**
* @brief Disable the 32kHz crystal oscillator
*/
static inline void clk_ll_xtal32k_disable(void)
{
// Set xtal32k xpd to be controlled by software
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
// Disable xtal32k xpd status
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
/**
* @brief Get the state of the 32kHz crystal clock
*
* @return True if the 32kHz XTAL is enabled
*/
static inline bool clk_ll_xtal32k_is_enabled(void)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
// disabled = xtal_xpd_sw && !xtal_xpd_st; enabled = !disbaled
bool enabled = !xtal_xpd_sw || xtal_xpd_st;
return enabled;
}
/**
* @brief Enable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
}
/**
* @brief Disable the internal oscillator output for RC_FAST_CLK
*/
static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/**
* @brief Get the state of the internal oscillator for RC_FAST_CLK
*
* @return True if the oscillator is enabled
*/
static inline bool clk_ll_rc_fast_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
}
/**
* @brief Enable the output from the internal oscillator to be passed into a configurable divider,
* which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Divider values other than 256 may be configured, but this facility is not currently needed,
* so is not exposed in the code.
* The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions.
*/
static inline void clk_ll_rc_fast_d256_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Disable the output from the internal oscillator to be passed into a configurable divider.
* i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256
*
* Disabling this divider could reduce power consumption.
*/
static inline void clk_ll_rc_fast_d256_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
/**
* @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK)
*
* @return True if the divided output is enabled
*/
static inline bool clk_ll_rc_fast_d256_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
/**
* @brief Enable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Disable the digital RC_FAST_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Get the state of the digital RC_FAST_CLK
*
* @return True if the digital RC_FAST_CLK is enabled
*/
static inline bool clk_ll_rc_fast_digi_is_enabled(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
}
/**
* @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals.
*/
static inline void clk_ll_rc_fast_d256_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN_M);
}
/**
* @brief Enable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Disable the digital XTAL32K_CLK, which is used to support peripherals.
*/
static inline void clk_ll_xtal32k_digi_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN_M);
}
/**
* @brief Get the state of the digital XTAL32K_CLK
*
* @return True if the digital XTAL32K_CLK is enabled
*/
static inline bool clk_ll_xtal32k_digi_is_enabled(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
}
/**
* @brief Get PLL_CLK frequency
*
* @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void)
{
uint32_t pll_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL);
switch (pll_freq_sel) {
case 0: // PLL_320M
return CLK_LL_PLL_320M_FREQ_MHZ;
case 1: // PLL_480M
return CLK_LL_PLL_480M_FREQ_MHZ;
default:
return 0;
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Digital part)
*
* @param pll_freq_mhz PLL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz)
{
switch (pll_freq_mhz) {
case CLK_LL_PLL_320M_FREQ_MHZ: // PLL_320M
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL, 0);
break;
case CLK_LL_PLL_480M_FREQ_MHZ: // PLL_480M
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL, 1);
break;
default:
abort();
}
}
/**
* @brief Set BBPLL frequency from XTAL source (Analog part)
*
* @param pll_freq_mhz PLL frequency, in MHz
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
uint8_t dbias;
if (pll_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) {
/* Configure 480M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 26;
dr1 = 1;
dr3 = 1;
dchgp = 4;
dcur = 0;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Configure 320M PLL */
switch (xtal_freq_mhz) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 6;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (1 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
}
/**
* @brief Select the clock source for CPU_CLK
*
* @param in_sel One of the clock sources in soc_cpu_clk_src_t
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_CPU_CLK_SRC_XTAL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 0);
break;
case SOC_CPU_CLK_SRC_PLL:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 1);
break;
case SOC_CPU_CLK_SRC_RC_FAST:
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, 2);
break;
default:
// Unsupported CPU_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for CPU_CLK
*
* @return Currently selected clock source (one of soc_cpu_clk_src_t values)
*/
static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (clk_sel) {
case 0:
return SOC_CPU_CLK_SRC_XTAL;
case 1:
return SOC_CPU_CLK_SRC_PLL;
case 2:
return SOC_CPU_CLK_SRC_RC_FAST;
default:
// Invalid SOC_CLK_SEL value
return SOC_CPU_CLK_SRC_INVALID;
}
}
/**
* @brief Set CPU frequency from PLL clock
*
* @param cpu_mhz CPU frequency value, in MHz
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz)
{
switch (cpu_mhz) {
case CLK_LL_PLL_80M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 0);
break;
case CLK_LL_PLL_160M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 1);
break;
case CLK_LL_PLL_240M_FREQ_MHZ:
REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, 2);
break;
default:
// Unsupported CPU_CLK freq from PLL
abort();
}
}
/**
* @brief Get CPU_CLK frequency from PLL_CLK source
*
* @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void)
{
uint32_t cpu_freq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL);
switch (cpu_freq_sel) {
case 0:
return CLK_LL_PLL_80M_FREQ_MHZ;
case 1:
return CLK_LL_PLL_160M_FREQ_MHZ;
case 2:
// When PLL frequency selection is 320MHz but CPU frequency selection is 240MHz, it is an undetermined state.
// It is checked in the upper layer.
return CLK_LL_PLL_240M_FREQ_MHZ;
default:
// Invalid CPUPERIOD_SEL value
return 0;
}
}
/**
* @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1.
*/
static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, divider - 1);
}
/**
* @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider
*
* @return Divider. Divider = (PRE_DIV_CNT + 1).
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void)
{
return REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
}
/**
* @brief Select the clock source for RTC_SLOW_CLK
*
* @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t
*/
static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 0);
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 1);
break;
case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, 2);
break;
default:
// Unsupported RTC_SLOW_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_SLOW_CLK
*
* @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values)
*/
static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_SLOW_CLK_SRC_RC_SLOW;
case 1:
return SOC_RTC_SLOW_CLK_SRC_XTAL32K;
case 2:
return SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256;
default:
// Invalid ANA_CLK_RTC_SEL value
HAL_ASSERT(false);
return SOC_RTC_SLOW_CLK_SRC_INVALID;
}
}
/**
* @brief Select the clock source for RTC_FAST_CLK
*
* @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t
*/
static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel)
{
switch (in_sel) {
case SOC_RTC_FAST_CLK_SRC_XTAL_D2:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 0);
break;
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, 1);
break;
default:
// Unsupported RTC_FAST_CLK mux input sel
abort();
}
}
/**
* @brief Get the clock source for RTC_FAST_CLK
*
* @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values)
*/
static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void)
{
uint32_t clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
switch (clk_sel) {
case 0:
return SOC_RTC_FAST_CLK_SRC_XTAL_D2;
case 1:
return SOC_RTC_FAST_CLK_SRC_RC_FAST;
default:
return SOC_RTC_FAST_CLK_SRC_INVALID;
}
}
/**
* @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX.
*
* @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_fast_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
/**
* @brief Get RC_FAST_CLK divider
*
* @return Divider. Divider = (CK8M_DIV_SEL + 1).
*/
static inline uint32_t clk_ll_rc_fast_get_divider(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL) + 1;
}
/**
* @brief Set RC_SLOW_CLK divider
*
* @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage.
*/
static inline void clk_ll_rc_slow_set_divider(uint32_t divider)
{
HAL_ASSERT(divider > 0);
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, divider - 1);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
/************************* RTC STORAGE REGISTER STORE/LOAD **************************/
/**
* @brief Store XTAL_CLK frequency in RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @param xtal_freq_mhz XTAL frequency, in MHz
*/
static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, (xtal_freq_mhz & UINT16_MAX) | ((xtal_freq_mhz & UINT16_MAX) << 16));
}
/**
* @brief Load XTAL_CLK frequency from RTC storage register
*
* Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit
* halves. These are the routines to work with that representation.
*
* @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid.
*/
static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void)
{
// Read from the RTC storage register
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) &&
xtal_freq_reg != 0 && xtal_freq_reg != UINT32_MAX) {
return xtal_freq_reg & UINT16_MAX;
}
// If the format in reg is invalid
return 0;
}
/**
* @brief Store RTC_SLOW_CLK calibration value in RTC storage register
*
* Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds,
* in Q13.19 fixed-point format).
*
* @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value)
{
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_value);
}
/**
* @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register
*
* This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches
*
* @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format
*/
static inline uint32_t clk_ll_rtc_slow_load_cal(void)
{
return REG_READ(RTC_SLOW_CLK_CAL_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#include "soc/regi2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset (Disable) the I2C internal bus for all regi2c registers
*/
static inline void regi2c_ctrl_ll_i2c_reset(void)
{
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register
*/
static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_BBPLL_M);
}
/**
* @brief Enable the I2C internal bus to do I2C read/write operation to the SAR_ADC register
*/
static inline void regi2c_ctrl_ll_i2c_saradc_enable(void)
{
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_SAR_M);
SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_SAR_CFG2_M);
}
/**
* @brief Start BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_start(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
}
/**
* @brief Stop BBPLL self-calibration
*/
static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_stop(void)
{
REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
}
/**
* @brief Check whether BBPLL calibration is done
*
* @return True if calibration is done; otherwise false
*/
static inline __attribute__((always_inline)) bool regi2c_ctrl_ll_bbpll_calibration_is_done(void)
{
return REG_GET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE);
}
#ifdef __cplusplus
}
#endif

View File

@@ -66,6 +66,7 @@ typedef enum {
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 40MHz crystal oscillator frequency multiplier, can be 480MHz or 320MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_APLL = 3, /*!< Select APLL_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -76,6 +77,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_XTAL32K = 1, /*!< Select XTAL32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256 = 2, /*!< Select RC_FAST_D256_CLK (referred as FOSC_DIV or 8m_d256/8md256 in TRM and reg. description) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -86,6 +88,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D4 = 0, /*!< Select XTAL_D4_CLK (may referred as XTAL_CLK_DIV_4) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D4, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D4` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SOC_DPORT_REG_H_
#define _SOC_DPORT_REG_H_
@@ -179,9 +171,6 @@
#define DPORT_CPUPERIOD_SEL_M ((DPORT_CPUPERIOD_SEL_V)<<(DPORT_CPUPERIOD_SEL_S))
#define DPORT_CPUPERIOD_SEL_V 0x3
#define DPORT_CPUPERIOD_SEL_S 0
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_CPUPERIOD_SEL_240 2
#define DPORT_PRO_CACHE_CTRL_REG (DR_REG_DPORT_BASE + 0x040)
/* DPORT_PRO_DRAM_HL : R/W ;bitpos:[16] ;default: 1'b0 ; */

View File

@@ -1,16 +1,8 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SOC_IO_MUX_REG_H_
#define _SOC_IO_MUX_REG_H_
@@ -98,6 +90,8 @@
#define SPI_D_GPIO_NUM 8
#define SPI_WP_GPIO_NUM 10
#define SPI_HD_GPIO_NUM 9
#define XTAL32K_P_GPIO_NUM 32
#define XTAL32K_N_GPIO_NUM 33
#define PIN_CTRL (DR_REG_IO_MUX_BASE +0x00)
#define CLK_OUT3 0xf

View File

@@ -47,6 +47,33 @@ extern "C" {
* - rtc_init: initialization
*/
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define SOC_DELAY_PLL_DBIAS_RAISE 3
#define SOC_DELAY_PLL_ENABLE_WITH_150K 80
#define SOC_DELAY_PLL_ENABLE_WITH_32K 160
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_ENABLE 50
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage needs to be increased in two cases:
* 1. running at 240 MHz
* 2. running with 80MHz Flash frequency
*
* There is a record in efuse which indicates the proper voltage for these two cases.
*/
#define RTC_CNTL_DBIAS_HP_VOLT (RTC_CNTL_DBIAS_1V25 - efuse_ll_get_vol_level_hp_inv())
#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_HP_VOLT
#else
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_1V10
#endif
#define DIG_DBIAS_240M RTC_CNTL_DBIAS_HP_VOLT
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
/**
* @brief Possible main XTAL frequency values.
*
@@ -84,7 +111,7 @@ typedef enum {
typedef struct rtc_clk_config_s {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_8m_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
uint32_t slow_clk_dcap : 8; //!< RTC 150k clock adjustment parameter (higher value leads to lower frequency)
@@ -241,9 +268,9 @@ void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -267,9 +294,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source

View File

@@ -893,10 +893,6 @@
#define RTC_CNTL_SOC_CLK_SEL_M ((RTC_CNTL_SOC_CLK_SEL_V)<<(RTC_CNTL_SOC_CLK_SEL_S))
#define RTC_CNTL_SOC_CLK_SEL_V 0x3
#define RTC_CNTL_SOC_CLK_SEL_S 27
#define RTC_CNTL_SOC_CLK_SEL_XTL 0
#define RTC_CNTL_SOC_CLK_SEL_PLL 1
#define RTC_CNTL_SOC_CLK_SEL_8M 2
#define RTC_CNTL_SOC_CLK_SEL_APLL 3
/* RTC_CNTL_CK8M_FORCE_PU : R/W ;bitpos:[26] ;default: 1'd0 ; */
/*description: CK8M force power up*/
#define RTC_CNTL_CK8M_FORCE_PU (BIT(26))

View File

@@ -62,6 +62,7 @@ typedef enum {
SOC_CPU_CLK_SRC_XTAL = 0, /*!< Select XTAL_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 40MHz crystal oscillator frequency multiplier, 480MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -72,6 +73,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_OSC_SLOW = 1, /*!< Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256 = 2, /*!< Select RC_FAST_D256_CLK (referred as FOSC_DIV or 8m_d256/8md256 in TRM and reg. description) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -82,6 +84,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D2 = 0, /*!< Select XTAL_D2_CLK (may referred as XTAL_CLK_DIV_2) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D2, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D2` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -125,6 +125,8 @@
#define SPI_D_GPIO_NUM 16
#define SPI_Q_GPIO_NUM 17
#define EXT_OSC_SLOW_GPIO_NUM 0
#define MAX_RTC_GPIO_NUM 5
#define MAX_PAD_GPIO_NUM 20
#define MAX_GPIO_NUM 24

View File

@@ -67,18 +67,17 @@ extern "C" {
#define RTC_CNTL_DBIAS_1V25 30
#define RTC_CNTL_DBIAS_1V30 31 //voltage is about 1.34v in fact
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_ENABLE 50
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage (to be supported) */
#define DIG_DBIAS_80M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_160M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_120M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
@@ -161,7 +160,7 @@ typedef enum {
typedef struct {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_rtc_clk_div : 8;
uint32_t clk_8m_clk_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
@@ -277,9 +276,9 @@ bool rtc_clk_8md256_enabled(void);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -303,9 +302,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source

View File

@@ -63,6 +63,7 @@ typedef enum {
SOC_CPU_CLK_SRC_XTAL = 0, /*!< Select XTAL_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 40MHz crystal oscillator frequency multiplier, can be 480MHz or 320MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -73,6 +74,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_XTAL32K = 1, /*!< Select XTAL32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256 = 2, /*!< Select RC_FAST_D256_CLK (referred as FOSC_DIV or 8m_d256/8md256 in TRM and reg. description) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -83,6 +85,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D2 = 0, /*!< Select XTAL_D2_CLK (may referred as XTAL_CLK_DIV_2) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D2, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D2` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -67,18 +67,20 @@ extern "C" {
#define RTC_CNTL_DBIAS_1V25 30
#define RTC_CNTL_DBIAS_1V30 31 //voltage is about 1.34v in fact
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_ENABLE 50
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage:
* Currently, ESP32C3 never adjust its wake voltage in runtime
* Only sets dig/rtc voltage dbias at startup time
*/
#define DIG_DBIAS_80M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_160M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
@@ -163,7 +165,7 @@ typedef enum {
typedef struct {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_rtc_clk_div : 8;
uint32_t clk_8m_clk_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
@@ -185,20 +187,6 @@ typedef struct {
.clk_8m_dfreq = RTC_CNTL_CK8M_DFREQ_DEFAULT, \
}
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} x32k_config_t;
#define X32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
typedef struct {
uint16_t wifi_powerup_cycles : 7;
uint16_t wifi_wait_cycles : 9;
@@ -317,9 +305,9 @@ bool rtc_clk_8md256_enabled(void);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -343,9 +331,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source

View File

@@ -152,6 +152,9 @@
#define USB_DM_GPIO_NUM 18
#define USB_DP_GPIO_NUM 19
#define XTAL32K_P_GPIO_NUM 0
#define XTAL32K_N_GPIO_NUM 1
#define MAX_RTC_GPIO_NUM 5
#define MAX_PAD_GPIO_NUM 40
#define MAX_GPIO_NUM 44

View File

@@ -127,6 +127,9 @@
#define USB_DM_GPIO_NUM 24
#define USB_DP_GPIO_NUM 25
#define XTAL32K_P_GPIO_NUM 10
#define XTAL32K_N_GPIO_NUM 11
#define MAX_RTC_GPIO_NUM 12 // GPIO7~12 are the rtc_io pads
#define MAX_PAD_GPIO_NUM 25
#define MAX_GPIO_NUM 29

View File

@@ -70,6 +70,7 @@ typedef enum {
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 32MHz crystal oscillator frequency multiplier, 96MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_XTAL_D2 = 3, /*!< Select XTAL_D2_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -80,6 +81,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_XTAL32K = 1, /*!< Select XTAL32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC32K = 2, /*!< Select RC32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -90,6 +92,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D2 = 0, /*!< Select XTAL_D2_CLK (may referred as XTAL_CLK_DIV_2) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D2, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D2` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,6 +13,7 @@
#define I2C_MST_ANA_CONF0_REG 0x6000E040
#define I2C_MST_BBPLL_STOP_FORCE_HIGH (BIT(2))
#define I2C_MST_BBPLL_STOP_FORCE_LOW (BIT(3))
#define I2C_MST_BBPLL_CAL_DONE (BIT(24))
#define ANA_CONFIG_REG 0x6000E044
#define ANA_CONFIG_S (8)
@@ -21,7 +22,6 @@
#define ANA_I2C_SAR_FORCE_PD BIT(18)
#define ANA_I2C_BBPLL_M BIT(17) /* Clear to enable BBPLL */
#define ANA_CONFIG2_REG 0x6000E048
#define ANA_CONFIG2_M BIT(18)

View File

@@ -87,18 +87,16 @@ extern "C" {
#define RTC_CNTL_DIG_DBIAS_1V15 6
#define RTC_CNTL_DIG_DBIAS_1V20 7
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage (to be supported) */
#define DIG_DBIAS_80M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_160M RTC_CNTL_DBIAS_1V20
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
@@ -109,7 +107,6 @@ extern "C" {
#define RTC_CNTL_CK8M_DFREQ_DEFAULT 600
#define RTC_CNTL_SCK_DCAP_DEFAULT 128
#define RTC_CNTL_RC32K_DFREQ_DEFAULT 707
/* Various delays to be programmed into power control state machines */
@@ -140,7 +137,6 @@ set sleep_init default param
*/
typedef enum {
RTC_XTAL_FREQ_32M = 32,
RTC_XTAL_FREQ_40M = 40, //!< 40 MHz XTAL
} rtc_xtal_freq_t;
/**
@@ -173,7 +169,7 @@ typedef enum {
typedef struct {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_rtc_clk_div : 8;
uint32_t clk_8m_clk_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
@@ -197,29 +193,6 @@ typedef struct {
.root_clk_slt = 0, \
}
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} x32k_config_t;
#define X32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
typedef struct {
uint32_t dfreq : 10;
} rc32k_config_t;
#define RC32K_CONFIG_DEFAULT() {\
.dfreq = RTC_CNTL_RC32K_DFREQ_DEFAULT,\
}
typedef struct {
uint16_t wifi_powerup_cycles : 7;
uint16_t wifi_wait_cycles : 9;
@@ -344,9 +317,9 @@ bool rtc_clk_8md256_enabled(void);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -370,9 +343,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source
@@ -455,18 +428,13 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
/**
* @brief Get the current stored APB frequency.
* @return The APB frequency value as last set via rtc_clk_apb_freq_update(), in Hz.
* @return The APB frequency value computed from upstream, in Hz.
*/
uint32_t rtc_clk_apb_freq_get(void);
void rtc_clk_cpu_freq_set(uint32_t source, uint32_t div);
/**
* @brief Get the current stored AHB frequency.
* @return The AHB frequency value as last set via rtc_clk_ahb_freq_set(), in Hz.
*/
uint32_t rtc_clk_ahb_freq_get(void);
uint32_t rtc_clk_select_root_clk(soc_cpu_clk_src_t cpu_clk_src);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
@@ -910,12 +878,6 @@ rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
/* Select clock root source for esp32h2. return source clk freq_mhz
*/
uint32_t root_clk_slt(uint32_t source);
uint32_t root_clk_get(void);
/**
* Regulator config
*/
@@ -946,12 +908,6 @@ typedef struct {
}
/**
* gpio hangup
*/
void rtc_gpio_hangup(uint32_t gpio_no);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.

View File

@@ -64,6 +64,7 @@ typedef enum {
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 40MHz crystal oscillator frequency multiplier, can be 480MHz or 320MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_APLL = 3, /*!< Select APLL_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -74,6 +75,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_XTAL32K = 1, /*!< Select XTAL32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256 = 2, /*!< Select RC_FAST_D256_CLK (referred as FOSC_DIV or 8m_d256/8md256 in TRM and reg. description) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -84,6 +86,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D4 = 0, /*!< Select XTAL_D4_CLK (may referred as XTAL_CLK_DIV_4) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D4, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D4` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -66,14 +66,13 @@ extern "C" {
#define RTC_CNTL_DBIAS_1V20 6
#define RTC_CNTL_DBIAS_1V25 7
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_ENABLE 50
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage needs to be increased in two cases:
* 1. running at 240 MHz
@@ -119,13 +118,6 @@ set sleep_init default param
#define RTC_CNTL_PD_CUR_SLEEP_ON 0
#define RTC_CNTL_PD_CUR_SLEEP_DEFAULT 1
#define APLL_SDM_STOP_VAL_1 0x09
#define APLL_SDM_STOP_VAL_2_REV0 0x69
#define APLL_SDM_STOP_VAL_2_REV1 0x49
#define APLL_CAL_DELAY_1 0x0f
#define APLL_CAL_DELAY_2 0x3f
#define APLL_CAL_DELAY_3 0x1f
/**
* @brief Possible main XTAL frequency values.
*
@@ -135,13 +127,6 @@ typedef enum {
RTC_XTAL_FREQ_40M = 40, //!< 40 MHz XTAL
} rtc_xtal_freq_t;
/** @brief Fixed crystal frequency for this SoC
On an SoC where only one crystal frequency is supported,
using this macro is an alternative to calling rtc_clk_xtal_freq_get()
*/
#define RTC_XTAL_FREQ RTC_XTAL_FREQ_40M
/**
* @brief CPU clock configuration structure
*/
@@ -173,7 +158,7 @@ typedef enum {
typedef struct {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_rtc_clk_div : 8;
uint32_t clk_8m_clk_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
@@ -195,42 +180,6 @@ typedef struct {
.clk_8m_dfreq = RTC_CNTL_CK8M_DFREQ_DEFAULT, \
}
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} x32k_config_t;
#define X32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
#if 0
#define X32K_CONFIG_BOOTSTRAP_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 0, \
}
typedef struct {
x32k_config_t x32k_cfg;
uint32_t bt_lpck_div_num : 12;
uint32_t bt_lpck_div_a : 12;
uint32_t bt_lpck_div_b : 12;
} x32k_bootstrap_config_t;
#define X32K_BOOTSTRAP_CONFIG_DEFAULT() { \
.x32k_cfg = X32K_CONFIG_BOOTSTRAP_DEFAULT(), \
.bt_lpck_div_num = 2441, \
.bt_lpck_div_a = 32, \
.bt_lpck_div_b = 13, \
}
#endif
typedef struct {
uint16_t wifi_powerup_cycles : 7;
uint16_t wifi_wait_cycles : 9;
@@ -274,10 +223,10 @@ void rtc_clk_init(rtc_clk_config_t cfg);
* Result is a constant as XTAL frequency is fixed.
*
* @note Function is included for ESP32 compatible code only. Code which only
* needs to support this SoC can use the macro RTC_XTAL_FREQ for this SoC's
* needs to support this SoC can use the macro CLK_LL_XTAL_FREQ_MHZ for this SoC's
* fixed crystal value.
*
* @return XTAL frequency in MHz, RTC_XTAL_FREQ_40M
* @return XTAL frequency in MHz
*/
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void);
@@ -381,9 +330,9 @@ void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -407,9 +356,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source

View File

@@ -1,16 +1,8 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SOC_SYSTEM_REG_H_
#define _SOC_SYSTEM_REG_H_
@@ -886,10 +878,6 @@ extern "C" {
#define DPORT_SOC_CLK_SEL_M ((DPORT_SOC_CLK_SEL_V)<<(DPORT_SOC_CLK_SEL_S))
#define DPORT_SOC_CLK_SEL_V 0x3
#define DPORT_SOC_CLK_SEL_S 10
#define DPORT_SOC_CLK_SEL_XTL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#define DPORT_SOC_CLK_SEL_APLL 3
/* DPORT_PRE_DIV_CNT : R/W ;bitpos:[9:0] ;default: 10'h1 ; */
/*description: */
#define DPORT_PRE_DIV_CNT 0x000003FF

View File

@@ -63,6 +63,7 @@ typedef enum {
SOC_CPU_CLK_SRC_XTAL = 0, /*!< Select XTAL_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_PLL = 1, /*!< Select PLL_CLK as CPU_CLK source (PLL_CLK is the output of 40MHz crystal oscillator frequency multiplier, can be 480MHz or 320MHz) */
SOC_CPU_CLK_SRC_RC_FAST = 2, /*!< Select RC_FAST_CLK as CPU_CLK source */
SOC_CPU_CLK_SRC_INVALID, /*!< Invalid CPU_CLK source */
} soc_cpu_clk_src_t;
/**
@@ -73,6 +74,7 @@ typedef enum {
SOC_RTC_SLOW_CLK_SRC_RC_SLOW = 0, /*!< Select RC_SLOW_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_XTAL32K = 1, /*!< Select XTAL32K_CLK as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256 = 2, /*!< Select RC_FAST_D256_CLK (referred as FOSC_DIV or 8m_d256/8md256 in TRM and reg. description) as RTC_SLOW_CLK source */
SOC_RTC_SLOW_CLK_SRC_INVALID, /*!< Invalid RTC_SLOW_CLK source */
} soc_rtc_slow_clk_src_t;
/**
@@ -83,6 +85,7 @@ typedef enum {
SOC_RTC_FAST_CLK_SRC_XTAL_D2 = 0, /*!< Select XTAL_D2_CLK (may referred as XTAL_CLK_DIV_2) as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_XTAL_DIV = SOC_RTC_FAST_CLK_SRC_XTAL_D2, /*!< Alias name for `SOC_RTC_FAST_CLK_SRC_XTAL_D2` */
SOC_RTC_FAST_CLK_SRC_RC_FAST = 1, /*!< Select RC_FAST_CLK as RTC_FAST_CLK source */
SOC_RTC_FAST_CLK_SRC_INVALID, /*!< Invalid RTC_FAST_CLK source */
} soc_rtc_fast_clk_src_t;
// Naming convention: SOC_MOD_CLK_{[upstream]clock_name}_[attr]

View File

@@ -156,6 +156,8 @@
#define SD_DATA3_GPIO_NUM 10
#define USB_DM_GPIO_NUM 19
#define USB_DP_GPIO_NUM 20
#define XTAL32K_P_GPIO_NUM 15
#define XTAL32K_N_GPIO_NUM 16
#define MAX_RTC_GPIO_NUM 21
#define MAX_PAD_GPIO_NUM 48

View File

@@ -68,14 +68,13 @@ extern "C" {
#define RTC_CNTL_DBIAS_1V25 30
#define RTC_CNTL_DBIAS_1V30 31 ///< voltage is about 1.34v in fact
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
#define SOC_DELAY_RTC_FAST_CLK_SWITCH 3
#define SOC_DELAY_RTC_SLOW_CLK_SWITCH 300
#define SOC_DELAY_RC_FAST_ENABLE 50
#define SOC_DELAY_RC_FAST_DIGI_SWITCH 5
/* Core voltage needs to be increased in two cases:
* 1. running at 240 MHz
@@ -168,7 +167,7 @@ typedef enum {
typedef struct {
rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency
uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz
soc_rtc_fast_clk_src_t fast_clk_src : 1; //!< RTC_FAST_CLK clock source to choose
soc_rtc_fast_clk_src_t fast_clk_src : 2; //!< RTC_FAST_CLK clock source to choose
soc_rtc_slow_clk_src_t slow_clk_src : 2; //!< RTC_SLOW_CLK clock source to choose
uint32_t clk_rtc_clk_div : 8;
uint32_t clk_8m_clk_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
@@ -190,20 +189,6 @@ typedef struct {
.clk_8m_dfreq = RTC_CNTL_CK8M_DFREQ_DEFAULT, \
}
typedef struct {
uint32_t dac : 6;
uint32_t dres : 3;
uint32_t dgm : 3;
uint32_t dbuf: 1;
} x32k_config_t;
#define X32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \
.dgm = 3, \
.dbuf = 1, \
}
typedef struct {
uint16_t wifi_powerup_cycles : 7;
uint16_t wifi_wait_cycles : 9;
@@ -330,9 +315,9 @@ bool rtc_clk_8md256_enabled(void);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of soc_rtc_slow_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_slow_clk_src_t values)
*/
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t slow_freq);
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src);
/**
* @brief Get the RTC_SLOW_CLK source
@@ -356,9 +341,9 @@ uint32_t rtc_clk_slow_freq_get_hz(void);
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of soc_rtc_fast_clk_src_t values)
* @param clk_src clock source (one of soc_rtc_fast_clk_src_t values)
*/
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t fast_freq);
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src);
/**
* @brief Get the RTC_FAST_CLK source

View File

@@ -1154,7 +1154,6 @@ components/soc/esp32/include/soc/can_periph.h
components/soc/esp32/include/soc/can_struct.h
components/soc/esp32/include/soc/clkout_channel.h
components/soc/esp32/include/soc/dac_channel.h
components/soc/esp32/include/soc/dport_reg.h
components/soc/esp32/include/soc/emac_dma_struct.h
components/soc/esp32/include/soc/emac_ext_struct.h
components/soc/esp32/include/soc/emac_mac_struct.h
@@ -1173,7 +1172,6 @@ components/soc/esp32/include/soc/host_struct.h
components/soc/esp32/include/soc/hwcrypto_reg.h
components/soc/esp32/include/soc/i2c_reg.h
components/soc/esp32/include/soc/i2c_struct.h
components/soc/esp32/include/soc/io_mux_reg.h
components/soc/esp32/include/soc/ledc_reg.h
components/soc/esp32/include/soc/ledc_struct.h
components/soc/esp32/include/soc/nrx_reg.h
@@ -1371,7 +1369,6 @@ components/soc/esp32s2/include/soc/spi_reg.h
components/soc/esp32s2/include/soc/spi_struct.h
components/soc/esp32s2/include/soc/syscon_reg.h
components/soc/esp32s2/include/soc/syscon_struct.h
components/soc/esp32s2/include/soc/system_reg.h
components/soc/esp32s2/include/soc/systimer_reg.h
components/soc/esp32s2/include/soc/systimer_struct.h
components/soc/esp32s2/include/soc/touch_sensor_channel.h