feat(esp_hw_support): isolate all digital io to suppress pad leakage on TOP pd sleep

This commit is contained in:
wuzhenghui
2026-05-07 08:39:56 +08:00
parent 8d3732c053
commit 7c10126309
12 changed files with 321 additions and 75 deletions
@@ -24,6 +24,7 @@
#include "soc/rtc_wdt_reg.h" #include "soc/rtc_wdt_reg.h"
#include "hal/rwdt_ll.h" #include "hal/rwdt_ll.h"
#endif #endif
#include "hal/gpio_ll.h"
#include "soc/pmu_reg.h" #include "soc/pmu_reg.h"
#include "hal/regi2c_ctrl_ll.h" #include "hal/regi2c_ctrl_ll.h"
#include "hal/modem_lpcon_ll.h" #include "hal/modem_lpcon_ll.h"
@@ -35,6 +36,14 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32s31");
static inline void bootloader_hardware_init(void) static inline void bootloader_hardware_init(void)
{ {
/* GPIO 41 is not bonded out to the package, Isolate it to suppress
* floating leakage.*/
gpio_ll_input_disable(&GPIO, 41);
gpio_ll_output_disable(&GPIO, 41);
gpio_ll_pullup_dis(&GPIO, 41);
gpio_ll_pulldown_dis(&GPIO, 41);
gpio_ll_func_sel(&GPIO, 41, PIN_FUNC_GPIO);
modem_lpcon_ll_enable_bus_clock(true); modem_lpcon_ll_enable_bus_clock(true);
#if !CONFIG_IDF_ENV_FPGA #if !CONFIG_IDF_ENV_FPGA
+2 -2
View File
@@ -1143,9 +1143,9 @@ esp_err_t gpio_dump_io_configuration(FILE *out_stream, uint64_t io_bit_mask)
fprintf(out_stream, "IO[%"PRIu32"]%s -\n", gpio_num, esp_gpio_is_reserved(BIT64(gpio_num)) ? " **RESERVED**" : ""); fprintf(out_stream, "IO[%"PRIu32"]%s -\n", gpio_num, esp_gpio_is_reserved(BIT64(gpio_num)) ? " **RESERVED**" : "");
fprintf(out_stream, " Pullup: %d, Pulldown: %d, DriveCap: %"PRIu32"\n", io_config.pu, io_config.pd, (uint32_t)io_config.drv); fprintf(out_stream, " Pullup: %d, Pulldown: %d, DriveCap: %"PRIu32"\n", io_config.pu, io_config.pd, (uint32_t)io_config.drv);
fprintf(out_stream, " InputEn: %d, OutputEn: %s%s, OpenDrain: %d\n", io_config.ie, oe_str, ((io_config.fun_sel == PIN_FUNC_GPIO) && (io_config.oe_inv)) ? " (inversed)" : "", io_config.od); fprintf(out_stream, " InputEn: %d, OutputEn: %s%s, OpenDrain: %d\n", io_config.ie, oe_str, ((io_config.fun_sel == PIN_FUNC_GPIO) && (io_config.oe_inv)) ? " (inversed)" : "", io_config.od);
fprintf(out_stream, " FuncSel: %"PRIu32" (%s)\n", io_config.fun_sel, (io_config.fun_sel == PIN_FUNC_GPIO) ? "GPIO" : "IOMUX"); fprintf(out_stream, " FuncSel: %"PRIu32" (%s)\n", (uint32_t)io_config.fun_sel, (io_config.fun_sel == PIN_FUNC_GPIO) ? "GPIO" : "IOMUX");
if (io_config.fun_sel == PIN_FUNC_GPIO) { if (io_config.fun_sel == PIN_FUNC_GPIO) {
fprintf(out_stream, " GPIO Matrix SigOut ID: %"PRIu32"%s\n", io_config.sig_out, (io_config.sig_out == SIG_GPIO_OUT_IDX) ? " (simple GPIO output)" : ""); fprintf(out_stream, " GPIO Matrix SigOut ID: %"PRIu32"%s\n", (uint32_t)io_config.sig_out, (io_config.sig_out == SIG_GPIO_OUT_IDX) ? " (simple GPIO output)" : "");
} }
if (io_config.ie && io_config.fun_sel == PIN_FUNC_GPIO) { if (io_config.ie && io_config.fun_sel == PIN_FUNC_GPIO) {
uint32_t cnt = 0; uint32_t cnt = 0;
@@ -57,6 +57,7 @@ extern "C" {
* @param gpio_num GPIO number * @param gpio_num GPIO number
* @param[out] io_config Pointer to the structure that saves the specific IO configuration * @param[out] io_config Pointer to the structure that saves the specific IO configuration
*/ */
__attribute__((always_inline))
static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, gpio_io_config_t *io_config) static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, gpio_io_config_t *io_config)
{ {
uint32_t bit_shift = (gpio_num < 32) ? gpio_num : (gpio_num - 32); uint32_t bit_shift = (gpio_num < 32) ? gpio_num : (gpio_num - 32);
@@ -74,6 +75,79 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, gpio
io_config->slp_sel = IO_MUX.gpio[gpio_num].slp_sel; io_config->slp_sel = IO_MUX.gpio[gpio_num].slp_sel;
} }
/**
* @brief Get a 64-bit mask of all digital GPIOs that are currently held.
* Reads the two hold control registers once, avoiding per-pin register access.
*
* @param hw Peripheral GPIO hardware instance address (unused, hold regs are in LP_SYS).
* @return Bitmask where bit N is set if GPIO N is held. Only digital IO bits are meaningful.
*/
__attribute__((always_inline))
static inline uint64_t gpio_ll_get_digital_gpio_hold_mask(gpio_dev_t *hw)
{
(void)hw;
uint32_t hold0 = LP_SYS.hp_gpio_o_hold_ctrl0.hp_gpio_0_hold_ctrl0;
uint32_t hold1 = LP_SYS.hp_gpio_o_hold_ctrl1.hp_gpio_0_hold_ctrl1;
return ((uint64_t)hold0 << SOC_RTCIO_PIN_COUNT) |
((uint64_t)hold1 << (32 + SOC_RTCIO_PIN_COUNT));
}
/**
* @brief Backup IOMUX pad configuration for sleep isolate.
* Only fills pu, pd, ie, fun_sel in io_config from a single IOMUX register read.
*
* @param gpio_num GPIO number
* @param[out] io_config Pointer to the IO configuration structure
*/
__attribute__((always_inline))
static inline void gpio_ll_backup_pad_config_for_sleep_isolate(uint32_t gpio_num, gpio_io_config_t *io_config)
{
uint32_t iomux_reg_val = IO_MUX.gpio[gpio_num].val;
io_config->pu = (iomux_reg_val & FUN_PU_M) >> FUN_PU_S;
io_config->pd = (iomux_reg_val & FUN_PD_M) >> FUN_PD_S;
io_config->ie = (iomux_reg_val & FUN_IE_M) >> FUN_IE_S;
io_config->fun_sel = (iomux_reg_val & MCU_SEL_M) >> MCU_SEL_S;
}
/**
* @brief Set pad configuration for sleep isolate with minimal register writes.
* Reads pu, pd, ie, oe, fun_sel from io_config and writes them to hardware registers
* in a single IOMUX read-modify-write plus one GPIO enable write.
*
* @param gpio_num GPIO number
* @param io_config Pointer to the IO configuration structure
*/
__attribute__((always_inline))
static inline void gpio_ll_set_pad_config_for_sleep_isolate(uint32_t gpio_num, gpio_io_config_t *io_config)
{
uint32_t iomux_reg_val = IO_MUX.gpio[gpio_num].val;
iomux_reg_val &= ~(FUN_PU_M | FUN_PD_M | FUN_IE_M | MCU_SEL_M);
if (io_config->pu) {
iomux_reg_val |= FUN_PU_M;
}
if (io_config->pd) {
iomux_reg_val |= FUN_PD_M;
}
if (io_config->ie) {
iomux_reg_val |= FUN_IE_M;
}
iomux_reg_val |= (io_config->fun_sel << MCU_SEL_S) & MCU_SEL_M;
IO_MUX.gpio[gpio_num].val = iomux_reg_val;
if (io_config->oe) {
if (gpio_num < 32) {
GPIO.enable_w1ts.enable_w1ts = (0x1 << gpio_num);
} else {
GPIO.enable1_w1ts.enable1_w1ts = (0x1 << (gpio_num - 32));
}
} else {
if (gpio_num < 32) {
GPIO.enable_w1tc.enable_w1tc = (0x1 << gpio_num);
} else {
GPIO.enable1_w1tc.enable1_w1tc = (0x1 << (gpio_num - 32));
}
}
}
/** /**
* @brief Enable pull-up on GPIO. * @brief Enable pull-up on GPIO.
* *
@@ -354,6 +428,23 @@ static inline void gpio_ll_output_enable(gpio_dev_t *hw, uint32_t gpio_num)
} }
} }
/**
* @brief Check if GPIO output is enabled.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return true if output is enabled, false otherwise
*/
__attribute__((always_inline))
static inline bool gpio_ll_output_is_enabled(gpio_dev_t *hw, uint32_t gpio_num)
{
if (gpio_num < 32) {
return (hw->enable.val >> gpio_num) & 0x1;
} else {
return (hw->enable1.val >> (gpio_num - 32)) & 0x1;
}
}
/** /**
* @brief Disable open-drain mode on GPIO. * @brief Disable open-drain mode on GPIO.
* *
@@ -157,17 +157,17 @@ typedef enum {
* @brief Structure that contains the configuration of an IO * @brief Structure that contains the configuration of an IO
*/ */
typedef struct { typedef struct {
uint32_t fun_sel; /*!< Value of IOMUX function selection */ gpio_drive_cap_t drv; /*!< Value of drive strength */
uint32_t sig_out; /*!< Index of the outputting peripheral signal */ uint32_t fun_sel : 8; /*!< Value of IOMUX function selection */
gpio_drive_cap_t drv; /*!< Value of drive strength */ uint32_t sig_out : 16;/*!< Index of the outputting peripheral signal */
bool pu; /*!< Status of pull-up enabled or not */ uint32_t pu : 1; /*!< Status of pull-up enabled or not */
bool pd; /*!< Status of pull-down enabled or not */ uint32_t pd : 1; /*!< Status of pull-down enabled or not */
bool ie; /*!< Status of input enabled or not */ uint32_t ie : 1; /*!< Status of input enabled or not */
bool oe; /*!< Status of output enabled or not */ uint32_t oe : 1; /*!< Status of output enabled or not */
bool oe_ctrl_by_periph; /*!< True if use output enable signal from peripheral, otherwise False */ uint32_t oe_ctrl_by_periph : 1; /*!< True if use output enable signal from peripheral, otherwise False */
bool oe_inv; /*!< Whether the output enable signal is inversed or not */ uint32_t oe_inv : 1; /*!< Whether the output enable signal is inversed or not */
bool od; /*!< Status of open-drain enabled or not */ uint32_t od : 1; /*!< Status of open-drain enabled or not */
bool slp_sel; /*!< Status of pin sleep mode enabled or not */ uint32_t slp_sel : 1; /*!< Status of pin sleep mode enabled or not */
} gpio_io_config_t; } gpio_io_config_t;
#ifdef __cplusplus #ifdef __cplusplus
@@ -10,12 +10,12 @@
// On S31, SPI pins defined here are all wrong. these pins are individual pins, don't use normal GPIO pins anymore. // On S31, SPI pins defined here are all wrong. these pins are individual pins, don't use normal GPIO pins anymore.
#define GPIO_NUM_INVALID -1 #define GPIO_NUM_INVALID -1
#define MSPI_IOMUX_PIN_NUM_CS1 GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_CS1 GPIO_NUM_INVALID
#define MSPI_IOMUX_PIN_NUM_HD GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_HD 30
#define MSPI_IOMUX_PIN_NUM_WP GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_WP 28
#define MSPI_IOMUX_PIN_NUM_CS0 GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_CS0 26
#define MSPI_IOMUX_PIN_NUM_CLK GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_CLK 31
#define MSPI_IOMUX_PIN_NUM_MISO GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_MISO 27
#define MSPI_IOMUX_PIN_NUM_MOSI GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_MOSI 32
#define MSPI_IOMUX_PIN_NUM_D4 GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_D4 GPIO_NUM_INVALID
#define MSPI_IOMUX_PIN_NUM_D5 GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_D5 GPIO_NUM_INVALID
#define MSPI_IOMUX_PIN_NUM_D6 GPIO_NUM_INVALID #define MSPI_IOMUX_PIN_NUM_D6 GPIO_NUM_INVALID
@@ -97,14 +97,36 @@ esp_err_t esp_sleep_acquire_lp_use_xtal(void);
esp_err_t esp_sleep_release_lp_use_xtal(void); esp_err_t esp_sleep_release_lp_use_xtal(void);
#endif #endif
#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
/** /**
* @brief Isolate all digital IOs except those that are held during deep sleep * @brief Soft-isolate valid digital IO pads (SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK) for leakage control
* *
* Reduce digital IOs current leakage during deep sleep. * Skips pads that are digitally held and pads reserved by the driver.
* MSPI signal pads are not in this pass; use esp_sleep_isolate_mspi_gpio() after cache/MSPI idle.
*
* @param do_backup If true, back up each pad's pu/pd/ie/oe/fun_sel before isolating so that
* esp_sleep_restore_isolated_digital_gpio() can restore them later.
* Pass false when restore is not needed (e.g. deep sleep).
*/ */
void esp_sleep_isolate_digital_gpio(void); void esp_sleep_isolate_digital_gpio(bool do_backup);
#endif
/**
* @brief Backup and isolate (or pull up) the five base MSPI lines (CLK/Q/D/HD/WP)
*
* If CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU && !SOC_MSPI_HAS_INDEPENT_IOMUX, enables pull-up only;
* otherwise full pad isolate like esp_sleep_isolate_digital_gpio. Intended after SPI bus is idle
* (e.g. light sleep with TOP power-down).
*/
void esp_sleep_isolate_mspi_gpio(void);
/**
* @brief Restore pu/pd/ie/oe and IOMUX fun_sel for every GPIO in the soft-isolate backup bitmap
*
* Reverses esp_sleep_isolate_digital_gpio / esp_sleep_isolate_mspi_gpio. Call after wake before
* normal Flash access.
*/
void esp_sleep_restore_isolated_digital_gpio(void);
#endif // !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
#if SOC_PM_SUPPORT_PMU_CLK_ICG #if SOC_PM_SUPPORT_PMU_CLK_ICG
/** /**
+2
View File
@@ -85,6 +85,8 @@ entries:
sleep_modes: esp_sleep_enable_vbat_under_volt_wakeup (noflash) sleep_modes: esp_sleep_enable_vbat_under_volt_wakeup (noflash)
sleep_modes: esp_sleep_sub_mode_config (noflash) sleep_modes: esp_sleep_sub_mode_config (noflash)
sleep_modes: esp_sleep_sub_mode_force_disable (noflash) sleep_modes: esp_sleep_sub_mode_force_disable (noflash)
if (SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP = n || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD = y):
esp_gpio_reserve (noflash)
[mapping:hal_gpio_pm] [mapping:hal_gpio_pm]
archive: libesp_hal_gpio.a archive: libesp_hal_gpio.a
+142 -41
View File
@@ -5,6 +5,7 @@
*/ */
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/param.h> #include <sys/param.h>
@@ -27,6 +28,7 @@
#include "hal/rtc_hal.h" #include "hal/rtc_hal.h"
#include "esp_private/esp_gpio_reserve.h"
#include "esp_private/gpio.h" #include "esp_private/gpio.h"
#include "esp_private/sleep_gpio.h" #include "esp_private/sleep_gpio.h"
#include "esp_private/spi_flash_os.h" #include "esp_private/spi_flash_os.h"
@@ -173,17 +175,99 @@ void esp_sleep_enable_gpio_switch(bool enable)
} }
#endif #endif
#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
IRAM_ATTR void esp_sleep_isolate_digital_gpio(void) IRAM_ATTR static void sleep_gpio_isolate_one_pin(gpio_num_t gpio_num)
{ {
gpio_hal_context_t gpio_hal = { #if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0) gpio_io_config_t isolate_config = { .pu = 0, .pd = 0, .ie = 0, .oe = 0, .fun_sel = PIN_FUNC_GPIO };
}; gpio_ll_set_pad_config_for_sleep_isolate(gpio_num, &isolate_config);
#else
gpio_hal_context_t gpio_hal = { .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) };
gpio_hal_input_disable(&gpio_hal, gpio_num);
gpio_hal_output_disable(&gpio_hal, gpio_num);
gpio_hal_pullup_dis(&gpio_hal, gpio_num);
gpio_hal_pulldown_dis(&gpio_hal, gpio_num);
gpio_hal_func_sel(&gpio_hal, gpio_num, PIN_FUNC_GPIO);
#endif
}
#if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
typedef struct {
uint64_t backuped;
uint64_t pu;
uint64_t pd;
uint64_t ie;
uint64_t oe;
uint8_t fun_sel[GPIO_NUM_MAX];
} gpio_isolate_backup_t;
static DRAM_ATTR gpio_isolate_backup_t s_gpio_isolate_backup;
IRAM_ATTR static void sleep_gpio_backup_one_pin(gpio_num_t gpio_num)
{
gpio_hal_context_t gpio_hal = { .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) };
gpio_io_config_t io_config;
gpio_ll_backup_pad_config_for_sleep_isolate(gpio_num, &io_config);
if (io_config.pu) {
s_gpio_isolate_backup.pu |= (1ULL << gpio_num);
}
if (io_config.pd) {
s_gpio_isolate_backup.pd |= (1ULL << gpio_num);
}
if (io_config.ie) {
s_gpio_isolate_backup.ie |= (1ULL << gpio_num);
}
if (gpio_ll_output_is_enabled(gpio_hal.dev, gpio_num)) {
s_gpio_isolate_backup.oe |= (1ULL << gpio_num);
}
s_gpio_isolate_backup.fun_sel[gpio_num] = (uint8_t)io_config.fun_sel;
s_gpio_isolate_backup.backuped |= (1ULL << gpio_num);
}
IRAM_ATTR void esp_sleep_isolate_mspi_gpio(void)
{
DRAM_ATTR static const esp_mspi_io_t s_mspi_pins[] = {
ESP_MSPI_IO_CLK, ESP_MSPI_IO_Q, ESP_MSPI_IO_D, ESP_MSPI_IO_HD, ESP_MSPI_IO_WP
};
for (size_t i = 0; i < sizeof(s_mspi_pins) / sizeof(s_mspi_pins[0]); i++) {
gpio_num_t gpio_num = (gpio_num_t)esp_mspi_get_io(s_mspi_pins[i]);
sleep_gpio_backup_one_pin(gpio_num);
#if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU && !SOC_MSPI_HAS_INDEPENT_IOMUX
gpio_hal_context_t gpio_hal = { .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) };
gpio_hal_pullup_en(&gpio_hal, gpio_num);
#else
sleep_gpio_isolate_one_pin(gpio_num);
#endif
}
}
IRAM_ATTR void esp_sleep_restore_isolated_digital_gpio(void)
{
uint64_t backuped = s_gpio_isolate_backup.backuped;
while (backuped) {
gpio_num_t gpio_num = (gpio_num_t)__builtin_ctzll(backuped);
gpio_io_config_t io_config = {
.pu = (s_gpio_isolate_backup.pu >> gpio_num) & 0x1,
.pd = (s_gpio_isolate_backup.pd >> gpio_num) & 0x1,
.ie = (s_gpio_isolate_backup.ie >> gpio_num) & 0x1,
.oe = (s_gpio_isolate_backup.oe >> gpio_num) & 0x1,
.fun_sel = (uint32_t)s_gpio_isolate_backup.fun_sel[gpio_num],
};
gpio_ll_set_pad_config_for_sleep_isolate(gpio_num, &io_config);
backuped &= backuped - 1;
}
}
#endif // SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
IRAM_ATTR void esp_sleep_isolate_digital_gpio(bool do_backup)
{
gpio_hal_context_t gpio_hal = { .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) };
#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
/* no need to do isolate if digital IOs are not being held in deep sleep */ /* no need to do isolate if digital IOs are not being held in deep sleep */
if (!gpio_hal_deep_sleep_hold_is_en(&gpio_hal)) { if (!gpio_hal_deep_sleep_hold_is_en(&gpio_hal)) {
return; return;
} }
#endif
/** /**
* there is a situation where we cannot isolate digital IO before deep sleep: * there is a situation where we cannot isolate digital IO before deep sleep:
@@ -193,42 +277,61 @@ IRAM_ATTR void esp_sleep_isolate_digital_gpio(void)
* the bottom current of deep sleep will be higher than light sleep, and there is no * the bottom current of deep sleep will be higher than light sleep, and there is no
* reason to use deep sleep at this time. * reason to use deep sleep at this time.
*/ */
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!"); assert(esp_ptr_internal(esp_cpu_get_sp()) && "If hold digital IO, the stack of the task calling esp_deep_sleep_start must be in internal ram!");
/* isolate digital IO that is not held(keep the configuration of digital IOs held by users) */ DRAM_ATTR static volatile uint64_t s_pad_mask = SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK;
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) { uint64_t pad_mask = s_pad_mask;
if (GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) && !gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num)) { #if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
if (do_backup) {
bool is_mspi_io_pad = false; s_gpio_isolate_backup.backuped = 0;
esp_mspi_io_t mspi_ios[] = { ESP_MSPI_IO_CS0, ESP_MSPI_IO_CLK, ESP_MSPI_IO_Q, ESP_MSPI_IO_D, ESP_MSPI_IO_HD, ESP_MSPI_IO_WP }; s_gpio_isolate_backup.pu = 0;
for (int i = 0; i < sizeof(mspi_ios) / sizeof(mspi_ios[0]); i++) { s_gpio_isolate_backup.pd = 0;
if (esp_mspi_get_io(mspi_ios[i]) == gpio_num) { s_gpio_isolate_backup.ie = 0;
is_mspi_io_pad = true; s_gpio_isolate_backup.oe = 0;
break;
}
}
// Ignore MSPI and default Console UART io pads, When the CPU executes
// the following instructions to configure the MSPI IO PAD, access on
// the MSPI signal lines (as CPU instruction execution and MSPI access
// operations are asynchronous) may cause the SoC to hang.
if (is_mspi_io_pad || gpio_num == U0RXD_GPIO_NUM || gpio_num == U0TXD_GPIO_NUM) {
continue;
}
/* disable I/O */
gpio_hal_input_disable(&gpio_hal, gpio_num);
gpio_hal_output_disable(&gpio_hal, gpio_num);
/* disable pull up/down */
gpio_hal_pullup_dis(&gpio_hal, gpio_num);
gpio_hal_pulldown_dis(&gpio_hal, gpio_num);
/* make pad work as gpio(otherwise, deep sleep bottom current will rise) */
gpio_hal_func_sel(&gpio_hal, gpio_num, PIN_FUNC_GPIO);
}
} }
uint64_t hold_mask = gpio_ll_get_digital_gpio_hold_mask(gpio_hal.dev);
gpio_io_config_t isolate_config = { .pu = 0, .pd = 0, .ie = 0, .oe = 0, .fun_sel = PIN_FUNC_GPIO };
while (pad_mask) {
gpio_num_t gpio_num = (gpio_num_t)__builtin_ctzll(pad_mask);
if (!(hold_mask & (1ULL << gpio_num)) &&
!esp_gpio_is_reserved(BIT64(gpio_num))) {
if (do_backup) {
gpio_io_config_t io_config;
gpio_ll_backup_pad_config_for_sleep_isolate(gpio_num, &io_config);
if (io_config.pu) {
s_gpio_isolate_backup.pu |= (1ULL << gpio_num);
}
if (io_config.pd) {
s_gpio_isolate_backup.pd |= (1ULL << gpio_num);
}
if (io_config.ie) {
s_gpio_isolate_backup.ie |= (1ULL << gpio_num);
}
if (gpio_ll_output_is_enabled(gpio_hal.dev, gpio_num)) {
s_gpio_isolate_backup.oe |= (1ULL << gpio_num);
}
s_gpio_isolate_backup.fun_sel[gpio_num] = (uint8_t)io_config.fun_sel;
s_gpio_isolate_backup.backuped |= (1ULL << gpio_num);
}
gpio_ll_set_pad_config_for_sleep_isolate(gpio_num, &isolate_config);
}
pad_mask &= pad_mask - 1;
}
#else
(void)do_backup;
while (pad_mask) {
gpio_num_t gpio_num = (gpio_num_t)__builtin_ctzll(pad_mask);
if (!gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num) &&
!esp_gpio_is_reserved(BIT64(gpio_num))) {
sleep_gpio_isolate_one_pin(gpio_num);
}
pad_mask &= pad_mask - 1;
}
#endif
} }
#endif //!SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #endif //!SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
#if SOC_DEEP_SLEEP_SUPPORTED #if SOC_DEEP_SLEEP_SUPPORTED
static void esp_deep_sleep_wakeup_io_reset(void) static void esp_deep_sleep_wakeup_io_reset(void)
@@ -250,10 +353,8 @@ static void esp_deep_sleep_wakeup_io_reset(void)
#endif #endif
#if SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP #if SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP
gpio_hal_context_t gpio_hal = { .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) };
uint64_t dslp_io_mask = SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_MASK; uint64_t dslp_io_mask = SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_MASK;
gpio_hal_context_t gpio_hal = {
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
};
while (dslp_io_mask) { while (dslp_io_mask) {
int gpio_num = __builtin_ctzll(dslp_io_mask); int gpio_num = __builtin_ctzll(dslp_io_mask);
bool wakeup_io_enabled = gpio_hal_wakeup_is_enabled_on_hp_periph_powerdown_sleep(&gpio_hal, gpio_num); bool wakeup_io_enabled = gpio_hal_wakeup_is_enabled_on_hp_periph_powerdown_sleep(&gpio_hal, gpio_num);
+22 -9
View File
@@ -251,7 +251,7 @@
#define LDO_POWER_TAKEOVER_PREPARATION_TIME_US (185) #define LDO_POWER_TAKEOVER_PREPARATION_TIME_US (185)
#elif CONFIG_IDF_TARGET_ESP32S31 #elif CONFIG_IDF_TARGET_ESP32S31
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (324) #define DEFAULT_SLEEP_OUT_OVERHEAD_US (324)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (240) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (780)
#endif #endif
// Actually costs 80us, using the fastest slow clock 150K calculation takes about 16 ticks // Actually costs 80us, using the fastest slow clock 150K calculation takes about 16 ticks
@@ -894,16 +894,16 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
} }
#endif #endif
if (deep_sleep) { if (deep_sleep) {
#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP || SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
esp_sleep_isolate_digital_gpio(); esp_sleep_isolate_digital_gpio(false);
#endif #endif
#if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP_SLEEP_SET_FLASH_DPD #if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP_SLEEP_SET_FLASH_DPD
if ((sleep_flags & RTC_SLEEP_FLASH_DPD) && (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300))) { if ((sleep_flags & RTC_SLEEP_FLASH_DPD) && (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300))) {
/* Switch Flash from standby mode to deep powerdown mode */ /* Switch Flash from standby mode to deep powerdown mode */
/* During bootloader phase following wakeup from deepsleep, flash will exit dpd mode */ /* During bootloader phase following wakeup from deepsleep, flash will exit dpd mode */
spi_flash_enable_deep_power_down_mode(true); spi_flash_enable_deep_power_down_mode(true);
} }
#endif #endif
#if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED #if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED
@@ -924,7 +924,7 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
#endif #endif
// Enter Deep Sleep // Enter Deep Sleep
#if!ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP #if !ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
#if SOC_PMU_SUPPORTED #if SOC_PMU_SUPPORTED
result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep); result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
#else #else
@@ -935,6 +935,11 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif #endif
} else { } else {
#if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
if (sleep_flags & RTC_SLEEP_PD_DIG) {
esp_sleep_isolate_digital_gpio(true);
}
#endif
/* Cache Suspend 1: will wait cache idle in cache suspend */ /* Cache Suspend 1: will wait cache idle in cache suspend */
suspend_cache(); suspend_cache();
if (!(sleep_flags & RTC_SLEEP_PD_VDDSDIO)) { if (!(sleep_flags & RTC_SLEEP_PD_VDDSDIO)) {
@@ -959,6 +964,9 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1); gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif #endif
#if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
esp_sleep_isolate_mspi_gpio();
#endif
#endif // !SOC_MSPI_HAS_INDEPENT_IOMUX #endif // !SOC_MSPI_HAS_INDEPENT_IOMUX
} }
#endif #endif
@@ -1018,6 +1026,11 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint
#endif // !SOC_MSPI_HAS_INDEPENT_IOMUX #endif // !SOC_MSPI_HAS_INDEPENT_IOMUX
} }
#endif #endif
#if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
if (sleep_flags & RTC_SLEEP_PD_DIG) {
esp_sleep_restore_isolated_digital_gpio();
}
#endif
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD #if CONFIG_ESP_SLEEP_SET_FLASH_DPD
if (sleep_flags & RTC_SLEEP_FLASH_DPD) { if (sleep_flags & RTC_SLEEP_FLASH_DPD) {
//Release Flash out from deep powerdown mode //Release Flash out from deep powerdown mode
@@ -463,6 +463,10 @@ config SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP
bool bool
default y default y
config SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD
bool
default y
config SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE config SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE
bool bool
default y default y
@@ -187,7 +187,7 @@
// GPIO0~7 on ESP32S31 can support chip deep sleep wakeup // GPIO0~7 on ESP32S31 can support chip deep sleep wakeup
#define SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP (1) #define SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP (1)
#define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP #define SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD (1)
#define SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE (1) #define SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE (1)
// LP IO peripherals have independent clock gating to manage // LP IO peripherals have independent clock gating to manage
+4
View File
@@ -82,6 +82,10 @@ entries:
if ESP_SLEEP_SET_FLASH_DPD = y: if ESP_SLEEP_SET_FLASH_DPD = y:
spi_flash_dpd_enable (noflash) spi_flash_dpd_enable (noflash)
if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD = y:
flash_ops: esp_mspi_get_io (noflash)
flash_ops: s_mspi_io_num_default (noflash)
[mapping:spi_flash_hal] [mapping:spi_flash_hal]
archive: libesp_hal_mspi.a archive: libesp_hal_mspi.a
entries: entries: