mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(esp_hw_support): isolate all digital io to suppress pad leakage on TOP pd sleep
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user