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 a58fce4922..88c2c44b7b 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -239,6 +239,7 @@ uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t sleep_flags, uint32_t slowclk * @brief Get default sleep configuration * @param config pmu_sleep_config instance * @param sleep_flags flags indicates the power domain that will be powered down and the sleep submode + * @param clk_flags indicates the clock ICG cell that will be ungated * @param adjustment total software and hardware time overhead * @param slowclk_period re-calibrated slow clock period in microseconds, * Q13.19 fixed point format @@ -248,7 +249,7 @@ uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t sleep_flags, uint32_t slowclk * @return hardware time overhead in us */ -const pmu_sleep_config_t* pmu_sleep_config_default(pmu_sleep_config_t *config, uint32_t sleep_flags, uint32_t adjustment, uint32_t slowclk_period, uint32_t fastclk_period, bool dslp); +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, uint32_t slowclk_period, uint32_t fastclk_period, bool dslp); /** * @brief Prepare the chip to enter sleep mode 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 747d426cd9..f1eaecc50e 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -83,6 +83,40 @@ int32_t* esp_sleep_sub_mode_dump_config(FILE *stream); void esp_sleep_isolate_digital_gpio(void); #endif +#if SOC_PM_SUPPORT_PMU_CLK_ICG +/** + * @brief Clock ICG cells which can be gated in sleep mode + */ +typedef enum { + ESP_SLEEP_CLOCK_IOMUX, //!< The clock ICG cell mapping of IOMUX + ESP_SLEEP_CLOCK_LEDC, //!< The clock ICG cell mapping of LEDC + ESP_SLEEP_CLOCK_UART0, //!< The clock ICG cell mapping of UART0 + ESP_SLEEP_CLOCK_UART1, //!< The clock ICG cell mapping of UART1 + ESP_SLEEP_CLOCK_MAX //!< Number of ICG cells +} esp_sleep_clock_t; + +/** + * @brief Clock ICG options + */ +typedef enum { + ESP_SLEEP_CLOCK_OPTION_GATE, //!< Gate the clock in sleep mode + ESP_SLEEP_CLOCK_OPTION_UNGATE //!< Ungate the clock in sleep mode +} esp_sleep_clock_option_t; + +/** + * @brief Gate or Ungate the specified clock in sleep mode + * + * If not set set using this API, all clock default to ESP_SLEEP_CLOCK_OPTION_GATE. + * + * @param clock the specified clock to configure + * @param option clock gate option (ESP_SLEEP_CLOCK_OPTION_GATE or ESP_SLEEP_CLOCK_OPTION_UNGATE) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if either of the arguments is out of range + */ +esp_err_t esp_sleep_clock_config(esp_sleep_clock_t clock, esp_sleep_clock_option_t option); +#endif + #if CONFIG_ESP_PHY_ENABLED /** * Register a callback to be called from the deep sleep prepare for maintain the PHY state diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index c588f4f917..493e5ff157 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -151,6 +151,7 @@ static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( 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, uint32_t slowclk_period, uint32_t fastclk_period, @@ -165,10 +166,15 @@ const pmu_sleep_config_t* pmu_sleep_config_default( 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, clk_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 { - pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags); + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); config->digital = digital_default; pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags); @@ -204,9 +210,13 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi 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) +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig, bool dslp) { - pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0)); + pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func); + if (!dslp) { + pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + } } static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) @@ -258,9 +268,7 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) { assert(PMU_instance()); pmu_sleep_power_init(PMU_instance(), &config->power, dslp); - if(!dslp){ - pmu_sleep_digital_init(PMU_instance(), &config->digital); - } + pmu_sleep_digital_init(PMU_instance(), &config->digital, dslp); pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); } diff --git a/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h index fed46a054b..40d9302b74 100644 --- a/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -324,12 +324,21 @@ typedef struct { typedef struct { pmu_hp_sys_cntl_reg_t syscntl; + uint32_t icg_func; } pmu_sleep_digital_config_t; -#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \ +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ .syscntl = { \ .dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ - } \ + }, \ + .icg_func = clk_flags \ +} + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 1, \ + }, \ + .icg_func = 0 \ } typedef struct { diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index e45424a166..d767463331 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -199,6 +199,7 @@ static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( 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, uint32_t slowclk_period, uint32_t fastclk_period, @@ -213,12 +214,16 @@ const pmu_sleep_config_t* pmu_sleep_config_default( 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, clk_flags); + config->digital = digital_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); + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); config->digital = digital_default; pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags); @@ -271,9 +276,13 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi 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) +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig, bool dslp) { - pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0)); + pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func); + if (!dslp) { + pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + } } static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) @@ -322,9 +331,7 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) { assert(PMU_instance()); pmu_sleep_power_init(PMU_instance(), &config->power, dslp); - if(!dslp){ - pmu_sleep_digital_init(PMU_instance(), &config->digital); - } + pmu_sleep_digital_init(PMU_instance(), &config->digital, dslp); pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); } diff --git a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h index 2a7fd75e67..a0974f6a19 100644 --- a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -320,12 +320,21 @@ typedef struct { typedef struct { pmu_hp_sys_cntl_reg_t syscntl; + uint32_t icg_func; } pmu_sleep_digital_config_t; -#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \ +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ .syscntl = { \ .dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ - } \ + }, \ + .icg_func = clk_flags \ +} + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 1, \ + }, \ + .icg_func = 0 \ } typedef struct { diff --git a/components/esp_hw_support/port/esp32c61/pmu_sleep.c b/components/esp_hw_support/port/esp32c61/pmu_sleep.c index c588f4f917..cd75f6d3c0 100644 --- a/components/esp_hw_support/port/esp32c61/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c61/pmu_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -151,6 +151,7 @@ static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( 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, uint32_t slowclk_period, uint32_t fastclk_period, @@ -165,10 +166,14 @@ const pmu_sleep_config_t* pmu_sleep_config_default( 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, clk_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 { - pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags); + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); config->digital = digital_default; pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags); @@ -204,9 +209,13 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi 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) +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig, bool dslp) { - pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0)); + pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func); + if (!dslp) { + pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + } } static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) @@ -258,9 +267,7 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) { assert(PMU_instance()); pmu_sleep_power_init(PMU_instance(), &config->power, dslp); - if(!dslp){ - pmu_sleep_digital_init(PMU_instance(), &config->digital); - } + pmu_sleep_digital_init(PMU_instance(), &config->digital, dslp); pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); } diff --git a/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h index abf1e7fbcc..06719990ac 100644 --- a/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -322,12 +322,21 @@ typedef struct { typedef struct { pmu_hp_sys_cntl_reg_t syscntl; + uint32_t icg_func; } pmu_sleep_digital_config_t; -#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \ +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ .syscntl = { \ .dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ - } \ + }, \ + .icg_func = clk_flags \ +} + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 1, \ + }, \ + .icg_func = 0 \ } typedef struct { diff --git a/components/esp_hw_support/port/esp32h2/pmu_sleep.c b/components/esp_hw_support/port/esp32h2/pmu_sleep.c index 3c6c5873ab..e1acf9896d 100644 --- a/components/esp_hw_support/port/esp32h2/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h2/pmu_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -131,6 +131,7 @@ static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( 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, uint32_t slowclk_period, uint32_t fastclk_period, @@ -144,11 +145,14 @@ const pmu_sleep_config_t* pmu_sleep_config_default( config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, sleep_flags, adjustment, slowclk_period, fastclk_period); if (dslp) { + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); + config->digital = digital_default; + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(sleep_flags); analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_slp_lp_dbias(); config->analog = analog_default; } else { - pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags); + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags); config->digital = digital_default; pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags); @@ -186,9 +190,13 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi 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) +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig, bool dslp) { - pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0)); + pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func); + if (!dslp) { + pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + } } static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) @@ -229,9 +237,7 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) { assert(PMU_instance()); pmu_sleep_power_init(PMU_instance(), &config->power, dslp); - if (!dslp) { - pmu_sleep_digital_init(PMU_instance(), &config->digital); - } + pmu_sleep_digital_init(PMU_instance(), &config->digital, dslp); pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); } diff --git a/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h index 2c00180027..23926878a3 100644 --- a/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -310,12 +310,21 @@ typedef struct { typedef struct { pmu_hp_sys_cntl_reg_t syscntl; + uint32_t icg_func; } pmu_sleep_digital_config_t; -#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \ +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ .syscntl = { \ .dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ - } \ + }, \ + .icg_func = clk_flags \ +} + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 1, \ + }, \ + .icg_func = 0 \ } typedef struct { diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index aff24145cc..bc9eee8647 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -149,6 +149,7 @@ static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( 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, uint32_t slowclk_period, uint32_t fastclk_period, diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 0c31d4738b..b1f358d8f3 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -116,6 +116,10 @@ #include "hal/gpio_ll.h" #endif +#if SOC_PM_SUPPORT_PMU_CLK_ICG +#include "soc/pmu_icg_mapping.h" +#endif + #if SOC_LP_TIMER_SUPPORTED #include "hal/lp_timer_hal.h" #endif @@ -225,6 +229,9 @@ typedef struct { int16_t refs; uint16_t reserved; /* reserved for 4 bytes aligned */ } domain[ESP_PD_DOMAIN_MAX]; +#if SOC_PM_SUPPORT_PMU_CLK_ICG + int16_t clock_icg_refs[ESP_SLEEP_CLOCK_MAX]; +#endif portMUX_TYPE lock; uint64_t sleep_duration; uint32_t wakeup_triggers : 20; @@ -274,6 +281,9 @@ static sleep_config_t s_config = { .refs = 0 } }, +#if SOC_PM_SUPPORT_PMU_CLK_ICG + .clock_icg_refs[0 ... ESP_SLEEP_CLOCK_MAX - 1] = 0, +#endif .lock = portMUX_INITIALIZER_UNLOCKED, .ccount_ticks_record = 0, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, @@ -295,6 +305,7 @@ static RTC_FAST_ATTR int32_t s_sleep_sub_mode_ref_cnt[ESP_SLEEP_MODE_MAX] = { 0 static uint32_t get_power_down_flags(void); static uint32_t get_sleep_flags(uint32_t pd_flags, bool deepsleep); +static uint32_t get_sleep_clock_icg_flags(void); #if SOC_PM_SUPPORT_EXT0_WAKEUP static void ext0_wakeup_prepare(void); #endif @@ -790,7 +801,7 @@ static IRAM_ATTR void sleep_low_power_clock_calibration(bool is_dslp) inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp); -static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection) +static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection) { // Stop UART output so that output is not lost due to APB frequency change. // For light sleep, suspend UART output — it will resume after wakeup. @@ -944,9 +955,8 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, esp_sleep_mode_ #endif pmu_sleep_config_t config; - pmu_sleep_init(pmu_sleep_config_default(&config, sleep_flags, s_config.sleep_time_adjustment, - s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period, - deep_sleep), deep_sleep); + pmu_sleep_init(pmu_sleep_config_default(&config, sleep_flags, clk_flags, s_config.sleep_time_adjustment, + s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period, deep_sleep), deep_sleep); #else rtc_sleep_config_t config; rtc_sleep_get_default_config(sleep_flags, &config); @@ -1206,7 +1216,7 @@ static esp_err_t IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) uint32_t sleep_flags = get_sleep_flags(force_pd_flags | pd_flags, true); // Enter sleep esp_err_t err = ESP_OK; - if (esp_sleep_start(sleep_flags, ESP_SLEEP_MODE_DEEP_SLEEP, allow_sleep_rejection) == ESP_ERR_SLEEP_REJECT) { + if (esp_sleep_start(sleep_flags, 0, ESP_SLEEP_MODE_DEEP_SLEEP, allow_sleep_rejection) == ESP_ERR_SLEEP_REJECT) { err = ESP_ERR_SLEEP_REJECT; #if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION /* Cache Resume 2: if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is enabled, cache has been suspended in esp_sleep_start */ @@ -1243,10 +1253,10 @@ esp_err_t IRAM_ATTR esp_deep_sleep_try_to_start(void) * Helper function which handles entry to and exit from light sleep * Placed into IRAM as flash may need some time to be powered on. */ -static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, +static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags, uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline)); -static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, +static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags, uint32_t flash_enable_time_us) { #if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED @@ -1254,7 +1264,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, #endif // Enter sleep - esp_err_t reject = esp_sleep_start(sleep_flags, ESP_SLEEP_MODE_LIGHT_SLEEP, true); + esp_err_t reject = esp_sleep_start(sleep_flags, clk_flags, ESP_SLEEP_MODE_LIGHT_SLEEP, true); #if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED // If VDDSDIO regulator was controlled by RTC registers before sleep, @@ -1387,6 +1397,8 @@ esp_err_t esp_light_sleep_start(void) uint32_t pd_flags = get_power_down_flags(); // Append flags to indicate the sleep sub-mode and modify the pd_flags according to sub-mode attributes. uint32_t sleep_flags = get_sleep_flags(pd_flags, false); + // Decide whicn clock can be ungate during sleep + uint32_t clk_flags = get_sleep_clock_icg_flags(); // Re-calibrate the RTC clock sleep_low_power_clock_calibration(false); @@ -1487,7 +1499,7 @@ esp_err_t esp_light_sleep_start(void) err = ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION; } else { // Enter sleep, then wait for flash to be ready on wakeup - err = esp_light_sleep_inner(sleep_flags, flash_enable_time_us); + err = esp_light_sleep_inner(sleep_flags, clk_flags, flash_enable_time_us); } // light sleep wakeup flag only makes sense after a successful light sleep @@ -2262,6 +2274,24 @@ int32_t* esp_sleep_sub_mode_dump_config(FILE *stream) { return s_sleep_sub_mode_ref_cnt; } +#if SOC_PM_SUPPORT_PMU_CLK_ICG +esp_err_t esp_sleep_clock_config(esp_sleep_clock_t clock, esp_sleep_clock_option_t option) +{ + if (clock > ESP_SLEEP_CLOCK_MAX || option > ESP_SLEEP_CLOCK_OPTION_UNGATE) { + return ESP_ERR_INVALID_ARG; + } + + int __attribute__((unused)) refs; + portENTER_CRITICAL_SAFE(&s_config.lock); + refs = (option == ESP_SLEEP_CLOCK_OPTION_UNGATE) ? s_config.clock_icg_refs[clock]++ \ + : (option == ESP_SLEEP_CLOCK_OPTION_GATE) ? --s_config.clock_icg_refs[clock] \ + : s_config.clock_icg_refs[clock]; + portEXIT_CRITICAL_SAFE(&s_config.lock); + assert(refs >= 0); + return ESP_OK; +} +#endif + /** * The modules in the CPU and modem power domains still depend on the top power domain. * To be safe, the CPU and Modem power domains must also be powered off and saved when @@ -2519,6 +2549,27 @@ static uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep) return sleep_flags; } +static uint32_t get_sleep_clock_icg_flags(void) +{ + uint32_t clk_flags = 0; + +#if SOC_PM_SUPPORT_PMU_CLK_ICG + if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_IOMUX] > 0) { + clk_flags |= BIT(PMU_ICG_FUNC_ENA_IOMUX); + } + if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_LEDC] > 0) { + clk_flags |= BIT(PMU_ICG_FUNC_ENA_LEDC); + } + if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_UART0] > 0) { + clk_flags |= BIT(PMU_ICG_FUNC_ENA_UART0); + } + if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_UART1] > 0) { + clk_flags |= BIT(PMU_ICG_FUNC_ENA_UART1); + } +#endif /* SOC_PM_SUPPORT_PMU_CLK_ICG */ + return clk_flags; +} + #if CONFIG_IDF_TARGET_ESP32 /* APP core of esp32 can't access to RTC FAST MEMORY, do not define it with RTC_IRAM_ATTR */ void diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index a6276d1b7d..a27799567b 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -17,6 +17,7 @@ entries: sleep_modes:timer_wakeup_prepare (noflash) sleep_modes:get_power_down_flags (noflash) sleep_modes:get_sleep_flags (noflash) + sleep_modes:get_sleep_clock_icg_flags (noflash) esp_clk:esp_clk_slowclk_cal_set (noflash) esp_clk:esp_clk_slowclk_cal_get (noflash) esp_clk:esp_rtc_get_time_us (noflash) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 02db5f53e3..19328f81bf 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1507,6 +1507,10 @@ config SOC_PM_SUPPORT_PMU_MODEM_STATE bool default y +config SOC_PM_SUPPORT_PMU_CLK_ICG + bool + default y + config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 734b11dbf7..802d640889 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -605,6 +605,8 @@ /* macro redefine for pass esp_wifi headers md5sum check */ #define MAC_SUPPORT_PMU_MODEM_STATE SOC_PM_SUPPORT_PMU_MODEM_STATE +#define SOC_PM_SUPPORT_PMU_CLK_ICG (1) + #define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!