diff --git a/components/esp_hal_pmu/esp32c5/include/hal/pau_ll.h b/components/esp_hal_pmu/esp32c5/include/hal/pau_ll.h index 877bb992b46..f480d84fc9b 100644 --- a/components/esp_hal_pmu/esp32c5/include/hal/pau_ll.h +++ b/components/esp_hal_pmu/esp32c5/include/hal/pau_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,6 +54,31 @@ static inline void pau_ll_set_regdma_entry_link_backup_start_enable(pau_dev_t *d dev->regdma_conf.start = enable; } +static inline void pau_ll_set_regdma_select_wifimac_link(pau_dev_t *dev) +{ + dev->regdma_conf.sel_mac = 1; +} + +static inline void pau_ll_set_regdma_deselect_wifimac_link(pau_dev_t *dev) +{ + dev->regdma_conf.sel_mac = 0; +} + +static inline void pau_ll_set_regdma_wifimac_link_backup_direction(pau_dev_t *dev, bool to_mem) +{ + dev->regdma_conf.to_mem_mac = to_mem ? 1 : 0; +} + +static inline void pau_ll_set_regdma_wifimac_link_backup_start_enable(pau_dev_t *dev) +{ + dev->regdma_conf.start_mac = 1; +} + +static inline void pau_ll_set_regdma_wifimac_link_backup_start_disable(pau_dev_t *dev) +{ + dev->regdma_conf.start_mac = 0; +} + static inline uint32_t pau_ll_get_regdma_current_link_addr(pau_dev_t *dev) { return dev->regdma_current_link_addr.val; diff --git a/components/esp_hal_pmu/esp32c5/pau_hal.c b/components/esp_hal_pmu/esp32c5/pau_hal.c index d0887f780ea..f627c746c34 100644 --- a/components/esp_hal_pmu/esp32c5/pau_hal.c +++ b/components/esp_hal_pmu/esp32c5/pau_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,6 +32,25 @@ void IRAM_ATTR pau_hal_stop_regdma_modem_link(pau_hal_context_t *hal) pau_ll_clear_regdma_backup_done_intr_state(hal->dev); } +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND +void IRAM_ATTR pau_hal_start_regdma_wifimac_link(pau_hal_context_t *hal, bool backup_or_restore) +{ + pau_ll_clear_regdma_backup_done_intr_state(hal->dev); + pau_ll_set_regdma_select_wifimac_link(hal->dev); + pau_ll_set_regdma_wifimac_link_backup_direction(hal->dev, backup_or_restore); + pau_ll_set_regdma_wifimac_link_backup_start_enable(hal->dev); + + while (!(pau_ll_get_regdma_intr_raw_signal(hal->dev) & PAU_DONE_INT_RAW)); +} + +void IRAM_ATTR pau_hal_stop_regdma_wifimac_link(pau_hal_context_t *hal) +{ + pau_ll_set_regdma_wifimac_link_backup_start_disable(hal->dev); + pau_ll_set_regdma_deselect_wifimac_link(hal->dev); + pau_ll_clear_regdma_backup_done_intr_state(hal->dev); +} +#endif + void IRAM_ATTR pau_hal_start_regdma_extra_link(pau_hal_context_t *hal, bool backup_or_restore) { pau_ll_clear_regdma_backup_done_intr_state(hal->dev); diff --git a/components/esp_hal_pmu/include/hal/pau_hal.h b/components/esp_hal_pmu/include/hal/pau_hal.h index 522889a85b6..60b5c129599 100644 --- a/components/esp_hal_pmu/include/hal/pau_hal.h +++ b/components/esp_hal_pmu/include/hal/pau_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -61,6 +61,23 @@ void pau_hal_start_regdma_modem_link(pau_hal_context_t *hal, bool backup_or_rest * @param hal regdma hal context */ void pau_hal_stop_regdma_modem_link(pau_hal_context_t *hal); + +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND +/** + * @brief Start transmission on regdma WiFi MAC SEL link + * + * @param hal regdma hal context + * @param backup_or_restore false: restore, true: backup + */ +void pau_hal_start_regdma_wifimac_link(pau_hal_context_t *hal, bool backup_or_restore); + +/** + * @brief Stop transmission on regdma WiFi MAC SEL link + * + * @param hal regdma hal context + */ +void pau_hal_stop_regdma_wifimac_link(pau_hal_context_t *hal); +#endif #endif #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA diff --git a/components/esp_hw_support/include/esp_private/esp_pau.h b/components/esp_hw_support/include/esp_private/esp_pau.h index f82d0f7dbbe..89b628affa9 100644 --- a/components/esp_hw_support/include/esp_private/esp_pau.h +++ b/components/esp_hw_support/include/esp_private/esp_pau.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,6 +41,18 @@ void pau_regdma_trigger_modem_link_backup(void); * @brief Software trigger regdma to perform modem link restore */ void pau_regdma_trigger_modem_link_restore(void); + +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND +/** + * @brief Software trigger REGDMA backup on WiFi MAC SEL link + */ +void pau_regdma_trigger_wifimac_link_backup(void); + +/** + * @brief Software trigger REGDMA restore on WiFi MAC SEL link + */ +void pau_regdma_trigger_wifimac_link_restore(void); +#endif #endif #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA diff --git a/components/esp_hw_support/include/esp_private/sleep_modem.h b/components/esp_hw_support/include/esp_private/sleep_modem.h index 5e6aa72fa3f..47ad7548e6e 100644 --- a/components/esp_hw_support/include/esp_private/sleep_modem.h +++ b/components/esp_hw_support/include/esp_private/sleep_modem.h @@ -83,8 +83,9 @@ void sleep_modem_mac_bb_power_up_prepare(void); * @brief The retention action in the modem state of WiFi PHY module * * @param restore true for restore the PHY context, false for backup the PHY context + * @param wifimac_link_is_sel true to trigger REGDMA via WiFi MAC link */ -void sleep_modem_wifi_do_phy_retention(bool restore); +void sleep_modem_wifi_do_phy_retention(bool restore, bool wifimac_link_is_sel); /** * @brief Get WiFi modem state diff --git a/components/esp_hw_support/include/esp_private/sleep_retention.h b/components/esp_hw_support/include/esp_private/sleep_retention.h index 3b5671eb828..e10199af0b8 100644 --- a/components/esp_hw_support/include/esp_private/sleep_retention.h +++ b/components/esp_hw_support/include/esp_private/sleep_retention.h @@ -293,8 +293,10 @@ void sleep_retention_do_system_retention(bool backup_or_restore); * * @param backup_or_restore true for backup register context to memory * or false for restore to register from memory + * @param wifimac_link_is_sel true to use dedicated WiFi MAC link, + * false to use modem entry link */ -void sleep_retention_do_phy_retention(bool backup_or_restore); +void sleep_retention_do_phy_retention(bool backup_or_restore, bool wifimac_link_is_sel); #endif /*SOC_PM_SUPPORT_PMU_MODEM_STATE */ #endif // SOC_PAU_SUPPORTED diff --git a/components/esp_hw_support/port/pau_regdma.c b/components/esp_hw_support/port/pau_regdma.c index 03281ce7b76..ae1bf22f8c9 100644 --- a/components/esp_hw_support/port/pau_regdma.c +++ b/components/esp_hw_support/port/pau_regdma.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +87,20 @@ void IRAM_ATTR pau_regdma_trigger_modem_link_restore(void) pau_hal_start_regdma_modem_link(PAU_instance()->hal, false); pau_hal_stop_regdma_modem_link(PAU_instance()->hal); } + +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND +void IRAM_ATTR pau_regdma_trigger_wifimac_link_backup(void) +{ + pau_hal_start_regdma_wifimac_link(PAU_instance()->hal, true); + pau_hal_stop_regdma_wifimac_link(PAU_instance()->hal); +} + +void IRAM_ATTR pau_regdma_trigger_wifimac_link_restore(void) +{ + pau_hal_start_regdma_wifimac_link(PAU_instance()->hal, false); + pau_hal_stop_regdma_wifimac_link(PAU_instance()->hal); +} +#endif #endif #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index 9bc27d130b3..1bffcf6129e 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -171,10 +171,10 @@ __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void) } } -void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore) +void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore, bool wifimac_link_is_sel) { sleep_modem_state_phy_link_config(s_sleep_modem.wifi.phy_link, 1); - sleep_retention_do_phy_retention(!restore); + sleep_retention_do_phy_retention(!restore, wifimac_link_is_sel); sleep_modem_state_phy_link_config(s_sleep_modem.wifi.phy_link, 0); if (!restore) { s_sleep_modem.wifi.modem_state_phy_done = 1; diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c index 73fbac4533c..eb4232a3e8b 100644 --- a/components/esp_hw_support/sleep_retention.c +++ b/components/esp_hw_support/sleep_retention.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1007,7 +1007,7 @@ void IRAM_ATTR sleep_retention_do_system_retention(bool backup_or_restore) #endif #if SOC_PM_SUPPORT_PMU_MODEM_STATE -void IRAM_ATTR sleep_retention_do_phy_retention(bool backup_or_restore) +void IRAM_ATTR sleep_retention_do_phy_retention(bool backup_or_restore, bool wifimac_link_is_sel) { /* since the PHY link and other module links are within the sleep-retention entry (4) context, * add mutex protection to avoid data race. @@ -1016,9 +1016,23 @@ void IRAM_ATTR sleep_retention_do_phy_retention(bool backup_or_restore) _lock_acquire_recursive(&s_retention.lock); #endif if (backup_or_restore) { - pau_regdma_trigger_modem_link_backup(); +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND + if (wifimac_link_is_sel) { + pau_regdma_trigger_wifimac_link_backup(); + } else +#endif + { + pau_regdma_trigger_modem_link_backup(); + } } else { - pau_regdma_trigger_modem_link_restore(); +#if SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND + if (wifimac_link_is_sel) { + pau_regdma_trigger_wifimac_link_restore(); + } else +#endif + { + pau_regdma_trigger_modem_link_restore(); + } } #if SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY _lock_release_recursive(&s_retention.lock); diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 50487e10227..ea990c6e857 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -23,6 +23,7 @@ #include "esp_private/esp_sleep_internal.h" #include "esp_check.h" #include "sdkconfig.h" +#include "soc/soc_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "endian.h" @@ -73,6 +74,9 @@ extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb; #if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP extern void pm_mac_modem_clear_rf_power_state(void); extern bool pm_mac_modem_rf_already_enabled(void); +#if SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC +extern bool pm_get_wifimac_regdma_link_selection(void); +#endif #endif static const char* TAG = "phy_init"; @@ -341,9 +345,23 @@ void esp_phy_enable(esp_phy_modem_t modem) s_is_phy_calibrated = true; } else { #if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + bool wifimac_link_is_sel = false; if (!pm_mac_modem_rf_already_enabled()) { if (sleep_modem_wifi_modem_state_enabled() && sleep_modem_wifi_modem_link_done()) { - sleep_modem_wifi_do_phy_retention(true); +#if SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC && SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND +/* + * A race exists between SoC wakeup and modem state sleep. After modem initiates sleep, + * SoC may wake up before REGDMA completes RF close, leaving mac_modem_sleep_flag uncleared + * (it depends on regdma done). The stale flag can incorrectly trigger a sleep request + * on the next modem entry, causing abnormal sleep behavior. + * + * Therefore, this workaround ensures that mac_modem_sleep_flag is properly + * cleared by regdma closing RF with wifimac link. + * See WIFI-7246 for details. +*/ + wifimac_link_is_sel = pm_get_wifimac_regdma_link_selection(); +#endif + sleep_modem_wifi_do_phy_retention(true, wifimac_link_is_sel); } else { // TODO: IDF-15338 #if CONFIG_IDF_TARGET_ESP32C5 @@ -419,7 +437,11 @@ void esp_phy_disable(esp_phy_modem_t modem) #if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP pm_mac_modem_clear_rf_power_state(); if (sleep_modem_wifi_modem_state_enabled()) { - sleep_modem_wifi_do_phy_retention(false); + bool wifimac_link_is_sel = false; +#if SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC && SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND + wifimac_link_is_sel = pm_get_wifimac_regdma_link_selection(); +#endif + sleep_modem_wifi_do_phy_retention(false, wifimac_link_is_sel); } else #endif /* SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP */ { diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 66db189d042..ad3b3049ea6 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1503,6 +1503,10 @@ config SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY bool default y +config SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND + bool + default y + config SOC_PM_PMU_MIN_SLP_SLOW_CLK_CYCLE_FIXED bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 17264727814..7f321774f65 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -608,6 +608,8 @@ #define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1) #define SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC (4) // The range of values for the link index is [0, SOC_PM_PAU_LINK_NUM) #define SOC_PM_PAU_REGDMA_COMMON_PHY_LINK_ENTRY (1) +/** Workaround: software-triggered modem PHY retention uses dedicated WiFi MAC REGDMA, not entry link_sel */ +#define SOC_PM_PAU_REGDMA_MODEM_WIFIMAC_WORKAROUND (1) #define SOC_PM_PMU_MIN_SLP_SLOW_CLK_CYCLE_FIXED (1)