1 /*
2  * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stddef.h>
8 #include <string.h>
9 #include <sys/lock.h>
10 #include <sys/param.h>
11 
12 #include "esp_attr.h"
13 #include "esp_sleep.h"
14 #include "esp_cpu.h"
15 
16 #include "soc/soc.h"
17 #include "soc/rtc.h"
18 #include "soc/soc_caps.h"
19 #include "hal/uart_ll.h"
20 
21 #if SOC_LP_TIMER_SUPPORTED
22 #include "hal/lp_timer_ll.h"
23 #include "hal/lp_timer_hal.h"
24 #else
25 #include "hal/rtc_cntl_ll.h"
26 #endif
27 
28 #if SOC_PMU_SUPPORTED
29 #include "hal/pmu_ll.h"
30 #endif
31 
32 #include "sdkconfig.h"
33 #include "esp_rom_uart.h"
34 #include "esp_rom_sys.h"
35 
36 #ifdef CONFIG_IDF_TARGET_ESP32
37 #include "esp32/rom/rtc.h"
38 #elif CONFIG_IDF_TARGET_ESP32S2
39 #include "esp32s2/rom/rtc.h"
40 #elif CONFIG_IDF_TARGET_ESP32S3
41 #include "esp32s3/rom/rtc.h"
42 #elif CONFIG_IDF_TARGET_ESP32C3
43 #include "esp32c3/rom/rtc.h"
44 #elif CONFIG_IDF_TARGET_ESP32C6
45 #include "esp32c6/rom/rtc.h"
46 #elif CONFIG_IDF_TARGET_ESP32H2
47 #include "esp32h2/rom/rtc.h"
48 #endif
49 
esp_wake_stub_sleep(esp_deep_sleep_wake_stub_fn_t new_stub)50 void RTC_IRAM_ATTR esp_wake_stub_sleep(esp_deep_sleep_wake_stub_fn_t new_stub)
51 {
52 
53 #if CONFIG_IDF_TARGET_ESP32
54     // Since the app core of esp32 does not support access to RTC_FAST_MEMORY,
55     // `esp_set_deep_sleep_wake_stub` is not declared in RTC_FAST_MEMORY,
56     // so we cannot call it here
57     REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub);
58 #else
59     esp_set_deep_sleep_wake_stub(new_stub);
60 #endif
61 
62 #if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
63     esp_set_deep_sleep_wake_stub_default_entry();
64 #else
65     set_rtc_memory_crc();
66 #endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_MEM
67 
68     // Go to sleep.
69 #if SOC_PMU_SUPPORTED
70     pmu_ll_hp_clear_wakeup_intr_status(&PMU);
71     pmu_ll_hp_clear_reject_intr_status(&PMU);
72     pmu_ll_hp_clear_reject_cause(&PMU);
73     pmu_ll_hp_set_sleep_enable(&PMU);
74 #else
75     rtc_cntl_ll_sleep_enable();
76 #endif
77 
78     // A few CPU cycles may be necessary for the sleep to start...
79 #if __XTENSA__
80     xt_utils_wait_for_intr();
81 #else
82     rv_utils_wait_for_intr();
83 #endif // __XTENSA__
84     // never reaches here.
85 }
86 
esp_wake_stub_uart_tx_wait_idle(uint8_t uart_no)87 void RTC_IRAM_ATTR esp_wake_stub_uart_tx_wait_idle(uint8_t uart_no)
88 {
89     while (!uart_ll_is_tx_idle(UART_LL_GET_HW(uart_no))) {};
90 }
91 
esp_wake_stub_set_wakeup_time(uint64_t time_in_us)92 void RTC_IRAM_ATTR esp_wake_stub_set_wakeup_time(uint64_t time_in_us)
93 {
94 #if SOC_LP_TIMER_SUPPORTED
95     uint64_t rtc_count_delta = lp_timer_ll_time_to_count(time_in_us);
96 
97     lp_timer_ll_counter_snapshot(&LP_TIMER);
98     uint32_t lo = lp_timer_ll_get_counter_value_low(&LP_TIMER, 0);
99     uint32_t hi = lp_timer_ll_get_counter_value_high(&LP_TIMER, 0);
100     uint64_t rtc_curr_count = (uint64_t)hi << 32 | lo;
101 
102     lp_timer_ll_clear_alarm_intr_status(&LP_TIMER);
103     lp_timer_ll_set_alarm_target(&LP_TIMER, 0, rtc_curr_count + rtc_count_delta);
104     lp_timer_ll_set_target_enable(&LP_TIMER, 0, true);
105 #else
106     uint64_t rtc_count_delta = rtc_cntl_ll_time_to_count(time_in_us);
107     uint64_t rtc_curr_count = rtc_cntl_ll_get_rtc_time();
108     rtc_cntl_ll_set_wakeup_timer(rtc_curr_count + rtc_count_delta);
109 #endif
110 
111 }
112 
esp_wake_stub_get_wakeup_cause(void)113 uint32_t RTC_IRAM_ATTR esp_wake_stub_get_wakeup_cause(void)
114 {
115 #if SOC_PMU_SUPPORTED
116     return pmu_ll_hp_get_wakeup_cause(&PMU);
117 #else
118     return rtc_cntl_ll_get_wakeup_cause();
119 #endif
120 }
121