1 /*
2  * SPDX-FileCopyrightText: 2015-2022 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_log.h"
15 #include "esp_memory_utils.h"
16 #include "soc/soc_caps.h"
17 
18 #include "sdkconfig.h"
19 
20 #include "driver/gpio.h"
21 #include "hal/gpio_hal.h"
22 #include "hal/rtc_io_hal.h"
23 #include "soc/rtc_io_periph.h"
24 
25 #if SOC_LP_AON_SUPPORTED
26 #include "hal/lp_aon_hal.h"
27 #else
28 #include "hal/rtc_hal.h"
29 #endif
30 
31 #include "esp_private/gpio.h"
32 #include "esp_private/sleep_gpio.h"
33 #include "esp_private/spi_flash_os.h"
34 #include "esp_private/startup_internal.h"
35 #include "bootloader_flash.h"
36 
37 static const char *TAG = "sleep";
38 
39 #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_apply(void)40 void gpio_sleep_mode_config_apply(void)
41 {
42     for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
43         if (GPIO_IS_VALID_GPIO(gpio_num)) {
44             gpio_sleep_pupd_config_apply(gpio_num);
45         }
46     }
47 }
48 
gpio_sleep_mode_config_unapply(void)49 IRAM_ATTR void gpio_sleep_mode_config_unapply(void)
50 {
51     for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
52         if (GPIO_IS_VALID_GPIO(gpio_num)) {
53             gpio_sleep_pupd_config_unapply(gpio_num);
54         }
55     }
56 }
57 #endif
58 
esp_sleep_config_gpio_isolate(void)59 void esp_sleep_config_gpio_isolate(void)
60 {
61     ESP_EARLY_LOGI(TAG, "Configure to isolate all GPIO pins in sleep state");
62     for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
63         if (GPIO_IS_VALID_GPIO(gpio_num)) {
64             gpio_sleep_set_direction(gpio_num, GPIO_MODE_DISABLE);
65             gpio_sleep_set_pull_mode(gpio_num, GPIO_FLOATING);
66         }
67     }
68 
69 #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
70     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS1), GPIO_PULLUP_ONLY);
71 #endif // CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
72 
73 #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
74     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS0), GPIO_PULLUP_ONLY);
75 #endif // CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
76 
77 #if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU
78     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CLK), GPIO_PULLUP_ONLY);
79     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_Q),   GPIO_PULLUP_ONLY);
80     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D),   GPIO_PULLUP_ONLY);
81     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_HD),  GPIO_PULLUP_ONLY);
82     gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_WP),  GPIO_PULLUP_ONLY);
83 #if SOC_SPI_MEM_SUPPORT_OPI_MODE
84     bool octal_mspi_required = bootloader_flash_is_octal_mode_enabled();
85 #if CONFIG_SPIRAM_MODE_OCT
86     octal_mspi_required |= true;
87 #endif // CONFIG_SPIRAM_MODE_OCT
88     if (octal_mspi_required) {
89         gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_DQS), GPIO_PULLUP_ONLY);
90         gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D4),  GPIO_PULLUP_ONLY);
91         gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D5),  GPIO_PULLUP_ONLY);
92         gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D6),  GPIO_PULLUP_ONLY);
93         gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D7),  GPIO_PULLUP_ONLY);
94     }
95 #endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
96 #endif // CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU
97 }
98 
esp_sleep_enable_gpio_switch(bool enable)99 void esp_sleep_enable_gpio_switch(bool enable)
100 {
101     ESP_EARLY_LOGI(TAG, "%s automatic switching of GPIO sleep configuration", enable ? "Enable" : "Disable");
102     for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
103         if (GPIO_IS_VALID_GPIO(gpio_num)) {
104             if (enable) {
105                 gpio_sleep_sel_en(gpio_num);
106             } else {
107                 gpio_sleep_sel_dis(gpio_num);
108             }
109         }
110     }
111 }
112 
113 #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio(void)114 IRAM_ATTR void esp_sleep_isolate_digital_gpio(void)
115 {
116     gpio_hal_context_t gpio_hal = {
117         .dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
118     };
119 
120     /* no need to do isolate if digital IOs are not being held in deep sleep */
121     if (!gpio_hal_deep_sleep_hold_is_en(&gpio_hal)) {
122         return;
123     }
124 
125     /**
126      * there is a situation where we cannot isolate digital IO before deep sleep:
127      * - task stack is located in external ram(mspi ram), since we will isolate mspi io
128      *
129      * assert here instead of returning directly, because if digital IO is not isolated,
130      * the bottom current of deep sleep will be higher than light sleep, and there is no
131      * reason to use deep sleep at this time.
132      */
133     assert(esp_ptr_internal(&gpio_hal) && "If hold digital IO, the stack of the task calling esp_deep_sleep_start must be in internal ram!");
134 
135     /* isolate digital IO that is not held(keep the configuration of digital IOs held by users) */
136     for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
137         if (GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) && !gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num)) {
138             /* disable I/O */
139             gpio_hal_input_disable(&gpio_hal, gpio_num);
140             gpio_hal_output_disable(&gpio_hal, gpio_num);
141 
142             /* disable pull up/down */
143             gpio_hal_pullup_dis(&gpio_hal, gpio_num);
144             gpio_hal_pulldown_dis(&gpio_hal, gpio_num);
145 
146             /* make pad work as gpio(otherwise, deep sleep bottom current will rise) */
147             gpio_hal_func_sel(&gpio_hal, gpio_num, PIN_FUNC_GPIO);
148         }
149     }
150 }
151 #endif // !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
152 
esp_deep_sleep_wakeup_io_reset(void)153 void esp_deep_sleep_wakeup_io_reset(void)
154 {
155 #if SOC_PM_SUPPORT_EXT1_WAKEUP
156     uint32_t rtc_io_mask = rtc_hal_ext1_get_wakeup_pins();
157     // Disable ext1 wakeup before releasing hold, such that wakeup status can reflect the correct wakeup pin
158     rtc_hal_ext1_clear_wakeup_pins();
159     for (int gpio_num = 0; gpio_num < SOC_GPIO_PIN_COUNT && rtc_io_mask != 0; ++gpio_num) {
160         int rtcio_num = rtc_io_num_map[gpio_num];
161         if ((rtc_io_mask & BIT(rtcio_num)) == 0) {
162             continue;
163         }
164         rtcio_hal_hold_disable(rtcio_num);
165         rtc_io_mask &= ~BIT(rtcio_num);
166     }
167 #endif
168 
169 #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
170     uint32_t dl_io_mask = SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK;
171     gpio_hal_context_t gpio_hal = {
172         .dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
173     };
174     while (dl_io_mask) {
175         int gpio_num = __builtin_ffs(dl_io_mask) - 1;
176         bool wakeup_io_enabled = gpio_hal_deepsleep_wakeup_is_enabled(&gpio_hal, gpio_num);
177         if (wakeup_io_enabled) {
178             // Disable the wakeup before releasing hold, such that wakeup status can reflect the correct wakeup pin
179             gpio_hal_deepsleep_wakeup_disable(&gpio_hal, gpio_num);
180             gpio_hal_hold_dis(&gpio_hal, gpio_num);
181         }
182         dl_io_mask &= ~BIT(gpio_num);
183     }
184 #endif
185 }
186 
187 #if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
188 ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
189 {
190 /* If the TOP domain is powered off, the GPIO will also be powered off during sleep,
191    and all configurations in the sleep state of GPIO will not take effect.*/
192 #if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
193     // Configure to isolate (disable the Input/Output/Pullup/Pulldown
194     // function of the pin) all GPIO pins in sleep state
195     esp_sleep_config_gpio_isolate();
196 #endif
197     // Enable automatic switching of GPIO configuration
198     esp_sleep_enable_gpio_switch(true);
199     return ESP_OK;
200 }
201 #endif
202