Jelajahi Sumber

sleep: light sleep supported for esp32c6

Li Shuai 3 tahun lalu
induk
melakukan
68594abe05

+ 1 - 1
components/driver/test_apps/gpio/main/test_gpio.c

@@ -844,7 +844,7 @@ TEST_CASE("GPIO_USB_DP_pin_pullup_disable_test", "[gpio]")
 }
 #endif //SOC_USB_SERIAL_JTAG_SUPPORTED
 
-#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) // TODO: IDF-5348, IDF-6267 Remove when light sleep is supported
+#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32H2) // TODO: IDF-6267 Remove when light sleep is supported
 // Ignored in CI because it needs manually connect TEST_GPIO_INPUT_LEVEL_LOW_PIN to 3.3v to wake up from light sleep
 TEST_CASE("GPIO_light_sleep_wake_up_test", "[gpio][ignore]")
 {

+ 1 - 1
components/esp_hw_support/Kconfig

@@ -67,7 +67,7 @@ menu "Hardware Settings"
 
         config ESP_SLEEP_GPIO_RESET_WORKAROUND
             bool "light sleep GPIO reset workaround"
-            default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 # TODO: IDF-5641 (esp32c6)
+            default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6
             select PM_SLP_DISABLE_GPIO if FREERTOS_USE_TICKLESS_IDLE
             help
                 esp32c2, esp32c3 and esp32s3 will reset at wake-up if GPIO is received a small electrostatic

+ 17 - 0
components/esp_hw_support/sleep_gpio.c

@@ -20,10 +20,15 @@
 #include "driver/gpio.h"
 #include "hal/gpio_hal.h"
 #include "hal/rtc_io_hal.h"
+
+#if !SOC_PMU_SUPPORTED
 #include "hal/rtc_hal.h"
+#endif
+
 #include "esp_private/gpio.h"
 #include "esp_private/sleep_gpio.h"
 #include "esp_private/spi_flash_os.h"
+#include "esp_private/startup_internal.h"
 #include "bootloader_flash.h"
 
 static const char *TAG = "sleep";
@@ -180,3 +185,15 @@ void esp_deep_sleep_wakeup_io_reset(void)
     }
 #endif
 }
+
+#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
+ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
+{
+    // Configure to isolate (disable the Input/Output/Pullup/Pulldown
+    // function of the pin) all GPIO pins in sleep state
+    esp_sleep_config_gpio_isolate();
+    // Enable automatic switching of GPIO configuration
+    esp_sleep_enable_gpio_switch(true);
+    return ESP_OK;
+}
+#endif

+ 53 - 55
components/esp_hw_support/sleep_modes.c

@@ -51,7 +51,6 @@
 #include "esp_private/brownout.h"
 #include "esp_private/sleep_cpu.h"
 #include "esp_private/esp_clk.h"
-#include "esp_private/startup_internal.h"
 #include "esp_private/esp_task_wdt.h"
 
 #ifdef CONFIG_IDF_TARGET_ESP32
@@ -75,6 +74,8 @@
 #include "esp32c2/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32C6
 #include "esp32c6/rom/rtc.h"
+#include "hal/lp_timer_hal.h"
+#include "esp_private/esp_pmu.h"
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/rtc.h"
 #include "esp32h2/rom/cache.h"
@@ -185,9 +186,7 @@ static sleep_config_t s_config = {
 
 /* Internal variable used to track if light sleep wakeup sources are to be
    expected when determining wakeup cause. */
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static bool s_light_sleep_wakeup = false;
-#endif
 
 /* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
    is not thread-safe, so we need to disable interrupts before going to deep sleep. */
@@ -210,13 +209,11 @@ static uint32_t get_power_down_flags(void);
 static void ext0_wakeup_prepare(void);
 static void ext1_wakeup_prepare(void);
 #endif
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static void timer_wakeup_prepare(void);
-#endif
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 static void touch_wakeup_prepare(void);
 #endif
-#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
+#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
 static void gpio_deep_sleep_wakeup_prepare(void);
 #endif
 
@@ -308,7 +305,6 @@ void esp_deep_sleep(uint64_t time_in_us)
 }
 
 // [refactor-todo] provide target logic for body of uart functions below
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static void IRAM_ATTR flush_uarts(void)
 {
     for (int i = 0; i < SOC_UART_NUM; ++i) {
@@ -353,7 +349,6 @@ static void IRAM_ATTR resume_uarts(void)
         uart_ll_force_xon(i);
     }
 }
-#endif
 
 /**
  * These save-restore workaround should be moved to lower layer
@@ -393,7 +388,7 @@ inline static void IRAM_ATTR misc_modules_wake_prepare(void)
 #endif
 }
 
-inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu);
+inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp);
 
 inline static bool is_light_sleep(uint32_t pd_flags)
 {
@@ -402,9 +397,6 @@ inline static bool is_light_sleep(uint32_t pd_flags)
 
 static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
 {
-#if CONFIG_IDF_TARGET_ESP32C6
-    return 0; // TODO: WIFI-5150
-#else
     // 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.
     // For deep sleep, wait for the contents of UART FIFO to be sent.
@@ -508,7 +500,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
     }
 
     // Enter sleep
-#if CONFIG_IDF_TARGET_ESP32C6
+#if SOC_PMU_SUPPORTED
     pmu_sleep_config_t config;
     pmu_sleep_init(pmu_sleep_config_default(&config, pd_flags, s_config.sleep_time_adjustment,
             s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period,
@@ -536,6 +528,8 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
         esp_sleep_isolate_digital_gpio();
 #endif
 
+#if !CONFIG_IDF_TARGET_ESP32C6  // TODO: IDF-5349
+
 #if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
         extern char _rtc_text_start[];
 #if CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM
@@ -546,7 +540,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
         size_t rtc_fast_length = (size_t)_rtc_force_fast_end - (size_t)_rtc_text_start;
 #endif
         esp_rom_set_rtc_wake_addr((esp_rom_wake_func_t)esp_wake_stub_entry, rtc_fast_length);
-        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
+        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
 #else
 #if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
         /* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
@@ -554,14 +548,26 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
         // RTC has no rtc memory, IDF-3901
         set_rtc_memory_crc();
 #endif
-        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
+        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
 #else
         /* Otherwise, need to call the dedicated soc function for this */
         result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
 #endif
 #endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
+
+#else
+        result = ESP_OK;
+#endif
     } else {
-        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
+#if SOC_PM_CPU_RETENTION_BY_SW
+        if (pd_flags & PMU_SLEEP_PD_CPU) {
+            result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
+        } else {
+            result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
+        }
+#else
+        result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
+#endif
     }
 
     // Restore CPU frequency
@@ -576,13 +582,14 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
     resume_uarts();
 
     return result;
-#endif
 }
 
-inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu)
+inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp)
 {
 #ifdef CONFIG_IDF_TARGET_ESP32
     return rtc_sleep_start(s_config.wakeup_triggers, reject_triggers);
+#elif SOC_PMU_SUPPORTED
+    return pmu_sleep_start(s_config.wakeup_triggers, reject_triggers, lslp_mem_inf_fpu, dslp);
 #else
     return rtc_sleep_start(s_config.wakeup_triggers, reject_triggers, lslp_mem_inf_fpu);
 #endif
@@ -647,16 +654,12 @@ void IRAM_ATTR esp_deep_sleep_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.
  */
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
                                        uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline));
 
 static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
                                        uint32_t flash_enable_time_us)
 {
-#if CONFIG_IDF_TARGET_ESP32C6
-    return ESP_ERR_NOT_SUPPORTED; // TODO: WIFI-5150
-#else
     // Enter sleep
     uint32_t reject = esp_sleep_start(pd_flags);
 
@@ -676,9 +679,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
     }
 
     return reject ? ESP_ERR_SLEEP_REJECT : ESP_OK;
-#endif
 }
-#endif
 
 /**
  * vddsdio is used for power supply of spi flash
@@ -730,7 +731,11 @@ esp_err_t esp_light_sleep_start(void)
      */
     esp_clk_private_lock();
 
+#if SOC_LP_TIMER_SUPPORTED
+    s_config.rtc_ticks_at_sleep_start = lp_timer_hal_get_cycle_count(0);
+#else
     s_config.rtc_ticks_at_sleep_start = rtc_time_get();
+#endif
     uint32_t ccount_at_sleep_start = esp_cpu_get_cycle_count();
     uint64_t high_res_time_at_start = esp_timer_get_time();
     uint32_t sleep_time_overhead_in = (ccount_at_sleep_start - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
@@ -763,10 +768,6 @@ esp_err_t esp_light_sleep_start(void)
     esp_clk_slowclk_cal_set(s_config.rtc_clk_cal_period);
 #endif
 
-#if CONFIG_IDF_TARGET_ESP32C6
-    s_config.fast_clk_cal_period = rtc_clk_cal(RTC_CAL_RC_FAST, FAST_CLK_SRC_CAL_CYCLES);
-#endif
-
     /*
      * Adjustment time consists of parts below:
      * 1. Hardware time waiting for internal 8M oscilate clock and XTAL;
@@ -775,7 +776,8 @@ esp_err_t esp_light_sleep_start(void)
      * 4. Code execution time which can be measured;
      */
 
-#if CONFIG_IDF_TARGET_ESP32C6
+#if SOC_PMU_SUPPORTED
+    s_config.fast_clk_cal_period = rtc_clk_cal(RTC_CAL_RC_FAST, FAST_CLK_SRC_CAL_CYCLES);
     int sleep_time_sw_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US + sleep_time_overhead_in + s_config.sleep_time_overhead_out;
     int sleep_time_hw_adjustment = pmu_sleep_calculate_hw_wait_time(pd_flags, s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period);
     s_config.sleep_time_adjustment = sleep_time_sw_adjustment + sleep_time_hw_adjustment;
@@ -864,7 +866,11 @@ esp_err_t esp_light_sleep_start(void)
     s_light_sleep_wakeup = (err == ESP_OK);
 
     // System timer has been stopped for the duration of the sleep, correct for that.
+#if SOC_LP_TIMER_SUPPORTED
+    uint64_t rtc_ticks_at_end = lp_timer_hal_get_cycle_count(0);
+#else
     uint64_t rtc_ticks_at_end = rtc_time_get();
+#endif
     uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start, s_config.rtc_clk_cal_period);
 
     /**
@@ -895,7 +901,6 @@ esp_err_t esp_light_sleep_start(void)
 
     s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
     return err;
-#endif
 }
 
 esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)
@@ -973,7 +978,6 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
     return ESP_OK;
 }
 
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static void timer_wakeup_prepare(void)
 {
     int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
@@ -982,9 +986,13 @@ static void timer_wakeup_prepare(void)
     }
 
     int64_t ticks = rtc_time_us_to_slowclk(sleep_duration, s_config.rtc_clk_cal_period);
+
+#if SOC_LP_TIMER_SUPPORTED
+    lp_timer_hal_set_alarm_target(0, s_config.rtc_ticks_at_sleep_start + ticks);
+#else
     rtc_hal_set_wakeup_timer(s_config.rtc_ticks_at_sleep_start + ticks);
-}
 #endif
+}
 
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 /* In deep sleep mode, only the sleep channel is supported, and other touch channels should be turned off. */
@@ -1167,16 +1175,20 @@ uint64_t esp_sleep_get_ext1_wakeup_status(void)
 #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
 uint64_t esp_sleep_get_gpio_wakeup_status(void)
 {
+#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5349
+    return 0;
+#else
     if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_GPIO) {
         return 0;
     }
 
     return rtc_hal_gpio_get_wakeup_status();
+#endif
 }
 
-#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
 static void gpio_deep_sleep_wakeup_prepare(void)
 {
+#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5349
     for (gpio_num_t gpio_idx = GPIO_NUM_0; gpio_idx < GPIO_NUM_MAX; gpio_idx++) {
         if (((1ULL << gpio_idx) & s_config.gpio_wakeup_mask) == 0) {
             continue;
@@ -1192,8 +1204,8 @@ static void gpio_deep_sleep_wakeup_prepare(void)
     }
     // Clear state from previous wakeup
     rtc_hal_gpio_clear_wakeup_status();
-}
 #endif
+}
 
 esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask, esp_deepsleep_gpio_wake_up_mode_t mode)
 {
@@ -1293,14 +1305,20 @@ esp_err_t esp_sleep_disable_bt_wakeup(void)
 
 esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
 {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5645
+#if CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5645
     return ESP_SLEEP_WAKEUP_UNDEFINED;
 #else
     if (esp_rom_get_reset_reason(0) != RESET_REASON_CORE_DEEP_SLEEP && !s_light_sleep_wakeup) {
         return ESP_SLEEP_WAKEUP_UNDEFINED;
     }
 
+#ifdef CONFIG_IDF_TARGET_ESP32
+    uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
+#elif SOC_PMU_SUPPORTED
+    uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU);
+#else
     uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause();
+#endif
 
     if (wakeup_cause & RTC_TIMER_TRIG_EN) {
         return ESP_SLEEP_WAKEUP_TIMER;
@@ -1489,11 +1507,7 @@ static uint32_t get_power_down_flags(void)
 #endif
 #if SOC_PM_SUPPORT_RC_FAST_PD
     if (s_config.domain[ESP_PD_DOMAIN_RC_FAST].pd_option != ESP_PD_OPTION_ON) {
-#if CONFIG_IDF_TARGET_ESP32C6
-        pd_flags |= PMU_SLEEP_PD_FOSC;
-#else
         pd_flags |= RTC_SLEEP_PD_INT_8M;
-#endif
     }
 #endif
 #if SOC_PM_SUPPORT_XTAL_PD
@@ -1503,11 +1517,7 @@ static uint32_t get_power_down_flags(void)
 #endif
 #if SOC_PM_SUPPORT_VDDSDIO_PD
     if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option != ESP_PD_OPTION_ON) {
-#if CONFIG_IDF_TARGET_ESP32C6
-        pd_flags |= PMU_SLEEP_PD_VDDSDIO;
-#else
         pd_flags |= RTC_SLEEP_PD_VDDSDIO;
-#endif
     }
 #endif
 
@@ -1535,15 +1545,3 @@ void rtc_sleep_enable_ultra_low(bool enable)
 {
     s_ultra_low_enabled = enable;
 }
-
-#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
-ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
-{
-    // Configure to isolate (disable the Input/Output/Pullup/Pulldown
-    // function of the pin) all GPIO pins in sleep state
-    esp_sleep_config_gpio_isolate();
-    // Enable automatic switching of GPIO configuration
-    esp_sleep_enable_gpio_switch(true);
-    return ESP_OK;
-}
-#endif

+ 1 - 1
components/esp_pm/Kconfig

@@ -87,7 +87,7 @@ menu "Power Management"
 
     config PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
         bool "Power down CPU in light sleep"
-        depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
+        depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6
         select PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP if ESP32S3_DATA_CACHE_16KB
         default y
         help

+ 1 - 1
components/esp_system/system_init_fn.txt

@@ -17,7 +17,7 @@
 100: esp_timer_startup_init in components/esp_timer/src/esp_timer.c on BIT(0)
 
 # esp_sleep doesn't have init dependencies
-105: esp_sleep_startup_init in components/esp_hw_support/sleep_modes.c on BIT(0)
+105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
 
 # app_trace has to be initialized before systemview
 115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES

+ 11 - 2
components/esp_system/test/test_sleep.c

@@ -19,7 +19,6 @@
 #include "soc/rtc.h"            // for wakeup trigger defines
 #include "soc/rtc_periph.h"     // for read rtc registers directly (cause)
 #include "soc/soc.h"            // for direct register read macros
-#include "hal/rtc_cntl_ll.h"
 #include "esp_newlib.h"
 #include "test_utils.h"
 #include "sdkconfig.h"
@@ -29,6 +28,12 @@
 #include "esp_private/esp_clk.h"
 #include "esp_random.h"
 
+#if SOC_PMU_SUPPORTED
+#include "esp_private/esp_pmu.h"
+#else
+#include "hal/rtc_cntl_ll.h"
+#endif
+
 #define ESP_EXT0_WAKEUP_LEVEL_LOW 0
 #define ESP_EXT0_WAKEUP_LEVEL_HIGH 1
 
@@ -445,7 +450,11 @@ __attribute__((unused)) static float get_time_ms(void)
 
 __attribute__((unused)) static uint32_t get_cause(void)
 {
+#if SOC_PMU_SUPPORTED
+    uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU);
+#else
     uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause();
+#endif
     return wakeup_cause;
 }
 
@@ -590,4 +599,4 @@ TEST_CASE("wake up using GPIO (2 or 4 low)", "[deepsleep][ignore]")
 }
 #endif // SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
 #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
-#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) TODO: IDF-5348, IDF-5349
+#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) TODO: IDF-5349