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