diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index c9beb449d1..caf9f72d03 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -39,7 +39,7 @@ static _lock_t s_modem_prepare_lock; #endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD #if CONFIG_MAC_BB_PD -#define MAC_BB_POWER_DOWN_CB_NO (3) +#define MAC_BB_POWER_DOWN_CB_NO (4) #define MAC_BB_POWER_UP_CB_NO (3) static DRAM_ATTR mac_bb_power_down_cb_t s_mac_bb_power_down_cb[MAC_BB_POWER_DOWN_CB_NO]; diff --git a/components/esp_phy/include/esp_private/phy.h b/components/esp_phy/include/esp_private/phy.h index 3bcf2f58e9..f3133b0221 100644 --- a/components/esp_phy/include/esp_private/phy.h +++ b/components/esp_phy/include/esp_private/phy.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,7 @@ extern "C" { #endif #define ESP_CAL_DATA_CHECK_FAIL 1 +#define ESP_MODEM_RF_FLAG_UPDATE_CB_REQUIRED (SOC_PM_MODEM_RF_FLAG_UPDATE_WORKAROUND || CONFIG_ESP_WIFI_MODEM_RF_FLAG_UPDATE_DEBUG) typedef struct { uint8_t cmd_type; /* the command type of the current phy i2c master command memory config */ @@ -243,6 +244,16 @@ uint32_t phy_ana_i2c_master_burst_rf_onoff(bool on); void phy_wakeup_from_modem_state_extra_init(void); #endif +#if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP && ESP_MODEM_RF_FLAG_UPDATE_CB_REQUIRED +/** + * @brief Update modem RF flag + * + * This function is called as a callback during MAC/BB power down operations. + * It checks if modem RF is already enabled and clears the RF power state accordingly. + */ +void esp_phy_modem_rf_flag_update(void); +#endif + #if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_MAC_BB_PD /** * @brief PHY module sleep data (includes AGC, TX, NRX, BB, FE, etc..) initialize. diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 16ddbc778f..8db6cabf91 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -60,6 +60,11 @@ extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb; #endif +#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); +#endif + static const char* TAG = "phy_init"; static _lock_t s_phy_access_lock; @@ -296,6 +301,18 @@ static inline void phy_digital_regs_load(void) } #endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP && ESP_MODEM_RF_FLAG_UPDATE_CB_REQUIRED +void IRAM_ATTR esp_phy_modem_rf_flag_update(void) +{ + if (pm_mac_modem_rf_already_enabled()) { +#if CONFIG_ESP_WIFI_MODEM_RF_FLAG_UPDATE_DEBUG + assert(0); +#endif + pm_mac_modem_clear_rf_power_state(); + } +} +#endif + void esp_phy_enable(esp_phy_modem_t modem) { _lock_acquire(&s_phy_access_lock); @@ -314,7 +331,6 @@ 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 - extern bool pm_mac_modem_rf_already_enabled(void); 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); @@ -382,7 +398,6 @@ void esp_phy_disable(esp_phy_modem_t modem) phy_digital_regs_store(); #endif #if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP - extern void pm_mac_modem_clear_rf_power_state(void); pm_mac_modem_clear_rf_power_state(); if (sleep_modem_wifi_modem_state_enabled()) { sleep_modem_wifi_do_phy_retention(false); diff --git a/components/esp_system/port/soc/esp32c5/system_internal.c b/components/esp_system/port/soc/esp32c5/system_internal.c index 81c954fe51..7f1ac5c060 100644 --- a/components/esp_system/port/soc/esp32c5/system_internal.c +++ b/components/esp_system/port/soc/esp32c5/system_internal.c @@ -57,6 +57,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); //ETM may directly control the GPIO or other peripherals even after CPU reset. Reset to stop these control. SET_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); @@ -67,6 +68,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); CLEAR_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); CLEAR_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + CLEAR_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Reset crypto peripherals. This ensures a clean state for the crypto peripherals after a CPU restart // and hence avoiding any possibility with crypto failure in ROM security workflows. diff --git a/components/esp_system/port/soc/esp32c6/system_internal.c b/components/esp_system/port/soc/esp32c6/system_internal.c index 1ad1068d1c..46e588f904 100644 --- a/components/esp_system/port/soc/esp32c6/system_internal.c +++ b/components/esp_system/port/soc/esp32c6/system_internal.c @@ -53,6 +53,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); //ETM may directly control the GPIO or other peripherals even after CPU reset. Reset to stop these control. SET_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); @@ -79,6 +80,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_HMAC_CONF_REG, PCR_HMAC_RST_EN); CLEAR_PERI_REG_MASK(PCR_RSA_CONF_REG, PCR_RSA_RST_EN); CLEAR_PERI_REG_MASK(PCR_SHA_CONF_REG, PCR_SHA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // UART's sclk is controlled in the PCR register and does not reset with the UART module. The ROM missed enabling // it when initializing the ROM UART. If it is not turned on, it will trigger LP_WDT in the ROM. diff --git a/components/esp_system/port/soc/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c index 83d6204f70..f0606935d9 100644 --- a/components/esp_system/port/soc/esp32c61/system_internal.c +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -58,6 +58,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_SDIO_SLAVE_CONF_REG, PCR_SDIO_SLAVE_RST_EN); //ETM may directly control the GPIO or other peripherals even after CPU reset. Reset to stop these control. SET_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); @@ -68,6 +69,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); CLEAR_PERI_REG_MASK(PCR_SDIO_SLAVE_CONF_REG, PCR_SDIO_SLAVE_RST_EN); CLEAR_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + CLEAR_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Reset crypto peripherals. This ensures a clean state for the crypto peripherals after a CPU restart // and hence avoiding any possibility with crypto failure in ROM security workflows. diff --git a/components/esp_system/port/soc/esp32h2/system_internal.c b/components/esp_system/port/soc/esp32h2/system_internal.c index 26975864a8..e87ad82435 100644 --- a/components/esp_system/port/soc/esp32h2/system_internal.c +++ b/components/esp_system/port/soc/esp32h2/system_internal.c @@ -50,6 +50,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); //ETM may directly control the GPIO or other peripherals even after CPU reset. Reset to stop these control. SET_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); @@ -60,6 +61,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); CLEAR_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); CLEAR_PERI_REG_MASK(PCR_ETM_CONF_REG, PCR_ETM_RST_EN); + CLEAR_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Reset crypto peripherals. This ensures a clean state for the crypto peripherals after a CPU restart // and hence avoiding any possibility with crypto failure in ROM security workflows. diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 6fec8447b4..0aa92a6aa4 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -768,6 +768,15 @@ menu "Wi-Fi" Select this configuration to free dynamic buffers during WiFi enterprise connection. This will enable chip to reduce heap consumption during WiFi enterprise connection. + config ESP_WIFI_MODEM_RF_FLAG_UPDATE_DEBUG + bool "Enable debug assertions for modem RF flag update" + depends on ESP_WIFI_ENHANCED_LIGHT_SLEEP + default n + help + Enable debug assertions to verify modem RF flag update operations. + This option enables assert checks to verify that modem RF power state + is correctly cleared before pmu sleep. + endif # wifi enabled endmenu # Wi-Fi diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 9fea6df9ff..ae6fbc7dfd 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -236,7 +236,10 @@ static esp_err_t wifi_deinit_internal(void) #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP esp_wifi_internal_modem_state_configure(false); esp_pm_unregister_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); +#if ESP_MODEM_RF_FLAG_UPDATE_CB_REQUIRED + esp_unregister_mac_bb_pd_callback(esp_phy_modem_rf_flag_update); #endif +#endif /* CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP */ #ifdef CONFIG_ESP_PHY_ENABLED esp_phy_modem_deinit(); #endif @@ -432,6 +435,12 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) if (sleep_modem_wifi_modem_state_enabled()) { esp_pm_register_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); esp_wifi_internal_modem_state_configure(true); /* require WiFi to enable automatically receives the beacon */ +#if ESP_MODEM_RF_FLAG_UPDATE_CB_REQUIRED + if (esp_register_mac_bb_pd_callback(esp_phy_modem_rf_flag_update) != ESP_OK) { + ESP_LOGE(TAG, "Failed to register modem RF flag update callback"); + goto _deinit; + } +#endif } #endif #if CONFIG_IDF_TARGET_ESP32 diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 5e82ed4214..a7f6dc46d1 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1447,6 +1447,10 @@ config SOC_EXT_MEM_CACHE_TAG_IN_CPU_DOMAIN bool default y +config SOC_PM_MODEM_RF_FLAG_UPDATE_WORKAROUND + bool + default y + config SOC_PM_PAU_LINK_NUM int default 4 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 5613cbcaf7..d55bd9cbe4 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -565,6 +565,8 @@ #define SOC_PM_RETENTION_HAS_CLOCK_BUG (1) #define SOC_EXT_MEM_CACHE_TAG_IN_CPU_DOMAIN (1) +#define SOC_PM_MODEM_RF_FLAG_UPDATE_WORKAROUND (1) + #define SOC_PM_PAU_LINK_NUM (4) #define SOC_PM_PAU_REGDMA_LINK_MULTI_ADDR (1) #define SOC_PM_PAU_REGDMA_LINK_WIFIMAC (1)