From 3ac387a2d6e89c817838ef680305031675ad2fec Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 28 Jan 2026 20:26:46 +0800 Subject: [PATCH] feat(esp_hw_support): esp32s31 PMU basic support --- .../esp32s31/include/hal/gpio_ll.h | 10 +- .../esp32s31/include/hal/pmu_hal.h | 26 +- .../esp_hal_pmu/esp32s31/include/hal/pmu_ll.h | 775 +++++++++++++++++- components/esp_hal_pmu/esp32s31/pmu_hal.c | 77 +- .../esp_hal_pmu/include/hal/pmu_types.h | 11 +- .../port/esp32s31/CMakeLists.txt | 3 + .../esp_hw_support/port/esp32s31/pmu_init.c | 208 +++++ .../esp_hw_support/port/esp32s31/pmu_param.c | 431 ++++++++++ .../esp_hw_support/port/esp32s31/pmu_sleep.c | 361 ++++++++ .../esp32s31/private_include/pmu_bit_defs.h | 46 ++ .../port/esp32s31/private_include/pmu_param.h | 526 ++++++++++++ components/esp_system/port/soc/esp32s31/clk.c | 1 + components/hal/esp32s31/include/hal/pmu_hal.h | 49 ++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 - components/soc/esp32p4/include/soc/soc_caps.h | 1 - .../esp32s31/include/soc/Kconfig.soc_caps.in | 104 +++ .../soc/esp32s31/include/soc/soc_caps.h | 37 +- 17 files changed, 2651 insertions(+), 19 deletions(-) create mode 100644 components/esp_hw_support/port/esp32s31/pmu_init.c create mode 100644 components/esp_hw_support/port/esp32s31/pmu_param.c create mode 100644 components/esp_hw_support/port/esp32s31/pmu_sleep.c create mode 100644 components/esp_hw_support/port/esp32s31/private_include/pmu_bit_defs.h create mode 100644 components/esp_hw_support/port/esp32s31/private_include/pmu_param.h create mode 100644 components/hal/esp32s31/include/hal/pmu_hal.h diff --git a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h index efe5d3814d..b36cb2fd33 100644 --- a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.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 */ @@ -636,8 +636,8 @@ static inline int gpio_ll_get_in_signal_connected_io(gpio_dev_t *hw, uint32_t in static inline void gpio_ll_force_hold_all(void) { // WT flag, it gets self-cleared after the configuration is done - PMU.imm_pad_hold_all.tie_high_hp_pad_hold_all = 1; - PMU.imm_pad_hold_all.tie_high_lp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_high_hp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1; } /** @@ -647,8 +647,8 @@ static inline void gpio_ll_force_hold_all(void) static inline void gpio_ll_force_unhold_all(void) { // WT flag, it gets self-cleared after the configuration is done - PMU.imm_pad_hold_all.tie_low_hp_pad_hold_all = 1; - PMU.imm_pad_hold_all.tie_low_lp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_low_hp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1; } /** diff --git a/components/esp_hal_pmu/esp32s31/include/hal/pmu_hal.h b/components/esp_hal_pmu/esp32s31/include/hal/pmu_hal.h index 310e1e5d2d..a0b153e3f6 100644 --- a/components/esp_hal_pmu/esp32s31/include/hal/pmu_hal.h +++ b/components/esp_hal_pmu/esp32s31/include/hal/pmu_hal.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 */ @@ -16,7 +16,29 @@ extern "C" { #endif -// TODO: ["ESP32S31"] IDF-14653 +typedef struct { + pmu_dev_t *dev; +} pmu_hal_context_t; + +void pmu_hal_hp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle); + +uint32_t pmu_hal_hp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal); + +void pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle); + +uint32_t pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_modem_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_modem_backup_disable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_modem_active_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_modem_active_backup_disable(pmu_hal_context_t *hal); #ifdef __cplusplus } diff --git a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h index f95b92f3d6..5a946239ad 100644 --- a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.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 */ @@ -16,13 +16,782 @@ #include "soc/pmu_struct.h" #include "hal/pmu_types.h" #include "hal/misc.h" -#include "hal/config.h" #ifdef __cplusplus extern "C" { #endif -// TODO: ["ESP32S31"] IDF-14642 +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_interrupt_raw(pmu_dev_t *hw) +{ + return hw->lp_ext.int_raw.val; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) +{ + hw->lp_ext.int_clr.val = mask; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw) +{ + hw->lp_ext.int_clr.hp_sw_trigger = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_enable_sw_intr(pmu_dev_t *hw, bool enable) +{ + hw->lp_ext.int_ena.hp_sw_trigger = enable; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_trigger_sw_intr(pmu_dev_t *hw) +{ + hw->hp_lp_cpu_comm.lp_trigger_hp = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_trigger_sw_intr(pmu_dev_t *hw) +{ + hw->hp_lp_cpu_comm.hp_trigger_lp = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_power(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t flag) +{ + hw->hp_sys[mode].dig_power.val = flag; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_func(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t icg_func0, uint32_t icg_func1) +{ + hw->hp_sys[mode].icg[0].icg_func = icg_func0; + hw->hp_sys[mode].icg[1].icg_func = icg_func1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_apb(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t bitmap0, uint32_t bitmap1) +{ + hw->hp_sys[mode].icg[0].icg_apb = bitmap0; + hw->hp_sys[mode].icg[1].icg_apb = bitmap1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_modem(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t code) +{ + hw->hp_sys[mode].icg_modem.code = code; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_c_channel_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool ena) +{ + hw->hp_sys[mode].syscntl.c_channel = ena ? 1 : 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_uart_wakeup_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool wakeup_en) +{ + hw->hp_sys[mode].syscntl.uart_wakeup_en = wakeup_en; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_hold_all_lp_pad(pmu_dev_t *hw, pmu_hp_mode_t mode, bool hold_all) +{ + hw->hp_sys[mode].syscntl.lp_pad_hold_all = hold_all; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_hold_all_hp_pad(pmu_dev_t *hw, pmu_hp_mode_t mode, bool hold_all) +{ + hw->hp_sys[mode].syscntl.hp_pad_hold_all = hold_all; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_pad_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel) +{ + hw->hp_sys[mode].syscntl.dig_pad_slp_sel = slp_sel; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_pause_watchdog(pmu_dev_t *hw, pmu_hp_mode_t mode, bool pause_wdt) +{ + hw->hp_sys[mode].syscntl.dig_pause_wdt = pause_wdt; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_cpu_stall(pmu_dev_t *hw, pmu_hp_mode_t mode, bool cpu_stall) +{ + hw->hp_sys[mode].syscntl.dig_cpu_stall = cpu_stall; +} + +/** + * @brief Set the power domain that needs to be powered down in the clock power + * + * @param hw Beginning address of the peripheral registers. + * @param mode The pmu mode + * @param flag Clock power domain flag + * + * @return None + */ +FORCE_INLINE_ATTR void pmu_ll_hp_set_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t xpd_flag) +{ + hw->hp_sys[mode].clk_power.val = xpd_flag; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_xtal_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_xtal) +{ + hw->hp_sys[mode].xtal.xpd_xtal = xpd_xtal; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_bias) +{ + hw->hp_sys[mode].bias.xpd_bias = xpd_bias; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_dbg_atten(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t value) +{ + hw->hp_sys[mode].bias.dbg_atten = value; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_current_power_off(pmu_dev_t *hw, pmu_hp_mode_t mode, bool off) +{ + hw->hp_sys[mode].bias.pd_cur = off; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_sleep_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool en) +{ + hw->hp_sys[mode].bias.bias_sleep = en; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_retention_param(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t param) +{ + hw->hp_sys[mode].backup_cfg.val = param; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_active_backup_enable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_ACTIVE].backup_cfg.hp_sleep2active_backup_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_active_backup_disable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_ACTIVE].backup_cfg.hp_sleep2active_backup_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_active_backup_enable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_ACTIVE].backup_cfg.hp_modem2active_backup_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_active_backup_disable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_ACTIVE].backup_cfg.hp_modem2active_backup_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_modem_backup_enable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_MODEM].backup_cfg.hp_sleep2modem_backup_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_modem_backup_disable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_MODEM].backup_cfg.hp_sleep2modem_backup_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_active_to_sleep_backup_enable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_SLEEP].backup_cfg.hp_active2sleep_backup_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_active_to_sleep_backup_disable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_SLEEP].backup_cfg.hp_active2sleep_backup_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_sleep_backup_enable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_SLEEP].backup_cfg.hp_modem2sleep_backup_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_sleep_backup_disable(pmu_dev_t *hw) +{ + hw->hp_sys[PMU_MODE_HP_SLEEP].backup_cfg.hp_modem2sleep_backup_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_backup_icg_func(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t icg_func0, uint32_t icg_func1) +{ + hw->hp_sys[mode].backup_clock[0] = icg_func0; + hw->hp_sys[mode].backup_clock[1] = icg_func1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sysclk_nodiv(pmu_dev_t *hw, pmu_hp_mode_t mode, bool sysclk_nodiv) +{ + hw->hp_sys[mode].sysclk.dig_sysclk_nodiv = sysclk_nodiv; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_sysclk_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool icg_sysclk_en) +{ + hw->hp_sys[mode].sysclk.icg_sysclk_en = icg_sysclk_en; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sysclk_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel) +{ + hw->hp_sys[mode].sysclk.sysclk_slp_sel = slp_sel; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_sysclk_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel) +{ + hw->hp_sys[mode].sysclk.icg_slp_sel = slp_sel; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_sysclk(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t sysclk_sel) +{ + hw->hp_sys[mode].sysclk.dig_sysclk_sel = sysclk_sel; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_lp_dbias_voltage(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t voltage) +{ + HAL_ASSERT(mode == PMU_MODE_HP_ACTIVE); + hw->hp_sys[mode].regulator0.lp_dbias_vol = voltage; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_hp_dbias_voltage(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t voltage) +{ + HAL_ASSERT(mode == PMU_MODE_HP_ACTIVE); + hw->hp_sys[mode].regulator0.hp_dbias_vol = voltage; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_dbias_select(pmu_dev_t *hw, pmu_hp_mode_t mode, bool sel) +{ + HAL_ASSERT(mode == PMU_MODE_HP_ACTIVE); + hw->hp_sys[mode].regulator0.dbias_sel = sel; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_dbias_init(pmu_dev_t *hw, pmu_hp_mode_t mode, bool init) +{ + HAL_ASSERT(mode == PMU_MODE_HP_ACTIVE); + hw->hp_sys[mode].regulator0.dig_dbias_init = init; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_logic_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_xpd) +{ + hw->hp_sys[mode].regulator0.slp_logic_xpd = slp_xpd; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_memory_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_xpd) +{ + hw->hp_sys[mode].regulator0.slp_mem_xpd = slp_xpd; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd) +{ + hw->hp_sys[mode].regulator0.xpd = xpd; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_logic_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t slp_dbias) +{ + hw->hp_sys[mode].regulator0.slp_logic_dbias = slp_dbias; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_memory_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t slp_dbias) +{ + hw->hp_sys[mode].regulator0.slp_mem_dbias = slp_dbias; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t dbias) +{ + hw->hp_sys[mode].regulator0.dbias = dbias; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_driver_bar(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t drv_b) +{ + hw->hp_sys[mode].regulator1.drv_b = drv_b; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_slp_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool slp_xpd) +{ + hw->lp_sys[mode].regulator0.slp_xpd = slp_xpd; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd) +{ + hw->lp_sys[mode].regulator0.xpd = xpd; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_sleep_dbias(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t slp_dbias) +{ + hw->lp_sys[mode].regulator0.slp_dbias = slp_dbias; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_dbias(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t dbias) +{ + hw->lp_sys[mode].regulator0.dbias = dbias; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_driver_bar(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t drv_b) +{ + hw->lp_sys[mode].regulator1.drv_b = drv_b; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_xtal_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd_xtal) +{ + HAL_ASSERT(mode == PMU_MODE_LP_SLEEP); + hw->lp_sys[mode].xtal.xpd_xtal = xpd_xtal; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_dig_power(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t flag) +{ + hw->lp_sys[mode].dig_power.val = flag; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_clk_power(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t xpd_flag) +{ + hw->lp_sys[mode].clk_power.val = xpd_flag; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_clk_power(pmu_dev_t *hw, pmu_lp_mode_t mode) +{ + return hw->lp_sys[mode].clk_power.val; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_bias_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd_bias) +{ + HAL_ASSERT(mode == PMU_MODE_LP_SLEEP); + hw->lp_sys[mode].bias.xpd_bias = xpd_bias; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_dbg_atten(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t value) +{ + HAL_ASSERT(mode == PMU_MODE_LP_SLEEP); + hw->lp_sys[mode].bias.dbg_atten = value; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_current_power_off(pmu_dev_t *hw, pmu_lp_mode_t mode, bool off) +{ + HAL_ASSERT(mode == PMU_MODE_LP_SLEEP); + hw->lp_sys[mode].bias.pd_cur = off; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_bias_sleep_enable(pmu_dev_t *hw, pmu_lp_mode_t mode, bool en) +{ + HAL_ASSERT(mode == PMU_MODE_LP_SLEEP); + hw->lp_sys[mode].bias.bias_sleep = en; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_set_clk_power(pmu_dev_t *hw, uint32_t flag0, uint32_t flag1) +{ + hw->imm.clk_power_0.val = flag0; + hw->imm.clk_power_1.val = flag1; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_set_icg_slp_sel(pmu_dev_t *hw, bool slp_sel) +{ + if (slp_sel) { + hw->imm.sleep_sysclk.tie_high_icg_slp_sel = 1; + } else { + hw->imm.sleep_sysclk.tie_low_icg_slp_sel = 1; + } +} + +FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_sysclk_sel(pmu_dev_t *hw, bool update) +{ + hw->imm.sleep_sysclk.update_dig_sysclk_sel = update; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_switch(pmu_dev_t *hw, bool update) +{ + hw->imm.sleep_sysclk.update_dig_icg_switch = update; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_func(pmu_dev_t *hw, bool icg_func_update) +{ + hw->imm.hp_func_icg.update_dig_icg_func_en = icg_func_update; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_apb(pmu_dev_t *hw, bool icg_apb_update) +{ + hw->imm.hp_apb_icg.update_dig_icg_apb_en = icg_apb_update; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_modem_code(pmu_dev_t *hw, bool icg_modem_update) +{ + hw->imm.modem_icg.update_dig_icg_modem_en = icg_modem_update; +} + +FORCE_INLINE_ATTR void pmu_ll_imm_set_lp_rootclk_sel(pmu_dev_t *hw, bool rootclk_sel) +{ + if (rootclk_sel) { + hw->imm.lp_icg.tie_high_lp_rootclk_sel = 1; + } else { + hw->imm.lp_icg.tie_low_lp_rootclk_sel = 1; + } +} + +FORCE_INLINE_ATTR void pmu_ll_imm_set_hp_pad_hold_all(pmu_dev_t *hw, bool hold_all) +{ + if (hold_all) { + hw->imm.pad_hold_all.tie_high_hp_pad_hold_all = 1; + } else { + hw->imm.pad_hold_all.tie_low_hp_pad_hold_all = 1; + } +} + +FORCE_INLINE_ATTR void pmu_ll_imm_set_lp_pad_hold_all(pmu_dev_t *hw, bool hold_all) +{ + if (hold_all) { + hw->imm.pad_hold_all.tie_high_lp_pad_hold_all = 1; + } else { + hw->imm.pad_hold_all.tie_low_lp_pad_hold_all = 1; + } +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_reset(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool rst) +{ + hw->power.hp_pd[domain].force_top_reset = rst; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_isolate(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool iso) +{ + hw->power.hp_pd[domain].force_top_iso = iso; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_power_up(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool fpu) +{ + hw->power.hp_pd[domain].force_top_pu = fpu; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_no_reset(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool no_rst) +{ + hw->power.hp_pd[domain].force_top_no_reset = no_rst; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_no_isolate(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool no_iso) +{ + hw->power.hp_pd[domain].force_top_no_iso = no_iso; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_power_down(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool fpd) +{ + hw->power.hp_pd[domain].force_top_pd = fpd; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_reset(pmu_dev_t *hw, bool rst) +{ + hw->power.lp_peri.force_lp_peri_reset = rst; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_isolate(pmu_dev_t *hw, bool iso) +{ + hw->power.lp_peri.force_lp_peri_iso = iso; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_power_up(pmu_dev_t *hw, bool fpu) +{ + hw->power.lp_peri.force_lp_peri_pu = fpu; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_no_reset(pmu_dev_t *hw, bool no_rst) +{ + hw->power.lp_peri.force_lp_peri_no_reset = no_rst; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_no_isolate(pmu_dev_t *hw, bool no_iso) +{ + hw->power.lp_peri.force_lp_peri_no_iso = no_iso; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_power_down(pmu_dev_t *hw, bool fpd) +{ + hw->power.lp_peri.force_lp_peri_pd = fpd; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_isolate(pmu_dev_t *hw, uint32_t iso) +{ + hw->power.mem_cntl.force_hp_mem_iso = iso; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_power_down(pmu_dev_t *hw, uint32_t fpd) +{ + hw->power.mem_cntl.force_hp_mem_pd = fpd; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_no_isolate(pmu_dev_t *hw, uint32_t no_iso) +{ + hw->power.mem_cntl.force_hp_mem_no_iso = no_iso; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_power_up(pmu_dev_t *hw, uint32_t fpu) +{ + hw->power.mem_cntl.force_hp_mem_pu = fpu; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_enable(pmu_dev_t *hw) +{ + hw->wakeup.cntl0.sleep_req = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_reject_enable(pmu_dev_t *hw, uint32_t reject) +{ + hw->wakeup.cntl1.sleep_reject_ena = reject; + hw->wakeup.cntl0.slp_reject_en = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_reject_disable(pmu_dev_t *hw) +{ + hw->wakeup.cntl0.slp_reject_en = 0; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_wakeup_enable(pmu_dev_t *hw, uint32_t wakeup) +{ + hw->wakeup.cntl2 = wakeup; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) +{ + hw->wakeup.cntl3.sleep_prt_sel = mode; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, slow_clk_cycle); +} + +FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) +{ + hw->wakeup.cntl4.slp_reject_cause_clr = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_set_modem_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->wakeup.cntl5.modem_wait_target = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_get_modem_wait_target_cycle(pmu_dev_t *hw) +{ + return hw->wakeup.cntl5.modem_wait_target; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); +} + +FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_wakeup(pmu_dev_t *hw) +{ + return (hw->hp_ext.int_raw.soc_wakeup == 1); +} + +FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_reject(pmu_dev_t *hw) +{ + return (hw->hp_ext.int_raw.soc_sleep_reject == 1); +} + +FORCE_INLINE_ATTR void pmu_ll_hp_clear_sw_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.sw = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_clear_wakeup_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.soc_wakeup = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.soc_sleep_reject = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable) +{ + hw->hp_ext.int_ena.sw = enable; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_wakeup_cause(pmu_dev_t *hw) +{ + return hw->wakeup.status0; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_reject_cause(pmu_dev_t *hw) +{ + return hw->wakeup.status1; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer0.powerdown_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_down_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer0.powerdown_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer1.powerdown_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer1.powerdown_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); +} + +FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); +} + +FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer1.wait_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_supply_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer1.wait_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_up_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer1.powerup_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer1.powerup_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer0.wait_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_supply_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer0.wait_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_up_wait_cycle(pmu_dev_t *hw, uint32_t cycle) +{ + hw->power.wait_timer0.powerup_timer = cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_up_wait_cycle(pmu_dev_t *hw) +{ + return hw->power.wait_timer0.powerup_timer; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_isolate_wait_cycle(pmu_dev_t *hw, uint32_t isolate_wait_cycle) +{ + hw->power.wait_timer2.dg_lp_iso_wait_timer = isolate_wait_cycle; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_set_reset_wait_cycle(pmu_dev_t *hw, uint32_t reset_wait_cycle) +{ + hw->power.wait_timer2.dg_lp_rst_wait_timer = reset_wait_cycle; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_isolate_wait_cycle(pmu_dev_t *hw, uint32_t isolate_wait_cycle) +{ + hw->power.wait_timer2.dg_hp_iso_wait_timer = isolate_wait_cycle; +} + +FORCE_INLINE_ATTR void pmu_ll_hp_set_reset_wait_cycle(pmu_dev_t *hw, uint32_t reset_wait_cycle) +{ + hw->power.wait_timer2.dg_hp_rst_wait_timer = reset_wait_cycle; +} + +FORCE_INLINE_ATTR uint32_t pmu_ll_get_sysclk_sleep_select_state(pmu_dev_t *hw) +{ + return hw->clk_state0.sysclk_slp_sel; +} + +/** + * @brief Get ext1 wakeup source status + * @return The lower 8 bits of the returned value are the bitmap of + * the wakeup source status, bit 0~7 corresponds to LP_IO 0~7 + */ +static inline uint32_t pmu_ll_ext1_get_wakeup_status(void) +{ + return REG_GET_FIELD(PMU_EXT_WAKEUP_ST_REG, PMU_EXT_WAKEUP_STATUS); +} + +/** + * @brief Clear the ext1 wakeup source status + */ +static inline void pmu_ll_ext1_clear_wakeup_status(void) +{ + REG_SET_BIT(PMU_EXT_WAKEUP_CNTL_REG, PMU_EXT_WAKEUP_STATUS_CLR); +} + +/** + * @brief Set the wake-up LP_IO of the ext1 wake-up source + * @param io_mask wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7 + * @param level_mask 0: Wake the chip when all selected GPIOs go low + * 1: Wake the chip when any of the selected GPIOs go high + */ +static inline void pmu_ll_ext1_set_wakeup_pins(uint32_t io_mask, int level_mask) +{ + REG_SET_FIELD(PMU_EXT_WAKEUP_SEL_REG, PMU_EXT_WAKEUP_SEL, io_mask); + REG_SET_FIELD(PMU_EXT_WAKEUP_LV_REG, PMU_EXT_WAKEUP_LV, level_mask); +} + +/** + * @brief Clear all ext1 wakup-source setting + */ +static inline void pmu_ll_ext1_clear_wakeup_pins(void) +{ + REG_SET_FIELD(PMU_EXT_WAKEUP_SEL_REG, PMU_EXT_WAKEUP_SEL, 0); +} + +/** + * @brief Get ext1 wakeup source setting + * @return The lower 8 bits of the returned value are the bitmap of + * the wakeup source status, bit 0~7 corresponds to LP_IO 0~7 + */ +static inline uint32_t pmu_ll_ext1_get_wakeup_pins(void) +{ + return REG_GET_FIELD(PMU_EXT_WAKEUP_SEL_REG, PMU_EXT_WAKEUP_SEL); +} #ifdef __cplusplus } diff --git a/components/esp_hal_pmu/esp32s31/pmu_hal.c b/components/esp_hal_pmu/esp32s31/pmu_hal.c index 260f27086e..79004cf28f 100644 --- a/components/esp_hal_pmu/esp32s31/pmu_hal.c +++ b/components/esp_hal_pmu/esp32s31/pmu_hal.c @@ -1,9 +1,82 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ // The HAL layer for PMU (ESP32-S31 specific part) -// TODO: ["ESP32S31"] IDF-14653 +#include "soc/soc.h" +#include "esp_attr.h" +#include "hal/pmu_hal.h" +#include "hal/pmu_types.h" + +void IRAM_ATTR pmu_hal_hp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle) +{ + pmu_ll_hp_set_digital_power_supply_wait_cycle(hal->dev, power_supply_wait_cycle); + pmu_ll_hp_set_digital_power_up_wait_cycle(hal->dev, power_up_wait_cycle); +} + +uint32_t IRAM_ATTR pmu_hal_hp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal) +{ + uint32_t power_supply_wait_cycle = pmu_ll_hp_get_digital_power_supply_wait_cycle(hal->dev); + uint32_t power_up_wait_cycle = pmu_ll_hp_get_digital_power_up_wait_cycle(hal->dev); + return power_supply_wait_cycle + power_up_wait_cycle; +} + +void IRAM_ATTR pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle) +{ + pmu_ll_lp_set_digital_power_supply_wait_cycle(hal->dev, power_supply_wait_cycle); + pmu_ll_lp_set_digital_power_up_wait_cycle(hal->dev, power_up_wait_cycle); +} + +uint32_t IRAM_ATTR pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal) +{ + uint32_t power_supply_wait_cycle = pmu_ll_lp_get_digital_power_supply_wait_cycle(hal->dev); + uint32_t power_up_wait_cycle = pmu_ll_lp_get_digital_power_up_wait_cycle(hal->dev); + return power_supply_wait_cycle + power_up_wait_cycle; +} + +void IRAM_ATTR pmu_hal_hp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle) +{ + pmu_ll_hp_set_isolate_wait_cycle(hal->dev, isolate_wait_cycle); + pmu_ll_hp_set_reset_wait_cycle(hal->dev, reset_wait_cycle); +} + +void IRAM_ATTR pmu_hal_lp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle) +{ + pmu_ll_lp_set_isolate_wait_cycle(hal->dev, isolate_wait_cycle); + pmu_ll_lp_set_reset_wait_cycle(hal->dev, reset_wait_cycle); +} + +void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_active_to_sleep_backup_enable(hal->dev); + pmu_ll_hp_set_sleep_to_active_backup_enable(hal->dev); +} + +void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_sleep_to_active_backup_disable(hal->dev); + pmu_ll_hp_set_active_to_sleep_backup_disable(hal->dev); +} + +void pmu_hal_hp_set_sleep_modem_backup_enable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_sleep_to_modem_backup_enable(hal->dev); +} + +void pmu_hal_hp_set_sleep_modem_backup_disable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_sleep_to_modem_backup_disable(hal->dev); +} + +void pmu_hal_hp_set_modem_active_backup_enable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_modem_to_active_backup_enable(hal->dev); +} + +void pmu_hal_hp_set_modem_active_backup_disable(pmu_hal_context_t *hal) +{ + pmu_ll_hp_set_modem_to_active_backup_disable(hal->dev); +} diff --git a/components/esp_hal_pmu/include/hal/pmu_types.h b/components/esp_hal_pmu/include/hal/pmu_types.h index e937fc9356..2176be3e88 100644 --- a/components/esp_hal_pmu/include/hal/pmu_types.h +++ b/components/esp_hal_pmu/include/hal/pmu_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,6 +43,15 @@ typedef enum { PMU_HP_PD_HPMEM = 2, PMU_HP_PD_CPU = 3, } pmu_hp_power_domain_t; +#elif SOC_IS(ESP32S31) +typedef enum { + PMU_HP_PD_TOP = 0, /*!< Power domain of digital top */ + PMU_HP_PD_HPALIVE, + PMU_HP_PD_MODEMPWR, + PMU_HP_PD_HPCPU, + PMU_HP_PD_HPCNNT, + PMU_HP_PD_MODEM +} pmu_hp_power_domain_t; #else typedef enum { PMU_HP_PD_TOP = 0, /*!< Power domain of digital top */ diff --git a/components/esp_hw_support/port/esp32s31/CMakeLists.txt b/components/esp_hw_support/port/esp32s31/CMakeLists.txt index 8858f89a59..9d5abf9c48 100644 --- a/components/esp_hw_support/port/esp32s31/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s31/CMakeLists.txt @@ -4,6 +4,9 @@ set(srcs "rtc_clk.c" "rtc_time.c" "chip_info.c" + "pmu_param.c" + "pmu_init.c" + "pmu_sleep.c" ) add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") diff --git a/components/esp_hw_support/port/esp32s31/pmu_init.c b/components/esp_hw_support/port/esp32s31/pmu_init.c new file mode 100644 index 0000000000..7c1053b9e0 --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/pmu_init.c @@ -0,0 +1,208 @@ +/* + * 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/chip_revision.h" +#include "soc/soc.h" +#include "soc/pmu_struct.h" +#include "hal/efuse_hal.h" +#include "hal/pmu_hal.h" +#include "pmu_param.h" +#include "esp_private/esp_pmu.h" +#include "esp_hw_log.h" + +ESP_HW_LOG_ATTR_TAG(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.clock[0], clock->icg_func.clock[1]); + pmu_ll_hp_set_icg_apb (ctx->hal->dev, mode, clock->icg_apb.clock[0], clock->icg_apb.clock[1]); + 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_c_channel_enable (ctx->hal->dev, mode, dig->syscntl.c_channel); + 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_dbg_atten (ctx->hal->dev, mode, anlg->bias.dbg_atten); + 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); + if (mode == PMU_MODE_HP_ACTIVE) { + pmu_ll_hp_set_regulator_lp_dbias_voltage(ctx->hal->dev, mode, anlg->regulator0.lp_dbias_vol); + pmu_ll_hp_set_regulator_hp_dbias_voltage(ctx->hal->dev, mode, anlg->regulator0.hp_dbias_vol); + pmu_ll_hp_set_regulator_dbias_select (ctx->hal->dev, mode, anlg->regulator0.dbias_sel); + pmu_ll_hp_set_regulator_dbias_init (ctx->hal->dev, mode, anlg->regulator0.dig_dbias_init); + } + pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_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_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd); + 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_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); + 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[0], ret->backup_clk[1]); + + /* 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_dbg_atten (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.dbg_atten); + 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_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias); + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_xpd); + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_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_HPALIVE, + PMU_HP_PD_MODEMPWR, + PMU_HP_PD_HPCPU, + PMU_HP_PD_HPCNNT, + PMU_HP_PD_MODEM + }; + + for (uint8_t idx = 0; idx < (sizeof(pmu_hp_domains) / sizeof(pmu_hp_power_domain_t)); idx++) { + 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); + pmu_ll_hp_set_power_force_isolate (ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_reset (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_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); + pmu_ll_lp_set_power_force_isolate (ctx->hal->dev, false); + pmu_ll_lp_set_power_force_reset (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(void) +{ + pmu_hp_system_init_default(PMU_instance()); + pmu_lp_system_init_default(PMU_instance()); + pmu_power_domain_force_default(PMU_instance()); +} diff --git a/components/esp_hw_support/port/esp32s31/pmu_param.c b/components/esp_hw_support/port/esp32s31/pmu_param.c new file mode 100644 index 0000000000..4a5a8bd05e --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/pmu_param.c @@ -0,0 +1,431 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "soc/soc.h" +#include "pmu_param.h" +#include "soc/pmu_icg_mapping.h" +#include "esp_private/esp_pmu.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_hw_log.h" +#include "soc/clk_tree_defs.h" + +ESP_HW_LOG_ATTR_TAG(TAG, "pmu_param"); + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#define PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 0, \ + .pd_hp_alive_pd_en = 0, \ + .hp_mem_dslp = 0, \ + .hp_mem_pd_en = 0, \ + .modem_top_pd_en = 0, \ + .hp_cnnt_pd_en = 0, \ + .hp_cpu_pd_en = 0, \ + .modem_pwr_pd_en = 0, \ + .top_pd_en = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 0, \ + .i2c_retention = 0, \ + .xpd_bb_i2c = 1, \ + .xpd_pll_i2c = 0xf, \ + .xpd_pll = 0xf \ + }, \ + .xtal = { \ + .xpd_xtal = 1 \ + } \ +} + +#define PMU_HP_MODEM_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 0, \ + .pd_hp_alive_pd_en = 0, \ + .hp_mem_dslp = 0, \ + .hp_mem_pd_en = 0, \ + .modem_top_pd_en = 0, \ + .hp_cnnt_pd_en = 0, \ + .hp_cpu_pd_en = 1, \ + .modem_pwr_pd_en = 0, \ + .top_pd_en = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 0, \ + .i2c_retention = 0, \ + .xpd_bb_i2c = 1, \ + .xpd_pll_i2c = 0xf, \ + .xpd_pll = 0xf \ + }, \ + .xtal = { \ + .xpd_xtal = 1 \ + } \ +} + +#define PMU_HP_SLEEP_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 1, \ + .pd_hp_alive_pd_en = 1, \ + .hp_mem_dslp = 1, \ + .hp_mem_pd_en = 0, \ + .modem_top_pd_en = 1, \ + .hp_cnnt_pd_en = 1, \ + .hp_cpu_pd_en = 1, \ + .modem_pwr_pd_en = 0, \ + .top_pd_en = 1 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 0, \ + .i2c_retention = 0, \ + .xpd_bb_i2c = 1, \ + .xpd_pll_i2c = 0xf, \ + .xpd_pll = 0xf \ + }, \ + .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.clock[0] = 0xffffffff, \ + .icg_func.clock[1] = 0xffffffff, \ + .icg_apb.clock[0] = 0xffffffff, \ + .icg_apb.clock[1] = 0xffffffff, \ + .icg_modem.code = PMU_HP_ICG_MODEM_CODE_ACTIVE, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 1, \ + .sysclk_slp_sel = 0, \ + .icg_slp_sel = 0, \ + .dig_sysclk_sel = SOC_CPU_CLK_SRC_XTAL \ + } \ +} + +#define PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT() { \ + .icg_func.clock[0] = 0, \ + .icg_func.clock[1] = 0, \ + .icg_apb.clock[0] = 0, \ + .icg_apb.clock[1] = 0, \ + .icg_modem.code = PMU_HP_ICG_MODEM_CODE_MODEM, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 1, \ + .sysclk_slp_sel = 1, \ + .icg_slp_sel = 1, \ + .dig_sysclk_sel = SOC_CPU_CLK_SRC_XTAL \ + } \ +} + +#define PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT() { \ + .icg_func.clock[0] = 0, \ + .icg_func.clock[1] = 0, \ + .icg_apb.clock[0] = 0, \ + .icg_apb.clock[1] = 0, \ + .icg_modem.code = PMU_HP_ICG_MODEM_CODE_SLEEP, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 0, \ + .sysclk_slp_sel = 1, \ + .icg_slp_sel = 1, \ + .dig_sysclk_sel = SOC_CPU_CLK_SRC_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 = { \ + .c_channel = 1, \ + .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 = { \ + .c_channel = 1, \ + .uart_wakeup_en = 0, \ + .lp_pad_hold_all = 0, \ + .hp_pad_hold_all = 0, \ + .dig_pad_slp_sel = 1, \ + .dig_pause_wdt = 1, \ + .dig_cpu_stall = 1 \ + } \ +} + +#define PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT() { \ + .syscntl = { \ + .c_channel = 1, \ + .uart_wakeup_en = 1, \ + .lp_pad_hold_all = 0, \ + .hp_pad_hold_all = 0, \ + .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_bias = 1, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .dig_dbias_init = 1, \ + .lp_dbias_vol = 0xd, \ + .hp_dbias_vol = 0x1c, \ + .dbias_sel = 1, \ + .slp_connect_en = 0, \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 0, \ + .slp_logic_dbias = 0, \ + .dbias = HP_CALI_DBIAS_DEFAULT\ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .slp_connect_en = 0, \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 0, \ + .slp_logic_dbias = 0, \ + .dbias = HP_CALI_DBIAS_DEFAULT\ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .slp_connect_en = 0, \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 1, \ + .slp_logic_dbias = 0, \ + .dbias = 1 \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +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)<<4) | (entry & 0xf)) & 0x1f) + +#define PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_sleep2active_backup_modem_clk_code = 2, \ + .hp_modem2active_backup_modem_clk_code = 2, \ + .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[0] = 0xffffffff, \ + .backup_clk[1] = 0xffffffff, \ +} + +#define PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_sleep2modem_backup_modem_clk_code = 1, \ + .hp_modem_retention_mode = 0, \ + .hp_sleep2modem_retention_en = 0, \ + .hp_sleep2modem_backup_clk_sel = SOC_CPU_CLK_SRC_XTAL, \ + .hp_sleep2modem_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 1), \ + .hp_sleep2modem_backup_en = 0, \ + }, \ + .backup_clk[0] = 0xffffffff, \ + .backup_clk[1] = 0xffffffff, \ +} + +#define PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_modem2sleep_backup_modem_clk_code = 0, \ + .hp_active2sleep_backup_modem_clk_code = 2, \ + .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[0] = 0xffffffff, \ + .backup_clk[1] = 0xffffffff, \ +} + +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 = 1, \ + .xpd_rc32k = 1, \ + .xpd_fosc = 1, \ + .pd_osc = 0 \ + } \ +} + +#define PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .mem_dslp = 0, \ + .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 = LP_CALI_DBIAS_DEFAULT \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0, \ + .pd_cur = 1, \ + .bias_sleep = 1, \ + }, \ + .regulator0 = { \ + .slp_xpd = 0, \ + .xpd = 1, \ + .slp_dbias = 0, \ + .dbias = 12 \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +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]; +} diff --git a/components/esp_hw_support/port/esp32s31/pmu_sleep.c b/components/esp_hw_support/port/esp32s31/pmu_sleep.c new file mode 100644 index 0000000000..2f4f9ba18c --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/pmu_sleep.c @@ -0,0 +1,361 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/pmu_struct.h" +#include "esp_private/esp_pmu.h" +#include "pmu_param.h" +#include "hal/lp_aon_hal.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_hw_log.h" + +ESP_HW_LOG_ATTR_TAG(TAG, "pmu_sleep"); + +#define HP(state) (PMU_MODE_HP_ ## state) +#define LP(state) (PMU_MODE_LP_ ## state) + + +static bool s_pmu_sleep_regdma_backup_enabled; + +void pmu_sleep_enable_regdma_backup(void) +{ + if(!s_pmu_sleep_regdma_backup_enabled){ + assert(PMU_instance()->hal); + /* entry 0, 1, 2 is used by pmu HP_SLEEP and HP_ACTIVE, HP_SLEEP + * and HP_MODEM or HP_MODEM and HP_ACTIVE states switching, + * respectively. entry 3 is reserved, not used yet! */ + pmu_hal_hp_set_sleep_active_backup_enable(PMU_instance()->hal); + pmu_hal_hp_set_sleep_modem_backup_enable(PMU_instance()->hal); + pmu_hal_hp_set_modem_active_backup_enable(PMU_instance()->hal); + s_pmu_sleep_regdma_backup_enabled = true; + } +} + +void pmu_sleep_disable_regdma_backup(void) +{ + if(s_pmu_sleep_regdma_backup_enabled){ + assert(PMU_instance()->hal); + pmu_hal_hp_set_sleep_active_backup_disable(PMU_instance()->hal); + pmu_hal_hp_set_sleep_modem_backup_disable(PMU_instance()->hal); + pmu_hal_hp_set_modem_active_backup_disable(PMU_instance()->hal); + s_pmu_sleep_regdma_backup_enabled = false; + } +} + +uint32_t pmu_sleep_calculate_lp_hw_wait_time(uint32_t sleep_flags, uint32_t slowclk_period, uint32_t fastclk_period) +{ + const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + /* LP core hardware wait time, microsecond */ + const int lp_wakeup_wait_time_us = rtc_time_slowclk_to_us(mc->lp.wakeup_wait_cycle, slowclk_period); + const int lp_clk_switch_time_us = rtc_time_slowclk_to_us(mc->lp.clk_switch_cycle, slowclk_period); + /* If XTAL is used as RTC_FAST clock source, it is started in LP_SLEEP -> LP_ACTIVE stage and the clock waiting time is counted into lp_hw_wait_time */ + const int lp_clk_power_on_wait_time_us = ((sleep_flags & PMU_SLEEP_PD_XTAL) && (sleep_flags & RTC_SLEEP_XTAL_AS_RTC_FAST)) \ + ? mc->lp.xtal_wait_stable_time_us \ + : rtc_time_slowclk_to_us(mc->lp.clk_power_on_wait_cycle, slowclk_period); + const int lp_control_wait_time_us = mc->lp.isolate_wait_time_us + mc->lp.reset_wait_time_us; + const int lp_hw_wait_time_us = mc->lp.min_slp_time_us + mc->lp.analog_wait_time_us + lp_clk_power_on_wait_time_us \ + + lp_wakeup_wait_time_us + lp_clk_switch_time_us + mc->lp.power_supply_wait_time_us \ + + mc->lp.power_up_wait_time_us + lp_control_wait_time_us; + + return (uint32_t)lp_hw_wait_time_us; +} + +uint32_t pmu_sleep_calculate_hp_hw_wait_time(uint32_t sleep_flags, uint32_t slowclk_period, uint32_t fastclk_period) +{ + pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + /* HP core hardware wait time, microsecond */ + const int hp_digital_power_up_wait_time_us = mc->hp.power_supply_wait_time_us + mc->hp.power_up_wait_time_us; + const int hp_control_wait_time_us = mc->hp.isolate_wait_time_us + mc->hp.reset_wait_time_us; + const int hp_regdma_wait_time_us = s_pmu_sleep_regdma_backup_enabled ? mc->hp.regdma_s2a_work_time_us : 0; + /* If XTAL is not used as RTC_FAST clock source, it is started in HP_SLEEP -> HP_ACTIVE stage and the clock waiting time is counted into hp_hw_wait_time */ + const int hp_clock_wait_time_us = ((sleep_flags & PMU_SLEEP_PD_XTAL) && !(sleep_flags & RTC_SLEEP_XTAL_AS_RTC_FAST)) \ + ? mc->hp.xtal_wait_stable_time_us + mc->hp.pll_wait_stable_time_us \ + : mc->hp.pll_wait_stable_time_us; + + const int hp_hw_wait_time_us = mc->hp.analog_wait_time_us + hp_digital_power_up_wait_time_us + hp_regdma_wait_time_us \ + + hp_clock_wait_time_us + hp_control_wait_time_us; + return (uint32_t)hp_hw_wait_time_us; +} + +uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t sleep_flags, soc_rtc_slow_clk_src_t slowclk_src, uint32_t slowclk_period, uint32_t fastclk_period) +{ + const uint32_t lp_hw_wait_time_us = pmu_sleep_calculate_lp_hw_wait_time(sleep_flags, slowclk_period, fastclk_period); + const uint32_t hp_hw_wait_time_us = pmu_sleep_calculate_hp_hw_wait_time(sleep_flags, slowclk_period, fastclk_period); + + /* When the SOC wakeup (lp timer or GPIO wakeup) and Modem wakeup (Beacon wakeup) complete, the soc + * wakeup will be delayed until the RF is turned on in Modem state. + * + * modem wakeup TBTT, RF on by HW + * | | + * \|/ \|/ + * PMU_HP_ACTIVE /------ + * PMU_HP_MODEM /------------////////////////// + * PMU_HP_SLEEP ----------------------////////////////// + * /|\ /|\ /|\ /|\ /|\ /|\ + * |<- some hw wait ->| | | |<- M2A switch ->| + * | slow cycles & | soc wakeup | | + * | FOSC cycles |<- S2M switch ->| | + * | | + * |<-- PMU guard time, also the maximum time for the SOC -->| + * | wake-up delay | + */ +#if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + int min_slp_time_adjustment_us = 0; +#if SOC_PM_PMU_MIN_SLP_SLOW_CLK_CYCLE_FIXED + if (slowclk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { + const uint32_t slowclk_period_fixed = rtc_clk_freq_to_period(SOC_CLK_RC_SLOW_FREQ_APPROX); + const int min_slp_cycle_fixed = rtc_time_us_to_slowclk(mc->hp.min_slp_time_us, slowclk_period_fixed); + const int min_slp_cycle_calib = rtc_time_us_to_slowclk(mc->hp.min_slp_time_us, slowclk_period); + const int min_slp_cycle_diff = (min_slp_cycle_calib > min_slp_cycle_fixed) ? \ + (min_slp_cycle_calib - min_slp_cycle_fixed) : (min_slp_cycle_fixed - min_slp_cycle_calib); + const int min_slp_time_diff = rtc_time_slowclk_to_us(min_slp_cycle_diff, slowclk_period_fixed); + min_slp_time_adjustment_us = (min_slp_cycle_calib > min_slp_cycle_fixed) ? min_slp_time_diff : -min_slp_time_diff; + } +#endif + const int rf_on_protect_time_us = mc->hp.regdma_rf_on_work_time_us; + const int total_hw_wait_time_us = lp_hw_wait_time_us + hp_hw_wait_time_us + mc->hp.clock_domain_sync_time_us + min_slp_time_adjustment_us; +#else + const int rf_on_protect_time_us = 0; + const int total_hw_wait_time_us = lp_hw_wait_time_us + hp_hw_wait_time_us; +#endif + return total_hw_wait_time_us + rf_on_protect_time_us; +} + +#define rtc_time_us_to_fastclk(time_us, period) rtc_time_us_to_slowclk((time_us), (period)) + +static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( + pmu_sleep_param_config_t *param, + pmu_sleep_power_config_t *power, /* We'll use the runtime power parameter to determine some hardware parameters */ + const uint32_t sleep_flags, + const uint32_t adjustment, + soc_rtc_slow_clk_src_t slowclk_src, + const uint32_t slowclk_period, + const uint32_t fastclk_period + ) +{ + const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + + param->hp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->hp.min_slp_time_us, slowclk_period); + param->hp_sys.analog_wait_target_cycle = rtc_time_us_to_fastclk(mc->hp.analog_wait_time_us, fastclk_period); + param->hp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_supply_wait_time_us, fastclk_period); + param->hp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_up_wait_time_us, fastclk_period); + param->hp_sys.pll_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.pll_wait_stable_time_us, fastclk_period); + param->hp_sys.isolate_wait_cycle = rtc_time_us_to_fastclk(mc->hp.isolate_wait_time_us, fastclk_period); + param->hp_sys.reset_wait_cycle = rtc_time_us_to_fastclk(mc->hp.reset_wait_time_us, fastclk_period); + + param->lp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.min_slp_time_us, slowclk_period); + param->lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(mc->lp.analog_wait_time_us, slowclk_period); + param->lp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_supply_wait_time_us, fastclk_period); + param->lp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_up_wait_time_us, fastclk_period); + param->lp_sys.isolate_wait_cycle = rtc_time_us_to_fastclk(mc->lp.isolate_wait_time_us, fastclk_period); + param->lp_sys.reset_wait_cycle = rtc_time_us_to_fastclk(mc->lp.reset_wait_time_us, fastclk_period); + + if (power->hp_sys.xtal.xpd_xtal) { + param->hp_lp.xtal_stable_wait_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.xtal_wait_stable_time_us, slowclk_period); + } else { + param->hp_lp.xtal_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.xtal_wait_stable_time_us, fastclk_period); + } + return param; +} + +const pmu_sleep_config_t* pmu_sleep_config_default( + pmu_sleep_config_t *config, + uint32_t sleep_flags, + uint32_t clk_flags, + uint32_t adjustment, + soc_rtc_slow_clk_src_t slowclk_src, + uint32_t slowclk_period, + uint32_t fastclk_period, + bool dslp + ) +{ + pmu_sleep_power_config_t power_default = PMU_SLEEP_POWER_CONFIG_DEFAULT(sleep_flags); + + if (dslp) { + config->param.lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US, slowclk_period); + + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags); + config->digital = digital_default; + + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(sleep_flags); + config->analog = analog_default; + } else { + // Get light sleep digital_default + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags); + config->digital = digital_default; + + // Get light sleep analog default + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags); + + if (!(sleep_flags & PMU_SLEEP_PD_XTAL)) + { + // Analog parameters in HP_SLEEP + analog_default.hp_sys.analog.pd_cur = PMU_PD_CUR_SLEEP_ON; + analog_default.hp_sys.analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; + analog_default.hp_sys.analog.dbg_atten = PMU_DBG_ATTEN_ACTIVE_DEFAULT; + analog_default.hp_sys.analog.dbias = HP_CALI_ACTIVE_DBIAS_DEFAULT; + + // Analog parameters in LP_SLEEP + analog_default.lp_sys[LP(SLEEP)].analog.pd_cur = PMU_PD_CUR_SLEEP_ON; + analog_default.lp_sys[LP(SLEEP)].analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; + analog_default.lp_sys[LP(SLEEP)].analog.dbg_atten = PMU_DBG_ATTEN_ACTIVE_DEFAULT; + } + config->analog = analog_default; + } + + if (sleep_flags & RTC_SLEEP_XTAL_AS_RTC_FAST) { + // Keep XTAL on in HP_SLEEP state if it is the clock source of RTC_FAST + power_default.hp_sys.xtal.xpd_xtal = 1; + config->analog.hp_sys.analog.pd_cur = PMU_PD_CUR_SLEEP_ON; + config->analog.hp_sys.analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; + config->analog.hp_sys.analog.dbg_atten = PMU_DBG_ATTEN_ACTIVE_DEFAULT; + config->analog.hp_sys.analog.dbias = HP_CALI_ACTIVE_DBIAS_DEFAULT; + } + + config->power = power_default; + pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(sleep_flags); + config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, sleep_flags, adjustment, slowclk_src, slowclk_period, fastclk_period); + + return config; +} + +static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_config_t *power, bool dslp) +{ + pmu_ll_hp_set_dig_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.dig_power.val); + pmu_ll_hp_set_clk_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.clk_power.val); + pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, HP(SLEEP), power->hp_sys.xtal.xpd_xtal); + + pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].dig_power.val); + pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].clk_power.val); + + pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].dig_power.val); + pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].clk_power.val); + pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].xtal.xpd_xtal); +} + +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig) +{ + pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, HP(SLEEP), dig->syscntl.lp_pad_hold_all); + pmu_ll_hp_set_c_channel_enable (ctx->hal->dev, HP(SLEEP), dig->syscntl.c_channel); +} + +static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) +{ + assert(ctx->hal); + pmu_ll_hp_set_current_power_off (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.pd_cur); + pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.bias_sleep); + pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_xpd); + pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_xpd); + pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd); + pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_dbias); + 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); + + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.slp_dbias); + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.dbias); + pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.drv_b); + + 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); + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.slp_xpd); + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.slp_dbias); + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbias); + pmu_ll_lp_set_dbg_atten (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbg_atten); + pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.drv_b); + + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.slp_xpd); + pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.xpd); +} + +static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_config_t *param, bool dslp) +{ + assert(ctx->hal); + pmu_ll_hp_set_min_sleep_cycle(ctx->hal->dev, param->hp_sys.min_slp_slow_clk_cycle); + pmu_ll_lp_set_min_sleep_cycle(ctx->hal->dev, param->lp_sys.min_slp_slow_clk_cycle); + + pmu_ll_hp_set_analog_wait_target_cycle(ctx->hal->dev, param->hp_sys.analog_wait_target_cycle); + pmu_ll_lp_set_analog_wait_target_cycle(ctx->hal->dev, param->lp_sys.analog_wait_target_cycle); + + pmu_hal_hp_set_digital_power_up_wait_cycle(ctx->hal, param->hp_sys.digital_power_supply_wait_cycle, param->hp_sys.digital_power_up_wait_cycle); + pmu_hal_lp_set_digital_power_up_wait_cycle(ctx->hal, param->lp_sys.digital_power_supply_wait_cycle, param->lp_sys.digital_power_up_wait_cycle); + + pmu_hal_hp_set_control_ready_wait_cycle(ctx->hal, param->hp_sys.isolate_wait_cycle, param->hp_sys.reset_wait_cycle); + pmu_hal_lp_set_control_ready_wait_cycle(ctx->hal, param->lp_sys.isolate_wait_cycle, param->lp_sys.reset_wait_cycle); + + pmu_ll_set_xtal_stable_wait_cycle(ctx->hal->dev, param->hp_lp.xtal_stable_wait_slow_clk_cycle); + pmu_ll_set_pll_stable_wait_cycle(ctx->hal->dev, param->hp_sys.pll_stable_wait_cycle); +} + +bool pmu_sleep_pll_already_enabled(void) +{ + return (pmu_ll_get_sysclk_sleep_select_state(PMU_instance()->hal->dev) != 0); +} + +void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) +{ + assert(PMU_instance()); + pmu_sleep_power_init(PMU_instance(), &config->power, dslp); + pmu_sleep_digital_init(PMU_instance(), &config->digital); + pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); + pmu_sleep_param_init(PMU_instance(), &config->param, dslp); +} + +IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) +{ + lp_aon_hal_inform_wakeup_type(dslp); + + pmu_ll_hp_set_wakeup_enable(&PMU, wakeup_opt); + pmu_ll_hp_set_reject_enable(&PMU, reject_opt); + + pmu_ll_hp_clear_wakeup_intr_status(&PMU); + pmu_ll_hp_clear_reject_intr_status(&PMU); + pmu_ll_hp_clear_reject_cause(&PMU); + + /* Start entry into sleep mode */ + pmu_ll_hp_set_sleep_enable(&PMU); + + while (!pmu_ll_hp_is_sleep_wakeup(&PMU) && + !pmu_ll_hp_is_sleep_reject(&PMU)) { + ; + } + return pmu_sleep_finish(dslp); +} + +IRAM_ATTR uint32_t pmu_sleep_get_wakeup_cause(void) +{ + return pmu_ll_hp_get_wakeup_cause(PMU_instance()->hal->dev); +} +IRAM_ATTR uint32_t pmu_sleep_get_reject_cause(void) +{ + return pmu_ll_hp_get_reject_cause(PMU_instance()->hal->dev); +} + +IRAM_ATTR bool pmu_sleep_finish(bool dslp) +{ +#ifndef CONFIG_IDF_ENV_FPGA + // Wait eFuse memory update done. + while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); +#endif + return pmu_ll_hp_is_sleep_reject(&PMU); +} + +uint32_t pmu_sleep_get_wakup_retention_cost(void) +{ + return 685; +} diff --git a/components/esp_hw_support/port/esp32s31/private_include/pmu_bit_defs.h b/components/esp_hw_support/port/esp32s31/private_include/pmu_bit_defs.h new file mode 100644 index 0000000000..b0fa33c2d2 --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/private_include/pmu_bit_defs.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define PMU_SDIO_WAKEUP_EN BIT(0) +#define PMU_LP_CORE_WAKEUP_EN BIT(1) +#define PMU_GPIO_WAKEUP_EN BIT(2) +#define PMU_USB_WAKEUP_EN BIT(3) +#define PMU_UART4_WAKEUP_EN BIT(4) +#define PMU_UART3_WAKEUP_EN BIT(5) +#define PMU_UART2_WAKEUP_EN BIT(6) +#define PMU_UART1_WAKEUP_EN BIT(7) +#define PMU_UART0_WAKEUP_EN BIT(8) +#define PMU_LP_GPIO_WAKEUP_EN BIT(9) +#define PMU_LP_UART_WAKEUP_EN BIT(10) +#define PMU_TOUCH_WAKEUP_EN BIT(11) +#define PMU_EXT1_WAKEUP_EN BIT(12) +#define PMU_LP_TIMER_WAKEUP_EN BIT(13) +#define PMU_BOD_WAKEUP_EN BIT(14) +#define PMU_VBAT_UNDERVOLT_WAKEUP_EN BIT(15) +#define PMU_LP_CORE_TRAP_WAKEUP_EN BIT(16) +#define PMU_ETM_WAKEUP_EN BIT(17) +#define PMU_LP_TIMER1_WAKEUP_EN BIT(18) +#define PMU_LP_I2S_WAKEUP_EN BIT(19) +#define PMU_WIFI_SOC_WAKEUP_EN BIT(22) +#define PMU_WIFI_BEACON_WAKEUP_EN BIT(23) +#define PMU_BLE_SOC_WAKEUP_EN BIT(24) + + +// BIT order in PLL control registers in PMU +#define PMU_CPLL_CTRL BIT(0) +#define PMU_SPLL_CTRL BIT(1) +#define PMU_APLL_CTRL BIT(2) +#define PMU_SDIOPLL_CTRL BIT(3) + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32s31/private_include/pmu_param.h b/components/esp_hw_support/port/esp32s31/private_include/pmu_param.h new file mode 100644 index 0000000000..92137f4d3c --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/private_include/pmu_param.h @@ -0,0 +1,526 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "soc/pmu_struct.h" +#include "hal/pmu_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HP_CALI_DBIAS_DEFAULT 28 +#define LP_CALI_DBIAS_DEFAULT 28 +#define HP_CALI_DBIAS_SLP_1V1 22 +#define LP_CALI_DBIAS_SLP_1V1 22 + +#define HP_CALI_ACTIVE_DBIAS_DEFAULT 24 // For HP regulator + +// FOR XTAL FORCE PU IN SLEEP +#define PMU_PD_CUR_SLEEP_ON 0 +#define PMU_BIASSLP_SLEEP_ON 0 + +// FOR BOTH LIGHTSLEEP & DEEPSLEEP +#define PMU_PD_CUR_SLEEP_DEFAULT 1 +#define PMU_BIASSLP_SLEEP_DEFAULT 1 +#define PMU_LP_XPD_SLEEP_DEFAULT 1 +#define PMU_LP_SLP_XPD_SLEEP_DEFAULT 0 +#define PMU_LP_SLP_DBIAS_SLEEP_DEFAULT 0 + +// FOR LIGHTSLEEP +#define PMU_HP_DRVB_LIGHTSLEEP 0 +#define PMU_LP_DRVB_LIGHTSLEEP 0 +#define PMU_HP_XPD_LIGHTSLEEP 1 + +#define PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT 0 +#define PMU_HP_DBIAS_LIGHTSLEEP_0V6 1 +#define PMU_LP_DBIAS_LIGHTSLEEP_0V7 12 + +// FOR LIGHTSLEEP: XTAL FORCE PU +#define PMU_DBG_ATTEN_ACTIVE_DEFAULT 0 + +// FOR DEEPSLEEP +#define PMU_DBG_HP_DEEPSLEEP 0 +#define PMU_HP_XPD_DEEPSLEEP 0 +#define PMU_LP_DRVB_DEEPSLEEP 0 + +#define PMU_DBG_ATTEN_DEEPSLEEP_DEFAULT 12 +#define PMU_LP_DBIAS_DEEPSLEEP_0V7 23 + +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 { + struct { + uint32_t clock[2]; + } icg_func; + struct { + uint32_t clock[2]; + } 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[2]; +} 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); + + +/* Following software configuration instance type from pmu_struct.h used for the PMU state machine in sleep flow*/ +typedef union { + struct { + uint32_t reserved_0 : 20; + uint32_t vdd_spi_pd_en : 1; + uint32_t pd_hp_alive_pd_en : 1; + uint32_t mem_dslp : 1; + uint32_t pd_hp_mem_pd_en : 4; + uint32_t pd_modem_top_pd_en: 1; + uint32_t pd_hp_cnnt_pd_en : 1; + uint32_t pd_hp_cpu_pd_en : 1; + uint32_t pd_modem_pwr_pd_en: 1; + uint32_t pd_top_pd_en : 1; + }; + struct { + uint32_t reserved_1 : 19; + uint32_t xpd_xtalx2 : 1; + uint32_t i2c_iso_en : 1; + uint32_t i2c_retention : 1; + uint32_t xpd_bb_i2c : 1; + uint32_t xpd_pll_i2c : 4; + uint32_t xpd_pll : 4; + uint32_t reserved_2 : 1; + }; + struct { + uint32_t reserved_3 : 31; + uint32_t xpd_xtal : 1; + }; + uint32_t val; +} pmu_hp_power_t; + +typedef union { + struct { + uint32_t reserved_0 : 30; + uint32_t mem_dslp : 1; + uint32_t peri_pd_en : 1; + }; + struct { + uint32_t reserved_1 : 28; + uint32_t xpd_xtal32k: 1; + uint32_t xpd_rc32k : 1; + uint32_t xpd_fosc : 1; + uint32_t pd_osc : 1; + }; + struct { + uint32_t reserved_2 : 31; + uint32_t xpd_xtal : 1; + }; + uint32_t val; +} pmu_lp_power_t; + +typedef struct { + struct { + uint32_t reserved_0 : 25; + uint32_t xpd_bias : 1; + uint32_t dbg_atten : 4; + uint32_t pd_cur : 1; + uint32_t bias_sleep : 1; + }; + struct { + uint32_t reserved_1 : 15; + uint32_t slp_connect_en : 1; + uint32_t slp_mem_xpd : 1; + uint32_t slp_logic_xpd : 1; + uint32_t xpd : 1; + uint32_t slp_mem_dbias : 4; + uint32_t slp_logic_dbias: 4; + uint32_t dbias : 5; + }; + struct { + uint32_t reserved_2 : 8; + uint32_t drv_b : 24; + }; +} pmu_hp_analog_t; + +typedef struct { + struct { + uint32_t reserved_0: 25; + uint32_t xpd_bias : 1; + uint32_t dbg_atten : 4; + uint32_t pd_cur : 1; + uint32_t bias_sleep: 1; + }; + struct { + uint32_t reserved_1: 21; + uint32_t slp_xpd : 1; + uint32_t xpd : 1; + uint32_t slp_dbias : 4; + uint32_t dbias : 5; + }; + struct { + uint32_t reserved_2: 28; + uint32_t drv_b : 4; + }; +} pmu_lp_analog_t; + +typedef struct { + uint32_t modem_wakeup_wait_cycle; + uint16_t analog_wait_target_cycle; + uint16_t digital_power_down_wait_cycle; + uint16_t digital_power_supply_wait_cycle; + uint16_t digital_power_up_wait_cycle; + uint16_t pll_stable_wait_cycle; + uint8_t modify_icg_cntl_wait_cycle; + uint8_t switch_icg_cntl_wait_cycle; + uint8_t min_slp_slow_clk_cycle; + uint8_t isolate_wait_cycle; + uint8_t reset_wait_cycle; +} pmu_hp_param_t; + +typedef struct { + uint16_t digital_power_supply_wait_cycle; + uint8_t min_slp_slow_clk_cycle; + uint8_t analog_wait_target_cycle; + uint8_t digital_power_down_wait_cycle; + uint8_t digital_power_up_wait_cycle; + uint8_t isolate_wait_cycle; + uint8_t reset_wait_cycle; +} pmu_lp_param_t; + +typedef struct { + union { + uint16_t xtal_stable_wait_slow_clk_cycle; + uint16_t xtal_stable_wait_cycle; + }; +} pmu_hp_lp_param_t; + +#define PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES (10) +#define PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES (10) + +#define PMU_HP_WAKEUP_DELAY_CYCLES (0) +#define PMU_HP_XTAL_STABLE_WAIT_CYCLES (3155) /* Not used, Fast OSC as PMU work clock source is about 201 us, corresponding to PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES */ +#define PMU_HP_PLL_STABLE_WAIT_CYCLES (2) +#define PMU_HP_ANALOG_WAIT_TARGET_CYCLES (23) /* Slow OSC as PMU work clock source is about 400 us */ +#define PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32) +#define PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES (32) +#define PMU_HP_MODEM_WAKEUP_WAIT_CYCLES (20700) /* Fast OSC as PMU work clock source is about 1318.6 us */ + +#define PMU_LP_WAKEUP_DELAY_CYCLES (0) +#define PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES (30) /* Slow OSC as PMU slow clock source is about 201 us */ +#define PMU_LP_ANALOG_WAIT_TARGET_CYCLES (23) /* Slow OSC as PMU slow clock source is about 154 us */ +#define PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */ +#define PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */ + +#define PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US (500) /* Slow OSC as PMU slow clock source in deepsleep is about 500 us */ + +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; + +#define PMU_SLEEP_POWER_CONFIG_DEFAULT(sleep_flags) { \ + .hp_sys = { \ + .dig_power = { \ + .vdd_spi_pd_en = ((sleep_flags) & PMU_SLEEP_PD_VDDSDIO) ? 1 : 0, \ + .pd_hp_alive_pd_en = 0, \ + .pd_modem_top_pd_en = ((sleep_flags) & PMU_SLEEP_PD_MODEM) ? 1 : 0, \ + .pd_hp_cnnt_pd_en = ((sleep_flags) & PMU_SLEEP_PD_CNNT) ? 1 : 0, \ + .pd_hp_cpu_pd_en = ((sleep_flags) & PMU_SLEEP_PD_CPU) ? 1 : 0, \ + .pd_modem_pwr_pd_en = 0, \ + .pd_top_pd_en = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 1 : 0, \ + .pd_hp_mem_pd_en = 0, \ + .mem_dslp = 0, \ + }, \ + .clk_power = { \ + .xpd_xtalx2 = 0, \ + .i2c_iso_en = 1, \ + .i2c_retention = 1, \ + .xpd_bb_i2c = 0, \ + .xpd_pll_i2c = 0, \ + .xpd_pll = 0 \ + }, \ + .xtal = { \ + .xpd_xtal = ((sleep_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_ACTIVE] = { \ + .dig_power = { \ + .peri_pd_en = 0, \ + .mem_dslp = 0 \ + }, \ + .clk_power = { \ + .xpd_xtal32k = ((sleep_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1, \ + .xpd_rc32k = ((sleep_flags) & PMU_SLEEP_PD_RC32K) ? 0 : 1, \ + .xpd_fosc = 1 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .dig_power = { \ + .peri_pd_en = ((sleep_flags) & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ + .mem_dslp = 0 \ + }, \ + .clk_power = { \ + .xpd_xtal32k = ((sleep_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1, \ + .xpd_rc32k = ((sleep_flags) & PMU_SLEEP_PD_RC32K) ? 0 : 1, \ + .xpd_fosc = ((sleep_flags) & PMU_SLEEP_PD_RC_FAST) ? 0 : 1 \ + }, \ + .xtal = { \ + .xpd_xtal = ((sleep_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \ + } \ + } \ +} + +typedef struct { + pmu_hp_sys_cntl_reg_t syscntl; +} pmu_sleep_digital_config_t; + + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 0, \ + .lp_pad_hold_all = (sleep_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ + .c_channel = (sleep_flags & PMU_SLEEP_PD_TOP) ? 0 : 1 \ + } \ +} + +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 0, \ + .lp_pad_hold_all = (sleep_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ + .c_channel = (sleep_flags & PMU_SLEEP_PD_TOP) ? 0 : 1 \ + } \ +} + +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; + +#define PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags) { \ + .hp_sys = { \ + .analog = { \ + .drv_b = PMU_HP_DRVB_LIGHTSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .xpd = PMU_HP_XPD_LIGHTSLEEP, \ + .dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT, \ + .dbias = PMU_HP_DBIAS_LIGHTSLEEP_0V6 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_ACTIVE] = { \ + .analog = { \ + .slp_xpd = 0, \ + .slp_dbias = 0, \ + .xpd = 1, \ + .dbias = 29, \ + .drv_b = 0x0 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .analog = { \ + .drv_b = PMU_LP_DRVB_LIGHTSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .slp_xpd = PMU_LP_SLP_XPD_SLEEP_DEFAULT, \ + .slp_dbias = PMU_LP_SLP_DBIAS_SLEEP_DEFAULT, \ + .xpd = PMU_LP_XPD_SLEEP_DEFAULT, \ + .dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT, \ + .dbias = PMU_LP_DBIAS_LIGHTSLEEP_0V7 \ + } \ + } \ +} + +#define PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(sleep_flags) { \ + .hp_sys = { \ + .analog = { \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .xpd = PMU_HP_XPD_DEEPSLEEP, \ + .dbg_atten = PMU_DBG_HP_DEEPSLEEP \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_ACTIVE] = { \ + .analog = { \ + .xpd = 1, \ + .dbias = 0x1a, \ + .slp_xpd = 0, \ + .slp_dbias = 0, \ + .drv_b = 0x7 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .analog = { \ + .drv_b = PMU_LP_DRVB_DEEPSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .slp_xpd = PMU_LP_SLP_XPD_SLEEP_DEFAULT, \ + .slp_dbias = PMU_LP_SLP_DBIAS_SLEEP_DEFAULT, \ + .xpd = PMU_LP_XPD_SLEEP_DEFAULT, \ + .dbg_atten = PMU_DBG_ATTEN_DEEPSLEEP_DEFAULT, \ + .dbias = PMU_LP_DBIAS_DEEPSLEEP_0V7 \ + } \ + } \ +} + +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; + +#define PMU_SLEEP_PARAM_CONFIG_DEFAULT(sleep_flags) { \ + .hp_sys = { \ + .min_slp_slow_clk_cycle = PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES, \ + .analog_wait_target_cycle = PMU_HP_ANALOG_WAIT_TARGET_CYCLES, \ + .digital_power_supply_wait_cycle = PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \ + .digital_power_up_wait_cycle = PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES, \ + .modem_wakeup_wait_cycle = PMU_HP_MODEM_WAKEUP_WAIT_CYCLES, \ + .pll_stable_wait_cycle = PMU_HP_PLL_STABLE_WAIT_CYCLES \ + }, \ + .lp_sys = { \ + .min_slp_slow_clk_cycle = PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES, \ + .analog_wait_target_cycle = PMU_LP_ANALOG_WAIT_TARGET_CYCLES, \ + .digital_power_supply_wait_cycle = PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \ + .digital_power_up_wait_cycle = PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES \ + }, \ + .hp_lp = { \ + .xtal_stable_wait_slow_clk_cycle = PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES \ + } \ +} + +typedef struct { + pmu_sleep_power_config_t power; + pmu_sleep_digital_config_t digital; + pmu_sleep_analog_config_t analog; + pmu_sleep_param_config_t param; +} pmu_sleep_config_t; + +typedef struct pmu_sleep_machine_constant { + struct { + uint16_t min_slp_time_us; /* Minimum sleep protection time (unit: microsecond) */ + uint8_t wakeup_wait_cycle; /* Modem wakeup signal (WiFi MAC and BEACON wakeup) waits for the slow & fast clock domain synchronization and the wakeup signal triggers the PMU FSM switching wait cycle (unit: slow clock cycle) */ + uint8_t reserved0; + uint16_t reserved1; + uint16_t analog_wait_time_us; /* LP LDO power up wait time (unit: microsecond) */ + uint16_t xtal_wait_stable_time_us; /* Main XTAL stabilization wait time (unit: microsecond) */ + uint8_t clk_switch_cycle; /* Clock switch to FOSC (unit: slow clock cycle) */ + uint8_t clk_power_on_wait_cycle; /* Clock power on wait cycle (unit: slow clock cycle) */ + uint8_t isolate_wait_time_us; /* Waiting for all isolate signals to be ready (unit: microsecond) */ + uint8_t reset_wait_time_us; /* Waiting for all reset signals to be ready (unit: microsecond) */ + uint16_t power_supply_wait_time_us; /* (unit: microsecond) */ + uint16_t power_up_wait_time_us; /* (unit: microsecond) */ + } lp; + struct { + uint16_t min_slp_time_us; /* Minimum sleep protection time (unit: microsecond) */ + uint16_t clock_domain_sync_time_us; /* The Slow OSC clock domain synchronizes time with the Fast OSC domain, at least 4 slow clock cycles (unit: microsecond) */ + uint16_t system_dfs_up_work_time_us; /* System DFS up scaling work time (unit: microsecond) */ + uint16_t analog_wait_time_us; /* HP LDO power up wait time (unit: microsecond) */ + uint8_t isolate_wait_time_us; /* Waiting for all isolate signals to be ready (unit: microsecond) */ + uint8_t reset_wait_time_us; /* Waiting for all reset signals to be ready (unit: microsecond) */ + uint16_t power_supply_wait_time_us; /* (unit: microsecond) */ + uint16_t power_up_wait_time_us; /* (unit: microsecond) */ + uint16_t regdma_s2m_work_time_us; /* Modem Subsystem (S2M switch) REGDMA restore time (unit: microsecond) */ + uint16_t regdma_s2a_work_time_us; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (S2A switch) restore time (unit: microsecond) */ + uint16_t regdma_m2a_work_time_us; /* Digital Peripheral (M2A switch) REGDMA restore time (unit: microsecond) */ + uint16_t regdma_a2s_work_time_us; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (A2S switch) backup time (unit: microsecond) */ + uint16_t regdma_rf_on_work_time_us; /* The REGDMA work time of RF enable (unit: microsecond) */ + uint16_t regdma_rf_off_work_time_us; /* The REGDMA work time of RF disable (unit: microsecond) */ + uint16_t xtal_wait_stable_time_us; /* Main XTAL stabilization wait time (unit: microsecond) */ + uint16_t pll_wait_stable_time_us; /* PLL stabilization wait time (unit: microsecond) */ + } hp; +} pmu_sleep_machine_constant_t; + +#define PMU_SLEEP_MC_DEFAULT() { \ + .lp = { \ + .min_slp_time_us = 450, \ + .wakeup_wait_cycle = 4, \ + .analog_wait_time_us = 154, \ + .xtal_wait_stable_time_us = 250, \ + .clk_switch_cycle = 1, \ + .clk_power_on_wait_cycle = 1, \ + .isolate_wait_time_us = 1, \ + .reset_wait_time_us = 1, \ + .power_supply_wait_time_us = 2, \ + .power_up_wait_time_us = 2 \ + }, \ + .hp = { \ + .min_slp_time_us = 450, \ + .clock_domain_sync_time_us = 150, \ + .system_dfs_up_work_time_us = 124, \ + .analog_wait_time_us = 154, \ + .isolate_wait_time_us = 1, \ + .reset_wait_time_us = 1, \ + .power_supply_wait_time_us = 2, \ + .power_up_wait_time_us = 2, \ + .regdma_s2m_work_time_us = 172, \ + .regdma_s2a_work_time_us = 685, \ + .regdma_m2a_work_time_us = 278, \ + .regdma_a2s_work_time_us = 382, \ + .regdma_rf_on_work_time_us = 70, \ + .regdma_rf_off_work_time_us = 23, \ + .xtal_wait_stable_time_us = 250, \ + .pll_wait_stable_time_us = 50 \ + } \ +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_system/port/soc/esp32s31/clk.c b/components/esp_system/port/soc/esp32s31/clk.c index db8c07b69b..4044067145 100644 --- a/components/esp_system/port/soc/esp32s31/clk.c +++ b/components/esp_system/port/soc/esp32s31/clk.c @@ -33,6 +33,7 @@ #include "esp_private/esp_sleep_internal.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" +#include "esp_private/esp_pmu.h" #include "esp_rom_serial_output.h" #include "esp_rom_sys.h" diff --git a/components/hal/esp32s31/include/hal/pmu_hal.h b/components/hal/esp32s31/include/hal/pmu_hal.h new file mode 100644 index 0000000000..81a21a4dbd --- /dev/null +++ b/components/hal/esp32s31/include/hal/pmu_hal.h @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The HAL layer for PMU + +#pragma once + +#include "soc/soc_caps.h" +#include "hal/pmu_ll.h" +#include "hal/pmu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + pmu_dev_t *dev; +} pmu_hal_context_t; + +void pmu_hal_hp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle); + +uint32_t pmu_hal_hp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal); + +void pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle); + +uint32_t pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle); + +void pmu_hal_lp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle); + +void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_modem_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_sleep_modem_backup_disable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_modem_active_backup_enable(pmu_hal_context_t *hal); + +void pmu_hal_hp_set_modem_active_backup_disable(pmu_hal_context_t *hal); + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 484a98ae06..7a226323dc 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1703,10 +1703,6 @@ config SOC_PM_EXT1_WAKEUP_BY_PMU bool default y -config SOC_PM_SUPPORT_WIFI_WAKEUP - bool - default y - config SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index c976e68a14..e2257b8448 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -653,7 +653,6 @@ #define SOC_PM_SUPPORT_EXT1_WAKEUP (1) #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*!