From b113517e707ff2d80bd9f5b586bc75a0f9a3038d Mon Sep 17 00:00:00 2001 From: hebinglin Date: Thu, 6 Nov 2025 19:25:20 +0800 Subject: [PATCH] feat(esp_hw_support): support lp uart wakeup during sleep v6.0 --- components/esp_driver_uart/src/uart_wakeup.c | 81 ++++++++++++---- .../include/esp_private/esp_pmu.h | 1 + .../include/esp_private/esp_sleep_internal.h | 19 ++++ .../esp_hw_support/port/esp32c5/pmu_sleep.c | 6 ++ .../esp_hw_support/port/esp32c6/pmu_sleep.c | 7 ++ .../esp_hw_support/port/esp32p4/pmu_sleep.c | 7 +- components/esp_hw_support/sleep_modes.c | 96 +++++++++++++++++-- .../hal/esp32c5/include/hal/clk_gate_ll.h | 13 +++ .../hal/esp32c6/include/hal/clk_gate_ll.h | 13 +++ .../hal/esp32p4/include/hal/clk_gate_ll.h | 15 +++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../buildv2_test_app/README.md | 3 + 13 files changed, 237 insertions(+), 29 deletions(-) diff --git a/components/esp_driver_uart/src/uart_wakeup.c b/components/esp_driver_uart/src/uart_wakeup.c index 8412487a1e..c4afcb07b4 100644 --- a/components/esp_driver_uart/src/uart_wakeup.c +++ b/components/esp_driver_uart/src/uart_wakeup.c @@ -17,6 +17,10 @@ #include "esp_private/esp_sleep_internal.h" #include "esp_log.h" +#if (SOC_UART_LP_NUM >= 1) +#include "soc/rtc.h" +#endif + const __attribute__((unused)) static char *TAG = "uart_wakeup"; #if SOC_UART_WAKEUP_SUPPORT_CHAR_SEQ_MODE @@ -62,24 +66,48 @@ esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg) }; soc_module_clk_t src_clk; uart_hal_get_sclk(&hal, &src_clk); - if (uart_num < SOC_UART_HP_NUM && cfg->wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { - // For wakeup modes except ACTIVE_THRESH, the function clock needs to be exist to trigger wakeup - ESP_RETURN_ON_FALSE(src_clk == SOC_MOD_CLK_XTAL, ESP_ERR_NOT_SUPPORTED, TAG, "failed to setup uart wakeup due to the clock source is not XTAL!"); - } esp_err_t ret = ESP_OK; // This should be mocked at ll level if the selection of the UART wakeup mode is not supported by this SOC. uart_ll_set_wakeup_mode(hw, cfg->wakeup_mode); + // When uarts are utilized, the src clk(hp_uart: main XTAL, lp_uart: RTC_FAST or XTAL_D2) need to be PU and ungate,and for hp uart UARTx & IOMX ICG need to be ungate + if (cfg->wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { + if (uart_num < SOC_UART_HP_NUM) { + // For wakeup modes except ACTIVE_THRESH, the function clock needs to be exist to trigger wakeup + ESP_RETURN_ON_FALSE(src_clk == SOC_MOD_CLK_XTAL, ESP_ERR_NOT_SUPPORTED, TAG, "failed to setup uart wakeup due to the clock source is not XTAL!"); #if SOC_PM_SUPPORT_PMU_CLK_ICG - // When hp uarts are utilized, the main XTAL need to be PU and UARTx & IOMX ICG need to be ungate - if (uart_num < SOC_UART_HP_NUM && cfg->wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { - esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); - esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_UNGATE); - esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_UNGATE); - } + esp_sleep_sub_mode_config(ESP_SLEEP_DIG_USE_XTAL_MODE, true); + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_UNGATE); + esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_UNGATE); #endif +#if (SOC_UART_LP_NUM >= 1) + } else { + // When lp uarts are utilized, the src clk need to be power up and lp clock need to be ungate + if ((src_clk == SOC_MOD_CLK_RTC_FAST && rtc_clk_fast_src_get() == SOC_RTC_FAST_CLK_SRC_RC_FAST) || (src_clk == SOC_MOD_CLK_RC_FAST)) { + esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_RC_FAST_MODE, true); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + } else if (src_clk == SOC_MOD_CLK_XTAL_D2) { +#if SOC_XTAL_CLOCK_PATH_DEPENDS_ON_TOP_DOMAIN + // TODO: PM-533 + // Currently, ESP32C5 and ESP32C6 don't support this feature temporarily. + ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "Not support when the source clock of the LP UART is XTAL_D2, and lp uart will be powered down."); +#else + // ESP32P4 supports this feature. + esp_sleep_acquire_lp_use_xtal(); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + ESP_LOGW(TAG, "Not support When the source clock of the LP UART is XTAL_D2 during deep sleep."); +#endif +#if SOC_CLK_LP_FAST_SUPPORT_LP_PLL + } else if (src_clk == SOC_MOD_CLK_LP_PLL) { + ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "Not support When the source clock of the LP UART is lp_pll, and lp uart will be powered down."); +#endif + } +#endif + } + } switch (cfg->wakeup_mode) { #if SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE @@ -119,13 +147,34 @@ esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg) esp_err_t uart_wakeup_clear(uart_port_t uart_num, uart_wakeup_mode_t wakeup_mode) { + if (wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { + // When hp uarts are utilized, the main XTAL need to be PU and UARTx & IOMX ICG need to be ungate + if (uart_num < SOC_UART_HP_NUM) { #if SOC_PM_SUPPORT_PMU_CLK_ICG - // When hp uarts are utilized, the main XTAL need to be PU and UARTx & IOMX ICG need to be ungate - if (uart_num < SOC_UART_HP_NUM && wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { - esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_GATE); - esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_GATE); - esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF); - } + esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_GATE); + esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_GATE); + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF); + esp_sleep_sub_mode_config(ESP_SLEEP_DIG_USE_XTAL_MODE, false); #endif +#if (SOC_UART_LP_NUM >= 1) + } else { + uart_dev_t *hw = UART_LL_GET_HW(uart_num); + uart_hal_context_t hal = { + .dev = hw, + }; + soc_module_clk_t src_clk; + uart_hal_get_sclk(&hal, &src_clk); + if ((src_clk == SOC_MOD_CLK_RTC_FAST && rtc_clk_fast_src_get() == SOC_RTC_FAST_CLK_SRC_RC_FAST) || (src_clk == SOC_MOD_CLK_RC_FAST)) { + esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_RC_FAST_MODE, false); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); + } else if (src_clk == SOC_MOD_CLK_XTAL_D2) { +#if !SOC_XTAL_CLOCK_PATH_DEPENDS_ON_TOP_DOMAIN + esp_sleep_release_lp_use_xtal(); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); +#endif + } +#endif + } + } return ESP_OK; } diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index 6200249da1..b12b24c99c 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -47,6 +47,7 @@ typedef enum { #define RTC_SLEEP_PD_MODEM PMU_SLEEP_PD_MODEM //!< Power down modem(include wifi, ble and 15.4) //These flags are not power domains, but will affect some sleep parameters +#define RTC_SLEEP_LP_PERIPH_USE_RC_FAST BIT(25) #define RTC_SLEEP_POWER_BY_VBAT BIT(26) #define RTC_SLEEP_DIG_USE_8M BIT(27) #define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(28) diff --git a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h index ec53ba31d8..e9c5a569fe 100644 --- a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h +++ b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h @@ -39,6 +39,7 @@ typedef enum { ESP_SLEEP_RTC_FAST_USE_XTAL_MODE, //!< The mode in which the crystal is used as the RTC_FAST clock source, need keep XTAL on in HP_SLEEP mode when ULP is working. ESP_SLEEP_DIG_USE_XTAL_MODE, //!< The mode requested by digital peripherals to keep XTAL clock on during sleep (both HP_SLEEP and LP_SLEEP mode). (!!! Only valid for lightsleep, will override the XTAL domain config by esp_sleep_pd_config) ESP_SLEEP_LP_USE_XTAL_MODE, //!< The mode requested by lp peripherals to keep XTAL clock on during sleep. Only valid for lightsleep. + ESP_SLEEP_LP_USE_RC_FAST_MODE, //!< The mode requested by lp peripherals to keep FOSC clock on during sleep. ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE, //!< The mode to switch power supply to VBAT during deep sleep. #if CONFIG_IDF_TARGET_ESP32 ESP_SLEEP_ANALOG_LOW_POWER_MODE, //!< If analog-related peripherals(ADC, TSENS, TOUCH) is not used in monitor mode, analog low power mode can be enabled to reduce power consumption (~300uA) in monitor state. @@ -78,6 +79,24 @@ esp_err_t esp_sleep_sub_mode_force_disable(esp_sleep_sub_mode_t mode); */ int32_t* esp_sleep_sub_mode_dump_config(FILE *stream); +#if SOC_PM_SUPPORT_RTC_PERIPH_PD +/** + * @brief Enable LP peripherals to use XTAL during sleep + * + * @return + * - ESP_OK on success + */ +esp_err_t esp_sleep_acquire_lp_use_xtal(void); + +/** + * @brief Disable LP peripherals to use XTAL during sleep + * + * @return + * - ESP_OK on success + */ +esp_err_t esp_sleep_release_lp_use_xtal(void); +#endif + #if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP /** * @brief Isolate all digital IOs except those that are held during deep sleep diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index 2fda0e71e4..d2bdfc3739 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -285,6 +285,12 @@ const pmu_sleep_config_t* pmu_sleep_config_default( config->analog.hp_sys.analog.dbias = get_act_hp_dbias(); } + if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_RC_FAST) { + config->analog.hp_sys.analog.dbias = get_act_hp_dbias(); + config->analog.lp_sys[LP(SLEEP)].analog.dbg_atten = 0; + config->analog.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); + } + 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); diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index 1a928885e4..399987e769 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -241,6 +241,7 @@ const pmu_sleep_config_t* pmu_sleep_config_default( pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(sleep_flags); analog_default.lp_sys[LP(SLEEP)].analog.dbg_atten = get_dslp_dbg(); analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_dslp_lp_dbias(); + config->analog = analog_default; } else { pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); @@ -279,6 +280,12 @@ const pmu_sleep_config_t* pmu_sleep_config_default( config->analog.hp_sys.analog.dbias = get_act_hp_dbias(); } + if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_RC_FAST) { + config->analog.hp_sys.analog.dbias = get_act_hp_dbias(); + config->analog.lp_sys[LP(SLEEP)].analog.dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_NODROP; + config->analog.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); + } + return config; } diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index dd7117ddaa..0064785ae6 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -30,7 +30,6 @@ #include "hal/pmu_hal.h" #include "hal/psram_ctrlr_ll.h" #include "hal/lp_sys_ll.h" -#include "hal/clk_gate_ll.h" #include "esp_private/esp_pmu.h" #include "pmu_param.h" #include "esp_rom_sys.h" @@ -224,8 +223,10 @@ const pmu_sleep_config_t* pmu_sleep_config_default( config->analog.hp_sys.analog.dbias = HP_CALI_ACTIVE_DBIAS_DEFAULT; } - if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_XTAL) { - _clk_gate_ll_xtal_to_lp_periph_en(true); + if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_RC_FAST) { + config->analog.hp_sys.analog.dbias = get_act_hp_dbias(); + config->analog.lp_sys[LP(SLEEP)].analog.dbg_atten = 0; + config->analog.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); } config->power = power_default; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 95d2326b2f..6730ae3838 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -101,9 +101,11 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/rtc.h" #include "hal/gpio_ll.h" +#include "hal/clk_gate_ll.h" #elif CONFIG_IDF_TARGET_ESP32C5 #include "esp32c5/rom/rtc.h" #include "hal/gpio_ll.h" +#include "hal/clk_gate_ll.h" #elif CONFIG_IDF_TARGET_ESP32C61 #include "esp32c61/rom/rtc.h" #include "hal/gpio_ll.h" @@ -123,6 +125,7 @@ #elif CONFIG_IDF_TARGET_ESP32P4 #include "esp32p4/rom/rtc.h" #include "hal/gpio_ll.h" +#include "hal/clk_gate_ll.h" #endif #if SOC_PM_SUPPORT_PMU_CLK_ICG @@ -710,6 +713,33 @@ static SLEEP_FN_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t return should_skip_sleep; } +/** + * LP peripherals prepare XTAL, FOSC or other clocks as the clock source for sleep. + */ +static SLEEP_FN_ATTR void lp_periph_use_clk_sleep_prepare(uint32_t sleep_flags, bool deep_sleep) +{ +#if SOC_PMU_SUPPORTED +#if CONFIG_IDF_TARGET_ESP32P4 + if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_XTAL) { + /* Force the xtal clk pass lp clock gate */ + _clk_gate_ll_xtal_to_lp_periph_en(true); + } else { + /* Set xtal lp clock gate controlled by hardware fsm */ + _clk_gate_ll_xtal_to_lp_periph_en(false); + } +#endif +#if SOC_LP_PERIPHERALS_SUPPORTED + if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_RC_FAST) { + /* Force the rtc_fast clk pass lp clock gate */ + _clk_gate_ll_rtc_fast_to_lp_periph_en(true); + } else { + /* Lp clock gate of rtc_fast clk is decided by FSM(PMU state)*/ + _clk_gate_ll_rtc_fast_to_lp_periph_en(false); + } +#endif +#endif +} + /** * These save-restore workaround should be moved to lower layer */ @@ -1107,6 +1137,9 @@ static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t cl } #endif + /* Prepare for LP peripherals to select a clock source. */ + lp_periph_use_clk_sleep_prepare(sleep_flags, deep_sleep); + // Enter sleep esp_err_t result; #if SOC_PMU_SUPPORTED @@ -1769,31 +1802,61 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) return ESP_OK; } -#if SOC_LP_VAD_SUPPORTED -esp_err_t esp_sleep_enable_vad_wakeup(void) +#if SOC_PM_SUPPORT_RTC_PERIPH_PD +esp_err_t esp_sleep_acquire_lp_use_xtal(void) { esp_err_t ret = ESP_FAIL; - ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "fail to keep rtc periph power on"); - return ret; - } - ret = esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); if (ret != ESP_OK) { ESP_LOGE(TAG, "fail to keep xtal power on"); return ret; } + ret = esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_XTAL_MODE, true); if (ret != ESP_OK) { ESP_LOGE(TAG, "fail to set to ESP_SLEEP_LP_USE_XTAL_MODE mode"); return ret; } - s_config.wakeup_triggers |= RTC_LP_VAD_TRIG_EN; return ESP_OK; } + +esp_err_t esp_sleep_release_lp_use_xtal(void) +{ + esp_err_t ret = ESP_FAIL; + + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "fail to keep xtal power off"); + return ret; + } + + ret = esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_XTAL_MODE, false); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "fail to disable ESP_SLEEP_LP_USE_XTAL_MODE mode"); + return ret; + } + + return ESP_OK; +} +#endif + +#if SOC_LP_VAD_SUPPORTED +esp_err_t esp_sleep_enable_vad_wakeup(void) +{ + esp_err_t ret = ESP_FAIL; + ret = esp_sleep_acquire_lp_use_xtal(); + + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "fail to keep rtc periph power on"); + return ret; + } + s_config.wakeup_triggers |= RTC_LP_VAD_TRIG_EN; + + return ret; +} #endif #if SOC_VBAT_SUPPORTED @@ -2210,6 +2273,10 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num) #if SOC_PMU_SUPPORTED && (SOC_UART_HP_NUM > 2) } else if (uart_num == UART_NUM_2) { s_config.wakeup_triggers |= RTC_UART2_TRIG_EN; +#endif +#if SOC_PM_SUPPORT_LP_UART_WAKEUP + } else if (uart_num == LP_UART_NUM_0) { + s_config.wakeup_triggers |= PMU_LP_UART_WAKEUP_EN; #endif } else { return ESP_ERR_INVALID_ARG; @@ -2503,6 +2570,7 @@ static const char* s_submode2str[] = { [ESP_SLEEP_RTC_FAST_USE_XTAL_MODE] = "ESP_SLEEP_RTC_FAST_USE_XTAL_MODE", [ESP_SLEEP_DIG_USE_XTAL_MODE] = "ESP_SLEEP_DIG_USE_XTAL_MODE", [ESP_SLEEP_LP_USE_XTAL_MODE] = "ESP_SLEEP_LP_USE_XTAL_MODE", + [ESP_SLEEP_LP_USE_RC_FAST_MODE] = "ESP_SLEEP_LP_USE_RC_FAST_MODE", [ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE] = "ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE", #if CONFIG_IDF_TARGET_ESP32 [ESP_SLEEP_ANALOG_LOW_POWER_MODE] = "ESP_SLEEP_ANALOG_LOW_POWER_MODE", @@ -2812,11 +2880,19 @@ static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsle sleep_flags |= RTC_SLEEP_XTAL_AS_RTC_FAST; } -#if SOC_LP_VAD_SUPPORTED +#if SOC_PMU_SUPPORTED +#if CONFIG_IDF_TARGET_ESP32P4 if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_LP_USE_XTAL_MODE] && !deepsleep) { sleep_flags |= RTC_SLEEP_LP_PERIPH_USE_XTAL; } #endif +#if SOC_LP_PERIPHERALS_SUPPORTED + if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_LP_USE_RC_FAST_MODE]) { + sleep_flags &= ~RTC_SLEEP_PD_INT_8M; + sleep_flags |= RTC_SLEEP_LP_PERIPH_USE_RC_FAST; + } +#endif +#endif #if SOC_VBAT_SUPPORTED if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE] && deepsleep) { diff --git a/components/hal/esp32c5/include/hal/clk_gate_ll.h b/components/hal/esp32c5/include/hal/clk_gate_ll.h index 4a1d7d2ac6..059c0b2e4b 100644 --- a/components/hal/esp32c5/include/hal/clk_gate_ll.h +++ b/components/hal/esp32c5/include/hal/clk_gate_ll.h @@ -14,6 +14,7 @@ extern "C" { #include #include "esp_attr.h" #include "soc/pcr_struct.h" +#include "soc/lp_clkrst_struct.h" /** * Enable or disable the clock gate for ref_12m. @@ -123,6 +124,18 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_240m_clk_en(bool enable) /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define clk_gate_ll_ref_240m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_240m_clk_en(__VA_ARGS__) +/** + * Enable or disable the clock gate for rtc_fast to lp periph + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_rtc_fast_to_lp_periph_en(bool enable) +{ + LP_CLKRST.lp_clk_en.fast_ori_gate = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_rtc_fast_to_lp_periph_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_rtc_fast_to_lp_periph_en(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/clk_gate_ll.h b/components/hal/esp32c6/include/hal/clk_gate_ll.h index 01d173aeed..93cf20c6aa 100644 --- a/components/hal/esp32c6/include/hal/clk_gate_ll.h +++ b/components/hal/esp32c6/include/hal/clk_gate_ll.h @@ -14,6 +14,7 @@ #include "soc/soc.h" #include "soc/soc_caps.h" #include "esp_attr.h" +#include "soc/lp_clkrst_struct.h" #ifdef __cplusplus extern "C" { @@ -194,6 +195,18 @@ static inline bool IRAM_ATTR periph_ll_periph_enabled(shared_periph_module_t per REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0; } +/** + * Enable or disable the clock gate for rtc_fast to lp periph + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_rtc_fast_to_lp_periph_en(bool enable) +{ + LP_CLKRST.lp_clk_en.fast_ori_gate = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_rtc_fast_to_lp_periph_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_rtc_fast_to_lp_periph_en(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 75e2572d6b..b55a76bf32 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -121,6 +121,21 @@ FORCE_INLINE_ATTR void _clk_gate_ll_xtal_to_lp_periph_en(bool enable) _clk_gate_ll_xtal_to_lp_periph_en(__VA_ARGS__); \ } while(0) +/** + * Enable or disable the clock gate for rtc fast to lp periph + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_rtc_fast_to_lp_periph_en(bool enable) +{ + LP_AON_CLKRST.lp_clk_en.fosc_clk_force_on = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_rtc_fast_to_lp_periph_en(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _clk_gate_ll_rtc_fast_to_lp_periph_en(__VA_ARGS__); \ + } while(0) + /** * Enable or disable the clock gate for ref_50m. * @param enable Enable / disable diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index ccb8d58c87..5e0fada7cd 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1879,6 +1879,10 @@ config SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP bool default y +config SOC_PM_SUPPORT_LP_UART_WAKEUP + bool + default y + config SOC_PM_SUPPORT_CPU_PD bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2a64a7ea71..60bc9e17f6 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -708,6 +708,7 @@ #define SOC_PM_EXT1_WAKEUP_BY_PMU (1) #define SOC_PM_SUPPORT_WIFI_WAKEUP (1) #define SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP (1) /*!