Merge branch 'feature/esp32h2_clock_basic_support' into 'master'
clk: Add basic clock support for esp32h2 Closes IDF-6265 and IDF-5973 See merge request espressif/esp-idf!21943
This commit is contained in:
@@ -105,7 +105,8 @@ if(NOT BOOTLOADER_BUILD)
|
||||
if(CONFIG_IDF_TARGET_ESP32H2)
|
||||
list(REMOVE_ITEM srcs
|
||||
"adc_share_hw_ctrl.c" # TODO: IDF-6215
|
||||
"port/clk_tree_common.c" # TODO: IDF-6265
|
||||
"sleep_cpu.c" # TODO: IDF-6267
|
||||
"sleep_modes.c" # TODO: IDF-6267
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "esp32c6/rom/rtc.h"
|
||||
#include "esp32c6/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#include "esp32h2/rtc.h"
|
||||
#endif
|
||||
|
||||
#define MHZ (1000000)
|
||||
@@ -73,7 +76,7 @@ int IRAM_ATTR esp_clk_cpu_freq(void)
|
||||
int IRAM_ATTR esp_clk_apb_freq(void)
|
||||
{
|
||||
// TODO: IDF-5173 Require cleanup, implementation should be unified
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
|
||||
return rtc_clk_apb_freq_get();
|
||||
#else
|
||||
return MIN(s_get_cpu_freq_mhz() * MHZ, APB_CLK_FREQ);
|
||||
|
||||
@@ -182,6 +182,10 @@ uint32_t clk_tree_lp_fast_get_freq_hz(clk_tree_src_freq_precision_t precision)
|
||||
#endif
|
||||
case SOC_RTC_FAST_CLK_SRC_RC_FAST:
|
||||
return clk_tree_rc_fast_get_freq_hz(precision) / clk_ll_rc_fast_get_divider();
|
||||
#if SOC_CLK_LP_FAST_SUPPORT_LP_PLL
|
||||
case SOC_RTC_FAST_CLK_SRC_LP_PLL:
|
||||
return clk_ll_lp_pll_get_freq_mhz() * MHZ;
|
||||
#endif
|
||||
default:
|
||||
// Invalid clock source
|
||||
assert(false);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
set(srcs "rtc_clk_init.c"
|
||||
"rtc_clk.c"
|
||||
# "rtc_init.c" // ESP32H2-TODO
|
||||
# "rtc_pm.c" // ESP32H2-TODO
|
||||
# "rtc_sleep.c" // ESP32H2-TODO
|
||||
"pmu_param.c"
|
||||
"pmu_init.c"
|
||||
"pmu_sleep.c"
|
||||
"rtc_time.c"
|
||||
"chip_info.c"
|
||||
)
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/clk_tree_common.h"
|
||||
|
||||
static const char *TAG = "clk_tree";
|
||||
|
||||
// TODO: IDF-6265
|
||||
esp_err_t clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -22,17 +24,32 @@ uint32_t *freq_value)
|
||||
|
||||
uint32_t clk_src_freq = 0;
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_XTAL:
|
||||
clk_src_freq = 32 * MHZ;
|
||||
case SOC_MOD_CLK_CPU:
|
||||
clk_src_freq = clk_hal_cpu_get_freq_hz();
|
||||
break;
|
||||
case SOC_MOD_CLK_PLL_F96M:
|
||||
clk_src_freq = 96 * MHZ;
|
||||
case SOC_MOD_CLK_XTAL:
|
||||
clk_src_freq = clk_hal_xtal_get_freq_mhz() * MHZ;
|
||||
break;
|
||||
case SOC_MOD_CLK_PLL_F48M:
|
||||
clk_src_freq = 48 * MHZ;
|
||||
clk_src_freq = CLK_LL_PLL_48M_FREQ_MHZ * MHZ;
|
||||
break;
|
||||
case SOC_MOD_CLK_PLL_F64M:
|
||||
clk_src_freq = CLK_LL_PLL_64M_FREQ_MHZ * MHZ;
|
||||
break;
|
||||
case SOC_MOD_CLK_PLL_F96M:
|
||||
clk_src_freq = CLK_LL_PLL_96M_FREQ_MHZ * MHZ;
|
||||
break;
|
||||
case SOC_MOD_CLK_RTC_SLOW:
|
||||
clk_src_freq = clk_tree_lp_slow_get_freq_hz(precision);
|
||||
break;
|
||||
case SOC_MOD_CLK_RTC_FAST:
|
||||
clk_src_freq = clk_tree_lp_fast_get_freq_hz(precision);
|
||||
break;
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
clk_src_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
|
||||
clk_src_freq = clk_tree_rc_fast_get_freq_hz(precision);
|
||||
break;
|
||||
case SOC_MOD_CLK_XTAL32K:
|
||||
clk_src_freq = clk_tree_xtal32k_get_freq_hz(precision);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_types.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/pmu_struct.h"
|
||||
#include "hal/pmu_hal.h"
|
||||
#include "pmu_param.h"
|
||||
#include "esp_private/esp_pmu.h"
|
||||
#include "soc/regi2c_pmu.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
|
||||
// TODO: IDF-6267
|
||||
|
||||
static __attribute__((unused)) const char *TAG = "pmu_init";
|
||||
|
||||
typedef struct {
|
||||
const pmu_hp_system_power_param_t *power;
|
||||
const pmu_hp_system_clock_param_t *clock;
|
||||
const pmu_hp_system_digital_param_t *digital;
|
||||
const pmu_hp_system_analog_param_t *analog;
|
||||
const pmu_hp_system_retention_param_t *retent;
|
||||
} pmu_hp_system_param_t;
|
||||
|
||||
typedef struct {
|
||||
const pmu_lp_system_power_param_t *power;
|
||||
const pmu_lp_system_analog_param_t *analog;
|
||||
} pmu_lp_system_param_t;
|
||||
|
||||
pmu_context_t * __attribute__((weak)) IRAM_ATTR PMU_instance(void)
|
||||
{
|
||||
/* It should be explicitly defined in the internal RAM, because this
|
||||
* instance will be used in pmu_sleep.c */
|
||||
static DRAM_ATTR pmu_hal_context_t pmu_hal = { .dev = &PMU };
|
||||
// static DRAM_ATTR pmu_sleep_machine_constant_t pmu_mc = PMU_SLEEP_MC_DEFAULT();
|
||||
static DRAM_ATTR pmu_context_t pmu_context = { .hal = &pmu_hal,
|
||||
// .mc = (void *)&pmu_mc
|
||||
};
|
||||
return &pmu_context;
|
||||
}
|
||||
|
||||
void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_param_t *param)
|
||||
{
|
||||
const pmu_hp_system_power_param_t *power = param->power;
|
||||
const pmu_hp_system_clock_param_t *clock = param->clock;
|
||||
const pmu_hp_system_digital_param_t *dig = param->digital;
|
||||
const pmu_hp_system_analog_param_t *anlg = param->analog;
|
||||
const pmu_hp_system_retention_param_t *ret = param->retent;
|
||||
|
||||
assert(ctx->hal);
|
||||
/* Default configuration of hp-system power in active, modem and sleep modes */
|
||||
pmu_ll_hp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val);
|
||||
pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val);
|
||||
pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal);
|
||||
|
||||
/* Default configuration of hp-system clock in active, modem and sleep modes */
|
||||
pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func);
|
||||
pmu_ll_hp_set_icg_apb (ctx->hal->dev, mode, clock->icg_apb);
|
||||
pmu_ll_hp_set_icg_modem (ctx->hal->dev, mode, clock->icg_modem.code);
|
||||
pmu_ll_hp_set_sysclk_nodiv (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_nodiv);
|
||||
pmu_ll_hp_set_icg_sysclk_enable (ctx->hal->dev, mode, clock->sysclk.icg_sysclk_en);
|
||||
pmu_ll_hp_set_sysclk_slp_sel (ctx->hal->dev, mode, clock->sysclk.sysclk_slp_sel);
|
||||
pmu_ll_hp_set_icg_sysclk_slp_sel(ctx->hal->dev, mode, clock->sysclk.icg_slp_sel);
|
||||
pmu_ll_hp_set_dig_sysclk (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_sel);
|
||||
|
||||
/* Default configuration of hp-system digital sub-system in active, modem
|
||||
* and sleep modes */
|
||||
pmu_ll_hp_set_uart_wakeup_enable(ctx->hal->dev, mode, dig->syscntl.uart_wakeup_en);
|
||||
pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, mode, dig->syscntl.lp_pad_hold_all);
|
||||
pmu_ll_hp_set_hold_all_hp_pad (ctx->hal->dev, mode, dig->syscntl.hp_pad_hold_all);
|
||||
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, mode, dig->syscntl.dig_pad_slp_sel);
|
||||
pmu_ll_hp_set_pause_watchdog (ctx->hal->dev, mode, dig->syscntl.dig_pause_wdt);
|
||||
pmu_ll_hp_set_cpu_stall (ctx->hal->dev, mode, dig->syscntl.dig_cpu_stall);
|
||||
|
||||
/* Default configuration of hp-system analog sub-system in active, modem and
|
||||
* sleep modes */
|
||||
pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias);
|
||||
pmu_ll_hp_set_trx_xpd (ctx->hal->dev, mode, anlg->bias.xpd_trx);
|
||||
pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur);
|
||||
pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep);
|
||||
pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_xpd);
|
||||
pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd);
|
||||
pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd);
|
||||
pmu_ll_hp_set_regulator_sleep_memory_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_mem_dbias);
|
||||
pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_logic_dbias);
|
||||
pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias);
|
||||
pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b);
|
||||
|
||||
/* Default configuration of hp-system retention sub-system in active, modem
|
||||
* and sleep modes */
|
||||
pmu_ll_hp_set_retention_param(ctx->hal->dev, mode, ret->retention.val);
|
||||
pmu_ll_hp_set_backup_icg_func(ctx->hal->dev, mode, ret->backup_clk);
|
||||
|
||||
// /* Some PMU initial parameter configuration */
|
||||
// pmu_ll_imm_update_dig_icg_modem_code(ctx->hal->dev, true);
|
||||
// pmu_ll_imm_update_dig_icg_switch(ctx->hal->dev, true);
|
||||
|
||||
// pmu_ll_hp_set_sleep_protect_mode(ctx->hal->dev, PMU_SLEEP_PROTECT_HP_LP_SLEEP);
|
||||
}
|
||||
|
||||
void pmu_lp_system_init(pmu_context_t *ctx, pmu_lp_mode_t mode, pmu_lp_system_param_t *param)
|
||||
{
|
||||
const pmu_lp_system_power_param_t *power = param->power;
|
||||
const pmu_lp_system_analog_param_t *anlg = param->analog;
|
||||
|
||||
assert(ctx->hal);
|
||||
/* Default configuration of lp-system power in active and sleep modes */
|
||||
pmu_ll_lp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val);
|
||||
pmu_ll_lp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val);
|
||||
pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, power->xtal.xpd_xtal);
|
||||
|
||||
/* Default configuration of lp-system analog sub-system in active and
|
||||
* sleep modes */
|
||||
pmu_ll_lp_set_bias_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.xpd_bias);
|
||||
pmu_ll_lp_set_current_power_off (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.pd_cur);
|
||||
pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.bias_sleep);
|
||||
pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_xpd);
|
||||
pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd);
|
||||
pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_dbias);
|
||||
pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias);
|
||||
pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b);
|
||||
}
|
||||
|
||||
static inline void pmu_power_domain_force_default(pmu_context_t *ctx)
|
||||
{
|
||||
assert(ctx);
|
||||
// for bypass reserved power domain
|
||||
const pmu_hp_power_domain_t pmu_hp_domains[] = {
|
||||
PMU_HP_PD_TOP,
|
||||
PMU_HP_PD_AON,
|
||||
PMU_HP_PD_CPU,
|
||||
PMU_HP_PD_WIFI
|
||||
};
|
||||
|
||||
for (uint8_t idx = 0; idx < (sizeof(pmu_hp_domains) / sizeof(pmu_hp_power_domain_t)); idx++) {
|
||||
pmu_ll_hp_set_power_force_reset (ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
pmu_ll_hp_set_power_force_isolate (ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
pmu_ll_hp_set_power_force_power_up (ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
pmu_ll_hp_set_power_force_no_reset (ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
pmu_ll_hp_set_power_force_no_isolate(ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
pmu_ll_hp_set_power_force_power_down(ctx->hal->dev, pmu_hp_domains[idx], false);
|
||||
}
|
||||
// /* Isolate all memory banks while sleeping, avoid memory leakage current */
|
||||
// pmu_ll_hp_set_memory_no_isolate (ctx->hal->dev, 0);
|
||||
|
||||
pmu_ll_lp_set_power_force_reset (ctx->hal->dev, false);
|
||||
pmu_ll_lp_set_power_force_isolate (ctx->hal->dev, false);
|
||||
pmu_ll_lp_set_power_force_power_up (ctx->hal->dev, false);
|
||||
pmu_ll_lp_set_power_force_no_reset (ctx->hal->dev, false);
|
||||
pmu_ll_lp_set_power_force_no_isolate(ctx->hal->dev, false);
|
||||
pmu_ll_lp_set_power_force_power_down(ctx->hal->dev, false);
|
||||
}
|
||||
|
||||
static inline void pmu_hp_system_param_default(pmu_hp_mode_t mode, pmu_hp_system_param_t *param)
|
||||
{
|
||||
param->power = pmu_hp_system_power_param_default(mode);
|
||||
param->clock = pmu_hp_system_clock_param_default(mode);
|
||||
param->digital = pmu_hp_system_digital_param_default(mode);
|
||||
param->analog = pmu_hp_system_analog_param_default(mode);
|
||||
param->retent = pmu_hp_system_retention_param_default(mode);
|
||||
}
|
||||
|
||||
static void pmu_hp_system_init_default(pmu_context_t *ctx)
|
||||
{
|
||||
assert(ctx);
|
||||
pmu_hp_system_param_t param = { 0 };
|
||||
for (pmu_hp_mode_t mode = PMU_MODE_HP_ACTIVE; mode < PMU_MODE_HP_MAX; mode++) {
|
||||
pmu_hp_system_param_default(mode, ¶m);
|
||||
pmu_hp_system_init(ctx, mode, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pmu_lp_system_param_default(pmu_lp_mode_t mode, pmu_lp_system_param_t *param)
|
||||
{
|
||||
param->power = pmu_lp_system_power_param_default(mode);
|
||||
param->analog = pmu_lp_system_analog_param_default(mode);
|
||||
}
|
||||
|
||||
static void pmu_lp_system_init_default(pmu_context_t *ctx)
|
||||
{
|
||||
assert(ctx);
|
||||
pmu_lp_system_param_t param;
|
||||
for (pmu_lp_mode_t mode = PMU_MODE_LP_ACTIVE; mode < PMU_MODE_LP_MAX; mode++) {
|
||||
pmu_lp_system_param_default(mode, ¶m);
|
||||
pmu_lp_system_init(ctx, mode, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
void pmu_init()
|
||||
{
|
||||
/* No peripheral reg i2c power up required on the target */
|
||||
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_EN_I2C_RTC_DREG, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_EN_I2C_DIG_DREG, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_EN_I2C_RTC_DREG_SLP, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_EN_I2C_DIG_DREG_SLP, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_OR_XPD_RTC_REG, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_OR_XPD_DIG_REG, 0);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_OR_XPD_TRX, 0);
|
||||
|
||||
WRITE_PERI_REG(PMU_POWER_PD_TOP_CNTL_REG, 0);
|
||||
WRITE_PERI_REG(PMU_POWER_PD_HPAON_CNTL_REG, 0);
|
||||
WRITE_PERI_REG(PMU_POWER_PD_HPCPU_CNTL_REG, 0);
|
||||
WRITE_PERI_REG(PMU_POWER_PD_HPPERI_RESERVE_REG, 0);
|
||||
WRITE_PERI_REG(PMU_POWER_PD_HPWIFI_CNTL_REG, 0);
|
||||
WRITE_PERI_REG(PMU_POWER_PD_LPPERI_CNTL_REG, 0);
|
||||
|
||||
pmu_hp_system_init_default(PMU_instance());
|
||||
pmu_lp_system_init_default(PMU_instance());
|
||||
|
||||
pmu_power_domain_force_default(PMU_instance());
|
||||
|
||||
REG_SET_FIELD(PMU_SLP_WAKEUP_CNTL5_REG, PMU_LP_ANA_WAIT_TARGET, 15); // wait lp ldo stable when wakeup from sleep, need about 100us (slow clk)
|
||||
REG_SET_FIELD(PMU_SLP_WAKEUP_CNTL7_REG, PMU_ANA_WAIT_TARGET, 1700); // wait hp ldo stable when wakeup from sleep, need about 100us (fast clk)
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_types.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
#include "pmu_param.h"
|
||||
#include "soc/pmu_icg_mapping.h"
|
||||
#include "esp_private/esp_pmu.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
//TODO: IDF-6254
|
||||
#define PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT() { \
|
||||
.dig_power = { \
|
||||
.vdd_spi_pd_en = 0, \
|
||||
.mem_dslp = 0, \
|
||||
.mem_pd_en = 0, \
|
||||
.wifi_pd_en = 0, \
|
||||
.cpu_pd_en = 0, \
|
||||
.aon_pd_en = 0, \
|
||||
.top_pd_en = 0 \
|
||||
}, \
|
||||
.clk_power = { \
|
||||
.i2c_iso_en = 0, \
|
||||
.i2c_retention = 0, \
|
||||
.xpd_bb_i2c = 1, \
|
||||
.xpd_bbpll_i2c = 1, \
|
||||
.xpd_bbpll = 1 \
|
||||
}, \
|
||||
.xtal = { \
|
||||
.xpd_xtal = 1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_MODEM_POWER_CONFIG_DEFAULT() { \
|
||||
.dig_power = { \
|
||||
.vdd_spi_pd_en = 0, \
|
||||
.mem_dslp = 1, \
|
||||
.mem_pd_en = 0, \
|
||||
.wifi_pd_en = 0, \
|
||||
.cpu_pd_en = 1, \
|
||||
.aon_pd_en = 0, \
|
||||
.top_pd_en = 0 \
|
||||
}, \
|
||||
.clk_power = { \
|
||||
.i2c_iso_en = 0, \
|
||||
.i2c_retention = 0, \
|
||||
.xpd_bb_i2c = 1, \
|
||||
.xpd_bbpll_i2c = 1, \
|
||||
.xpd_bbpll = 1 \
|
||||
}, \
|
||||
.xtal = { \
|
||||
.xpd_xtal = 1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_SLEEP_POWER_CONFIG_DEFAULT() { \
|
||||
.dig_power = { \
|
||||
.vdd_spi_pd_en = 1, \
|
||||
.mem_dslp = 0, \
|
||||
.mem_pd_en = 0, \
|
||||
.wifi_pd_en = 1, \
|
||||
.cpu_pd_en = 1, \
|
||||
.aon_pd_en = 0, \
|
||||
.top_pd_en = 1 \
|
||||
}, \
|
||||
.clk_power = { \
|
||||
.i2c_iso_en = 1, \
|
||||
.i2c_retention = 0, \
|
||||
.xpd_bb_i2c = 0, \
|
||||
.xpd_bbpll_i2c = 0, \
|
||||
.xpd_bbpll = 0, \
|
||||
}, \
|
||||
.xtal = { \
|
||||
.xpd_xtal = 0 \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_hp_system_power_param_t * pmu_hp_system_power_param_default(pmu_hp_mode_t mode)
|
||||
{
|
||||
static const pmu_hp_system_power_param_t hp_power[] = {
|
||||
PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT(),
|
||||
PMU_HP_MODEM_POWER_CONFIG_DEFAULT(),
|
||||
PMU_HP_SLEEP_POWER_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(hp_power));
|
||||
return &hp_power[mode];
|
||||
}
|
||||
|
||||
#define PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT() { \
|
||||
.icg_func = 0xffffffff, \
|
||||
.icg_apb = 0xffffffff, \
|
||||
.icg_modem = { \
|
||||
.code = 0 \
|
||||
}, \
|
||||
.sysclk = { \
|
||||
.dig_sysclk_nodiv = 0, \
|
||||
.icg_sysclk_en = 1, \
|
||||
.sysclk_slp_sel = 0, \
|
||||
.icg_slp_sel = 0, \
|
||||
.dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT() { \
|
||||
.icg_func = 0, \
|
||||
.icg_apb = 0, \
|
||||
.icg_modem = { \
|
||||
.code = 0 \
|
||||
}, \
|
||||
.sysclk = { \
|
||||
.dig_sysclk_nodiv = 0, \
|
||||
.icg_sysclk_en = 1, \
|
||||
.sysclk_slp_sel = 1, \
|
||||
.icg_slp_sel = 1, \
|
||||
.dig_sysclk_sel = PMU_HP_SYSCLK_PLL \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT() { \
|
||||
.icg_func = 0, \
|
||||
.icg_apb = 0, \
|
||||
.icg_modem = { \
|
||||
.code = 2 \
|
||||
}, \
|
||||
.sysclk = { \
|
||||
.dig_sysclk_nodiv = 0, \
|
||||
.icg_sysclk_en = 0, \
|
||||
.sysclk_slp_sel = 1, \
|
||||
.icg_slp_sel = 1, \
|
||||
.dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_hp_system_clock_param_t * pmu_hp_system_clock_param_default(pmu_hp_mode_t mode)
|
||||
{
|
||||
static const pmu_hp_system_clock_param_t hp_clock[] = {
|
||||
PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT(),
|
||||
PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT(),
|
||||
PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(hp_clock));
|
||||
return &hp_clock[mode];
|
||||
}
|
||||
|
||||
#define PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT() { \
|
||||
.syscntl = { \
|
||||
.uart_wakeup_en = 0, \
|
||||
.lp_pad_hold_all = 0, \
|
||||
.hp_pad_hold_all = 0, \
|
||||
.dig_pad_slp_sel = 0, \
|
||||
.dig_pause_wdt = 0, \
|
||||
.dig_cpu_stall = 0 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT() { \
|
||||
.syscntl = { \
|
||||
.uart_wakeup_en = 1, \
|
||||
.lp_pad_hold_all = 0, \
|
||||
.hp_pad_hold_all = 1, \
|
||||
.dig_pad_slp_sel = 1, \
|
||||
.dig_pause_wdt = 1, \
|
||||
.dig_cpu_stall = 1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT() { \
|
||||
.syscntl = { \
|
||||
.uart_wakeup_en = 1, \
|
||||
.lp_pad_hold_all = 1, \
|
||||
.hp_pad_hold_all = 1, \
|
||||
.dig_pad_slp_sel = 0, \
|
||||
.dig_pause_wdt = 1, \
|
||||
.dig_cpu_stall = 1 \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_hp_system_digital_param_t * pmu_hp_system_digital_param_default(pmu_hp_mode_t mode)
|
||||
{
|
||||
static const pmu_hp_system_digital_param_t hp_digital[] = {
|
||||
PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT(),
|
||||
PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT(),
|
||||
PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(hp_digital));
|
||||
return &hp_digital[mode];
|
||||
}
|
||||
|
||||
#define PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \
|
||||
.bias = { \
|
||||
.xpd_trx = 1, \
|
||||
.xpd_bias = 1, \
|
||||
.pd_cur = 0, \
|
||||
.bias_sleep = 0 \
|
||||
}, \
|
||||
.regulator0 = { \
|
||||
.lp_dbias_vol = 0xd, \
|
||||
.hp_dbias_vol = 0x1c,\
|
||||
.dbias_sel = 1, \
|
||||
.dbias_init = 1, \
|
||||
.slp_mem_xpd = 0, \
|
||||
.slp_logic_xpd = 0, \
|
||||
.xpd = 1, \
|
||||
.slp_mem_dbias = 0x5, \
|
||||
.slp_logic_dbias = 0xc, \
|
||||
.dbias = 0xc \
|
||||
}, \
|
||||
.regulator1 = { \
|
||||
.drv_b = 0x1a \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT() { \
|
||||
.bias = { \
|
||||
.xpd_trx = 1, \
|
||||
.xpd_bias = 1, \
|
||||
.pd_cur = 0, \
|
||||
.bias_sleep = 0 \
|
||||
}, \
|
||||
.regulator0 = { \
|
||||
.slp_mem_xpd = 0, \
|
||||
.slp_logic_xpd = 0, \
|
||||
.xpd = 1, \
|
||||
.slp_mem_dbias = 0x5, \
|
||||
.slp_logic_dbias = 0xc, \
|
||||
.dbias = 0xd \
|
||||
}, \
|
||||
.regulator1 = { \
|
||||
.drv_b = 0x1b \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT() { \
|
||||
.bias = { \
|
||||
.xpd_trx = 0, \
|
||||
.xpd_bias = 0, \
|
||||
.pd_cur = 1, \
|
||||
.bias_sleep = 1 \
|
||||
}, \
|
||||
.regulator0 = { \
|
||||
.slp_mem_xpd = 1, \
|
||||
.slp_logic_xpd = 1, \
|
||||
.xpd = 0, \
|
||||
.slp_mem_dbias = 0x1, \
|
||||
.slp_logic_dbias = 0x5, \
|
||||
.dbias = 0 \
|
||||
}, \
|
||||
.regulator1 = { \
|
||||
.drv_b = 0x13 \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_hp_system_analog_param_t * pmu_hp_system_analog_param_default(pmu_hp_mode_t mode)
|
||||
{
|
||||
static const pmu_hp_system_analog_param_t hp_analog[] = {
|
||||
PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT(),
|
||||
PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT(),
|
||||
PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(hp_analog));
|
||||
return &hp_analog[mode];
|
||||
}
|
||||
|
||||
#define PMU_HP_RETENTION_REGDMA_CONFIG(dir, entry) ((((dir)<<2) | (entry & 0x3)) & 0x7)
|
||||
|
||||
#define PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT() { \
|
||||
.retention = { \
|
||||
.hp_sleep2active_backup_modem_clk_code = 3, \
|
||||
.hp_modem2active_backup_modem_clk_code = 1, \
|
||||
.hp_active_retention_mode = 0, \
|
||||
.hp_sleep2active_retention_en = 0, \
|
||||
.hp_modem2active_retention_en = 0, \
|
||||
.hp_sleep2active_backup_clk_sel = 0, \
|
||||
.hp_modem2active_backup_clk_sel = 0, \
|
||||
.hp_sleep2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 0), \
|
||||
.hp_modem2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 2), \
|
||||
.hp_sleep2active_backup_en = 0, \
|
||||
.hp_modem2active_backup_en = 0, \
|
||||
}, \
|
||||
.backup_clk = (BIT(PMU_ICG_FUNC_ENA_REGDMA) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_TG0) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_HPBUS) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_MSPI) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_IOMUX) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SPI2) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SEC) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_PWM) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_UART0)), \
|
||||
}
|
||||
|
||||
#define PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT() { \
|
||||
.retention = { \
|
||||
.hp_sleep2modem_backup_modem_clk_code = 3, \
|
||||
.hp_modem_retention_mode = 0, \
|
||||
.hp_sleep2modem_retention_en = 0, \
|
||||
.hp_sleep2modem_backup_clk_sel = 0, \
|
||||
.hp_sleep2modem_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 1), \
|
||||
.hp_sleep2modem_backup_en = 0, \
|
||||
}, \
|
||||
.backup_clk = (BIT(PMU_ICG_FUNC_ENA_REGDMA) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_TG0) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_HPBUS) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_MSPI) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_IOMUX) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SPI2) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SEC) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_PWM) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_UART0)), \
|
||||
}
|
||||
|
||||
#define PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT() { \
|
||||
.retention = { \
|
||||
.hp_modem2sleep_backup_modem_clk_code = 3, \
|
||||
.hp_active2sleep_backup_modem_clk_code = 3, \
|
||||
.hp_sleep_retention_mode = 0, \
|
||||
.hp_modem2sleep_retention_en = 0, \
|
||||
.hp_active2sleep_retention_en = 0, \
|
||||
.hp_modem2sleep_backup_clk_sel = 0, \
|
||||
.hp_active2sleep_backup_clk_sel = 0, \
|
||||
.hp_modem2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 1), \
|
||||
.hp_active2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 0), \
|
||||
.hp_modem2sleep_backup_en = 0, \
|
||||
.hp_active2sleep_backup_en = 0, \
|
||||
}, \
|
||||
.backup_clk = (BIT(PMU_ICG_FUNC_ENA_REGDMA) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_TG0) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_HPBUS) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_MSPI) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_IOMUX) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SPI2) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SEC) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_PWM) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
|
||||
| BIT(PMU_ICG_FUNC_ENA_UART0)), \
|
||||
}
|
||||
|
||||
const pmu_hp_system_retention_param_t * pmu_hp_system_retention_param_default(pmu_hp_mode_t mode)
|
||||
{
|
||||
static const pmu_hp_system_retention_param_t hp_retention[] = {
|
||||
PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT(),
|
||||
PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT(),
|
||||
PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(hp_retention));
|
||||
return &hp_retention[mode];
|
||||
}
|
||||
|
||||
|
||||
/** LP system default parameter */
|
||||
|
||||
#define PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT() { \
|
||||
.dig_power = { \
|
||||
.mem_dslp = 0, \
|
||||
.peri_pd_en = 0, \
|
||||
}, \
|
||||
.clk_power = { \
|
||||
.xpd_xtal32k = 0, \
|
||||
.xpd_rc32k = 0, \
|
||||
.xpd_fosc = 1, \
|
||||
.pd_osc = 0 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() { \
|
||||
.dig_power = { \
|
||||
.mem_dslp = 1, \
|
||||
.peri_pd_en = 0, \
|
||||
}, \
|
||||
.clk_power = { \
|
||||
.xpd_xtal32k = 0, \
|
||||
.xpd_rc32k = 0, \
|
||||
.xpd_fosc = 0, \
|
||||
.pd_osc = 0 \
|
||||
}, \
|
||||
.xtal = { \
|
||||
.xpd_xtal = 0 \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_lp_system_power_param_t * pmu_lp_system_power_param_default(pmu_lp_mode_t mode)
|
||||
{
|
||||
static const pmu_lp_system_power_param_t lp_power[] = {
|
||||
PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT(),
|
||||
PMU_LP_SLEEP_POWER_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(lp_power));
|
||||
return &lp_power[mode];
|
||||
}
|
||||
|
||||
#define PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \
|
||||
.regulator0 = { \
|
||||
.slp_xpd = 0, \
|
||||
.xpd = 1, \
|
||||
.slp_dbias = 0, \
|
||||
.dbias = 0xe \
|
||||
}, \
|
||||
.regulator1 = { \
|
||||
.drv_b = 3 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT() { \
|
||||
.bias = { \
|
||||
.xpd_bias = 0, \
|
||||
.pd_cur = 1, \
|
||||
.bias_sleep = 1, \
|
||||
}, \
|
||||
.regulator0 = { \
|
||||
.slp_xpd = 1, \
|
||||
.xpd = 0, \
|
||||
.slp_dbias = 0xf, \
|
||||
.dbias = 0 \
|
||||
}, \
|
||||
.regulator1 = { \
|
||||
.drv_b = 9 \
|
||||
} \
|
||||
}
|
||||
|
||||
const pmu_lp_system_analog_param_t * pmu_lp_system_analog_param_default(pmu_lp_mode_t mode)
|
||||
{
|
||||
static const pmu_lp_system_analog_param_t lp_analog[] = {
|
||||
PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT(),
|
||||
PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT()
|
||||
};
|
||||
assert(mode < ARRAY_SIZE(lp_analog));
|
||||
return &lp_analog[mode];
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// TODO: IDF-6267
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_types.h>
|
||||
#include "soc/pmu_struct.h"
|
||||
#include "hal/pmu_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pmu_hp_dig_power_reg_t dig_power;
|
||||
pmu_hp_clk_power_reg_t clk_power;
|
||||
pmu_hp_xtal_reg_t xtal;
|
||||
} pmu_hp_system_power_param_t;
|
||||
|
||||
const pmu_hp_system_power_param_t * pmu_hp_system_power_param_default(pmu_hp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
uint32_t icg_func;
|
||||
uint32_t icg_apb;
|
||||
pmu_hp_icg_modem_reg_t icg_modem;
|
||||
pmu_hp_sysclk_reg_t sysclk;
|
||||
} pmu_hp_system_clock_param_t;
|
||||
|
||||
const pmu_hp_system_clock_param_t * pmu_hp_system_clock_param_default(pmu_hp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
pmu_hp_sys_cntl_reg_t syscntl;
|
||||
} pmu_hp_system_digital_param_t;
|
||||
|
||||
const pmu_hp_system_digital_param_t * pmu_hp_system_digital_param_default(pmu_hp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
pmu_hp_bias_reg_t bias;
|
||||
pmu_hp_regulator0_reg_t regulator0;
|
||||
pmu_hp_regulator1_reg_t regulator1;
|
||||
} pmu_hp_system_analog_param_t;
|
||||
|
||||
const pmu_hp_system_analog_param_t * pmu_hp_system_analog_param_default(pmu_hp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
pmu_hp_backup_reg_t retention;
|
||||
uint32_t backup_clk;
|
||||
} pmu_hp_system_retention_param_t;
|
||||
|
||||
const pmu_hp_system_retention_param_t * pmu_hp_system_retention_param_default(pmu_hp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
pmu_lp_dig_power_reg_t dig_power;
|
||||
pmu_lp_clk_power_reg_t clk_power;
|
||||
pmu_lp_xtal_reg_t xtal;
|
||||
} pmu_lp_system_power_param_t;
|
||||
|
||||
const pmu_lp_system_power_param_t * pmu_lp_system_power_param_default(pmu_lp_mode_t mode);
|
||||
|
||||
typedef struct {
|
||||
pmu_lp_bias_reg_t bias;
|
||||
pmu_lp_regulator0_reg_t regulator0;
|
||||
pmu_lp_regulator1_reg_t regulator1;
|
||||
} pmu_lp_system_analog_param_t;
|
||||
|
||||
const pmu_lp_system_analog_param_t * pmu_lp_system_analog_param_default(pmu_lp_mode_t mode);
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
pmu_hp_power_t dig_power;
|
||||
pmu_hp_power_t clk_power;
|
||||
pmu_hp_power_t xtal;
|
||||
} hp_sys;
|
||||
struct {
|
||||
pmu_lp_power_t dig_power;
|
||||
pmu_lp_power_t clk_power;
|
||||
pmu_lp_power_t xtal;
|
||||
} lp_sys[PMU_MODE_LP_MAX];
|
||||
} pmu_sleep_power_config_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
pmu_hp_analog_t analog;
|
||||
} hp_sys;
|
||||
struct {
|
||||
pmu_lp_analog_t analog;
|
||||
} lp_sys[PMU_MODE_LP_MAX];
|
||||
} pmu_sleep_analog_config_t;
|
||||
|
||||
typedef struct {
|
||||
pmu_hp_param_t hp_sys;
|
||||
pmu_lp_param_t lp_sys;
|
||||
pmu_hp_lp_param_t hp_lp;
|
||||
} pmu_sleep_param_config_t;
|
||||
|
||||
typedef struct {
|
||||
pmu_sleep_power_config_t power;
|
||||
pmu_sleep_analog_config_t analog;
|
||||
pmu_sleep_param_config_t param;
|
||||
} pmu_sleep_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -18,20 +18,102 @@
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "soc/lp_clkrst_reg.h"
|
||||
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/lp_aon_reg.h"
|
||||
|
||||
static const char *TAG = "rtc_clk";
|
||||
|
||||
// Current PLL frequency, in 96MHz. Zero if PLL is not enabled.
|
||||
static int s_cur_pll_freq;
|
||||
|
||||
static bool rtc_clk_set_bbpll_always_on(void);
|
||||
|
||||
void rtc_clk_32k_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
|
||||
} else {
|
||||
clk_ll_xtal32k_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_32k_enable_external(void)
|
||||
{
|
||||
// EXT_OSC_SLOW_GPIO_NUM == GPIO_NUM_13
|
||||
PIN_INPUT_ENABLE(IO_MUX_GPIO13_REG);
|
||||
REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(EXT_OSC_SLOW_GPIO_NUM));
|
||||
clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
|
||||
}
|
||||
|
||||
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;
|
||||
rtc_clk_32k_enable(true);
|
||||
}
|
||||
|
||||
bool rtc_clk_32k_enabled(void)
|
||||
{
|
||||
return clk_ll_xtal32k_is_enabled();
|
||||
}
|
||||
|
||||
void rtc_clk_rc32k_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
clk_ll_rc32k_enable();
|
||||
esp_rom_delay_us(SOC_DELAY_RC32K_ENABLE);
|
||||
} else {
|
||||
clk_ll_rc32k_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_8m_enable(bool clk_8m_en)
|
||||
{
|
||||
if (clk_8m_en) {
|
||||
clk_ll_rc_fast_enable();
|
||||
esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
|
||||
} else {
|
||||
clk_ll_rc_fast_disable();
|
||||
}
|
||||
}
|
||||
|
||||
bool rtc_clk_8m_enabled(void)
|
||||
{
|
||||
return clk_ll_rc_fast_is_enabled();
|
||||
}
|
||||
|
||||
void rtc_clk_lp_pll_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
clk_ll_lp_pll_enable();
|
||||
esp_rom_delay_us(SOC_DELAY_LP_PLL_ENABLE);
|
||||
} else {
|
||||
clk_ll_lp_pll_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_lp_pll_src_set(soc_lp_pll_clk_src_t clk_src)
|
||||
{
|
||||
clk_ll_lp_pll_set_src(clk_src);
|
||||
esp_rom_delay_us(SOC_DELAY_LP_PLL_SWITCH);
|
||||
}
|
||||
|
||||
void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
|
||||
{
|
||||
clk_ll_rtc_slow_set_src(clk_src);
|
||||
esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
|
||||
}
|
||||
|
||||
soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
|
||||
{
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
return REG_GET_FIELD(LP_CLKRST_LP_CLK_CONF_REG, LP_CLKRST_SLOW_CLK_SEL);
|
||||
return clk_ll_rtc_slow_get_src();
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_slow_freq_get_hz(void)
|
||||
{
|
||||
switch (rtc_clk_slow_freq_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_RC32K: return SOC_CLK_RC32K_FREQ_APPROX;
|
||||
@@ -40,33 +122,295 @@ uint32_t rtc_clk_slow_freq_get_hz(void)
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
|
||||
{
|
||||
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 clk_ll_rtc_fast_get_src();
|
||||
}
|
||||
|
||||
static void rtc_clk_bbpll_disable(void)
|
||||
{
|
||||
clk_ll_bbpll_disable();
|
||||
s_cur_pll_freq = 0;
|
||||
}
|
||||
|
||||
static void rtc_clk_bbpll_enable(void)
|
||||
{
|
||||
clk_ll_bbpll_enable();
|
||||
}
|
||||
|
||||
static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
|
||||
{
|
||||
/* Digital part */
|
||||
clk_ll_bbpll_set_freq_mhz(pll_freq);
|
||||
/* Analog part */
|
||||
/* BBPLL CALIBRATION START */
|
||||
regi2c_ctrl_ll_bbpll_calibration_start();
|
||||
clk_ll_bbpll_set_config(pll_freq, xtal_freq);
|
||||
/* WAIT CALIBRATION DONE */
|
||||
while(!regi2c_ctrl_ll_bbpll_calibration_is_done());
|
||||
/* BBPLL CALIBRATION STOP */
|
||||
regi2c_ctrl_ll_bbpll_calibration_stop();
|
||||
|
||||
s_cur_pll_freq = pll_freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to XTAL frequency. Does not disable the PLL.
|
||||
*/
|
||||
static void rtc_clk_cpu_freq_to_xtal(int freq, int div)
|
||||
{
|
||||
// let f_cpu = f_ahb
|
||||
clk_ll_cpu_set_divider(div);
|
||||
clk_ll_ahb_set_divider(div);
|
||||
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
|
||||
clk_ll_bus_update();
|
||||
ets_update_cpu_frequency(freq);
|
||||
}
|
||||
|
||||
static void rtc_clk_cpu_freq_to_8m(void)
|
||||
{
|
||||
// let f_cpu = f_ahb
|
||||
clk_ll_cpu_set_divider(1);
|
||||
clk_ll_ahb_set_divider(1);
|
||||
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
|
||||
clk_ll_bus_update();
|
||||
ets_update_cpu_frequency(8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
|
||||
* PLL must already be enabled.
|
||||
* @param cpu_freq new CPU frequency
|
||||
*/
|
||||
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
|
||||
{
|
||||
// f_hp_root = 96MHz
|
||||
uint32_t cpu_divider = CLK_LL_PLL_96M_FREQ_MHZ / cpu_freq_mhz;
|
||||
clk_ll_cpu_set_divider(cpu_divider);
|
||||
// Constraint: f_ahb <= 32MHz; f_cpu = N * f_ahb (N = 1, 2, 3...)
|
||||
uint32_t ahb_divider = (cpu_divider == 1) ? 3 :
|
||||
(cpu_divider == 2) ? 4 : cpu_divider;
|
||||
clk_ll_ahb_set_divider(ahb_divider);
|
||||
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
|
||||
clk_ll_bus_update();
|
||||
ets_update_cpu_frequency(cpu_freq_mhz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to FLASH_PLL as cpu clock source.
|
||||
* On ESP32H2, FLASH_PLL frequency is 64MHz.
|
||||
* PLL must alreay be enabled.
|
||||
*/
|
||||
static void rtc_clk_cpu_freq_to_flash_pll(uint32_t cpu_freq_mhz, uint32_t cpu_divider)
|
||||
{
|
||||
// f_hp_root = 64MHz
|
||||
clk_ll_cpu_set_divider(cpu_divider);
|
||||
// Constraint: f_ahb <= 32MHz; f_cpu = N * f_ahb (N = 1, 2, 3...)
|
||||
uint32_t ahb_divider = (cpu_divider == 1) ? 2 : cpu_divider;
|
||||
clk_ll_ahb_set_divider(ahb_divider);
|
||||
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_FLASH_PLL);
|
||||
clk_ll_bus_update();
|
||||
ets_update_cpu_frequency(cpu_freq_mhz);
|
||||
}
|
||||
|
||||
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
|
||||
{
|
||||
uint32_t source_freq_mhz;
|
||||
soc_cpu_clk_src_t source;
|
||||
uint32_t divider; // divider = freq of SOC_ROOT_CLK / freq of CPU_CLK
|
||||
uint32_t real_freq_mhz;
|
||||
|
||||
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 */
|
||||
if (real_freq_mhz != freq_mhz) {
|
||||
// no suitable divider
|
||||
return false;
|
||||
}
|
||||
|
||||
source_freq_mhz = xtal_freq;
|
||||
source = SOC_CPU_CLK_SRC_XTAL;
|
||||
} else if (freq_mhz == 96) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = SOC_CPU_CLK_SRC_PLL;
|
||||
source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
|
||||
divider = 1;
|
||||
} else if (freq_mhz == 64) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = SOC_CPU_CLK_SRC_FLASH_PLL;
|
||||
source_freq_mhz = CLK_LL_PLL_64M_FREQ_MHZ;
|
||||
divider = 1;
|
||||
} else if (freq_mhz == 48) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = SOC_CPU_CLK_SRC_PLL;
|
||||
source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
|
||||
divider = 2;
|
||||
} else {
|
||||
// unsupported frequency
|
||||
return false;
|
||||
}
|
||||
*out_config = (rtc_cpu_freq_config_t) {
|
||||
.source = source,
|
||||
.div = divider,
|
||||
.source_freq_mhz = source_freq_mhz,
|
||||
.freq_mhz = real_freq_mhz
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
|
||||
{
|
||||
soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
|
||||
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
|
||||
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
|
||||
if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL || old_cpu_clk_src == SOC_CPU_CLK_SRC_FLASH_PLL) &&
|
||||
!rtc_clk_set_bbpll_always_on()) {
|
||||
rtc_clk_bbpll_disable();
|
||||
}
|
||||
} else if (config->source == SOC_CPU_CLK_SRC_PLL) {
|
||||
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL && old_cpu_clk_src != SOC_CPU_CLK_SRC_FLASH_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 ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL || old_cpu_clk_src == SOC_CPU_CLK_SRC_FLASH_PLL) &&
|
||||
!rtc_clk_set_bbpll_always_on()) {
|
||||
rtc_clk_bbpll_disable();
|
||||
}
|
||||
} else if (config->source == SOC_CPU_CLK_SRC_FLASH_PLL) {
|
||||
if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL && old_cpu_clk_src != SOC_CPU_CLK_SRC_FLASH_PLL) {
|
||||
// On ESP32H2, FLASH_PLL (64MHz) is directly derived from the BBPLL (96MHz)
|
||||
// Therefore, enabling and configuration are applied to BBPLL.
|
||||
rtc_clk_bbpll_enable();
|
||||
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_96M_FREQ_MHZ);
|
||||
}
|
||||
rtc_clk_cpu_freq_to_flash_pll(config->freq_mhz, config->div);
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
|
||||
{
|
||||
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
|
||||
uint32_t source_freq_mhz;
|
||||
uint32_t div = clk_ll_cpu_get_divider(); // div = freq of SOC_ROOT_CLK / freq of CPU_CLK
|
||||
uint32_t freq_mhz;
|
||||
switch (source) {
|
||||
case SOC_CPU_CLK_SRC_XTAL: {
|
||||
source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
|
||||
freq_mhz = source_freq_mhz / div;
|
||||
break;
|
||||
}
|
||||
case SOC_CPU_CLK_SRC_PLL: {
|
||||
source_freq_mhz = clk_ll_bbpll_get_freq_mhz();
|
||||
freq_mhz = source_freq_mhz / div;
|
||||
break;
|
||||
}
|
||||
case SOC_CPU_CLK_SRC_RC_FAST:
|
||||
source_freq_mhz = 8;
|
||||
freq_mhz = source_freq_mhz / div;
|
||||
break;
|
||||
case SOC_CPU_CLK_SRC_FLASH_PLL:
|
||||
source_freq_mhz = clk_ll_flash_pll_get_freq_mhz();
|
||||
freq_mhz = source_freq_mhz / div;
|
||||
break;
|
||||
default:
|
||||
ESP_HW_LOGE(TAG, "unsupported frequency configuration");
|
||||
abort();
|
||||
}
|
||||
*out_config = (rtc_cpu_freq_config_t) {
|
||||
.source = source,
|
||||
.source_freq_mhz = source_freq_mhz,
|
||||
.div = div,
|
||||
.freq_mhz = freq_mhz
|
||||
};
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
|
||||
{
|
||||
if (config->source == SOC_CPU_CLK_SRC_XTAL) {
|
||||
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
|
||||
} else if (config->source == SOC_CPU_CLK_SRC_PLL &&
|
||||
s_cur_pll_freq == config->source_freq_mhz) {
|
||||
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
|
||||
} else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
|
||||
rtc_clk_cpu_freq_to_8m();
|
||||
} else if (config->source == SOC_CPU_CLK_SRC_FLASH_PLL &&
|
||||
s_cur_pll_freq == clk_ll_bbpll_get_freq_mhz()) {
|
||||
// On ESP32H2, FLASH_PLL (64MHz) is directly derived from the BBPLL (96MHz)
|
||||
// Therefore, as long as bbpll was not disabled, no need to re-enable and re-configure parameters for the source clock
|
||||
rtc_clk_cpu_freq_to_flash_pll(config->freq_mhz, config->div);
|
||||
} else {
|
||||
/* fallback */
|
||||
rtc_clk_cpu_freq_set_config(config);
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_xtal(void)
|
||||
{
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
int freq_mhz = (int)rtc_clk_xtal_freq_get();
|
||||
|
||||
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
|
||||
// TODO: IDF-6243 MSPI clock source could also depend on bbpll, cpu restart should not disable bbpll
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
|
||||
{
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_xtal_freq_get() has not benn implemented yet");
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
return 32;
|
||||
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 (rtc_xtal_freq_t)xtal_freq_mhz;
|
||||
}
|
||||
|
||||
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
|
||||
{
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
clk_ll_xtal_store_freq_mhz(xtal_freq);
|
||||
}
|
||||
|
||||
void rtc_clk_apb_freq_update(uint32_t apb_freq)
|
||||
static uint32_t rtc_clk_ahb_freq_get(void)
|
||||
{
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
|
||||
uint32_t soc_root_freq_mhz;
|
||||
uint32_t divider = clk_ll_ahb_get_divider();
|
||||
switch (source) {
|
||||
case SOC_CPU_CLK_SRC_XTAL:
|
||||
soc_root_freq_mhz = rtc_clk_xtal_freq_get();
|
||||
break;
|
||||
case SOC_CPU_CLK_SRC_PLL:
|
||||
soc_root_freq_mhz = clk_ll_bbpll_get_freq_mhz();
|
||||
break;
|
||||
case SOC_CPU_CLK_SRC_RC_FAST:
|
||||
soc_root_freq_mhz = 8;
|
||||
break;
|
||||
case SOC_CPU_CLK_SRC_FLASH_PLL:
|
||||
soc_root_freq_mhz = clk_ll_flash_pll_get_freq_mhz();
|
||||
break;
|
||||
default:
|
||||
// Unknown SOC_ROOT clock source
|
||||
soc_root_freq_mhz = 0;
|
||||
ESP_HW_LOGE(TAG, "Invalid SOC_ROOT_CLK");
|
||||
break;
|
||||
}
|
||||
return soc_root_freq_mhz / divider;
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_apb_freq_get(void)
|
||||
{
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_apb_freq_get() has not benn implemented yet");
|
||||
// ESP32H2-TODO: IDF-6254
|
||||
return 0;
|
||||
return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ;
|
||||
}
|
||||
|
||||
void rtc_dig_clk8m_enable(void)
|
||||
@@ -80,3 +424,23 @@ void rtc_dig_clk8m_disable(void)
|
||||
clk_ll_rc_fast_digi_disable();
|
||||
esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
|
||||
}
|
||||
|
||||
bool rtc_dig_8m_enabled(void)
|
||||
{
|
||||
return clk_ll_rc_fast_digi_is_enabled();
|
||||
}
|
||||
|
||||
static bool rtc_clk_set_bbpll_always_on(void)
|
||||
{
|
||||
/* We just keep the rtc bbpll clock on just under the case that
|
||||
user selects the `RTC_CLOCK_BBPLL_POWER_ON_WITH_USB` as well as
|
||||
the USB_SERIAL_JTAG is connected with PC.
|
||||
*/
|
||||
bool is_bbpll_on = false;
|
||||
#if CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB
|
||||
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
|
||||
is_bbpll_on = true;
|
||||
}
|
||||
#endif
|
||||
return is_bbpll_on;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -12,10 +12,11 @@
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#include "esp32h2/rom/uart.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "esp_hw_log.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "soc/lp_clkrst_reg.h"
|
||||
#include "soc/regi2c_pmu.h"
|
||||
#include "esp_hw_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_uart.h"
|
||||
|
||||
@@ -23,36 +24,24 @@ static const char *TAG = "rtc_clk_init";
|
||||
|
||||
void rtc_clk_init(rtc_clk_config_t cfg)
|
||||
{
|
||||
ESP_HW_LOGW(TAG, "rtc_clk_init() has not been implemented yet");
|
||||
#if 0 // ESP32H2-TODO
|
||||
rtc_cpu_freq_config_t old_config, new_config;
|
||||
|
||||
/* Set tuning parameters for 8M and 150k clocks.
|
||||
/* Set tuning parameters for RC_FAST, RC_SLOW, and RC32K clocks.
|
||||
* Note: this doesn't attempt to set the clocks to precise frequencies.
|
||||
* Instead, we calibrate these clocks against XTAL frequency later, when necessary.
|
||||
* - SCK_DCAP value controls tuning of 150k clock.
|
||||
* - SCK_DCAP value controls tuning of RC_SLOW clock.
|
||||
* The higher the value of DCAP is, the lower is the frequency.
|
||||
* - CK8M_DFREQ value controls tuning of 8M clock.
|
||||
* - CK8M_DFREQ value controls tuning of RC_FAST clock.
|
||||
* CLK_8M_DFREQ constant gives the best temperature characteristics.
|
||||
* - RC32K_DFREQ value controls tuning of RC32K clock.
|
||||
*/
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap);
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq);
|
||||
|
||||
/* Configure 150k clock division */
|
||||
rtc_clk_divider_set(cfg.clk_rtc_clk_div);
|
||||
|
||||
/* 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 BBPLL */
|
||||
regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config
|
||||
REG_SET_FIELD(LP_CLKRST_FOSC_CNTL_REG, LP_CLKRST_FOSC_DFREQ, cfg.clk_8m_dfreq);
|
||||
REGI2C_WRITE_MASK(I2C_PMU, I2C_PMU_OC_SCK_DCAP, cfg.slow_clk_dcap);
|
||||
REG_SET_FIELD(LP_CLKRST_RC32K_CNTL_REG, LP_CLKRST_RC32K_DFREQ, cfg.rc32k_dfreq);
|
||||
|
||||
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
|
||||
esp_rom_uart_tx_wait_idle(0);
|
||||
rtc_clk_xtal_freq_update(xtal_freq);
|
||||
rtc_clk_apb_freq_update(xtal_freq * MHZ);
|
||||
|
||||
/* Set CPU frequency */
|
||||
rtc_clk_cpu_freq_get_config(&old_config);
|
||||
@@ -71,14 +60,14 @@ void rtc_clk_init(rtc_clk_config_t cfg)
|
||||
// We will not power off RC_FAST in bootloader stage even if it is not being used as any
|
||||
// cpu / rtc_fast / rtc_slow clock sources, this is because RNG always needs it in the bootloader stage.
|
||||
bool need_rc_fast_en = true;
|
||||
bool need_rc_fast_d256_en = false;
|
||||
if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
|
||||
rtc_clk_32k_enable(true);
|
||||
} else if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
|
||||
need_rc_fast_d256_en = true;
|
||||
} else if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
|
||||
rtc_clk_32k_enable_external();
|
||||
} else if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) {
|
||||
rtc_clk_rc32k_enable(true);
|
||||
}
|
||||
rtc_clk_8m_enable(need_rc_fast_en, need_rc_fast_d256_en);
|
||||
rtc_clk_8m_enable(need_rc_fast_en);
|
||||
rtc_clk_fast_src_set(cfg.fast_clk_src);
|
||||
rtc_clk_slow_src_set(cfg.slow_clk_src);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -7,9 +7,13 @@
|
||||
#include <stdint.h>
|
||||
#include "esp32h2/rom/ets_sys.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/lp_timer_reg.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "assert.h"
|
||||
|
||||
static const char *TAG = "rtc_time";
|
||||
|
||||
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
|
||||
* This feature counts the number of XTAL clock cycles within a given number of
|
||||
@@ -23,80 +27,216 @@
|
||||
* enabled using TIMG_RTC_CALI_START bit.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
|
||||
* @param cal_clk which clock to calibrate
|
||||
* @param slowclk_cycles number of slow clock cycles to count
|
||||
* @return number of XTAL clock cycles within the given number of slow clock cycles
|
||||
/* On ESP32H2, TIMG_RTC_CALI_CLK_SEL can config to 0, 1, 2, 3
|
||||
* 0 or 3: calibrate RC_SLOW clock
|
||||
* 1: calibrate RC_FAST clock
|
||||
* 2: calibrate 32K clock, which 32k depends on reg_32k_sel: 0: Internal 32 kHz RC oscillator, 1: External 32 kHz XTAL, 2: External 32kHz clock input by gpio13
|
||||
*/
|
||||
// ESP32H2-TODO
|
||||
static const char *TAG = "rtc_time";
|
||||
#define TIMG_RTC_CALI_CLK_SEL_RC_SLOW 0
|
||||
#define TIMG_RTC_CALI_CLK_SEL_RC_FAST 1
|
||||
#define TIMG_RTC_CALI_CLK_SEL_32K 2
|
||||
|
||||
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_cal_internal() has not been implemented yet");
|
||||
return 0;
|
||||
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
|
||||
|
||||
uint32_t cali_clk_sel = 0;
|
||||
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
|
||||
soc_rtc_slow_clk_src_t old_32k_cal_clk_sel = clk_ll_32k_calibration_get_target();
|
||||
if (cal_clk == RTC_CAL_RTC_MUX) {
|
||||
cal_clk = (rtc_cal_sel_t)slow_clk_src;
|
||||
}
|
||||
if (cal_clk == RTC_CAL_RC_FAST) {
|
||||
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
|
||||
} else if (cal_clk == RTC_CAL_RC_SLOW) {
|
||||
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
|
||||
} else {
|
||||
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K;
|
||||
clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk);
|
||||
}
|
||||
|
||||
|
||||
/* Enable requested clock (150k clock is always on) */
|
||||
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
|
||||
// Only enable if orignally was disabled, and set back to the disable state after calibration is done
|
||||
// If the clock is already on, then do nothing
|
||||
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 rc_fast_enabled = clk_ll_rc_fast_is_enabled();
|
||||
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
|
||||
if (cal_clk == RTC_CAL_RC_FAST) {
|
||||
if (!rc_fast_enabled) {
|
||||
rtc_clk_8m_enable(true);
|
||||
}
|
||||
if (!dig_rc_fast_enabled) {
|
||||
rtc_dig_clk8m_enable();
|
||||
}
|
||||
}
|
||||
|
||||
bool rc32k_enabled = clk_ll_rc32k_is_enabled();
|
||||
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
|
||||
if (cal_clk == RTC_CAL_RC32K) {
|
||||
if (!rc32k_enabled) {
|
||||
rtc_clk_rc32k_enable(true);
|
||||
}
|
||||
if (!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.
|
||||
*/
|
||||
if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING)) {
|
||||
/**
|
||||
* Set a small timeout threshold to accelerate the generation of timeout.
|
||||
* The internal circuit will be reset when the timeout occurs and will not affect the next calibration.
|
||||
*/
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, 1);
|
||||
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)
|
||||
&& !GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT));
|
||||
}
|
||||
|
||||
/* Prepare calibration */
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cali_clk_sel);
|
||||
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
|
||||
/* Figure out how long to wait for calibration to finish */
|
||||
|
||||
/* Set timeout reg and expect time delay*/
|
||||
uint32_t expected_freq;
|
||||
if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_32K) {
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
|
||||
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
|
||||
} else if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_8M_CAL_TIMEOUT_THRES(slowclk_cycles));
|
||||
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
|
||||
} else {
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_150K_CAL_TIMEOUT_THRES(slowclk_cycles));
|
||||
expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX;
|
||||
}
|
||||
uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq);
|
||||
/* Start calibration */
|
||||
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
|
||||
/* Wait for calibration to finish up to another us_time_estimate */
|
||||
esp_rom_delay_us(us_time_estimate);
|
||||
uint32_t cal_val;
|
||||
while (true) {
|
||||
if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
|
||||
cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
|
||||
break;
|
||||
}
|
||||
if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) {
|
||||
cal_val = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
|
||||
/* 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_RC_FAST) {
|
||||
if (!dig_rc_fast_enabled) {
|
||||
rtc_dig_clk8m_disable();
|
||||
}
|
||||
if (!rc_fast_enabled) {
|
||||
rtc_clk_8m_enable(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (cal_clk == RTC_CAL_RC32K) {
|
||||
if (!dig_rc32k_enabled) {
|
||||
clk_ll_rc32k_digi_disable();
|
||||
}
|
||||
if (!rc32k_enabled) {
|
||||
rtc_clk_rc32k_enable(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Always set back the calibration 32kHz clock selection
|
||||
if (old_32k_cal_clk_sel != SOC_RTC_SLOW_CLK_SRC_INVALID) {
|
||||
clk_ll_32k_calibration_set_target(old_32k_cal_clk_sel);
|
||||
}
|
||||
|
||||
return cal_val;
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
static bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_cal_ratio() has not been implemented yet");
|
||||
return 0;
|
||||
uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768
|
||||
uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 = 0.05% error range
|
||||
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_cal() has not been implemented yet");
|
||||
return 0;
|
||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
|
||||
|
||||
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid(xtal_freq, slowclk_cycles, xtal_cycles)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
|
||||
uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
|
||||
uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
|
||||
return period;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_us_to_slowclk(uint64_t time_in_us, uint32_t period)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_time_us_to_slowclk() has not been implemented yet");
|
||||
return 0;
|
||||
/* Overflow will happen in this function if time_in_us >= 2^45, which is about 400 days.
|
||||
* TODO: fix overflow.
|
||||
*/
|
||||
return (time_in_us << RTC_CLK_CAL_FRACT) / period;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_time_slowclk_to_us() has not been implemented yet");
|
||||
return 0;
|
||||
return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_get(void)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_time_get() has not been implemented yet");
|
||||
return 0;
|
||||
SET_PERI_REG_MASK(LP_TIMER_UPDATE_REG, LP_TIMER_MAIN_TIMER_UPDATE);
|
||||
uint64_t t = READ_PERI_REG(LP_TIMER_MAIN_BUF0_LOW_REG);
|
||||
t |= ((uint64_t) READ_PERI_REG(LP_TIMER_MAIN_BUF0_HIGH_REG)) << 32;
|
||||
return t;
|
||||
}
|
||||
|
||||
uint64_t rtc_light_slp_time_get(void)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
// TODO: IDF-6267
|
||||
ESP_EARLY_LOGW(TAG, "rtc_light_slp_time_get() has not been implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t rtc_deep_slp_time_get(void)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_deep_slp_time_get() has not been implemented yet");
|
||||
return 0;
|
||||
uint64_t t_slp = READ_PERI_REG(LP_TIMER_MAIN_BUF1_LOW_REG);
|
||||
t_slp |= ((uint64_t) READ_PERI_REG(LP_TIMER_MAIN_BUF1_HIGH_REG)) << 32;
|
||||
uint64_t t_wake = rtc_time_get();
|
||||
return (t_wake - t_slp);
|
||||
}
|
||||
|
||||
void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any more
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
// TODO: IDF-6254
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_wait_for_slow_cycle() has not been implemented yet");
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_freq_cal(uint32_t cal_val)
|
||||
{
|
||||
// ESP32H2-TODO
|
||||
ESP_EARLY_LOGW(TAG, "rtc_clk_freq_cal() has not been implemented yet");
|
||||
return 0;
|
||||
if (cal_val == 0) {
|
||||
return 0; // cal_val will be denominator, return 0 as the symbol of failure.
|
||||
}
|
||||
return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user