diff --git a/components/esp_hw_support/port/esp32s31/CMakeLists.txt b/components/esp_hw_support/port/esp32s31/CMakeLists.txt index a532e998522..f2ca9c029a0 100644 --- a/components/esp_hw_support/port/esp32s31/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s31/CMakeLists.txt @@ -15,6 +15,10 @@ if(NOT BOOTLOADER_BUILD) ) endif() +if(NOT BOOTLOADER_BUILD AND CONFIG_ESP_ENABLE_PVT) + list(APPEND srcs "pmu_pvt.c") +endif() + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") diff --git a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c index 422a2c601a4..60e41383b73 100644 --- a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c @@ -384,7 +384,10 @@ void esp_clk_tree_initialize(void) if (cpu_src != SOC_CPU_CLK_SRC_CPLL && flash_clk_src != FLASH_CLK_SRC_CPLL) { clk_ll_cpll_disable(); } +#if !CONFIG_ESP_ENABLE_PVT + // PLL_F160M must always on if PVT is enabled. _clk_gate_ll_ref_160m_clk_en(false); +#endif _clk_gate_ll_ref_120m_clk_en(false); _clk_gate_ll_ref_80m_clk_en(false); _clk_gate_ll_ref_60m_clk_en(false); @@ -531,7 +534,12 @@ FORCE_INLINE_ATTR esp_err_t esp_clk_tree_enable_gated_clk(const esp_clk_tree_gat esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) { - if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID || clk_src == SOC_MOD_CLK_XTAL) { + if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID || clk_src == SOC_MOD_CLK_XTAL +#if CONFIG_ESP_ENABLE_PVT + // PLL_F160M must always on if PVT is enabled. + || clk_src == SOC_MOD_CLK_PLL_F160M +#endif + ) { /* Not managed by esp_clk_tree*/ return ESP_OK; } diff --git a/components/esp_hw_support/port/esp32s31/include/soc/rtc.h b/components/esp_hw_support/port/esp32s31/include/soc/rtc.h index 3dcefc3e484..8be278f8bbe 100644 --- a/components/esp_hw_support/port/esp32s31/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32s31/include/soc/rtc.h @@ -63,6 +63,37 @@ extern "C" { #define RTC_CNTL_SCK_DCAP_DEFAULT 128 #define RTC_CNTL_RC32K_DFREQ_DEFAULT 700 +#if CONFIG_ESP_ENABLE_PVT +/* +set pvt default param +*/ +#define PVT_CHANNEL0_SEL 33 +#define PVT_CHANNEL1_SEL 37 +#define PVT_CHANNEL0_CFG 0x11fff +#define PVT_CHANNEL1_CFG 0x17fff +#define PVT_CHANNEL2_CFG 0x10000 +#define PVT_CMD0 0x24 +#define PVT_CMD1 0x5 +#define PVT_CMD2 0x427 +#define PVT_TARGET 0xffff +#define PVT_CLK_DIV 1 +#define PVT_EDG_MODE 1 +#define PVT_DELAY_NUM_HIGH 151 +#define PVT_DELAY_NUM_LOW 141 +#define PVT_PUMP_CHANNEL_CODE 1 +#define PVT_PUMP_BITMAP 22 +#define PVT_PUMP_DRV 0 +#define PVT_DELAY_NUM_PUMP 134 + +/** + * @brief Enable or disable auto dbias functions + * + * @param enable true to enable, false to disable + */ +void pvt_auto_dbias_enable(bool enable); + +#endif //#if CONFIG_ESP_ENABLE_PVT + /** * @brief CPU clock configuration structure */ diff --git a/components/esp_hw_support/port/esp32s31/pmu_init.c b/components/esp_hw_support/port/esp32s31/pmu_init.c index d4f63ce8f41..f0a90bb8de1 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_init.c +++ b/components/esp_hw_support/port/esp32s31/pmu_init.c @@ -22,6 +22,8 @@ #include "esp_private/esp_pmu.h" #include "esp_hw_log.h" #include "hal/regi2c_ctrl_ll.h" +#include "soc/rtc.h" +#include "hal/efuse_hal.h" ESP_HW_LOG_ATTR_TAG(TAG, "pmu_init"); @@ -239,4 +241,16 @@ void pmu_init(void) pmu_hp_system_init_default(PMU_instance()); pmu_lp_system_init_default(PMU_instance()); pmu_power_domain_force_default(PMU_instance()); + +#if CONFIG_ESP_ENABLE_PVT + /*setup pvt function*/ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 1) { + pvt_auto_dbias_enable(true); + esp_rom_delay_us(1000); + } + else { + ESP_HW_LOGW(TAG, "blk_version is less than 1, pvt function not supported in efuse."); + } +#endif } diff --git a/components/esp_hw_support/port/esp32s31/pmu_pvt.c b/components/esp_hw_support/port/esp32s31/pmu_pvt.c new file mode 100644 index 00000000000..6ee6286e748 --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/pmu_pvt.c @@ -0,0 +1,183 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/pmu_struct.h" +#include "soc/pvt_reg.h" +#include "soc/pmu_reg.h" +#include "hal/pmu_hal.h" +#include "pmu_param.h" +#include "esp_rom_sys.h" +#include "esp_private/esp_pmu.h" +#include "soc/regi2c_dig_reg.h" +#include "regi2c_ctrl.h" +#include "soc/rtc.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_hw_log.h" +#include "soc/hp_sys_clkrst_reg.h" + +static __attribute__((unused)) const char *TAG = "pmu_pvt"; + +#if CONFIG_ESP_ENABLE_PVT +static bool pvt_enable_flag = false; + +static uint8_t get_lp_hp_gap(void) +{ + int8_t lp_hp_gap = 0; + uint32_t blk_version = efuse_hal_blk_version(); + uint8_t lp_hp_gap_efuse = 0; + if (blk_version >= 1) { + lp_hp_gap_efuse = efuse_ll_get_dbias_vol_gap(); + bool gap_flag = lp_hp_gap_efuse >> 4; + uint8_t gap_abs_value = lp_hp_gap_efuse & 0xf; + if (gap_flag) { + lp_hp_gap = -1 * gap_abs_value; + } else { + lp_hp_gap = gap_abs_value; + } + lp_hp_gap = lp_hp_gap - 8; + if (lp_hp_gap < 0) { + if (lp_hp_gap >= -15) { + lp_hp_gap = 16 - lp_hp_gap; + } else { + // pvt offset value only has 4 bit + lp_hp_gap = 31; + } + } + } + return lp_hp_gap; +} + +static void set_pvt_hp_lp_gap(uint8_t value) +{ + bool flag = value >> 4; + uint8_t abs_value = value & 0xf; + + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_FLAG, flag, PVT_DBIAS_CMD0_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD0_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_FLAG, flag, PVT_DBIAS_CMD1_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD1_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_FLAG, flag, PVT_DBIAS_CMD2_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD2_OFFSET_VALUE_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_hp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_lp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_LP_DBIAS_VOL_V, PMU_LP_DBIAS_VOL_S); +} + +FORCE_INLINE_ATTR void pvt_auto_dbias_init(void) +{ + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_SYS_CLK_EN); + /*config for dbias func*/ + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); + esp_rom_delay_us(1); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL0_SEL, PVT_CHANNEL0_SEL, PVT_DBIAS_CHANNEL0_SEL_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL1_SEL, PVT_CHANNEL1_SEL, PVT_DBIAS_CHANNEL1_SEL_S); // Select monitor cell ,which used to monitor PVT situation + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL0_SEL_REG, PVT_DBIAS_CHANNEL0_CFG, PVT_CHANNEL0_CFG, PVT_DBIAS_CHANNEL0_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL1_SEL_REG, PVT_DBIAS_CHANNEL1_CFG, PVT_CHANNEL1_CFG, PVT_DBIAS_CHANNEL1_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL2_SEL_REG, PVT_DBIAS_CHANNEL2_CFG, PVT_CHANNEL2_CFG, PVT_DBIAS_CHANNEL2_CFG_S); // Configure filter threshold for avoiding auto-dbias overly sensitive regulation + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_PVT, PVT_CMD0, PVT_DBIAS_CMD0_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_PVT, PVT_CMD1, PVT_DBIAS_CMD1_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_PVT, PVT_CMD2, PVT_DBIAS_CMD2_PVT_S); // Configure auto-dbias adjust property, such as adjusting step + SET_PERI_REG_BITS(PVT_DBIAS_TIMER_REG, PVT_TIMER_TARGET, PVT_TARGET, PVT_TIMER_TARGET_S); // Configure auto-dbias voltage regulation cycle + + SET_PERI_REG_BITS(HP_SYS_CLKRST_PVT0_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_CLK_DIV_NUM, PVT_CLK_DIV, HP_SYS_CLKRST_REG_PVT0_CLK_DIV_NUM_S);//pvt function clock divider number + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_PERI_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_PERI_GROUP1_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_PERI_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_PERI_GROUP2_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_PERI_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_PERI_GROUP3_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_PERI_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_PERI_GROUP4_CLK_EN); + + /*config for pvt cell: unit0; site2; vt1*/ + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF2_REG, PVT_MONITOR_EDG_MOD_VT1_PD_SITE2_UNIT0, PVT_EDG_MODE, PVT_MONITOR_EDG_MOD_VT1_PD_SITE2_UNIT0_S); // Select edge_mode + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0, PVT_DELAY_NUM_HIGH, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0_S); // The threshold for determining whether the voltage is too high + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT1_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1, PVT_DELAY_NUM_LOW, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1_S); // The threshold for determining whether the voltage is too low + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT2_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2, PVT_DELAY_NUM_PUMP, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2_S); // The threshold for chargepump + + /*config lp offset for pvt func*/ + uint8_t lp_hp_gap = get_lp_hp_gap(); + set_pvt_hp_lp_gap(lp_hp_gap); + +} + +FORCE_INLINE_ATTR void pvt_func_enable(bool enable) +{ + if (enable) { + SET_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_CLK_EN); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // start calibration @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // once enable cannot be closed + SET_PERI_REG_MASK(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_MONITOR_EN_VT1_PD_SITE2_UNIT0); // enable pvt clk + esp_rom_delay_us(10); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pvt + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // must clear @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // enable auto dbias + esp_rom_delay_us(50); + } else { + uint32_t pvt_hp_dbias = get_pvt_hp_dbias(); + uint32_t pvt_lp_dbias = get_pvt_lp_dbias(); // update pvt_cali_dbias + SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, pvt_hp_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S); + SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, pvt_lp_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); //disable auto dbias + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pmu + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_PVT0_CTRL0_REG, HP_SYS_CLKRST_REG_PVT0_CLK_EN); + } +} + +FORCE_INLINE_ATTR void charge_pump_init(void) +{ + /*config for charge pump*/ + SET_PERI_REG_BITS(PVT_PMUP_CHANNEL_CFG_REG, PVT_PUMP_CHANNEL_CODE0, PVT_PUMP_CHANNEL_CODE, PVT_PUMP_CHANNEL_CODE0_S); //Set channel code + WRITE_PERI_REG(PVT_PMUP_BITMAP_LOW0_REG, (1 << PVT_PUMP_BITMAP)); // Select monitor cell for charge pump + SET_PERI_REG_BITS(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_DRV0, PVT_PUMP_DRV, PVT_PUMP_DRV0_S); //Configure the charging intensity +} + +FORCE_INLINE_ATTR void charge_pump_enable(bool enable) +{ + if (enable) { + SET_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); // enable charge pump + } else { + CLEAR_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); //disable charge pump + } +} + +void pvt_auto_dbias_enable(bool enable) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 1) { + if (enable) { + if (pvt_enable_flag == true) { + return; + } + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, true); + pvt_auto_dbias_init(); + charge_pump_init(); + pvt_func_enable(true); + charge_pump_enable(true); + pvt_enable_flag = true; + } else { + if (pvt_enable_flag == false) { + return; + } + charge_pump_enable(false); + pvt_func_enable(false); + esp_clk_tree_enable_src(SOC_MOD_CLK_BBPLL, false); + pvt_enable_flag = false; + } + } +} +#endif diff --git a/components/esp_hw_support/port/esp32s31/pmu_sleep.c b/components/esp_hw_support/port/esp32s31/pmu_sleep.c index 31481ba649c..6b9cd3acea3 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32s31/pmu_sleep.c @@ -304,7 +304,13 @@ static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_con pmu_ll_hp_set_dbg_atten (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbg_atten); pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias); pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b); - +#if CONFIG_ESP_ENABLE_PVT + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 1) { + uint32_t pvt_hp_dbias = GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(MODEM), pvt_hp_dbias); + } +#endif pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur); pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.bias_sleep); pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.xpd); diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk.c b/components/esp_hw_support/port/esp32s31/rtc_clk.c index b057b9c8b95..e826eed4ed2 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk.c @@ -22,6 +22,7 @@ #include "esp_attr.h" #include "esp_private/esp_clk_tree_common.h" #include "hal/clk_gate_ll.h" +#include "esp_private/esp_pmu.h" static const char *TAG = "rtc_clk"; @@ -336,7 +337,7 @@ __attribute__((weak)) void rtc_clk_set_cpu_switch_to_pll(int event_id) { } -static void rtc_clk_update_pll_state_on_cpu_src_switching_start(soc_cpu_clk_src_t new_src, uint32_t new_src_freq_mhz) +static void rtc_clk_update_pll_state_on_cpu_src_switching_start(soc_cpu_clk_src_t old_src, soc_cpu_clk_src_t new_src, uint32_t new_src_freq_mhz) { #ifdef BOOTLOADER_BUILD if (new_src == SOC_CPU_CLK_SRC_CPLL) { @@ -364,12 +365,24 @@ static void rtc_clk_update_pll_state_on_cpu_src_switching_start(soc_cpu_clk_src_ } s_cur_bbpll_freq = CLK_LL_PLL_480M_FREQ_MHZ; } + if (((old_src != SOC_CPU_CLK_SRC_CPLL) && (old_src != SOC_CPU_CLK_SRC_PLL_F240M)) && + ((new_src == SOC_CPU_CLK_SRC_CPLL) || (new_src == SOC_CPU_CLK_SRC_PLL_F240M))) { +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_enable(true); +#endif + } #endif } #ifndef BOOTLOADER_BUILD -static void rtc_clk_update_pll_state_on_cpu_src_switching_end(soc_cpu_clk_src_t old_src) +static void rtc_clk_update_pll_state_on_cpu_src_switching_end(soc_cpu_clk_src_t old_src, soc_cpu_clk_src_t new_src) { + if (((old_src == SOC_CPU_CLK_SRC_CPLL) || (old_src == SOC_CPU_CLK_SRC_PLL_F240M)) && + ((new_src != SOC_CPU_CLK_SRC_CPLL) && (new_src != SOC_CPU_CLK_SRC_PLL_F240M))) { +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_enable(false); +#endif + } if (old_src == SOC_CPU_CLK_SRC_CPLL) { assert(s_is_cpll_acquired); esp_clk_tree_enable_src(SOC_MOD_CLK_CPLL, false); @@ -390,15 +403,15 @@ static void rtc_clk_update_pll_state_on_cpu_src_switching_end(soc_cpu_clk_src_t 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(); #ifdef BOOTLOADER_BUILD // Always trigger clock source preparing in bootloader bool src_changed = true; #else - soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); bool src_changed = (old_cpu_clk_src != config->source); #endif if (src_changed) { - rtc_clk_update_pll_state_on_cpu_src_switching_start(config->source, config->source_freq_mhz); + rtc_clk_update_pll_state_on_cpu_src_switching_start(old_cpu_clk_src, config->source, config->source_freq_mhz); } if (config->source == SOC_CPU_CLK_SRC_XTAL) { @@ -415,7 +428,7 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) #ifndef BOOTLOADER_BUILD if (src_changed) { - rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src, config->source); } #endif } @@ -516,9 +529,7 @@ void rtc_clk_cpu_freq_set_xtal(void) int freq_mhz = (int)rtc_clk_xtal_freq_get(); rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); - if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) { - rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src); - } + rtc_clk_update_pll_state_on_cpu_src_switching_end(old_cpu_clk_src, SOC_CPU_CLK_SRC_XTAL); } FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) @@ -537,6 +548,9 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) rtc_clk_cpu_freq_to_xtal(freq_mhz, 1, false); s_cur_cpll_freq = 0; s_cur_bbpll_freq = 0; +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_enable(false); +#endif } void rtc_clk_apll_enable(bool enable) diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk_init.c b/components/esp_hw_support/port/esp32s31/rtc_clk_init.c index 75ffc533bbb..1363595c707 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk_init.c @@ -70,6 +70,8 @@ void rtc_clk_init(rtc_clk_config_t cfg) // No need to wait UART0 TX idle since its default clock source is XTAL, should not be affected by system clock configuration + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu + /* Disable PLLs to save power, the PLLs will be enabled by the user in application code */ rtc_clk_pll_disable(cfg); diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 1d5322b5879..1568bd73024 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -247,6 +247,7 @@ #elif CONFIG_IDF_TARGET_ESP32S31 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (324) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (780) +#define PVT_REINIT_COST_US (95) #endif // Actually costs 80us, using the fastest slow clock 150K calculation takes about 16 ticks diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 4ba97729ad9..9aa3785b264 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -125,7 +125,7 @@ esp_err_t sleep_pau_retention_init(void) } #endif -#if CONFIG_ESP_ENABLE_PVT +#if CONFIG_ESP_ENABLE_PVT && SOC_PVT_RETENTION_BY_REGDMA esp_err_t sleep_pvt_retention_init(void) { esp_err_t err = sleep_retention_entries_create(pvt_regs_retention, ARRAY_SIZE(pvt_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); diff --git a/components/hal/esp32s31/include/hal/efuse_ll.h b/components/hal/esp32s31/include/hal/efuse_ll.h index df8c426b1da..6ad327f839a 100644 --- a/components/hal/esp32s31/include/hal/efuse_ll.h +++ b/components/hal/esp32s31/include/hal/efuse_ll.h @@ -99,6 +99,11 @@ __attribute__((always_inline)) static inline uint32_t efuse_ll_get_recovery_boot return EFUSE.rd_repeat_data5.recovery_bootloader_flash_sector; } +__attribute__((always_inline)) static inline int32_t efuse_ll_get_dbias_vol_gap(void) +{ + return EFUSE.rd_mac_sys5.lp_hp_dbias_vol_gap; +} + __attribute__((always_inline)) static inline uint32_t efuse_ll_get_coding_error(unsigned index) { switch (index) { diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 2b8912bda55..14ecb0fe44e 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -231,6 +231,10 @@ config SOC_PMU_SUPPORTED bool default y +config SOC_PMU_PVT_SUPPORTED + bool + default y + config SOC_RTC_TIMER_SUPPORTED bool default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index bd3df84588f..2cac9c07699 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -81,6 +81,7 @@ // #define SOC_APM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14620 #define SOC_PAU_SUPPORTED 1 #define SOC_PMU_SUPPORTED 1 +#define SOC_PMU_PVT_SUPPORTED 1 #define SOC_RTC_TIMER_SUPPORTED 1 #define SOC_ULP_LP_UART_SUPPORTED 1 #define SOC_LP_GPIO_MATRIX_SUPPORTED 1 diff --git a/components/soc/esp32s31/register/soc/pvt_reg.h b/components/soc/esp32s31/register/soc/pvt_reg.h index 581deb57730..06512dd376a 100644 --- a/components/soc/esp32s31/register/soc/pvt_reg.h +++ b/components/soc/esp32s31/register/soc/pvt_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -369,10 +369,12 @@ extern "C" { /** PVT_DBIAS_CMD0 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD0 0x0001FFFFU -#define PVT_DBIAS_CMD0_M (PVT_DBIAS_CMD0_V << PVT_DBIAS_CMD0_S) -#define PVT_DBIAS_CMD0_V 0x0001FFFFU -#define PVT_DBIAS_CMD0_S 0 +#define PVT_DBIAS_CMD0_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD0_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD0_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD0_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD0_PVT 0x7FF +#define PVT_DBIAS_CMD0_PVT_S 0 /** PVT_DBIAS_CMD1_REG register * needs desc @@ -381,10 +383,12 @@ extern "C" { /** PVT_DBIAS_CMD1 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD1 0x0001FFFFU -#define PVT_DBIAS_CMD1_M (PVT_DBIAS_CMD1_V << PVT_DBIAS_CMD1_S) -#define PVT_DBIAS_CMD1_V 0x0001FFFFU -#define PVT_DBIAS_CMD1_S 0 +#define PVT_DBIAS_CMD1_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD1_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD1_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD1_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD1_PVT 0x7FF +#define PVT_DBIAS_CMD1_PVT_S 0 /** PVT_DBIAS_CMD2_REG register * needs desc @@ -393,10 +397,12 @@ extern "C" { /** PVT_DBIAS_CMD2 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD2 0x0001FFFFU -#define PVT_DBIAS_CMD2_M (PVT_DBIAS_CMD2_V << PVT_DBIAS_CMD2_S) -#define PVT_DBIAS_CMD2_V 0x0001FFFFU -#define PVT_DBIAS_CMD2_S 0 +#define PVT_DBIAS_CMD2_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD2_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD2_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD2_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD2_PVT 0x7FF +#define PVT_DBIAS_CMD2_PVT_S 0 /** PVT_DBIAS_CMD3_REG register * needs desc diff --git a/components/soc/esp32s31/register/soc/pvt_struct.h b/components/soc/esp32s31/register/soc/pvt_struct.h index ce6c903aeac..f8169746324 100644 --- a/components/soc/esp32s31/register/soc/pvt_struct.h +++ b/components/soc/esp32s31/register/soc/pvt_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -351,10 +351,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd0 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd0 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd0:17; + uint32_t dbias_cmd0_pvt:11; + /** dbias_cmd0_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_value:5; + /** dbias_cmd0_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -365,10 +373,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd1 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd1 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd1:17; + uint32_t dbias_cmd1_pvt:11; + /** dbias_cmd1_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_value:5; + /** dbias_cmd1_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -379,10 +395,19 @@ typedef union { */ typedef union { struct { - /** dbias_cmd2 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd2 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd2:17; + uint32_t dbias_cmd2_pvt:11; + /** dbias_cmd2_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd2_offset_value:5; + /** dbias_cmd2_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + + uint32_t dbias_cmd2_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val;