Эх сурвалжийг харах

Merge branch 'feature/wifi_lightsleep_optimization' into 'master'

esp_wifi: Wi-Fi lightsleep optimization

See merge request espressif/esp-idf!11811
Jiang Jiang Jian 5 жил өмнө
parent
commit
3748fdbbb3

+ 19 - 0
components/driver/include/driver/periph_ctrl.h

@@ -91,6 +91,25 @@ void wifi_bt_common_module_enable(void);
  */
 void wifi_bt_common_module_disable(void);
 
+/**
+ * @brief      enable wifi module
+ *
+ * @note Enable wifi module only.
+ *
+ * @return     NULL
+ *
+ */
+void wifi_module_enable(void);
+
+/**
+ * @brief      disable wifi module
+ *
+ * @note Disable wifi module only.
+ *
+ * @return     NULL
+ *
+ */
+void wifi_module_disable(void);
 #ifdef __cplusplus
 }
 #endif

+ 10 - 0
components/driver/periph_ctrl.c

@@ -68,3 +68,13 @@ IRAM_ATTR void wifi_bt_common_module_disable(void)
     }
     portEXIT_CRITICAL_SAFE(&periph_spinlock);
 }
+
+void wifi_module_enable(void)
+{
+    periph_ll_wifi_module_enable_clk_clear_rst();
+}
+
+void wifi_module_disable(void)
+{
+    periph_ll_wifi_module_disable_clk_set_rst();
+}

+ 27 - 0
components/esp32/ld/esp32_fragments.lf

@@ -96,6 +96,18 @@ entries:
 entries:
     .phyiram+
 
+[sections:wifi_slp_iram]
+entries:
+    .wifislpiram+
+
+[sections:wifi_or_slp_iram]
+entries:
+    .wifiorslpiram+
+
+[sections:wifi_slp_rx_iram]
+entries:
+    .wifislprxiram+
+
 [scheme:default]
 entries:
     if APP_BUILD_USE_FLASH_SECTIONS = y:
@@ -127,6 +139,9 @@ entries:
     iram_coredump -> iram_coredump
     rtc_coredump -> rtc_coredump
     rtc_fast_coredump -> rtc_fast_coredump
+    wifi_slp_iram -> flash_text
+    wifi_or_slp_iram -> flash_text
+    wifi_slp_rx_iram -> flash_text
 
 [scheme:rtc]
 entries:
@@ -165,3 +180,15 @@ entries:
 entries:
     bss -> extern_ram
     common -> extern_ram
+
+[scheme:wifi_slp_iram]
+entries:
+    wifi_slp_iram -> iram0_text
+
+[scheme:wifi_or_slp_iram]
+entries:
+    wifi_or_slp_iram -> iram0_text
+
+[scheme:wifi_slp_rx_iram]
+entries:
+    wifi_slp_rx_iram -> iram0_text

+ 27 - 0
components/esp32c3/ld/esp32c3_fragments.lf

@@ -76,6 +76,18 @@ entries:
 entries:
     .wifirxiram+
 
+[sections:wifi_slp_iram]
+entries:
+    .wifislpiram+
+
+[sections:wifi_or_slp_iram]
+entries:
+    .wifiorslpiram+
+
+[sections:wifi_slp_rx_iram]
+entries:
+    .wifislprxiram+
+
 [scheme:default]
 entries:
     if APP_BUILD_USE_FLASH_SECTIONS = y:
@@ -101,6 +113,9 @@ entries:
     iram_coredump -> iram_coredump
     rtc_coredump -> rtc_coredump
     rtc_fast_coredump -> rtc_fast_coredump
+    wifi_slp_iram -> flash_text
+    wifi_or_slp_iram -> flash_text
+    wifi_slp_rx_iram -> flash_text
 
 [scheme:rtc]
 entries:
@@ -130,3 +145,15 @@ entries:
 [scheme:wifi_rx_iram]
 entries:
     wifi_rx_iram -> iram0_text
+
+[scheme:wifi_slp_iram]
+entries:
+    wifi_slp_iram -> iram0_text
+
+[scheme:wifi_or_slp_iram]
+entries:
+    wifi_or_slp_iram -> iram0_text
+
+[scheme:wifi_slp_rx_iram]
+entries:
+    wifi_slp_rx_iram -> iram0_text

+ 27 - 0
components/esp32s2/ld/esp32s2_fragments.lf

@@ -64,6 +64,18 @@ entries:
 entries:
     .wifirxiram+
 
+[sections:wifi_slp_iram]
+entries:
+    .wifislpiram+
+
+[sections:wifi_or_slp_iram]
+entries:
+    .wifiorslpiram+
+
+[sections:wifi_slp_rx_iram]
+entries:
+    .wifislprxiram+
+
 [scheme:default]
 entries:
     text -> flash_text
@@ -82,6 +94,9 @@ entries:
     dram_coredump -> dram_coredump
     rtc_coredump -> rtc_coredump
     rtc_fast_coredump -> rtc_fast_coredump
+    wifi_slp_iram -> flash_text
+    wifi_or_slp_iram -> flash_text
+    wifi_slp_rx_iram -> flash_text
 
 [scheme:rtc]
 entries:
@@ -111,3 +126,15 @@ entries:
 [scheme:wifi_rx_iram]
 entries:
     wifi_rx_iram -> iram0_text
+
+[scheme:wifi_slp_iram]
+entries:
+    wifi_slp_iram -> iram0_text
+
+[scheme:wifi_or_slp_iram]
+entries:
+    wifi_or_slp_iram -> iram0_text
+
+[scheme:wifi_slp_rx_iram]
+entries:
+    wifi_slp_rx_iram -> iram0_text

+ 30 - 2
components/esp_pm/include/esp_private/pm_impl.h

@@ -112,7 +112,6 @@ void esp_pm_impl_dump_stats(FILE* out);
  */
 void esp_pm_impl_waiti(void);
 
-#if CONFIG_IDF_TARGET_ESP32S2
 /**
  * @brief Callback function type for peripherals to skip light sleep.
  *
@@ -142,7 +141,36 @@ esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
   *   - ESP_ERR_INVALID_STATE if the given callback hasn't been registered before
   */
 esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
-#endif
+
+/**
+ * @brief Callback function type for peripherals to know light sleep wakeup overhead.
+ *
+ */
+typedef void (* inform_out_light_sleep_overhead_cb_t)(uint32_t);
+
+/**
+  * @brief  Register informing peripherals light sleep wakeup overhead time callback
+  *
+  * This function allows you to register a callback that informs the peripherals of
+  * the wakeup overhead time of light sleep.
+  * @param cb function to inform time
+  * @return
+  *   - ESP_OK on success
+  *   - ESP_ERR_NO_MEM if no more callback slots are available
+  */
+esp_err_t esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb);
+
+/**
+  * @brief  Unregister informing peripherals light sleep wakeup overhead time callback
+  *
+  * This function allows you to unregister a callback that informs the peripherals of
+  * the wakeup overhead time of light sleep.
+  * @param cb function to inform time
+  * @return
+  *   - ESP_OK on success
+  *   - ESP_ERR_INVALID_STATE if the given callback hasn't been registered before
+  */
+esp_err_t esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb);
 
 #ifdef CONFIG_PM_PROFILING
 #define WITH_PROFILING

+ 2 - 0
components/esp_pm/linker.lf

@@ -4,6 +4,8 @@ entries:
     if PM_RTOS_IDLE_OPT = y:
         pm_impl:esp_pm_impl_idle_hook (noflash)
         pm_impl:esp_pm_impl_waiti (noflash)
+    if PM_SLP_IRAM_OPT = y && IDF_TARGET_ESP32 = n:
+        pm_impl:periph_inform_out_light_sleep_overhead (noflash)
 
 [mapping:esp_common_pm]
 archive: libesp_common.a

+ 95 - 60
components/esp_pm/pm_impl.c

@@ -112,12 +112,10 @@ static uint32_t s_ccount_mul;
 
 #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
 
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 #define PERIPH_SKIP_LIGHT_SLEEP_NO 1
 
 /* Indicates if light sleep shoule be skipped by peripherals. */
 static skip_light_sleep_cb_t s_periph_skip_light_sleep_cb[PERIPH_SKIP_LIGHT_SLEEP_NO];
-#endif
 
 /* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU.
  * This in turn gets used in IDLE hook to decide if `waiti` needs
@@ -488,61 +486,8 @@ static void IRAM_ATTR leave_idle(void)
     }
 }
 
-void esp_pm_impl_idle_hook(void)
-{
-    int core_id = xPortGetCoreID();
-    uint32_t state = portENTER_CRITICAL_NESTED();
-    if (!s_core_idle[core_id]) {
-        esp_pm_lock_release(s_rtos_lock_handle[core_id]);
-        s_core_idle[core_id] = true;
-    }
-    portEXIT_CRITICAL_NESTED(state);
-    ESP_PM_TRACE_ENTER(IDLE, core_id);
-}
-
-void IRAM_ATTR esp_pm_impl_isr_hook(void)
-{
-    int core_id = xPortGetCoreID();
-    ESP_PM_TRACE_ENTER(ISR_HOOK, core_id);
-    /* Prevent higher level interrupts (than the one this function was called from)
-     * from happening in this section, since they will also call into esp_pm_impl_isr_hook.
-     */
-    uint32_t state = portENTER_CRITICAL_NESTED();
-#if portNUM_PROCESSORS == 2
-    if (s_need_update_ccompare[core_id]) {
-        update_ccompare();
-        s_need_update_ccompare[core_id] = false;
-    } else {
-        leave_idle();
-    }
-#else
-    leave_idle();
-#endif // portNUM_PROCESSORS == 2
-    portEXIT_CRITICAL_NESTED(state);
-    ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
-}
-
-void esp_pm_impl_waiti(void)
-{
-#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
-    int core_id = xPortGetCoreID();
-    if (s_skipped_light_sleep[core_id]) {
-        asm("waiti 0");
-        /* Interrupt took the CPU out of waiti and s_rtos_lock_handle[core_id]
-         * is now taken. However since we are back to idle task, we can release
-         * the lock so that vApplicationSleep can attempt to enter light sleep.
-         */
-        esp_pm_impl_idle_hook();
-        s_skipped_light_sleep[core_id] = false;
-    }
-#else
-    asm("waiti 0");
-#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
-}
-
 #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
 
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb)
 {
     for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) {
@@ -578,7 +523,6 @@ static inline bool IRAM_ATTR periph_should_skip_light_sleep(void)
     }
     return false;
 }
-#endif
 
 static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
 {
@@ -589,11 +533,8 @@ static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
         return true;
     }
 #endif // portNUM_PROCESSORS == 2
-#if CONFIG_IDF_TARGET_ESP32
-    if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
-#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+
     if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching || periph_should_skip_light_sleep()) {
-#endif
         s_skipped_light_sleep[core_id] = true;
     } else {
         s_skipped_light_sleep[core_id] = false;
@@ -743,3 +684,97 @@ void esp_pm_impl_init(void)
     esp_pm_configure(&cfg);
 #endif //CONFIG_PM_DFS_INIT_AUTO
 }
+
+void esp_pm_impl_idle_hook(void)
+{
+    int core_id = xPortGetCoreID();
+    uint32_t state = portENTER_CRITICAL_NESTED();
+    if (!s_core_idle[core_id]
+#ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    && !periph_should_skip_light_sleep()
+#endif
+    ) {
+        esp_pm_lock_release(s_rtos_lock_handle[core_id]);
+        s_core_idle[core_id] = true;
+    }
+    portEXIT_CRITICAL_NESTED(state);
+    ESP_PM_TRACE_ENTER(IDLE, core_id);
+}
+
+void IRAM_ATTR esp_pm_impl_isr_hook(void)
+{
+    int core_id = xPortGetCoreID();
+    ESP_PM_TRACE_ENTER(ISR_HOOK, core_id);
+    /* Prevent higher level interrupts (than the one this function was called from)
+     * from happening in this section, since they will also call into esp_pm_impl_isr_hook.
+     */
+    uint32_t state = portENTER_CRITICAL_NESTED();
+#if portNUM_PROCESSORS == 2
+    if (s_need_update_ccompare[core_id]) {
+        update_ccompare();
+        s_need_update_ccompare[core_id] = false;
+    } else {
+        leave_idle();
+    }
+#else
+    leave_idle();
+#endif // portNUM_PROCESSORS == 2
+    portEXIT_CRITICAL_NESTED(state);
+    ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
+}
+
+void esp_pm_impl_waiti(void)
+{
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    int core_id = xPortGetCoreID();
+    if (s_skipped_light_sleep[core_id]) {
+        asm("waiti 0");
+        /* Interrupt took the CPU out of waiti and s_rtos_lock_handle[core_id]
+         * is now taken. However since we are back to idle task, we can release
+         * the lock so that vApplicationSleep can attempt to enter light sleep.
+         */
+        esp_pm_impl_idle_hook();
+        s_skipped_light_sleep[core_id] = false;
+    }
+#else
+    asm("waiti 0");
+#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
+}
+
+#define PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO 1
+
+/* Inform peripherals of light sleep wakeup overhead time */
+static inform_out_light_sleep_overhead_cb_t s_periph_inform_out_light_sleep_overhead_cb[PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO];
+
+esp_err_t esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
+{
+    for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
+        if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
+            return ESP_OK;
+        } else if (s_periph_inform_out_light_sleep_overhead_cb[i] == NULL) {
+            s_periph_inform_out_light_sleep_overhead_cb[i] = cb;
+            return ESP_OK;
+        }
+    }
+    return ESP_ERR_NO_MEM;
+}
+
+esp_err_t esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
+{
+    for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
+        if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
+            s_periph_inform_out_light_sleep_overhead_cb[i] = NULL;
+            return ESP_OK;
+        }
+    }
+    return ESP_ERR_INVALID_STATE;
+}
+
+void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)
+{
+    for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
+        if (s_periph_inform_out_light_sleep_overhead_cb[i]) {
+            s_periph_inform_out_light_sleep_overhead_cb[i](out_light_sleep_time);
+        }
+    }
+}

+ 4 - 0
components/esp_system/sleep_modes.c

@@ -125,6 +125,8 @@
 #define DEEP_SLEEP_WAKEUP_DELAY     0
 #endif
 
+extern void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time);
+
 // Minimal amount of time we can sleep for
 #define LIGHT_SLEEP_MIN_TIME_US     200
 
@@ -602,6 +604,8 @@ esp_err_t esp_light_sleep_start(void)
     }
 #endif //CONFIG_ESP_SYSTEM_PD_FLASH
 
+    periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in);
+
     rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
 
     // Safety net: enable WDT in case exit from light sleep fails

+ 10 - 0
components/esp_wifi/Kconfig

@@ -321,6 +321,16 @@ menu "Wi-Fi"
             PMF (Protected Management Frames) is a prerequisite feature for a WPA3 connection, it needs to be
             explicitly configured before attempting connection. Please refer to the Wi-Fi Driver API Guide for details.
 
+    config ESP_WIFI_SLP_IRAM_OPT
+        bool "WiFi SLP IRAM speed optimization"
+        help
+            Select this option to place called Wi-Fi library TBTT process and receive beacon functions in IRAM.
+            Some functions can be put in IRAM either by ESP32_WIFI_IRAM_OPT and ESP32_WIFI_RX_IRAM_OPT, or this one.
+            If already enabled ESP32_WIFI_IRAM_OPT, the other 7.3KB IRAM memory would be taken by this option.
+            If already enabled ESP32_WIFI_RX_IRAM_OPT, the other 1.3KB IRAM memory would be taken by this option.
+            If neither of them are enabled, the other 7.4KB IRAM memory would be taken by this option.
+            Wi-Fi power-save mode average current would be reduced if this option is enabled.
+
 endmenu  # Wi-Fi
 
 menu "PHY"

+ 2 - 2
components/esp_wifi/esp32/esp_adapter.c

@@ -460,12 +460,12 @@ static void wifi_reset_mac_wrapper(void)
 
 static void wifi_clock_enable_wrapper(void)
 {
-    periph_module_enable(PERIPH_WIFI_MODULE);
+    wifi_module_enable();
 }
 
 static void wifi_clock_disable_wrapper(void)
 {
-    periph_module_disable(PERIPH_WIFI_MODULE);
+    wifi_module_disable();
 }
 
 static int get_time_wrapper(void *t)

+ 2 - 2
components/esp_wifi/esp32c3/esp_adapter.c

@@ -422,12 +422,12 @@ static void IRAM_ATTR wifi_rtc_disable_iso_wrapper(void)
 
 static void IRAM_ATTR wifi_clock_enable_wrapper(void)
 {
-    periph_module_enable(PERIPH_WIFI_MODULE);
+    wifi_module_enable();
 }
 
 static void IRAM_ATTR wifi_clock_disable_wrapper(void)
 {
-    periph_module_disable(PERIPH_WIFI_MODULE);
+    wifi_module_disable();
 }
 
 static int get_time_wrapper(void *t)

+ 2 - 2
components/esp_wifi/esp32s2/esp_adapter.c

@@ -437,12 +437,12 @@ static void wifi_reset_mac_wrapper(void)
 
 static void wifi_clock_enable_wrapper(void)
 {
-    periph_module_enable(PERIPH_WIFI_MODULE);
+    wifi_module_enable();
 }
 
 static void wifi_clock_disable_wrapper(void)
 {
-    periph_module_disable(PERIPH_WIFI_MODULE);
+    wifi_module_disable();
 }
 
 static int get_time_wrapper(void *t)

+ 12 - 1
components/esp_wifi/include/esp_private/wifi.h

@@ -467,7 +467,7 @@ esp_err_t esp_wifi_internal_get_negotiated_channel(wifi_interface_t ifx, uint8_t
   */
 esp_err_t esp_wifi_internal_get_negotiated_bandwidth(wifi_interface_t ifx, uint8_t aid, uint8_t *bw);
 
-#if CONFIG_IDF_TARGET_ESP32S2
+#if SOC_WIFI_HW_TSF
 /**
   * @brief     Check if WiFi TSF is active
   *
@@ -476,6 +476,12 @@ esp_err_t esp_wifi_internal_get_negotiated_bandwidth(wifi_interface_t ifx, uint8
   *    - false: Not active
   */
 bool esp_wifi_internal_is_tsf_active(void);
+
+/**
+  * @brief     Update WIFI light sleep wake ahead time
+  *
+  */
+void esp_wifi_internal_update_light_sleep_wake_ahead_time(uint32_t);
 #endif
 
 #if CONFIG_MAC_BB_PD
@@ -526,6 +532,11 @@ esp_err_t esp_wifi_set_tx_done_cb(wifi_tx_done_cb_t cb);
  */
 esp_err_t esp_wifi_internal_set_spp_amsdu(wifi_interface_t ifidx, bool spp_cap, bool spp_req);
 
+/**
+  * @brief    Apply WiFi sleep optimization parameters
+  *
+  */
+void esp_wifi_internal_optimize_wake_ahead_time(void);
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit 22a92a009e4107341665ad307e4dd3c605ae31b3
+Subproject commit ab4eb6bee5c1d7a007ac955ec8100f882a32ecb4

+ 48 - 0
components/esp_wifi/linker.lf

@@ -2,6 +2,8 @@
 archive: libphy.a
 entries:
     * (noflash_data)
+    if ESP_WIFI_SLP_IRAM_OPT = y && IDF_TARGET_ESP32 = y:
+        * (phy_iram)
 
 [mapping:rtc]
 archive: librtc.a
@@ -17,6 +19,15 @@ entries:
     if ESP32_WIFI_RX_IRAM_OPT = y:
         * (wifi_rx_iram)
 
+    if ESP_WIFI_SLP_IRAM_OPT = y:
+        * (wifi_slp_iram)
+
+    if ESP32_WIFI_IRAM_OPT || ESP_WIFI_SLP_IRAM_OPT:
+        * (wifi_or_slp_iram)
+
+    if ESP32_WIFI_RX_IRAM_OPT || ESP_WIFI_SLP_IRAM_OPT:
+        * (wifi_slp_rx_iram)
+
     if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y:
         * (extram_bss)
 
@@ -31,3 +42,40 @@ entries:
 
     if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y:
         * (extram_bss)
+
+    if ESP_WIFI_SLP_IRAM_OPT = y:
+        * (wifi_slp_iram)
+
+    if ESP32_WIFI_RX_IRAM_OPT || ESP_WIFI_SLP_IRAM_OPT:
+        * (wifi_slp_rx_iram)
+
+[mapping:coexist]
+archive: libcoexist.a
+entries:
+    if ESP_WIFI_SLP_IRAM_OPT = y:
+        * (wifi_slp_iram)
+
+[mapping:esp_wifi]
+archive: libesp_wifi.a
+entries:
+    if ESP_WIFI_SLP_IRAM_OPT =y:
+        esp_adapter:wifi_clock_enable_wrapper (noflash)
+        esp_adapter:wifi_clock_disable_wrapper (noflash)
+        phy_init:esp_phy_enable (noflash)
+        phy_init:esp_phy_disable (noflash)
+        wifi_init:wifi_apb80m_request (noflash)
+        wifi_init:wifi_apb80m_release (noflash)
+
+[mapping:driver_wifi_pm]
+archive: libdriver.a
+entries:
+    if ESP_WIFI_SLP_IRAM_OPT =y:
+        periph_ctrl:wifi_module_enable (noflash)
+        periph_ctrl:wifi_module_disable (noflash)
+
+[mapping:esp_timer_wifi_pm]
+archive: libesp_timer.a
+entries:
+    if ESP_WIFI_SLP_IRAM_OPT = y && IDF_TARGET_ESP32 = y:
+        esp_timer:timer_task (noflash)
+        esp_timer:timer_process_alarm (noflash)

+ 0 - 1
components/esp_wifi/src/phy_init.c

@@ -207,7 +207,6 @@ IRAM_ATTR void esp_phy_enable(void)
         phy_update_wifi_mac_time(false, s_phy_rf_en_ts);
 #endif
         esp_phy_common_clock_enable();
-        phy_set_wifi_mode_only(0);
 
         if (s_is_phy_calibrated == false) {
             esp_phy_load_cal_and_init();

+ 11 - 0
components/esp_wifi/src/wifi_init.c

@@ -143,6 +143,7 @@ esp_err_t esp_wifi_deinit(void)
 #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
 #if SOC_WIFI_HW_TSF
     esp_pm_unregister_skip_light_sleep_callback(esp_wifi_internal_is_tsf_active);
+    esp_pm_unregister_inform_out_light_sleep_overhead_callback(esp_wifi_internal_update_light_sleep_wake_ahead_time);
 #endif
 #endif
 
@@ -175,6 +176,11 @@ static void esp_wifi_config_info(void)
     ESP_LOGI(TAG, "WiFi RX IRAM OP enabled");
 #endif
 
+#ifdef CONFIG_ESP_WIFI_SLP_IRAM_OPT
+    esp_wifi_internal_optimize_wake_ahead_time();
+    ESP_LOGI(TAG, "WiFi SLP IRAM OP enabled");
+#endif
+
 #ifdef CONFIG_LWIP_IRAM_OPTIMIZATION
     ESP_LOGI(TAG, "LWIP IRAM OP enabled");
 #endif
@@ -202,6 +208,11 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
         ESP_LOGE(TAG, "Failed to register skip light sleep callback (0x%x)", ret);
         return ret;
     }
+    ret = esp_pm_register_inform_out_light_sleep_overhead_callback(esp_wifi_internal_update_light_sleep_wake_ahead_time);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to register inform light sleep overhead callback (0x%x)", ret);
+        return ret;
+    }
     esp_sleep_enable_wifi_wakeup();
 #endif
 #endif

+ 12 - 0
components/hal/esp32/include/hal/clk_gate_ll.h

@@ -267,6 +267,18 @@ static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
         DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
 }
 
+static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
+{
+    DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
+    DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
+}
+
+static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
+{
+    DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
+    DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 12 - 0
components/hal/esp32c3/include/hal/clk_gate_ll.h

@@ -235,6 +235,18 @@ static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
     return DPORT_REG_GET_BIT(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)) == 0 &&
            DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
 }
+
+static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
+{
+    DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
+    DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
+}
+
+static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
+{
+    DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
+    DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
+}
 #ifdef __cplusplus
 }
 #endif

+ 11 - 0
components/hal/esp32s2/include/hal/clk_gate_ll.h

@@ -287,6 +287,17 @@ static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
         DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
 }
 
+static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
+{
+    DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
+    DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
+}
+
+static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
+{
+    DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
+    DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
+}
 #ifdef __cplusplus
 }
 #endif

+ 11 - 0
components/hal/esp32s3/include/hal/clk_gate_ll.h

@@ -283,6 +283,17 @@ static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
            DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
 }
 
+static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
+{
+    DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
+    DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
+}
+
+static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
+{
+    DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
+    DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
+}
 #ifdef __cplusplus
 }
 #endif

+ 2 - 0
examples/wifi/power_save/sdkconfig.defaults

@@ -12,3 +12,5 @@ CONFIG_PM_RTOS_IDLE_OPT=y
 # Disable all GPIO at light sleep
 CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL=y
 CONFIG_PM_SLP_DISABLE_GPIO=y
+# Enable wifi sleep iram optimization
+CONFIG_ESP_WIFI_SLP_IRAM_OPT=y