diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 4210a5169a..a632af4b37 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -18,6 +18,11 @@ extern "C" { #endif +/* + Definitions for the deepsleep prepare callbacks +*/ +typedef void (*esp_deep_sleep_cb_t)(void); + /** * @brief Logic function used for EXT1 wakeup mode. */ @@ -453,6 +458,27 @@ esp_err_t esp_light_sleep_start(void); void esp_deep_sleep(uint64_t time_in_us) __attribute__((noreturn)); +/** + * @brief Register a callback to be called from the deep sleep prepare + * + * @warning deepsleep callbacks should without parameters, and MUST NOT, + * UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK. + * + * @param new_dslp_cb Callback to be called + * + * @return + * - ESP_OK: Callback registered to the deepsleep misc_modules_sleep_prepare + * - ESP_ERR_NO_MEM: No more hook space for register the callback + */ +esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb); + +/** + * @brief Unregister an deepsleep callback + * + * @param old_dslp_cb Callback to be unregistered + */ +void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb); + /** * @brief Get the wakeup source which caused wakeup from sleep * diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index ffb5f9aab3..587498bb75 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -64,7 +64,7 @@ static void IRAM_ATTR modem_clock_wifi_bb_configure(modem_clock_context_t *ctx, static void IRAM_ATTR modem_clock_ble_mac_configure(modem_clock_context_t *ctx, bool enable) { modem_syscon_ll_enable_etm_clock(ctx->hal->syscon_dev, enable); - modem_syscom_ll_enable_modem_sec_clock(ctx->hal->syscon_dev, enable); + modem_syscon_ll_enable_modem_sec_clock(ctx->hal->syscon_dev, enable); modem_syscon_ll_enable_ble_timer_clock(ctx->hal->syscon_dev, enable); } @@ -98,7 +98,6 @@ static void IRAM_ATTR modem_clock_fe_configure(modem_clock_context_t *ctx, bool static void IRAM_ATTR modem_clock_i2c_master_configure(modem_clock_context_t *ctx, bool enable) { modem_lpcon_ll_enable_i2c_master_clock(ctx->hal->lpcon_dev, enable); - modem_lpcon_ll_enable_i2c_master_160m_clock(ctx->hal->lpcon_dev, enable); } static void IRAM_ATTR modem_clock_etm_configure(modem_clock_context_t *ctx, bool enable) diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index de07db0e36..213858f7a4 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -20,23 +20,32 @@ #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) { - 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); + 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) { - 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); + 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_hw_wait_time(uint32_t pd_flags, uint32_t slowclk_period, uint32_t fastclk_period) diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index f5ebf1b854..438ce28099 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -203,15 +203,14 @@ static __attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void) [22] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x14), I2C_ANA_MST_ANA_CONF0_REG, 0x4, 0xc, 0, 1), /* BBPLL calibration disable */ [23] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x15), MODEM_LPCON_CLK_CONF_REG, 0, MODEM_LPCON_CLK_I2C_MST_EN_M, 0, 1), /* I2C MST disable */ - [24] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x16), MODEM_LPCON_I2C_MST_CLK_CONF_REG, 0, MODEM_LPCON_CLK_I2C_MST_SEL_160M_M, 0, 1), /* I2C MST sel 160m disable */ /* PMU to trigger disable RXBLOCK */ - [25] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x17), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1), - [26] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x18), WDEVTXQ_BLOCK, WDEV_RXBLOCK, 0x1000, 0, 1), - [27] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x19), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1), + [24] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x17), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1), + [25] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x18), WDEVTXQ_BLOCK, WDEV_RXBLOCK, 0x1000, 0, 1), + [26] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x19), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1), - [28] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1a), PMU_SLP_WAKEUP_CNTL7_REG, 0x200000, 0xffff0000, 1, 0), - [29] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1b), PMU_SLP_WAKEUP_CNTL7_REG, 0x9730000, 0xffff0000, 0, 1) + [27] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1a), PMU_SLP_WAKEUP_CNTL7_REG, 0x200000, 0xffff0000, 1, 0), + [28] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1b), PMU_SLP_WAKEUP_CNTL7_REG, 0x9730000, 0xffff0000, 0, 1) }; wifi_modem_config[7].write_wait.value = I2C_BURST_VAL(cmd.config[1].host_id, cmd.config[1].start, cmd.config[1].end); wifi_modem_config[18].write_wait.value = I2C_BURST_VAL(cmd.config[0].host_id, cmd.config[0].start, cmd.config[0].end); diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index c83c44c5a4..8eac356940 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -150,6 +150,10 @@ #define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \ (source == value)) +#define MAX_DSLP_HOOKS 3 + +static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS]={0}; + /** * Internal structure which holds all requested deep sleep parameters */ @@ -343,6 +347,32 @@ void esp_deep_sleep(uint64_t time_in_us) esp_deep_sleep_start(); } +esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb) +{ + portENTER_CRITICAL(&spinlock_rtc_deep_sleep); + for(int n = 0; n < MAX_DSLP_HOOKS; n++){ + if (s_dslp_cb[n]==NULL || s_dslp_cb[n]==new_dslp_cb) { + s_dslp_cb[n]=new_dslp_cb; + portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); + return ESP_OK; + } + } + portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); + ESP_LOGE(TAG, "Registered deepsleep callbacks exceeds MAX_DSLP_HOOKS"); + return ESP_ERR_NO_MEM; +} + +void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb) +{ + portENTER_CRITICAL(&spinlock_rtc_deep_sleep); + for(int n = 0; n < MAX_DSLP_HOOKS; n++){ + if(s_dslp_cb[n] == old_dslp_cb) { + s_dslp_cb[n] = NULL; + } + } + portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); +} + // [refactor-todo] provide target logic for body of uart functions below static void IRAM_ATTR flush_uarts(void) { @@ -392,21 +422,29 @@ static void IRAM_ATTR resume_uarts(void) /** * These save-restore workaround should be moved to lower layer */ -inline static void IRAM_ATTR misc_modules_sleep_prepare(void) +inline static void IRAM_ATTR misc_modules_sleep_prepare(bool deep_sleep) { + if (deep_sleep){ + for (int n = 0; n < MAX_DSLP_HOOKS; n++) { + if (s_dslp_cb[n] != NULL) { + s_dslp_cb[n](); + } + } + } else { #if CONFIG_MAC_BB_PD - mac_bb_power_down_cb_execute(); + mac_bb_power_down_cb_execute(); #endif #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL - gpio_sleep_mode_config_apply(); + gpio_sleep_mode_config_apply(); #endif #if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL - sleep_enable_cpu_retention(); + sleep_enable_cpu_retention(); #endif #if REGI2C_ANA_CALI_PD_WORKAROUND - regi2c_analog_cali_reg_read(); + regi2c_analog_cali_reg_read(); #endif - sar_periph_ctrl_power_disable(); + sar_periph_ctrl_power_disable(); + } } /** @@ -511,9 +549,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo #endif #endif //!CONFIG_IDF_TARGET_ESP32C6 - if (!deep_sleep) { - misc_modules_sleep_prepare(); - } + misc_modules_sleep_prepare(deep_sleep); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 if (deep_sleep) { @@ -723,8 +759,7 @@ void IRAM_ATTR esp_deep_sleep_start(void) #if SOC_PMU_SUPPORTED uint32_t force_pd_flags = PMU_SLEEP_PD_TOP | PMU_SLEEP_PD_VDDSDIO | PMU_SLEEP_PD_MODEM | PMU_SLEEP_PD_HP_PERIPH \ - | PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_MEM | PMU_SLEEP_PD_XTAL | PMU_SLEEP_PD_RC_FAST \ - | PMU_SLEEP_PD_XTAL32K |PMU_SLEEP_PD_RC32K; + | PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_MEM | PMU_SLEEP_PD_XTAL; #else uint32_t force_pd_flags = RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | RTC_SLEEP_PD_INT_8M | RTC_SLEEP_PD_XTAL; #endif diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c index a8f6e466e8..c78f8c20a4 100644 --- a/components/esp_hw_support/sleep_retention.c +++ b/components/esp_hw_support/sleep_retention.c @@ -9,9 +9,11 @@ #include #include +#include "esp_err.h" #include "esp_attr.h" #include "esp_log.h" #include "esp_heap_caps.h" +#include "esp_sleep.h" #include "soc/soc_caps.h" #include "esp_private/esp_regdma.h" #include "esp_private/esp_pau.h" @@ -433,6 +435,7 @@ esp_err_t sleep_retention_entries_create(const sleep_retention_entries_config_t err = sleep_retention_entries_create_wrapper(retent, num, priority, module); if (err) goto error; pmu_sleep_enable_regdma_backup(); + ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&pmu_sleep_disable_regdma_backup)); error: return err; diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 62ea775656..6011bb236a 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -19,6 +19,7 @@ #include "nvs_flash.h" #include "esp_efuse.h" #include "esp_timer.h" +#include "esp_sleep.h" #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" @@ -246,8 +247,7 @@ void esp_phy_enable(void) if (s_is_phy_calibrated == false) { esp_phy_load_cal_and_init(); s_is_phy_calibrated = true; - } - else { + } else { #if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP extern bool pm_mac_modem_rf_already_enabled(void); if (!pm_mac_modem_rf_already_enabled()) { @@ -815,6 +815,8 @@ void esp_phy_load_cal_and_init(void) esp_phy_release_init_data(init_data); #endif + ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&phy_close_rf)); + free(cal_data); // PHY maintains a copy of calibration data, so we can free this } diff --git a/components/hal/esp32c6/include/hal/modem_syscon_ll.h b/components/hal/esp32c6/include/hal/modem_syscon_ll.h index f89e4f7d81..563ee1f84e 100644 --- a/components/hal/esp32c6/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32c6/include/hal/modem_syscon_ll.h @@ -49,7 +49,7 @@ static inline void modem_syscon_ll_enable_ieee802154_mac_clock(modem_syscon_dev_ } __attribute__((always_inline)) -static inline void modem_syscom_ll_enable_modem_sec_clock(modem_syscon_dev_t *hw, bool en) +static inline void modem_syscon_ll_enable_modem_sec_clock(modem_syscon_dev_t *hw, bool en) { hw->clk_conf.clk_modem_sec_en = en; hw->clk_conf.clk_modem_sec_ecb_en = en; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 2373c9452d..0afb1e8909 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1103,6 +1103,10 @@ config SOC_PM_SUPPORT_MAC_BB_PD bool default y +config SOC_PM_SUPPORT_RTC_PERIPH_PD + bool + default y + config SOC_PM_SUPPORT_PMU_MODEM_STATE bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 6f12018405..eb076c8561 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -454,6 +454,7 @@ #define SOC_PM_SUPPORT_VDDSDIO_PD (1) #define SOC_PM_SUPPORT_TOP_PD (1) #define SOC_PM_SUPPORT_MAC_BB_PD (1) +#define SOC_PM_SUPPORT_RTC_PERIPH_PD (1) #define SOC_PM_SUPPORT_PMU_MODEM_STATE (1) /* macro redefine for pass esp_wifi headers md5sum check */