Merge branch 'feature/bringup_esp32c6_light_sleep_pd_cpu' into 'master'

esp32c6: support light_sleep (Stage 1: support CPU power down)

See merge request espressif/esp-idf!21985
This commit is contained in:
Wu Zheng Hui 2023-02-01 14:11:15 +08:00
commit 33ae2e1073
84 changed files with 4794 additions and 4011 deletions

View File

@ -94,6 +94,7 @@ menu "Bootloader config"
choice BOOTLOADER_VDDSDIO_BOOST
bool "VDDSDIO LDO voltage"
default BOOTLOADER_VDDSDIO_BOOST_1_9V
depends on SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
help
If this option is enabled, and VDDSDIO LDO is set to 1.8V (using eFuse
or MTDI bootstrapping pin), bootloader will change LDO settings to

View File

@ -27,7 +27,7 @@ bootloader_usable_dram_end = 0x4087c610;
bootloader_stack_overhead = 0x2000; /* For safety margin between bootloader data section and startup stacks */
bootloader_dram_seg_len = 0x5000;
bootloader_iram_loader_seg_len = 0x7000;
bootloader_iram_seg_len = 0x2000;
bootloader_iram_seg_len = 0x2100;
/* Start of the lower region is determined by region size and the end of the higher region */
bootloader_dram_seg_end = bootloader_usable_dram_end - bootloader_stack_overhead;

View File

@ -95,8 +95,8 @@ __attribute__((weak)) void bootloader_clock_configure(void)
CLEAR_PERI_REG_MASK(LP_TIMER_LP_INT_ENA_REG, LP_TIMER_MAIN_TIMER_LP_INT_ENA); /* MAIN_TIMER */
CLEAR_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_ENA_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
// CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); // TODO: IDF-5348 /* SLP_REJECT */
// CLEAR_PERI_REG_MASK(PMU_SOC_SLEEP_REJECT_INT_ENA, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
// SET CLR
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
SET_PERI_REG_MASK(LP_TIMER_LP_INT_CLR_REG, LP_TIMER_MAIN_TIMER_LP_INT_CLR); /* MAIN_TIMER */
@ -108,13 +108,13 @@ __attribute__((weak)) void bootloader_clock_configure(void)
CLEAR_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_ENA_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
CLEAR_PERI_REG_MASK(PMU_SOC_SLEEP_REJECT_INT_ENA, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
// SET CLR
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
SET_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_CLR_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
// SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); // TODO: IDF-5348 /* SLP_REJECT */
// SET_PERI_REG_MASK(PMU_SOC_SLEEP_REJECT_INT_CLR, PMU_SOC_SLEEP_REJECT_INT_CLR); /* SLP_WAKEUP */
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */
SET_PERI_REG_MASK(PMU_SOC_SLEEP_REJECT_INT_CLR, PMU_SOC_SLEEP_REJECT_INT_CLR); /* SLP_WAKEUP */
#else
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -237,8 +237,8 @@ static inline void bootloader_hardware_init(void)
esp_rom_spiflash_fix_dummylen(1, 1);
#endif
// TODO: IDF-5990 need update, enable i2c mst clk by force on temporarily
SET_PERI_REG_MASK(MODEM_LPCON_CLK_CONF_FORCE_ON_REG, MODEM_LPCON_CLK_I2C_MST_FO);
/* Enable analog i2c master clock */
SET_PERI_REG_MASK(MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN);
SET_PERI_REG_MASK(MODEM_LPCON_I2C_MST_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_SEL_160M);
}

View File

@ -844,7 +844,7 @@ TEST_CASE("GPIO_USB_DP_pin_pullup_disable_test", "[gpio]")
}
#endif //SOC_USB_SERIAL_JTAG_SUPPORTED
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) // TODO: IDF-5348, IDF-6267 Remove when light sleep is supported
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32H2) // TODO: IDF-6267 Remove when light sleep is supported
// Ignored in CI because it needs manually connect TEST_GPIO_INPUT_LEVEL_LOW_PIN to 3.3v to wake up from light sleep
TEST_CASE("GPIO_light_sleep_wake_up_test", "[gpio][ignore]")
{

View File

@ -470,7 +470,7 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
p_twai_obj_dummy->module = twai_controller_periph_signals.controllers[controller_id].module;
#ifdef CONFIG_PM_ENABLE
#if CONFIG_PM_ENABLE && SOC_TWAI_CLK_SUPPORT_APB
if (clk_src == TWAI_CLK_SRC_APB) {
// TODO: pm_lock name should also reflect the controller ID
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "twai", &(p_twai_obj_dummy->pm_lock));
@ -478,7 +478,7 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
goto err;
}
}
#endif //CONFIG_PM_ENABLE
#endif //CONFIG_PM_ENABLE && SOC_TWAI_CLK_SUPPORT_APB
//Initialize TWAI peripheral registers, and allocate interrupt
TWAI_ENTER_CRITICAL();

View File

@ -30,8 +30,8 @@ if(NOT BOOTLOADER_BUILD)
"port/${target}/clk_tree.c"
"port/clk_tree_common.c")
if(NOT CONFIG_IDF_TARGET_ESP32 AND NOT CONFIG_IDF_TARGET_ESP32S2)
list(APPEND srcs "sleep_retention.c")
if(CONFIG_SOC_PM_SUPPORT_CPU_PD)
list(APPEND srcs "sleep_cpu.c")
endif()
# [refactor-todo]: requires "driver" for GPIO and RTC (by sleep_gpio and sleep_modes)
@ -73,6 +73,14 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "esp_ds.c")
endif()
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
list(APPEND srcs "sleep_cpu_asm.S")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_save")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_restore")
endif()
if(CONFIG_SOC_MODEM_CLOCK_IS_INDEPENDENT)
list(APPEND srcs "modem_clock.c")
endif()

View File

@ -67,7 +67,7 @@ menu "Hardware Settings"
config ESP_SLEEP_GPIO_RESET_WORKAROUND
bool "light sleep GPIO reset workaround"
default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 # TODO: IDF-5641 (esp32c6)
default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6
select PM_SLP_DISABLE_GPIO if FREERTOS_USE_TICKLESS_IDLE
help
esp32c2, esp32c3 and esp32s3 will reset at wake-up if GPIO is received a small electrostatic

View File

@ -0,0 +1,220 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_PMU_SUPPORTED
#include "hal/pmu_hal.h"
#include "pmu_param.h"
#define RTC_SLEEP_PD_DIG PMU_SLEEP_PD_TOP //!< Deep sleep (power down digital domain)
#define RTC_SLEEP_PD_RTC_PERIPH PMU_SLEEP_PD_LP_PERIPH //!< Power down RTC peripherals
// #define RTC_SLEEP_PD_RTC_SLOW_MEM BIT(2) //!< Power down RTC SLOW memory
// #define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) //!< Power down RTC FAST memory
// #define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) //!< RTC FAST and SLOW memories are automatically powered up and down along with the CPU
#define RTC_SLEEP_PD_VDDSDIO PMU_SLEEP_PD_VDDSDIO //!< Power down VDDSDIO regulator
#define RTC_SLEEP_PD_CPU PMU_SLEEP_PD_CPU //!< Power down CPU when in lightsleep, but not restart
#define RTC_SLEEP_PD_DIG_PERIPH PMU_SLEEP_PD_HP_PERIPH //!< Power down DIG peripherals
#define RTC_SLEEP_PD_INT_8M PMU_SLEEP_PD_RC_FAST //!< Power down Internal 20M oscillator
#define RTC_SLEEP_PD_XTAL PMU_SLEEP_PD_XTAL //!< Power down main XTAL
//These flags are not power domains, but will affect some sleep parameters
#define RTC_SLEEP_DIG_USE_8M BIT(16)
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
#define RTC_GPIO_TRIG_EN PMU_GPIO_WAKEUP_EN //!< GPIO wakeup
#define RTC_TIMER_TRIG_EN PMU_LP_TIMER_WAKEUP_EN //!< Timer wakeup
#define RTC_WIFI_TRIG_EN PMU_WIFI_SOC_WAKEUP_EN //!< WIFI wakeup (light sleep only)
#define RTC_UART0_TRIG_EN PMU_UART0_WAKEUP_EN //!< UART0 wakeup (light sleep only)
#define RTC_UART1_TRIG_EN PMU_UART1_WAKEUP_EN //!< UART1 wakeup (light sleep only)
#define RTC_BT_TRIG_EN PMU_BLE_SOC_WAKEUP_EN //!< BT wakeup (light sleep only)
#define RTC_USB_TRIG_EN PMU_USB_WAKEUP_EN
#define RTC_XTAL32K_DEAD_TRIG_EN 0 // TODO
#define RTC_BROWNOUT_DET_TRIG_EN 0 // TODO
/**
* RTC_SLEEP_REJECT_MASK records sleep reject sources supported by chip
*/
#define RTC_SLEEP_REJECT_MASK (RTC_GPIO_TRIG_EN | \
RTC_TIMER_TRIG_EN | \
RTC_WIFI_TRIG_EN | \
RTC_UART0_TRIG_EN | \
RTC_UART1_TRIG_EN | \
RTC_BT_TRIG_EN | \
RTC_XTAL32K_DEAD_TRIG_EN | \
RTC_USB_TRIG_EN | \
RTC_BROWNOUT_DET_TRIG_EN)
#define PMU_GPIO_WAKEUP_EN BIT(2)
#define PMU_WIFI_BEACON_WAKEUP_EN BIT(3)
#define PMU_LP_TIMER_WAKEUP_EN BIT(4)
#define PMU_WIFI_SOC_WAKEUP_EN BIT(5)
#define PMU_UART0_WAKEUP_EN BIT(6)
#define PMU_UART1_WAKEUP_EN BIT(7)
#define PMU_SDIO_WAKEUP_EN BIT(8)
#define PMU_BLE_SOC_WAKEUP_EN BIT(10)
#define PMU_USB_WAKEUP_EN BIT(14)
#define PMU_SLEEP_PD_TOP BIT(0)
#define PMU_SLEEP_PD_VDDSDIO BIT(1)
#define PMU_SLEEP_PD_MODEM BIT(2)
#define PMU_SLEEP_PD_HP_PERIPH BIT(3)
#define PMU_SLEEP_PD_CPU BIT(4)
#define PMU_SLEEP_PD_AON BIT(5)
#define PMU_SLEEP_PD_MEM_G0 BIT(6)
#define PMU_SLEEP_PD_MEM_G1 BIT(7)
#define PMU_SLEEP_PD_MEM_G2 BIT(8)
#define PMU_SLEEP_PD_MEM_G3 BIT(9)
#define PMU_SLEEP_PD_XTAL BIT(10)
#define PMU_SLEEP_PD_RC_FAST BIT(11)
#define PMU_SLEEP_PD_XTAL32K BIT(12)
#define PMU_SLEEP_PD_RC32K BIT(13)
#define PMU_SLEEP_PD_LP_PERIPH BIT(14)
typedef struct {
pmu_hal_context_t *hal;
void *mc;
} pmu_context_t;
pmu_context_t * PMU_instance(void);
typedef enum pmu_hp_sysclk_src {
PMU_HP_SYSCLK_XTAL = 0,
PMU_HP_SYSCLK_PLL,
PMU_HP_SYSCLK_FOSC
} pmu_hp_sysclk_src_t;
typedef enum pmu_sleep_protect_mode {
PMU_SLEEP_PROTECT_HP_SLEEP = 0,
PMU_SLEEP_PROTECT_XTAL,
PMU_SLEEP_PROTECT_HP_LP_SLEEP,
PMU_SLEEP_PROTECT_DISABLE
} pmu_sleep_protect_mode_t;
typedef enum pmu_sleep_regdma_entry {
PMU_SLEEP_REGDMA_ENTRY_0 = 0,
PMU_SLEEP_REGDMA_ENTRY_1,
PMU_SLEEP_REGDMA_ENTRY_2,
PMU_SLEEP_REGDMA_ENTRY_3,
PMU_SLEEP_REGDMA_ENTRY_MAX
} pmu_sleep_regdma_entry_t;
/**
* @brief PMU ICG modem code of HP system
*/
typedef enum {
PMU_HP_ICG_MODEM_CODE_SLEEP = 0,
PMU_HP_ICG_MODEM_CODE_MODEM = 1,
PMU_HP_ICG_MODEM_CODE_ACTIVE = 2,
} pmu_hp_icg_modem_mode_t;
/**
* @brief Enable_regdma_backup.
*/
void pmu_sleep_enable_regdma_backup(void);
/**
* @brief Disable_regdma_backup.
*/
void pmu_sleep_disable_regdma_backup(void);
/**
* @brief Calculate the hardware time overhead during sleep to compensate for sleep time
*
* @param pd_flags flags indicates the power domain that will be powered down
* @param slowclk_period re-calibrated slow clock period
* @param fastclk_period re-calibrated fast clock period
*
* @return hardware time overhead in us
*/
uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t pd_flags, uint32_t slowclk_period, uint32_t fastclk_period);
/**
* @brief Get default sleep configuration
* @param config pmu_sleep_config instance
* @param pd_flags flags indicates the power domain that will be powered down
* @param adjustment total software and hardware time overhead
* @param slowclk_period re-calibrated slow clock period in microseconds,
* Q13.19 fixed point format
* @param fastclk_period re-calibrated fast clock period in microseconds,
* Q13.19 fixed point format
* @param dslp configuration for deep sleep mode
* @return hardware time overhead in us
*/
const pmu_sleep_config_t* pmu_sleep_config_default(pmu_sleep_config_t *config, uint32_t pd_flags, uint32_t adjustment, uint32_t slowclk_period, uint32_t fastclk_period, bool dslp);
/**
* @brief Prepare the chip to enter sleep mode
*
* This function configures various power/analog parameters and lp/lp system configuration
* used in sleep state machines
*
* This function does not actually enter sleep mode; this is done using
* pmu_sleep_start function. Software may do some other actions between
* pmu_sleep_init and pmu_sleep_start, such as set wakeup timer and configure
* wakeup sources.
*
* @param config sleep mode configuration
*
* @param dslp is initialize for deep sleep mode
*/
void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp);
/**
* @brief Enter deep or light sleep mode
*
* This function enters the sleep mode previously configured using pmu_sleep_init
* function. Before entering sleep, software should configure wake up sources
* appropriately (set up GPIO wakeup registers, timer wakeup registers,
* and so on).
*
* If deep sleep mode was configured using pmu_sleep_init, and sleep is not
* rejected by hardware (based on reject_opt flags), this function never returns.
* When the chip wakes up from deep sleep, CPU is reset and execution starts
* from ROM bootloader.
*
* If light sleep mode was configured using pmu_sleep_init, this function
* returns on wakeup, or if sleep is rejected by hardware.
*
* @param wakeup_opt bit mask wake up reasons to enable (RTC_xxx_TRIG_EN flags
* combined with OR)
* @param reject_opt bit mask of sleep reject reasons, used to
* prevent wakeup source set before the sleep request)
* @param lslp_mem_inf_fpu If non-zero then the low power config is restored
* immediately on wake. Recommended for light sleep,
* has no effect if the system goes into deep sleep.
*
* @return non-zero if sleep was rejected by hardware
*/
uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp);
/**
* @brief Initialize PMU related power/clock/digital parameters and functions
*/
void pmu_init(void);
#endif //#if SOC_PMU_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sleep_cpu.h
*
* This file contains declarations of cpu retention related functions in light sleep mode.
*/
#if SOC_PM_SUPPORT_CPU_PD
/**
* @brief Whether to allow the cpu power domain to be powered off.
*
* In light sleep mode, only when the system can provide enough memory
* for cpu retention, the cpu power domain can be powered off.
*/
bool cpu_domain_pd_allowed(void);
#endif
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
/**
* @brief Enable cpu retention of some modules.
*
* In light sleep mode, before the system goes to sleep, enable the cpu
* retention of modules such as CPU and I/D-cache tag memory.
*/
void sleep_enable_cpu_retention(void);
/**
* @brief Disable cpu retention of some modules.
*
* In light sleep mode, after the system exits sleep, disable the cpu
* retention of moudles such as CPU and I/D-cache tag memory.
*/
void sleep_disable_cpu_retention(void);
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
esp_err_t esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool),
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp);
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
#ifdef __cplusplus
}
#endif

View File

@ -1,55 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sleep_retention.h
*
* This file contains declarations of memory retention related functions in light sleeo mode.
*/
#if SOC_PM_SUPPORT_CPU_PD
/**
* @brief Whether to allow the cpu power domain to be powered off.
*
* In light sleep mode, only when the system can provide enough memory
* for cpu retention, the cpu power domain can be powered off.
*/
bool cpu_domain_pd_allowed(void);
#endif
#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD
/**
* @brief Enable memory retention of some modules.
*
* In light sleep mode, before the system goes to sleep, enable the memory
* retention of modules such as CPU and I/D-cache tag memory.
*/
void sleep_enable_memory_retention(void);
/**
* @brief Disable memory retention of some modules.
*
* In light sleep mode, after the system exits sleep, disable the memory
* retention of moudles such as CPU and I/D-cache tag memory.
*/
void sleep_disable_memory_retention(void);
#endif // SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD
#ifdef __cplusplus
}
#endif

View File

@ -48,10 +48,10 @@ typedef enum {
#endif
ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator
#if SOC_PM_SUPPORT_XTAL32K_PD
ESP_PD_DOMAIN_XTAL32K,
ESP_PD_DOMAIN_XTAL32K, //!< External 32 kHz XTAL oscillator
#endif
#if SOC_PM_SUPPORT_RC32K_PD
ESP_PD_DOMAIN_RC32K,
ESP_PD_DOMAIN_RC32K, //!< Internal 32 kHz RC oscillator
#endif
#if SOC_PM_SUPPORT_RC_FAST_PD
ESP_PD_DOMAIN_RC_FAST, //!< Internal Fast oscillator
@ -59,7 +59,9 @@ typedef enum {
#if SOC_PM_SUPPORT_CPU_PD
ESP_PD_DOMAIN_CPU, //!< CPU core
#endif
#if SOC_PM_SUPPORT_VDDSDIO_PD
ESP_PD_DOMAIN_VDDSDIO, //!< VDD_SDIO
#endif
ESP_PD_DOMAIN_MAX //!< Number of domains
} esp_sleep_pd_domain_t;
@ -484,15 +486,44 @@ void esp_default_wake_deep_sleep(void);
void esp_deep_sleep_disable_rom_logging(void);
#ifdef SOC_PM_SUPPORT_CPU_PD
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
/**
* @brief CPU Power down low-level initialize
*
* @param enable enable or disable CPU power down during light sleep
* @brief CPU Power down low-level initialize, enable CPU power down during light sleep
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough retention memory
*/
esp_err_t esp_sleep_cpu_pd_low_init(bool enable);
esp_err_t esp_sleep_cpu_pd_low_init(void);
/**
* @brief CPU Power down low-level deinitialize, disable CPU power down during light sleep
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough retention memory
*/
esp_err_t esp_sleep_cpu_pd_low_deinit(void);
#endif
/**
* @brief CPU Power down initialize
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough retention memory
*/
esp_err_t esp_sleep_cpu_retention_init(void);
/**
* @brief CPU Power down de-initialize
*
* @return
* - ESP_OK on success
*
* Release system retention memory.
*/
esp_err_t esp_sleep_cpu_retention_deinit(void);
#endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH

View File

@ -13,11 +13,14 @@ entries:
cpu: esp_cpu_compare_and_set (noflash)
esp_memory_utils (noflash)
rtc_clk (noflash)
if IDF_TARGET_ESP32C6 = n && IDF_TARGET_ESP32H2 = n: # TODO: IDF-5645
if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED:
rtc_init:rtc_vddsdio_set_config (noflash)
if IDF_TARGET_ESP32C6 = n && IDF_TARGET_ESP32H2 = n: # TODO: IDF-5645
rtc_pm (noflash_text)
rtc_sleep (noflash_text)
rtc_time (noflash_text)
if SOC_PMU_SUPPORTED = y:
pmu_sleep (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_wdt (noflash_text)
if PERIPH_CTRL_FUNC_IN_IRAM = y:

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,6 +13,7 @@
#include "freertos/FreeRTOS.h"
#include "hal/clk_gate_ll.h"
#include "esp_private/esp_modem_clock.h"
#include "esp_private/esp_pmu.h"
#include "esp_sleep.h"
// Please define the frequently called modules in the low bit,
@ -136,30 +137,25 @@ modem_clock_context_t * __attribute__((weak)) IRAM_ATTR MODEM_CLOCK_instance(voi
return &modem_clock_context;
}
// TODO: IDF-5351: move to esp_pmu.h after support pmu driver
#define PMU_SLEEP 0
#define PMU_MODEM 1
#define PMU_ACTIVE 2
#define SLEEP_MODE BIT(PMU_SLEEP)
#define MODEM_MODE BIT(PMU_MODEM)
#define ACTIVE_MODE BIT(PMU_ACTIVE)
static void IRAM_ATTR modem_clock_domain_power_state_icg_map_init(modem_clock_context_t *ctx)
{
#define ICG_NOGATING_SLEEP (BIT(PMU_HP_ICG_MODEM_CODE_SLEEP))
#define ICG_NOGATING_MODEM (BIT(PMU_HP_ICG_MODEM_CODE_MODEM))
#define ICG_NOGATING_ACTIVE (BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE))
/* the ICG code's bit 0, 1 and 2 indicates the ICG state
* of pmu SLEEP, MODEM and ACTIVE mode respectively */
const uint32_t code[MODEM_CLOCK_DOMAIN_MAX] = {
[MODEM_CLOCK_DOMAIN_MODEM_APB] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_MODEM_PERIPH] = ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_WIFI] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_BT] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_FE] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_IEEE802154] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_LP_APB] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_I2C_MASTER] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_COEX] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_WIFIPWR] = MODEM_MODE | ACTIVE_MODE,
[MODEM_CLOCK_DOMAIN_MODEM_APB] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_MODEM_PERIPH] = ICG_NOGATING_ACTIVE,
[MODEM_CLOCK_DOMAIN_WIFI] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_BT] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_FE] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_IEEE802154] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_LP_APB] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_I2C_MASTER] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_COEX] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
[MODEM_CLOCK_DOMAIN_WIFIPWR] = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM,
};
for (modem_clock_domain_t domain = MODEM_CLOCK_DOMAIN_MODEM_APB; domain < MODEM_CLOCK_DOMAIN_MAX; domain++) {
modem_clock_hal_set_clock_domain_icg_bitmap(ctx->hal, domain, code[domain]);
@ -167,16 +163,8 @@ static void IRAM_ATTR modem_clock_domain_power_state_icg_map_init(modem_clock_co
}
#include "soc/pmu_reg.h"
void modem_clock_domain_pmu_state_icg_map_init(void)
{
// Set modem clock ICG code map, should implement with pmu driver // TODO: IDF-5351
REG_SET_FIELD(PMU_HP_SLEEP_ICG_MODEM_REG, PMU_HP_SLEEP_DIG_ICG_MODEM_CODE, PMU_SLEEP);
REG_SET_FIELD(PMU_HP_MODEM_ICG_MODEM_REG, PMU_HP_MODEM_DIG_ICG_MODEM_CODE, PMU_MODEM);
REG_SET_FIELD(PMU_HP_ACTIVE_ICG_MODEM_REG, PMU_HP_ACTIVE_DIG_ICG_MODEM_CODE, PMU_ACTIVE);
REG_SET_BIT(PMU_IMM_MODEM_ICG_REG, PMU_UPDATE_DIG_ICG_MODEM_EN);
REG_SET_BIT(PMU_IMM_SLEEP_SYSCLK_REG, PMU_UPDATE_DIG_ICG_SWITCH);
modem_clock_domain_power_state_icg_map_init(MODEM_CLOCK_instance());
}

View File

@ -129,16 +129,6 @@ void rtc_init(rtc_config_t cfg)
#endif
}
rtc_vddsdio_config_t rtc_vddsdio_get_config(void)
{
rtc_vddsdio_config_t result = {0};
return result;
}
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
{
}
static void set_ocode_by_efuse(int ocode_scheme_ver)
{
assert(ocode_scheme_ver == 1);

View File

@ -159,43 +159,6 @@ void rtc_init(rtc_config_t cfg)
#endif
}
rtc_vddsdio_config_t rtc_vddsdio_get_config(void)
{
rtc_vddsdio_config_t result;
uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG);
result.drefh = (sdio_conf_reg & RTC_CNTL_DREFH_SDIO_M) >> RTC_CNTL_DREFH_SDIO_S;
result.drefm = (sdio_conf_reg & RTC_CNTL_DREFM_SDIO_M) >> RTC_CNTL_DREFM_SDIO_S;
result.drefl = (sdio_conf_reg & RTC_CNTL_DREFL_SDIO_M) >> RTC_CNTL_DREFL_SDIO_S;
if (sdio_conf_reg & RTC_CNTL_SDIO_FORCE) {
// Get configuration from RTC
result.force = 1;
result.enable = (sdio_conf_reg & RTC_CNTL_XPD_SDIO_REG_M) >> RTC_CNTL_XPD_SDIO_REG_S;
result.tieh = (sdio_conf_reg & RTC_CNTL_SDIO_TIEH_M) >> RTC_CNTL_SDIO_TIEH_S;
return result;
} else {
result.force = 0;
}
// Otherwise, VDD_SDIO is controlled by bootstrapping pin
uint32_t strap_reg = REG_READ(GPIO_STRAP_REG);
result.force = 0;
result.tieh = (strap_reg & BIT(5)) ? RTC_VDDSDIO_TIEH_1_8V : RTC_VDDSDIO_TIEH_3_3V;
result.enable = 1;
return result;
}
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
{
uint32_t val = 0;
val |= (config.force << RTC_CNTL_SDIO_FORCE_S);
val |= (config.enable << RTC_CNTL_XPD_SDIO_REG_S);
val |= (config.drefh << RTC_CNTL_DREFH_SDIO_S);
val |= (config.drefm << RTC_CNTL_DREFM_SDIO_S);
val |= (config.drefl << RTC_CNTL_DREFL_SDIO_S);
val |= (config.tieh << RTC_CNTL_SDIO_TIEH_S);
val |= RTC_CNTL_SDIO_PD_EN;
REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val);
}
static void set_ocode_by_efuse(int calib_version)
{

View File

@ -1,10 +1,11 @@
set(srcs "rtc_clk_init.c"
"rtc_clk.c"
"rtc_init.c"
# "rtc_pm.c" // TODO: IDF-5645
# "rtc_sleep.c" // TODO: IDF-5645
"pmu_param.c"
"pmu_init.c"
"pmu_sleep.c"
"rtc_time.c"
"chip_info.c")
"chip_info.c"
)
if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "sar_periph_ctrl.c"

View File

@ -0,0 +1,207 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/pmu_struct.h"
#include "hal/pmu_hal.h"
#include "pmu_param.h"
#include "esp_private/esp_pmu.h"
#include "soc/regi2c_dig_reg.h"
#include "regi2c_ctrl.h"
static __attribute__((unused)) const char *TAG = "pmu_init";
typedef struct {
const pmu_hp_system_power_param_t *power;
const pmu_hp_system_clock_param_t *clock;
const pmu_hp_system_digital_param_t *digital;
const pmu_hp_system_analog_param_t *analog;
const pmu_hp_system_retention_param_t *retent;
} pmu_hp_system_param_t;
typedef struct {
const pmu_lp_system_power_param_t *power;
const pmu_lp_system_analog_param_t *analog;
} pmu_lp_system_param_t;
pmu_context_t * __attribute__((weak)) IRAM_ATTR PMU_instance(void)
{
/* It should be explicitly defined in the internal RAM, because this
* instance will be used in pmu_sleep.c */
static DRAM_ATTR pmu_hal_context_t pmu_hal = { .dev = &PMU };
static DRAM_ATTR pmu_sleep_machine_constant_t pmu_mc = PMU_SLEEP_MC_DEFAULT();
static DRAM_ATTR pmu_context_t pmu_context = { .hal = &pmu_hal, .mc = (void *)&pmu_mc };
return &pmu_context;
}
void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_param_t *param)
{
const pmu_hp_system_power_param_t *power = param->power;
const pmu_hp_system_clock_param_t *clock = param->clock;
const pmu_hp_system_digital_param_t *dig = param->digital;
const pmu_hp_system_analog_param_t *anlg = param->analog;
const pmu_hp_system_retention_param_t *ret = param->retent;
assert(ctx->hal);
/* Default configuration of hp-system power in active, modem and sleep modes */
pmu_ll_hp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val);
pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val);
pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal);
/* Default configuration of hp-system clock in active, modem and sleep modes */
pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func);
pmu_ll_hp_set_icg_apb (ctx->hal->dev, mode, clock->icg_apb);
pmu_ll_hp_set_icg_modem (ctx->hal->dev, mode, clock->icg_modem.code);
pmu_ll_hp_set_sysclk_nodiv (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_nodiv);
pmu_ll_hp_set_icg_sysclk_enable (ctx->hal->dev, mode, clock->sysclk.icg_sysclk_en);
pmu_ll_hp_set_sysclk_slp_sel (ctx->hal->dev, mode, clock->sysclk.sysclk_slp_sel);
pmu_ll_hp_set_icg_sysclk_slp_sel(ctx->hal->dev, mode, clock->sysclk.icg_slp_sel);
pmu_ll_hp_set_dig_sysclk (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_sel);
/* Default configuration of hp-system digital sub-system in active, modem
* and sleep modes */
pmu_ll_hp_set_uart_wakeup_enable(ctx->hal->dev, mode, dig->syscntl.uart_wakeup_en);
pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, mode, dig->syscntl.lp_pad_hold_all);
pmu_ll_hp_set_hold_all_hp_pad (ctx->hal->dev, mode, dig->syscntl.hp_pad_hold_all);
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, mode, dig->syscntl.dig_pad_slp_sel);
pmu_ll_hp_set_pause_watchdog (ctx->hal->dev, mode, dig->syscntl.dig_pause_wdt);
pmu_ll_hp_set_cpu_stall (ctx->hal->dev, mode, dig->syscntl.dig_cpu_stall);
/* Default configuration of hp-system analog sub-system in active, modem and
* sleep modes */
pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias);
pmu_ll_hp_set_dbg_atten (ctx->hal->dev, mode, anlg->bias.dbg_atten);
pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur);
pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep);
pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_xpd);
pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd);
pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd);
pmu_ll_hp_set_regulator_sleep_memory_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_mem_dbias);
pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_logic_dbias);
pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias);
pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b);
/* Default configuration of hp-system retention sub-system in active, modem
* and sleep modes */
pmu_ll_hp_set_retention_param(ctx->hal->dev, mode, ret->retention.val);
pmu_ll_hp_set_backup_icg_func(ctx->hal->dev, mode, ret->backup_clk);
/* Some PMU initial parameter configuration */
pmu_ll_imm_update_dig_icg_modem_code(ctx->hal->dev, true);
pmu_ll_imm_update_dig_icg_switch(ctx->hal->dev, true);
pmu_ll_hp_set_sleep_protect_mode(ctx->hal->dev, PMU_SLEEP_PROTECT_HP_LP_SLEEP);
}
void pmu_lp_system_init(pmu_context_t *ctx, pmu_lp_mode_t mode, pmu_lp_system_param_t *param)
{
const pmu_lp_system_power_param_t *power = param->power;
const pmu_lp_system_analog_param_t *anlg = param->analog;
assert(ctx->hal);
/* Default configuration of lp-system power in active and sleep modes */
pmu_ll_lp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val);
pmu_ll_lp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val);
pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, power->xtal.xpd_xtal);
/* Default configuration of lp-system analog sub-system in active and
* sleep modes */
pmu_ll_lp_set_bias_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.xpd_bias);
pmu_ll_lp_set_dbg_atten (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.dbg_atten);
pmu_ll_lp_set_current_power_off (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.pd_cur);
pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.bias_sleep);
pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_xpd);
pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd);
pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_dbias);
pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias);
pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b);
}
static inline void pmu_power_domain_force_default(pmu_context_t *ctx)
{
assert(ctx);
// for bypass reserved power domain
const pmu_hp_power_domain_t pmu_hp_domains[] = {
PMU_HP_PD_TOP,
PMU_HP_PD_AON,
PMU_HP_PD_CPU,
PMU_HP_PD_WIFI
};
for (uint8_t idx = 0; idx < (sizeof(pmu_hp_domains) / sizeof(pmu_hp_power_domain_t)); idx++) {
pmu_ll_hp_set_power_force_reset (ctx->hal->dev, pmu_hp_domains[idx], false);
pmu_ll_hp_set_power_force_isolate (ctx->hal->dev, pmu_hp_domains[idx], false);
pmu_ll_hp_set_power_force_power_up (ctx->hal->dev, pmu_hp_domains[idx], false);
pmu_ll_hp_set_power_force_no_reset (ctx->hal->dev, pmu_hp_domains[idx], false);
pmu_ll_hp_set_power_force_no_isolate(ctx->hal->dev, pmu_hp_domains[idx], false);
pmu_ll_hp_set_power_force_power_down(ctx->hal->dev, pmu_hp_domains[idx], false);
}
/* Isolate all memory banks while sleeping, avoid memory leakage current */
pmu_ll_hp_set_memory_no_isolate (ctx->hal->dev, 0);
pmu_ll_lp_set_power_force_reset (ctx->hal->dev, false);
pmu_ll_lp_set_power_force_isolate (ctx->hal->dev, false);
pmu_ll_lp_set_power_force_power_up (ctx->hal->dev, false);
pmu_ll_lp_set_power_force_no_reset (ctx->hal->dev, false);
pmu_ll_lp_set_power_force_no_isolate(ctx->hal->dev, false);
pmu_ll_lp_set_power_force_power_down(ctx->hal->dev, false);
}
static inline void pmu_hp_system_param_default(pmu_hp_mode_t mode, pmu_hp_system_param_t *param)
{
param->power = pmu_hp_system_power_param_default(mode);
param->clock = pmu_hp_system_clock_param_default(mode);
param->digital = pmu_hp_system_digital_param_default(mode);
param->analog = pmu_hp_system_analog_param_default(mode);
param->retent = pmu_hp_system_retention_param_default(mode);
}
static void pmu_hp_system_init_default(pmu_context_t *ctx)
{
assert(ctx);
pmu_hp_system_param_t param = { 0 };
for (pmu_hp_mode_t mode = PMU_MODE_HP_ACTIVE; mode < PMU_MODE_HP_MAX; mode++) {
pmu_hp_system_param_default(mode, &param);
pmu_hp_system_init(ctx, mode, &param);
}
}
static inline void pmu_lp_system_param_default(pmu_lp_mode_t mode, pmu_lp_system_param_t *param)
{
param->power = pmu_lp_system_power_param_default(mode);
param->analog = pmu_lp_system_analog_param_default(mode);
}
static void pmu_lp_system_init_default(pmu_context_t *ctx)
{
assert(ctx);
pmu_lp_system_param_t param;
for (pmu_lp_mode_t mode = PMU_MODE_LP_ACTIVE; mode < PMU_MODE_LP_MAX; mode++) {
pmu_lp_system_param_default(mode, &param);
pmu_lp_system_init(ctx, mode, &param);
}
}
void pmu_init(void)
{
/* Peripheral reg i2c power up */
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_RTC_DREG, 1);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_DIG_DREG, 1);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_DIG_REG, 0);
pmu_hp_system_init_default(PMU_instance());
pmu_lp_system_init_default(PMU_instance());
pmu_power_domain_force_default(PMU_instance());
}

View File

@ -0,0 +1,441 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "soc/soc.h"
#include "pmu_param.h"
#include "soc/pmu_icg_mapping.h"
#include "esp_private/esp_pmu.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
#define PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.vdd_spi_pd_en = 0, \
.mem_dslp = 0, \
.mem_pd_en = 0, \
.wifi_pd_en = 0, \
.cpu_pd_en = 0, \
.aon_pd_en = 0, \
.top_pd_en = 0 \
}, \
.clk_power = { \
.i2c_iso_en = 0, \
.i2c_retention = 0, \
.xpd_bb_i2c = 1, \
.xpd_bbpll_i2c = 1, \
.xpd_bbpll = 1 \
}, \
.xtal = { \
.xpd_xtal = 1 \
} \
}
#define PMU_HP_MODEM_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.vdd_spi_pd_en = 0, \
.mem_dslp = 0, \
.mem_pd_en = 0, \
.wifi_pd_en = 0, \
.cpu_pd_en = 1, \
.aon_pd_en = 0, \
.top_pd_en = 0 \
}, \
.clk_power = { \
.i2c_iso_en = 0, \
.i2c_retention = 0, \
.xpd_bb_i2c = 1, \
.xpd_bbpll_i2c = 1, \
.xpd_bbpll = 1 \
}, \
.xtal = { \
.xpd_xtal = 1 \
} \
}
#define PMU_HP_SLEEP_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.vdd_spi_pd_en = 1, \
.mem_dslp = 0, \
.mem_pd_en = 0, \
.wifi_pd_en = 1, \
.cpu_pd_en = 0, \
.aon_pd_en = 0, \
.top_pd_en = 0 \
}, \
.clk_power = { \
.i2c_iso_en = 1, \
.i2c_retention = 1, \
.xpd_bb_i2c = 1, \
.xpd_bbpll_i2c = 0, \
.xpd_bbpll = 0, \
}, \
.xtal = { \
.xpd_xtal = 0 \
} \
}
const pmu_hp_system_power_param_t * pmu_hp_system_power_param_default(pmu_hp_mode_t mode)
{
static const pmu_hp_system_power_param_t hp_power[] = {
PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT(),
PMU_HP_MODEM_POWER_CONFIG_DEFAULT(),
PMU_HP_SLEEP_POWER_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(hp_power));
return &hp_power[mode];
}
#define PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT() { \
.icg_func = 0xffffffff, \
.icg_apb = 0xffffffff, \
.icg_modem = { \
.code = PMU_HP_ICG_MODEM_CODE_ACTIVE \
}, \
.sysclk = { \
.dig_sysclk_nodiv = 0, \
.icg_sysclk_en = 1, \
.sysclk_slp_sel = 0, \
.icg_slp_sel = 0, \
.dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \
} \
}
#define PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT() { \
.icg_func = 0, \
.icg_apb = 0, \
.icg_modem = { \
.code = PMU_HP_ICG_MODEM_CODE_MODEM \
}, \
.sysclk = { \
.dig_sysclk_nodiv = 0, \
.icg_sysclk_en = 1, \
.sysclk_slp_sel = 1, \
.icg_slp_sel = 1, \
.dig_sysclk_sel = PMU_HP_SYSCLK_PLL \
} \
}
#define PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT() { \
.icg_func = 0, \
.icg_apb = 0, \
.icg_modem = { \
.code = PMU_HP_ICG_MODEM_CODE_SLEEP \
}, \
.sysclk = { \
.dig_sysclk_nodiv = 0, \
.icg_sysclk_en = 0, \
.sysclk_slp_sel = 1, \
.icg_slp_sel = 1, \
.dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \
} \
}
const pmu_hp_system_clock_param_t * pmu_hp_system_clock_param_default(pmu_hp_mode_t mode)
{
static const pmu_hp_system_clock_param_t hp_clock[] = {
PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT(),
PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT(),
PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(hp_clock));
return &hp_clock[mode];
}
#define PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT() { \
.syscntl = { \
.uart_wakeup_en = 0, \
.lp_pad_hold_all = 0, \
.hp_pad_hold_all = 0, \
.dig_pad_slp_sel = 0, \
.dig_pause_wdt = 0, \
.dig_cpu_stall = 0 \
} \
}
#define PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT() { \
.syscntl = { \
.uart_wakeup_en = 1, \
.lp_pad_hold_all = 0, \
.hp_pad_hold_all = 0, \
.dig_pad_slp_sel = 0, \
.dig_pause_wdt = 1, \
.dig_cpu_stall = 1 \
} \
}
#define PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT() { \
.syscntl = { \
.uart_wakeup_en = 1, \
.lp_pad_hold_all = 0, \
.hp_pad_hold_all = 0, \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = 1, \
.dig_cpu_stall = 1 \
} \
}
const pmu_hp_system_digital_param_t * pmu_hp_system_digital_param_default(pmu_hp_mode_t mode)
{
static const pmu_hp_system_digital_param_t hp_digital[] = {
PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT(),
PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT(),
PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(hp_digital));
return &hp_digital[mode];
}
#define PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \
.bias = { \
.xpd_bias = 1, \
.dbg_atten = 0x0, \
.pd_cur = 0, \
.bias_sleep = 0 \
}, \
.regulator0 = { \
.lp_dbias_vol = 0xd, \
.hp_dbias_vol = 0x1c,\
.dbias_sel = 1, \
.dbias_init = 1, \
.slp_mem_xpd = 0, \
.slp_logic_xpd = 0, \
.xpd = 1, \
.slp_mem_dbias = 0xc, \
.slp_logic_dbias = 0xc, \
.dbias = 0x19 \
}, \
.regulator1 = { \
.drv_b = 0x0 \
} \
}
#define PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT() { \
.bias = { \
.xpd_bias = 0, \
.dbg_atten = 0x0, \
.pd_cur = 0, \
.bias_sleep = 0 \
}, \
.regulator0 = { \
.slp_mem_xpd = 0, \
.slp_logic_xpd = 0, \
.xpd = 1, \
.slp_mem_dbias = 0xc, \
.slp_logic_dbias = 0xc, \
.dbias = 0x1a \
}, \
.regulator1 = { \
.drv_b = 0x0 \
} \
}
#define PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT() { \
.bias = { \
.xpd_bias = 0, \
.dbg_atten = 0x0, \
.pd_cur = 0, \
.bias_sleep = 0 \
}, \
.regulator0 = { \
.slp_mem_xpd = 1, \
.slp_logic_xpd = 1, \
.xpd = 0, \
.slp_mem_dbias = 0x4, \
.slp_logic_dbias = 0x4, \
.dbias = 0x1a \
}, \
.regulator1 = { \
.drv_b = 0x0 \
} \
}
const pmu_hp_system_analog_param_t * pmu_hp_system_analog_param_default(pmu_hp_mode_t mode)
{
static const pmu_hp_system_analog_param_t hp_analog[] = {
PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT(),
PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT(),
PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(hp_analog));
return &hp_analog[mode];
}
#define PMU_HP_RETENTION_REGDMA_CONFIG(dir, entry) ((((dir)<<2) | (entry & 0x3)) & 0x7)
#define PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT() { \
.retention = { \
.hp_sleep2active_backup_modem_clk_code = 2, \
.hp_modem2active_backup_modem_clk_code = 2, \
.hp_active_retention_mode = 0, \
.hp_sleep2active_retention_en = 0, \
.hp_modem2active_retention_en = 0, \
.hp_sleep2active_backup_clk_sel = 0, \
.hp_modem2active_backup_clk_sel = 0, \
.hp_sleep2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 0), \
.hp_modem2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 2), \
.hp_sleep2active_backup_en = 0, \
.hp_modem2active_backup_en = 0, \
}, \
.backup_clk = ( \
BIT(PMU_ICG_FUNC_ENA_REGDMA) | \
BIT(PMU_ICG_FUNC_ENA_TG0) | \
BIT(PMU_ICG_FUNC_ENA_TG1) | \
BIT(PMU_ICG_FUNC_ENA_HPBUS) | \
BIT(PMU_ICG_FUNC_ENA_MSPI) | \
BIT(PMU_ICG_FUNC_ENA_IOMUX) | \
BIT(PMU_ICG_FUNC_ENA_SPI2) | \
BIT(PMU_ICG_FUNC_ENA_UART0) | \
BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
) \
}
#define PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT() { \
.retention = { \
.hp_sleep2modem_backup_modem_clk_code = 1, \
.hp_modem_retention_mode = 0, \
.hp_sleep2modem_retention_en = 0, \
.hp_sleep2modem_backup_clk_sel = 0, \
.hp_sleep2modem_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 1), \
.hp_sleep2modem_backup_en = 0, \
}, \
.backup_clk = ( \
BIT(PMU_ICG_FUNC_ENA_REGDMA) | \
BIT(PMU_ICG_FUNC_ENA_TG0) | \
BIT(PMU_ICG_FUNC_ENA_TG1) | \
BIT(PMU_ICG_FUNC_ENA_HPBUS) | \
BIT(PMU_ICG_FUNC_ENA_MSPI) | \
BIT(PMU_ICG_FUNC_ENA_IOMUX) | \
BIT(PMU_ICG_FUNC_ENA_SPI2) | \
BIT(PMU_ICG_FUNC_ENA_UART0) | \
BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
) \
}
#define PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT() { \
.retention = { \
.hp_modem2sleep_backup_modem_clk_code = 0, \
.hp_active2sleep_backup_modem_clk_code = 2, \
.hp_sleep_retention_mode = 0, \
.hp_modem2sleep_retention_en = 0, \
.hp_active2sleep_retention_en = 0, \
.hp_modem2sleep_backup_clk_sel = 0, \
.hp_active2sleep_backup_clk_sel = 0, \
.hp_modem2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 1), \
.hp_active2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 0), \
.hp_modem2sleep_backup_en = 0, \
.hp_active2sleep_backup_en = 0, \
}, \
.backup_clk = ( \
BIT(PMU_ICG_FUNC_ENA_REGDMA) | \
BIT(PMU_ICG_FUNC_ENA_TG0) | \
BIT(PMU_ICG_FUNC_ENA_TG1) | \
BIT(PMU_ICG_FUNC_ENA_HPBUS) | \
BIT(PMU_ICG_FUNC_ENA_MSPI) | \
BIT(PMU_ICG_FUNC_ENA_IOMUX) | \
BIT(PMU_ICG_FUNC_ENA_SPI2) | \
BIT(PMU_ICG_FUNC_ENA_UART0) | \
BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \
) \
}
const pmu_hp_system_retention_param_t * pmu_hp_system_retention_param_default(pmu_hp_mode_t mode)
{
static const pmu_hp_system_retention_param_t hp_retention[] = {
PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT(),
PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT(),
PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(hp_retention));
return &hp_retention[mode];
}
/** LP system default parameter */
#define PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.mem_dslp = 0, \
.peri_pd_en = 0, \
}, \
.clk_power = { \
.xpd_xtal32k = 1, \
.xpd_rc32k = 1, \
.xpd_fosc = 1, \
.pd_osc = 0 \
} \
}
#define PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.mem_dslp = 1, \
.peri_pd_en = 0, \
}, \
.clk_power = { \
.xpd_xtal32k = 0, \
.xpd_rc32k = 0, \
.xpd_fosc = 0, \
.pd_osc = 0 \
}, \
.xtal = { \
.xpd_xtal = 0 \
} \
}
const pmu_lp_system_power_param_t * pmu_lp_system_power_param_default(pmu_lp_mode_t mode)
{
static const pmu_lp_system_power_param_t lp_power[] = {
PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT(),
PMU_LP_SLEEP_POWER_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(lp_power));
return &lp_power[mode];
}
#define PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \
.regulator0 = { \
.slp_xpd = 0, \
.xpd = 1, \
.slp_dbias = 0x0, \
.dbias = 0x1a \
}, \
.regulator1 = { \
.drv_b = 0x0 \
} \
}
#define PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT() { \
.bias = { \
.xpd_bias = 0, \
.dbg_atten = 0x0, \
.pd_cur = 1, \
.bias_sleep = 1, \
}, \
.regulator0 = { \
.slp_xpd = 1, \
.xpd = 0, \
.slp_dbias = 0x0, \
.dbias = 0x12 \
}, \
.regulator1 = { \
.drv_b = 0x0 \
} \
}
const pmu_lp_system_analog_param_t * pmu_lp_system_analog_param_default(pmu_lp_mode_t mode)
{
static const pmu_lp_system_analog_param_t lp_analog[] = {
PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT(),
PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT()
};
assert(mode < ARRAY_SIZE(lp_analog));
return &lp_analog[mode];
}

View File

@ -0,0 +1,256 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <sys/param.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/pmu_struct.h"
#include "esp_private/esp_pmu.h"
#define HP(state) (PMU_MODE_HP_ ## state)
#define LP(state) (PMU_MODE_LP_ ## state)
void pmu_sleep_enable_regdma_backup(void)
{
assert(PMU_instance()->hal);
/* entry 0, 1, 2 is used by pmu HP_SLEEP and HP_ACTIVE, HP_SLEEP
* and HP_MODEM or HP_MODEM and HP_ACTIVE states switching,
* respectively. entry 3 is reserved, not used yet! */
pmu_hal_hp_set_sleep_active_backup_enable(PMU_instance()->hal);
pmu_hal_hp_set_sleep_modem_backup_enable(PMU_instance()->hal);
pmu_hal_hp_set_modem_active_backup_enable(PMU_instance()->hal);
}
void pmu_sleep_disable_regdma_backup(void)
{
assert(PMU_instance()->hal);
pmu_hal_hp_set_sleep_active_backup_disable(PMU_instance()->hal);
pmu_hal_hp_set_sleep_modem_backup_disable(PMU_instance()->hal);
pmu_hal_hp_set_modem_active_backup_disable(PMU_instance()->hal);
}
uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t pd_flags, uint32_t slowclk_period, uint32_t fastclk_period)
{
const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc;
/* LP core hardware wait time, microsecond */
const int lp_wakeup_wait_time = rtc_time_slowclk_to_us(mc->lp.wakeup_wait_cycle, slowclk_period);
const int lp_clk_switch_time = rtc_time_slowclk_to_us(mc->lp.clk_switch_cycle, slowclk_period);
const int lp_clk_power_on_wait_time = (pd_flags & PMU_SLEEP_PD_XTAL) ? mc->lp.xtal_wait_stable_time_ms \
: rtc_time_slowclk_to_us(mc->lp.clk_power_on_wait_cycle, slowclk_period);
const int lp_hw_wait_time = mc->lp.min_slp_time_ms + mc->lp.analog_wait_time_ms + lp_clk_power_on_wait_time \
+ lp_wakeup_wait_time + lp_clk_switch_time + mc->lp.power_supply_wait_time_ms \
+ mc->lp.power_up_wait_time_ms;
/* HP core hardware wait time, microsecond */
const int hp_digital_power_up_wait_time_ms = mc->hp.power_supply_wait_time_ms + mc->hp.power_up_wait_time_ms;
const int hp_regdma_wait_time = MAX(mc->hp.regdma_s2m_work_time_ms + mc->hp.regdma_m2a_work_time_ms, mc->hp.regdma_s2a_work_time_ms);
const int hp_clock_wait_time = mc->hp.xtal_wait_stable_time_ms + mc->hp.pll_wait_stable_time_ms;
const int hp_hw_wait_time = mc->hp.analog_wait_time_ms + MAX(hp_digital_power_up_wait_time_ms + hp_regdma_wait_time, hp_clock_wait_time);
/* When the SOC wakeup (lp timer or GPIO wakeup) and Modem wakeup (Beacon wakeup) complete, the soc
* wakeup will be delayed until the RF is turned on in Modem state.
*
* modem wakeup TBTT, RF on by HW
* | |
* \|/ \|/
* PMU_HP_ACTIVE /------
* PMU_HP_MODEM /------------//////////////////
* PMU_HP_SLEEP ----------------------//////////////////
* /|\ /|\ /|\ /|\ /|\ /|\
* |<- some hw wait ->| | | |<- M2A switch ->|
* | slow cycles & | soc wakeup | |
* | FOSC cycles |<- S2M switch ->| |
* | |
* |<-- PMU guard time, also the maximum time for the SOC -->|
* | wake-up delay |
*/
#if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_AUTO_BEACON_ENABLE
const int rf_on_protect_time = mc->hp.regdma_rf_on_work_time_ms;
const int total_hw_wait_time = lp_hw_wait_time + hp_hw_wait_time + mc->hp.clock_domain_sync_time_ms;
#else
const int rf_on_protect_time = 0;
const int total_hw_wait_time = lp_hw_wait_time + hp_hw_wait_time;
#endif
return total_hw_wait_time + rf_on_protect_time;
}
#define rtc_time_us_to_fastclk(time_us, period) rtc_time_us_to_slowclk((time_us), (period))
static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default(
pmu_sleep_param_config_t *param,
pmu_sleep_power_config_t *power, /* We'll use the runtime power parameter to determine some hardware parameters */
const uint32_t pd_flags,
const uint32_t adjustment,
const uint32_t slowclk_period,
const uint32_t fastclk_period
)
{
const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc;
param->hp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->hp.min_slp_time_ms, slowclk_period);
param->hp_sys.analog_wait_target_cycle = rtc_time_us_to_fastclk(mc->hp.analog_wait_time_ms, fastclk_period);
param->hp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_supply_wait_time_ms, fastclk_period);
param->hp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_up_wait_time_ms, fastclk_period);
param->hp_sys.pll_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.pll_wait_stable_time_ms, fastclk_period);
const int hw_wait_time = pmu_sleep_calculate_hw_wait_time(pd_flags, slowclk_period, fastclk_period);
const int modem_state_skip_time = mc->hp.regdma_m2a_work_time_ms + mc->hp.system_dfs_up_work_time_ms + mc->lp.min_slp_time_ms;
const int modem_wakeup_wait_time = adjustment - hw_wait_time + modem_state_skip_time + mc->hp.regdma_rf_on_work_time_ms;
param->hp_sys.modem_wakeup_wait_cycle = rtc_time_us_to_fastclk(modem_wakeup_wait_time, fastclk_period);
param->lp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.min_slp_time_ms, slowclk_period);
param->lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(mc->lp.analog_wait_time_ms, slowclk_period);
param->lp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_supply_wait_time_ms, fastclk_period);
param->lp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_up_wait_time_ms, fastclk_period);
if (power->hp_sys.xtal.xpd_xtal) {
param->hp_lp.xtal_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.xtal_wait_stable_time_ms, fastclk_period);
} else {
param->hp_lp.xtal_stable_wait_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.xtal_wait_stable_time_ms, slowclk_period);
}
return param;
}
const pmu_sleep_config_t* pmu_sleep_config_default(
pmu_sleep_config_t *config,
uint32_t pd_flags,
uint32_t adjustment,
uint32_t slowclk_period,
uint32_t fastclk_period,
bool dslp
)
{
pmu_sleep_power_config_t power_default = PMU_SLEEP_POWER_CONFIG_DEFAULT(pd_flags);
uint32_t iram_pd_flags = 0;
iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G0) ? BIT(0) : 0;
iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G1) ? BIT(1) : 0;
iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G2) ? BIT(2) : 0;
iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G3) ? BIT(3) : 0;
config->power = power_default;
pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags);
config->param = *pmu_sleep_param_config_default(&param_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period);
if (dslp) {
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags);
config->analog = analog_default;
} else {
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags);
if (!(pd_flags & PMU_SLEEP_PD_MODEM)){
analog_default.hp_sys.analog.slp_logic_dbias += 2;
}
if (!(pd_flags & PMU_SLEEP_PD_TOP)){
analog_default.hp_sys.analog.slp_logic_dbias += 2;
}
config->analog = analog_default;
}
return config;
}
static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_config_t *power, bool dslp)
{
pmu_ll_hp_set_dig_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.dig_power.val);
pmu_ll_hp_set_clk_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.clk_power.val);
pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, HP(SLEEP), power->hp_sys.xtal.xpd_xtal);
pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].dig_power.val);
pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].clk_power.val);
pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].dig_power.val);
pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].clk_power.val);
pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].xtal.xpd_xtal);
if (dslp) {
// TODO: IDF-5349
} else {
}
}
static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp)
{
assert(ctx->hal);
pmu_ll_hp_set_current_power_off (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.pd_cur);
pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.bias_sleep);
pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_xpd);
pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_xpd);
pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd);
pmu_ll_hp_set_regulator_sleep_memory_dbias(ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_dbias);
pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_logic_dbias);
pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias);
pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b);
pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.slp_dbias);
pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.dbias);
pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, LP(ACTIVE), analog->lp_sys[LP(ACTIVE)].analog.drv_b);
pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur);
pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.bias_sleep);
pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.xpd);
pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.slp_dbias);
pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbias);
pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.drv_b);
if (dslp) {
// TODO: IDF-5349
} else {
}
}
static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_config_t *param, bool dslp)
{
assert(ctx->hal);
pmu_ll_hp_set_min_sleep_cycle(ctx->hal->dev, param->hp_sys.min_slp_slow_clk_cycle);
pmu_ll_lp_set_min_sleep_cycle(ctx->hal->dev, param->lp_sys.min_slp_slow_clk_cycle);
pmu_ll_hp_set_analog_wait_target_cycle(ctx->hal->dev, param->hp_sys.analog_wait_target_cycle);
pmu_ll_lp_set_analog_wait_target_cycle(ctx->hal->dev, param->lp_sys.analog_wait_target_cycle);
pmu_hal_hp_set_digital_power_up_wait_cycle(ctx->hal, param->hp_sys.digital_power_supply_wait_cycle, param->hp_sys.digital_power_up_wait_cycle);
pmu_hal_lp_set_digital_power_up_wait_cycle(ctx->hal, param->lp_sys.digital_power_supply_wait_cycle, param->lp_sys.digital_power_up_wait_cycle);
pmu_ll_set_modem_wait_target_cycle(ctx->hal->dev, param->hp_sys.modem_wakeup_wait_cycle);
pmu_ll_set_xtal_stable_wait_cycle(ctx->hal->dev, param->hp_lp.xtal_stable_wait_slow_clk_cycle);
pmu_ll_set_pll_stable_wait_cycle(ctx->hal->dev, param->hp_sys.pll_stable_wait_cycle);
}
void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp)
{
assert(PMU_instance());
pmu_sleep_power_init(PMU_instance(), &config->power, dslp);
pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp);
pmu_sleep_param_init(PMU_instance(), &config->param, dslp);
}
uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
assert(PMU_instance()->hal);
pmu_ll_hp_set_wakeup_enable(PMU_instance()->hal->dev, wakeup_opt);
pmu_ll_hp_set_reject_enable(PMU_instance()->hal->dev, reject_opt);
pmu_ll_hp_clear_wakeup_intr_status(PMU_instance()->hal->dev);
pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev);
pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev);
/* Start entry into sleep mode */
pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev);
while (!pmu_ll_hp_is_sleep_wakeup(PMU_instance()->hal->dev) &&
!pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) {
;
}
return ESP_OK;
}

View File

@ -0,0 +1,336 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "soc/pmu_struct.h"
#include "hal/pmu_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
pmu_hp_dig_power_reg_t dig_power;
pmu_hp_clk_power_reg_t clk_power;
pmu_hp_xtal_reg_t xtal;
} pmu_hp_system_power_param_t;
const pmu_hp_system_power_param_t* pmu_hp_system_power_param_default(pmu_hp_mode_t mode);
typedef struct {
uint32_t icg_func;
uint32_t icg_apb;
pmu_hp_icg_modem_reg_t icg_modem;
pmu_hp_sysclk_reg_t sysclk;
} pmu_hp_system_clock_param_t;
const pmu_hp_system_clock_param_t* pmu_hp_system_clock_param_default(pmu_hp_mode_t mode);
typedef struct {
pmu_hp_sys_cntl_reg_t syscntl;
} pmu_hp_system_digital_param_t;
const pmu_hp_system_digital_param_t* pmu_hp_system_digital_param_default(pmu_hp_mode_t mode);
typedef struct {
pmu_hp_bias_reg_t bias;
pmu_hp_regulator0_reg_t regulator0;
pmu_hp_regulator1_reg_t regulator1;
} pmu_hp_system_analog_param_t;
const pmu_hp_system_analog_param_t* pmu_hp_system_analog_param_default(pmu_hp_mode_t mode);
typedef struct {
pmu_hp_backup_reg_t retention;
uint32_t backup_clk;
} pmu_hp_system_retention_param_t;
const pmu_hp_system_retention_param_t* pmu_hp_system_retention_param_default(pmu_hp_mode_t mode);
typedef struct {
pmu_lp_dig_power_reg_t dig_power;
pmu_lp_clk_power_reg_t clk_power;
pmu_lp_xtal_reg_t xtal;
} pmu_lp_system_power_param_t;
const pmu_lp_system_power_param_t* pmu_lp_system_power_param_default(pmu_lp_mode_t mode);
typedef struct {
pmu_lp_bias_reg_t bias;
pmu_lp_regulator0_reg_t regulator0;
pmu_lp_regulator1_reg_t regulator1;
} pmu_lp_system_analog_param_t;
const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mode_t mode);
#define PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES (10)
#define PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES (10)
#define PMU_HP_WAKEUP_DELAY_CYCLES (0)
#define PMU_HP_XTAL_STABLE_WAIT_CYCLES (3155) /* Not used, Fast OSC as PMU work clock source is about 201 us, corresponding to PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES */
#define PMU_HP_PLL_STABLE_WAIT_CYCLES (2)
#define PMU_HP_ANALOG_WAIT_TARGET_CYCLES (2419) /* Fast OSC as PMU work clock source is about 154 us */
#define PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32)
#define PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES (32)
#define PMU_HP_MODEM_WAKEUP_WAIT_CYCLES (20700) /* Fast OSC as PMU work clock source is about 1318.6 us */
#define PMU_LP_WAKEUP_DELAY_CYCLES (0)
#define PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES (30) /* Slow OSC as PMU slow clock source is about 201 us */
#define PMU_LP_ANALOG_WAIT_TARGET_CYCLES (23) /* Slow OSC as PMU slow clock source is about 154 us */
#define PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */
#define PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */
typedef struct {
struct {
pmu_hp_power_t dig_power;
pmu_hp_power_t clk_power;
pmu_hp_power_t xtal;
} hp_sys;
struct {
pmu_lp_power_t dig_power;
pmu_lp_power_t clk_power;
pmu_lp_power_t xtal;
} lp_sys[PMU_MODE_LP_MAX];
} pmu_sleep_power_config_t;
#define PMU_SLEEP_POWER_CONFIG_DEFAULT(pd_flags) { \
.hp_sys = { \
.dig_power = { \
.vdd_spi_pd_en = ((pd_flags) & PMU_SLEEP_PD_VDDSDIO) ? 1 : 0, \
.wifi_pd_en = ((pd_flags) & PMU_SLEEP_PD_MODEM) ? 1 : 0, \
.cpu_pd_en = ((pd_flags) & PMU_SLEEP_PD_CPU) ? 1 : 0, \
.aon_pd_en = ((pd_flags) & PMU_SLEEP_PD_AON) ? 1 : 0, \
.top_pd_en = ((pd_flags) & PMU_SLEEP_PD_TOP) ? 1 : 0, \
.mem_pd_en = 0, \
.mem_dslp = 0 \
}, \
.clk_power = { \
.i2c_iso_en = 1, \
.i2c_retention = 1, \
.xpd_bb_i2c = 0, \
.xpd_bbpll_i2c = 0, \
.xpd_bbpll = 0 \
}, \
.xtal = { \
.xpd_xtal = ((pd_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \
} \
}, \
.lp_sys[PMU_MODE_LP_ACTIVE] = { \
.dig_power = { \
.peri_pd_en = 0, \
.mem_dslp = 0 \
}, \
.clk_power = { \
.xpd_xtal32k = 1, \
.xpd_rc32k = 1, \
.xpd_fosc = 1 \
} \
}, \
.lp_sys[PMU_MODE_LP_SLEEP] = { \
.dig_power = { \
.peri_pd_en = ((pd_flags) & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \
.mem_dslp = 1 \
}, \
.clk_power = { \
.xpd_xtal32k = ((pd_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1, \
.xpd_rc32k = ((pd_flags) & PMU_SLEEP_PD_RC32K) ? 0 : 1, \
.xpd_fosc = ((pd_flags) & PMU_SLEEP_PD_RC_FAST) ? 0 : 1 \
}, \
.xtal = { \
.xpd_xtal = ((pd_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \
} \
} \
}
typedef struct {
struct {
pmu_hp_analog_t analog;
} hp_sys;
struct {
pmu_lp_analog_t analog;
} lp_sys[PMU_MODE_LP_MAX];
} pmu_sleep_analog_config_t;
#define PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags) { \
.hp_sys = { \
.analog = { \
.xpd_bias = 0x0, \
.dbg_atten = 0x0, \
.pd_cur = 1, \
.bias_sleep = 1, \
.slp_mem_xpd = 1, \
.slp_logic_xpd = 1, \
.slp_mem_dbias = 0x4, \
.slp_logic_dbias = 0x4, \
.xpd = 0, \
.dbias = 0, \
.drv_b = 0 \
} \
}, \
.lp_sys[PMU_MODE_LP_ACTIVE] = { \
.analog = { \
.slp_xpd = 0, \
.slp_dbias = 0xc, \
.xpd = 1, \
.dbias = 0x1a, \
.drv_b = 0x0 \
} \
}, \
.lp_sys[PMU_MODE_LP_SLEEP] = { \
.analog = { \
.xpd_bias = 0, \
.dbg_atten = 0x0, \
.pd_cur = 1, \
.bias_sleep = 1, \
.xpd = 0, \
.dbias = 0x1c, \
.slp_xpd = 1, \
.slp_dbias = 0x3, \
.drv_b = 0x0 \
} \
} \
}
#define PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags) { \
.hp_sys = { \
.analog = { \
.xpd_bias = 0, \
.dbg_atten = 0x3, \
.pd_cur = 1, \
.bias_sleep = 1, \
.xpd = 0, \
.dbias = 0x15, \
.slp_mem_xpd = 1, \
.slp_mem_dbias = 0xc, \
.slp_logic_xpd = 1, \
.slp_logic_dbias = 0x5, \
.drv_b = 0x18c \
} \
}, \
.lp_sys[PMU_MODE_LP_ACTIVE] = { \
.analog = { \
.xpd = 1, \
.dbias = 0x1a, \
.slp_xpd = 0, \
.slp_dbias = 0, \
.drv_b = 0x7 \
} \
}, \
.lp_sys[PMU_MODE_LP_SLEEP] = { \
.analog = { \
.xpd_bias = 0, \
.dbg_atten = 0xe, \
.pd_cur = 1, \
.bias_sleep = 1, \
.xpd = 0, \
.dbias = 0, \
.slp_xpd = 1, \
.slp_dbias = 0xe, \
.drv_b = 0 \
} \
} \
}
typedef struct {
pmu_hp_param_t hp_sys;
pmu_lp_param_t lp_sys;
pmu_hp_lp_param_t hp_lp;
} pmu_sleep_param_config_t;
#define PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags) { \
.hp_sys = { \
.min_slp_slow_clk_cycle = PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES, \
.analog_wait_target_cycle = PMU_HP_ANALOG_WAIT_TARGET_CYCLES, \
.digital_power_supply_wait_cycle = PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \
.digital_power_up_wait_cycle = PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES, \
.modem_wakeup_wait_cycle = PMU_HP_MODEM_WAKEUP_WAIT_CYCLES, \
.pll_stable_wait_cycle = PMU_HP_PLL_STABLE_WAIT_CYCLES \
}, \
.lp_sys = { \
.min_slp_slow_clk_cycle = PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES, \
.analog_wait_target_cycle = PMU_LP_ANALOG_WAIT_TARGET_CYCLES, \
.digital_power_supply_wait_cycle = PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \
.digital_power_up_wait_cycle = PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES \
}, \
.hp_lp = { \
.xtal_stable_wait_slow_clk_cycle = PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES \
} \
}
typedef struct {
pmu_sleep_power_config_t power;
pmu_sleep_analog_config_t analog;
pmu_sleep_param_config_t param;
} pmu_sleep_config_t;
typedef struct pmu_sleep_machine_constant {
struct {
uint16_t min_slp_time_ms; /* Mininum sleep protection time (unit: microsecond) */
uint8_t wakeup_wait_cycle; /* Modem wakeup signal (WiFi MAC and BEACON wakeup) waits for the slow & fast clock domain synchronization and the wakeup signal triggers the PMU FSM switching wait cycle (unit: slow clock cycle) */
uint8_t reserved0;
uint16_t reserved1;
uint16_t analog_wait_time_ms; /* LP LDO power up wait time (unit: microsecond) */
uint16_t xtal_wait_stable_time_ms; /* Main XTAL stabilization wait time (unit: microsecond) */
uint8_t clk_switch_cycle; /* Clock switch to FOSC (unit: slow clock cycle) */
uint8_t clk_power_on_wait_cycle; /* Clock power on wait cycle (unit: slow clock cycle) */
uint16_t power_supply_wait_time_ms; /* (unit: microsecond) */
uint16_t power_up_wait_time_ms; /* (unit: microsecond) */
} lp;
struct {
uint16_t min_slp_time_ms; /* Mininum sleep protection time (unit: microsecond) */
uint16_t clock_domain_sync_time_ms; /* The Slow OSC clock domain synchronizes time with the Fast OSC domain, at least 4 slow clock cycles (unit: microsecond) */
uint16_t system_dfs_up_work_time_ms; /* System DFS up scaling work time (unit: microsecond) */
uint16_t analog_wait_time_ms; /* HP LDO power up wait time (unit: microsecond) */
uint16_t power_supply_wait_time_ms; /* (unit: microsecond) */
uint16_t power_up_wait_time_ms; /* (unit: microsecond) */
uint16_t regdma_s2m_work_time_ms; /* Modem Subsystem (S2M switch) REGDMA restore time (unit: microsecond) */
uint16_t regdma_s2a_work_time_ms; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (S2A switch) restore time (unit: microsecond) */
uint16_t regdma_m2a_work_time_ms; /* Digital Peripheral (M2A switch) REGDMA restore time (unit: microsecond) */
uint16_t regdma_a2s_work_time_ms; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (A2S switch) backup time (unit: microsecond) */
uint16_t regdma_rf_on_work_time_ms; /* The REGDMA work time of RF enable (unit: microsecond) */
uint16_t regdma_rf_off_work_time_ms; /* The REGDMA work time of RF disable (unit: microsecond) */
uint16_t xtal_wait_stable_time_ms; /* Main XTAL stabilization wait time (unit: microsecond) */
uint16_t pll_wait_stable_time_ms; /* PLL stabilization wait time (unit: microsecond) */
} hp;
} pmu_sleep_machine_constant_t;
#define PMU_SLEEP_MC_DEFAULT() { \
.lp = { \
.min_slp_time_ms = 450, \
.wakeup_wait_cycle = 4, \
.analog_wait_time_ms = 154, \
.xtal_wait_stable_time_ms = 250, \
.clk_switch_cycle = 1, \
.clk_power_on_wait_cycle = 1, \
.power_supply_wait_time_ms = 2, \
.power_up_wait_time_ms = 2 \
}, \
.hp = { \
.min_slp_time_ms = 450, \
.clock_domain_sync_time_ms = 150, \
.system_dfs_up_work_time_ms = 124, \
.analog_wait_time_ms = 154, \
.power_supply_wait_time_ms = 2, \
.power_up_wait_time_ms = 2, \
.regdma_s2m_work_time_ms = 172, \
.regdma_s2a_work_time_ms = 430, \
.regdma_m2a_work_time_ms = 265, \
.regdma_a2s_work_time_ms = 338, \
.regdma_rf_on_work_time_ms = 70, \
.regdma_rf_off_work_time_ms = 23, \
.xtal_wait_stable_time_ms = 250, \
.pll_wait_stable_time_ms = 1 \
} \
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -19,14 +19,47 @@
#include "esp_hw_log.h"
#include "sdkconfig.h"
#include "esp_rom_uart.h"
#include "esp_private/esp_pmu.h"
#include "hal/clk_tree_ll.h"
#include "hal/pmu_ll.h"
#include "hal/modem_syscon_ll.h"
#include "hal/modem_lpcon_ll.h"
static const char *TAG = "rtc_clk_init";
/**
* Initialize the ICG map of some modem clock domains in the PMU_ACTIVE state
*
* A pre-initialization interface is used to initialize the ICG map of the
* MODEM_APB, I2C_MST and LP_APB clock domains in the PMU_ACTIVE state, and
* disable the clock gating of these clock domains in the PMU_ACTIVE state,
* because the system clock source (PLL) in the system boot up process needs
* to use the i2c master peripheral.
*
* ICG map of all modem clock domains under different power states (PMU_ACTIVE,
* PMU_MODEM and PMU_SLEEP) will be initialized in esp_perip_clk_init().
*/
static void rtc_clk_modem_clock_domain_active_state_icg_map_preinit(void)
{
/* Configure modem ICG code in PMU_ACTIVE state */
pmu_ll_hp_set_icg_modem(&PMU, PMU_MODE_HP_ACTIVE, PMU_HP_ICG_MODEM_CODE_ACTIVE);
/* Disable clock gating for MODEM_APB, I2C_MST and LP_APB clock domains in PMU_ACTIVE state */
modem_syscon_ll_set_modem_apb_icg_bitmap(&MODEM_SYSCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE));
modem_lpcon_ll_set_i2c_master_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE));
modem_lpcon_ll_set_lp_apb_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE));
/* Software trigger force update modem ICG code and ICG switch */
pmu_ll_imm_update_dig_icg_modem_code(&PMU, true);
pmu_ll_imm_update_dig_icg_switch(&PMU, true);
}
void rtc_clk_init(rtc_clk_config_t cfg)
{
rtc_cpu_freq_config_t old_config, new_config;
rtc_clk_modem_clock_domain_active_state_icg_map_preinit();
/* Set tuning parameters for RC_FAST, RC_SLOW, and RC32K clocks.
* Note: this doesn't attempt to set the clocks to precise frequencies.
* Instead, we calibrate these clocks against XTAL frequency later, when necessary.

View File

@ -1,26 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/rtc.h"
#include "soc/pmu_reg.h"
#include "soc/regi2c_dig_reg.h"
#include "regi2c_ctrl.h"
// TODO: IDF-5781
void rtc_init(rtc_config_t cfg)
{
/* Peripheral reg i2c power up */
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_RTC_DREG, 1);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_DIG_DREG, 1);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_DIG_REG, 0);
REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, 25);
REG_SET_FIELD(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, 26);
}

View File

@ -1,7 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// TODO: IDF-5645

View File

@ -8,8 +8,8 @@
#include "esp32c6/rom/ets_sys.h"
#include "soc/rtc.h"
#include "soc/lp_timer_reg.h"
#include "hal/lp_timer_hal.h"
#include "hal/clk_tree_ll.h"
#include "hal/rtc_cntl_ll.h"
#include "soc/timer_group_reg.h"
#include "esp_rom_sys.h"
#include "assert.h"
@ -207,7 +207,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period)
uint64_t rtc_time_get(void)
{
return rtc_cntl_ll_get_rtc_time();
return lp_timer_hal_get_cycle_count(0);
}
uint64_t rtc_light_slp_time_get(void)

View File

@ -174,40 +174,3 @@ void dslp_osc_pd(void){
REG_SET_FIELD(RTC_CNTL_RC32K_CTRL_REG,RTC_CNTL_RC32K_XPD, 0);
REG_SET_FIELD(RTC_CNTL_PLL8M_REG, RTC_CNTL_XPD_PLL8M, 0);
}
rtc_vddsdio_config_t rtc_vddsdio_get_config(void)
{
rtc_vddsdio_config_t result;
uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG);
result.drefh = (sdio_conf_reg & RTC_CNTL_DREFH_SDIO_M) >> RTC_CNTL_DREFH_SDIO_S;
result.drefm = (sdio_conf_reg & RTC_CNTL_DREFM_SDIO_M) >> RTC_CNTL_DREFM_SDIO_S;
result.drefl = (sdio_conf_reg & RTC_CNTL_DREFL_SDIO_M) >> RTC_CNTL_DREFL_SDIO_S;
if (sdio_conf_reg & RTC_CNTL_SDIO_FORCE) {
// Get configuration from RTC
result.force = 1;
result.enable = (sdio_conf_reg & RTC_CNTL_XPD_SDIO_REG_M) >> RTC_CNTL_XPD_SDIO_REG_S;
result.tieh = (sdio_conf_reg & RTC_CNTL_SDIO_TIEH_M) >> RTC_CNTL_SDIO_TIEH_S;
return result;
} else {
result.force = 0;
}
// Otherwise, VDD_SDIO is controlled by bootstrapping pin
uint32_t strap_reg = REG_READ(GPIO_STRAP_REG);
result.force = 0;
result.tieh = (strap_reg & BIT(5)) ? RTC_VDDSDIO_TIEH_1_8V : RTC_VDDSDIO_TIEH_3_3V;
result.enable = 1;
return result;
}
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
{
uint32_t val = 0;
val |= (config.force << RTC_CNTL_SDIO_FORCE_S);
val |= (config.enable << RTC_CNTL_XPD_SDIO_REG_S);
val |= (config.drefh << RTC_CNTL_DREFH_SDIO_S);
val |= (config.drefm << RTC_CNTL_DREFM_SDIO_S);
val |= (config.drefl << RTC_CNTL_DREFL_SDIO_S);
val |= (config.tieh << RTC_CNTL_SDIO_TIEH_S);
val |= RTC_CNTL_SDIO_PD_EN;
REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val);
}

View File

@ -0,0 +1,646 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "soc/soc_caps.h"
#include "esp_private/sleep_cpu.h"
#include "sdkconfig.h"
#if !SOC_PMU_SUPPORTED
#include "hal/rtc_hal.h"
#endif
#include "soc/rtc_periph.h"
#ifdef CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/rtc.h"
#include "riscv/rvsleep-frames.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "esp32c6/rom/cache.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep";
typedef struct {
uint32_t start;
uint32_t end;
} cpu_domain_dev_regs_region_t;
typedef struct {
cpu_domain_dev_regs_region_t *region;
int region_num;
uint32_t *regs_frame;
} cpu_domain_dev_sleep_frame_t;
/**
* Internal structure which holds all requested light sleep cpu retention parameters
*/
typedef struct {
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
rtc_cntl_sleep_retent_t retent;
#elif SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *intpri_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *plic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
#endif
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
#if CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
static uint32_t cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t code_seg_size, uint32_t data_seg_vaddr, uint32_t data_seg_size)
{
uint32_t sets; /* i/d-cache total set counts */
uint32_t index; /* virtual address mapping i/d-cache row offset */
uint32_t waysgrp;
uint32_t icache_tagmem_blk_gs, dcache_tagmem_blk_gs;
struct cache_mode imode = { .icache = 1 };
struct cache_mode dmode = { .icache = 0 };
/* calculate/prepare i-cache tag memory retention parameters */
Cache_Get_Mode(&imode);
sets = imode.cache_size / imode.cache_ways / imode.cache_line_size;
index = (code_seg_vaddr / imode.cache_line_size) % sets;
waysgrp = imode.cache_ways >> 2;
code_seg_size = ALIGNUP(imode.cache_line_size, code_seg_size);
s_cpu_retention.retent.tagmem.icache.start_point = index;
s_cpu_retention.retent.tagmem.icache.size = (sets * waysgrp) & 0xff;
s_cpu_retention.retent.tagmem.icache.vld_size = s_cpu_retention.retent.tagmem.icache.size;
if (code_seg_size < imode.cache_size / imode.cache_ways) {
s_cpu_retention.retent.tagmem.icache.vld_size = (code_seg_size / imode.cache_line_size) * waysgrp;
}
s_cpu_retention.retent.tagmem.icache.enable = (code_seg_size != 0) ? 1 : 0;
icache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.icache.vld_size ? s_cpu_retention.retent.tagmem.icache.vld_size : sets * waysgrp;
icache_tagmem_blk_gs = ALIGNUP(4, icache_tagmem_blk_gs);
ESP_LOGD(TAG, "I-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (imode.cache_size>>10),
imode.cache_line_size, imode.cache_ways, sets, index, icache_tagmem_blk_gs);
/* calculate/prepare d-cache tag memory retention parameters */
Cache_Get_Mode(&dmode);
sets = dmode.cache_size / dmode.cache_ways / dmode.cache_line_size;
index = (data_seg_vaddr / dmode.cache_line_size) % sets;
waysgrp = dmode.cache_ways >> 2;
data_seg_size = ALIGNUP(dmode.cache_line_size, data_seg_size);
s_cpu_retention.retent.tagmem.dcache.start_point = index;
s_cpu_retention.retent.tagmem.dcache.size = (sets * waysgrp) & 0x1ff;
s_cpu_retention.retent.tagmem.dcache.vld_size = s_cpu_retention.retent.tagmem.dcache.size;
#ifndef CONFIG_ESP32S3_DATA_CACHE_16KB
if (data_seg_size < dmode.cache_size / dmode.cache_ways) {
s_cpu_retention.retent.tagmem.dcache.vld_size = (data_seg_size / dmode.cache_line_size) * waysgrp;
}
s_cpu_retention.retent.tagmem.dcache.enable = (data_seg_size != 0) ? 1 : 0;
#else
s_cpu_retention.retent.tagmem.dcache.enable = 1;
#endif
dcache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.dcache.vld_size ? s_cpu_retention.retent.tagmem.dcache.vld_size : sets * waysgrp;
dcache_tagmem_blk_gs = ALIGNUP(4, dcache_tagmem_blk_gs);
ESP_LOGD(TAG, "D-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (dmode.cache_size>>10),
dmode.cache_line_size, dmode.cache_ways, sets, index, dcache_tagmem_blk_gs);
/* For I or D cache tagmem retention, backup and restore are performed through
* RTC DMA (its bus width is 128 bits), For I/D Cache tagmem blocks (i-cache
* tagmem blocks = 92 bits, d-cache tagmem blocks = 88 bits), RTC DMA automatically
* aligns its bit width to 96 bits, therefore, 3 times RTC DMA can transfer 4
* i/d-cache tagmem blocks (128 bits * 3 = 96 bits * 4) */
return (((icache_tagmem_blk_gs + dcache_tagmem_blk_gs) << 2) * 3);
}
#endif // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
static esp_err_t esp_sleep_tagmem_pd_low_init(void)
{
#if CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
if (s_cpu_retention.retent.tagmem.link_addr == NULL) {
extern char _stext[], _etext[];
uint32_t code_start = (uint32_t)_stext;
uint32_t code_size = (uint32_t)(_etext - _stext);
#if !(CONFIG_SPIRAM && CONFIG_SOC_PM_SUPPORT_TAGMEM_PD)
extern char _rodata_start[], _rodata_reserved_end[];
uint32_t data_start = (uint32_t)_rodata_start;
uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else
uint32_t data_start = SOC_DROM_LOW;
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
#endif
ESP_LOGI(TAG, "Code start at 0x%08"PRIx32", total %"PRIu32", data start at 0x%08"PRIx32", total %"PRIu32" Bytes",
code_start, code_size, data_start, data_size);
uint32_t tagmem_sz = cache_tagmem_retention_setup(code_start, code_size, data_start, data_size);
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_TAGMEM_PD_DMA_ADDR_ALIGN, 1,
tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.tagmem.link_addr = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, tagmem_sz, NULL);
} else {
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
return ESP_ERR_NO_MEM;
}
}
#else // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
#endif // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
return ESP_OK;
}
static esp_err_t esp_sleep_tagmem_pd_low_deinit(void)
{
#if SOC_PM_SUPPORT_TAGMEM_PD
if (s_cpu_retention.retent.tagmem.link_addr) {
heap_caps_free(s_cpu_retention.retent.tagmem.link_addr);
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
}
#endif
return ESP_OK;
}
#endif // SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
esp_err_t esp_sleep_cpu_pd_low_init(void)
{
if (s_cpu_retention.retent.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, 1,
SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
if (esp_sleep_tagmem_pd_low_init() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
#endif
return ESP_OK;
}
esp_err_t esp_sleep_cpu_pd_low_deinit(void)
{
if (s_cpu_retention.retent.cpu_pd_mem) {
heap_caps_free(s_cpu_retention.retent.cpu_pd_mem);
s_cpu_retention.retent.cpu_pd_mem = NULL;
}
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
if (esp_sleep_tagmem_pd_low_deinit() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
#endif
return ESP_OK;
}
void sleep_enable_cpu_retention(void)
{
rtc_cntl_hal_enable_cpu_retention(&s_cpu_retention.retent);
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_enable_tagmem_retention(&s_cpu_retention.retent);
#endif
}
void IRAM_ATTR sleep_disable_cpu_retention(void)
{
rtc_cntl_hal_disable_cpu_retention(&s_cpu_retention.retent);
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_disable_tagmem_retention(&s_cpu_retention.retent);
#endif
}
#endif
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
#define CUSTOM_CSR_CPU_TESTBUS_CTRL 0x7e3
#define CUSTOM_CSR_PCER_USER 0x800
#define CUSTOM_CSR_PCMR_USER 0x801
#define CUSTOM_CSR_PCCR_USER 0x802
#define CUSTOM_CSR_GPIO_OEN_USER 0x803
#define CUSTOM_CSR_GPIO_IN_USER 0x804
#define CUSTOM_CSR_GPIO_OUT_USER 0x805
#define CUSTOM_CSR_CO_EXCEPTION_CAUSE 0x7f0
#define CUSTOM_CSR_CO_HWLP 0x7f1
#define CUSTOM_CSR_CO_AIA 0x7f2
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num)
{
const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num;
int regs_frame_sz = 0;
for (int num = 0; num < region_num; num++) {
regs_frame_sz += regions[num].end - regions[num].start;
}
void *frame = heap_caps_malloc(sizeof(cpu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame) {
cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t));
memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t));
void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz;
memset(regs_frame, 0, regs_frame_sz);
*(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) {
.region = region,
.region_num = region_num,
.regs_frame = (uint32_t *)regs_frame
};
}
return frame;
}
static inline void * cpu_domain_intpri_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = INTPRI_CORE0_CPU_INT_ENABLE_REG, .end = INTPRI_RND_ECO_LOW_REG + 4 },
{ .start = INTPRI_RND_ECO_HIGH_REG, .end = INTPRI_RND_ECO_HIGH_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = EXTMEM_DCACHE_CTRL_REG, .end = EXTMEM_DCACHE_CTRL_REG + 4 },
{ .start = EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, .end = EXTMEM_CACHE_WRAP_AROUND_CTRL_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_plic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = PLIC_MXINT_ENABLE_REG, .end = PLIC_MXINT_CLAIM_REG + 4 },
{ .start = PLIC_MXINT_CONF_REG, .end = PLIC_MXINT_CONF_REG + 4 },
{ .start = PLIC_UXINT_ENABLE_REG, .end = PLIC_UXINT_CLAIM_REG + 4 },
{ .start = PLIC_UXINT_CONF_REG, .end = PLIC_UXINT_CONF_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clint_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_UINT_SIP_REG, .end = CLINT_UINT_UTIMECMP_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static esp_err_t esp_sleep_cpu_retention_init_impl(void)
{
if (s_cpu_retention.retent.critical_frame == NULL) {
void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.intpri_frame == NULL) {
void *frame = cpu_domain_intpri_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.plic_frame == NULL) {
void *frame = cpu_domain_plic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
static esp_err_t esp_sleep_cpu_retention_deinit_impl(void)
{
if (s_cpu_retention.retent.critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.critical_frame);
s_cpu_retention.retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (s_cpu_retention.retent.non_critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame);
s_cpu_retention.retent.non_critical_frame = NULL;
}
if (s_cpu_retention.retent.intpri_frame) {
heap_caps_free((void *)s_cpu_retention.retent.intpri_frame);
s_cpu_retention.retent.intpri_frame = NULL;
}
if (s_cpu_retention.retent.cache_config_frame) {
heap_caps_free((void *)s_cpu_retention.retent.cache_config_frame);
s_cpu_retention.retent.cache_config_frame = NULL;
}
if (s_cpu_retention.retent.plic_frame) {
heap_caps_free((void *)s_cpu_retention.retent.plic_frame);
s_cpu_retention.retent.plic_frame = NULL;
}
if (s_cpu_retention.retent.clint_frame) {
heap_caps_free((void *)s_cpu_retention.retent.clint_frame);
s_cpu_retention.retent.clint_frame = NULL;
}
return ESP_OK;
}
static inline IRAM_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
uint32_t mstatus;
__asm__ __volatile__ (
"csrr %0, mstatus\n"
"csrci mstatus, 0x8\n"
: "=r"(mstatus)
);
return mstatus;
}
static inline IRAM_ATTR void restore_mstatus(uint32_t mstatus)
{
__asm__ __volatile__ ("csrw mstatus, %0\n" :: "r"(mstatus));
}
static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void)
{
assert(s_cpu_retention.retent.non_critical_frame);
RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame;
frame->mscratch = RV_READ_CSR(mscratch);
frame->mideleg = RV_READ_CSR(mideleg);
frame->misa = RV_READ_CSR(misa);
frame->tselect = RV_READ_CSR(tselect);
frame->tdata1 = RV_READ_CSR(tdata1);
frame->tdata2 = RV_READ_CSR(tdata2);
frame->tcontrol = RV_READ_CSR(tcontrol);
frame->pmpcfg0 = RV_READ_CSR(pmpcfg0);
frame->pmpcfg1 = RV_READ_CSR(pmpcfg1);
frame->pmpcfg2 = RV_READ_CSR(pmpcfg2);
frame->pmpcfg3 = RV_READ_CSR(pmpcfg3);
frame->pmpaddr0 = RV_READ_CSR(pmpaddr0);
frame->pmpaddr1 = RV_READ_CSR(pmpaddr1);
frame->pmpaddr2 = RV_READ_CSR(pmpaddr2);
frame->pmpaddr3 = RV_READ_CSR(pmpaddr3);
frame->pmpaddr4 = RV_READ_CSR(pmpaddr4);
frame->pmpaddr5 = RV_READ_CSR(pmpaddr5);
frame->pmpaddr6 = RV_READ_CSR(pmpaddr6);
frame->pmpaddr7 = RV_READ_CSR(pmpaddr7);
frame->pmpaddr8 = RV_READ_CSR(pmpaddr8);
frame->pmpaddr9 = RV_READ_CSR(pmpaddr9);
frame->pmpaddr10 = RV_READ_CSR(pmpaddr10);
frame->pmpaddr11 = RV_READ_CSR(pmpaddr11);
frame->pmpaddr12 = RV_READ_CSR(pmpaddr12);
frame->pmpaddr13 = RV_READ_CSR(pmpaddr13);
frame->pmpaddr14 = RV_READ_CSR(pmpaddr14);
frame->pmpaddr15 = RV_READ_CSR(pmpaddr15);
frame->utvec = RV_READ_CSR(utvec);
frame->ustatus = RV_READ_CSR(ustatus);
frame->uepc = RV_READ_CSR(uepc);
frame->ucause = RV_READ_CSR(ucause);
frame->mpcer = RV_READ_CSR(CUSTOM_CSR_PCER_MACHINE);
frame->mpcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_MACHINE);
frame->mpccr = RV_READ_CSR(CUSTOM_CSR_PCCR_MACHINE);
frame->cpu_testbus_ctrl = RV_READ_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL);
frame->upcer = RV_READ_CSR(CUSTOM_CSR_PCER_USER);
frame->upcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_USER);
frame->upccr = RV_READ_CSR(CUSTOM_CSR_PCCR_USER);
frame->ugpio_oen = RV_READ_CSR(CUSTOM_CSR_GPIO_OEN_USER);
frame->ugpio_in = RV_READ_CSR(CUSTOM_CSR_GPIO_IN_USER);
frame->ugpio_out = RV_READ_CSR(CUSTOM_CSR_GPIO_OUT_USER);
return frame;
}
static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFrame *frame)
{
assert(frame);
RV_WRITE_CSR(mscratch, frame->mscratch);
RV_WRITE_CSR(mideleg, frame->mideleg);
RV_WRITE_CSR(misa, frame->misa);
RV_WRITE_CSR(tselect, frame->tselect);
RV_WRITE_CSR(tdata1, frame->tdata1);
RV_WRITE_CSR(tdata2, frame->tdata2);
RV_WRITE_CSR(tcontrol, frame->tcontrol);
RV_WRITE_CSR(pmpcfg0, frame->pmpcfg0);
RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1);
RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2);
RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3);
RV_WRITE_CSR(pmpaddr0, frame->pmpaddr0);
RV_WRITE_CSR(pmpaddr1, frame->pmpaddr1);
RV_WRITE_CSR(pmpaddr2, frame->pmpaddr2);
RV_WRITE_CSR(pmpaddr3, frame->pmpaddr3);
RV_WRITE_CSR(pmpaddr4, frame->pmpaddr4);
RV_WRITE_CSR(pmpaddr5, frame->pmpaddr5);
RV_WRITE_CSR(pmpaddr6, frame->pmpaddr6);
RV_WRITE_CSR(pmpaddr7, frame->pmpaddr7);
RV_WRITE_CSR(pmpaddr8, frame->pmpaddr8);
RV_WRITE_CSR(pmpaddr9, frame->pmpaddr9);
RV_WRITE_CSR(pmpaddr10,frame->pmpaddr10);
RV_WRITE_CSR(pmpaddr11,frame->pmpaddr11);
RV_WRITE_CSR(pmpaddr12,frame->pmpaddr12);
RV_WRITE_CSR(pmpaddr13,frame->pmpaddr13);
RV_WRITE_CSR(pmpaddr14,frame->pmpaddr14);
RV_WRITE_CSR(pmpaddr15,frame->pmpaddr15);
RV_WRITE_CSR(utvec, frame->utvec);
RV_WRITE_CSR(ustatus, frame->ustatus);
RV_WRITE_CSR(uepc, frame->uepc);
RV_WRITE_CSR(ucause, frame->ucause);
RV_WRITE_CSR(CUSTOM_CSR_PCER_MACHINE, frame->mpcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_MACHINE, frame->mpcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_MACHINE, frame->mpccr);
RV_WRITE_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL, frame->cpu_testbus_ctrl);
RV_WRITE_CSR(CUSTOM_CSR_PCER_USER, frame->upcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_USER, frame->upcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_USER, frame->upccr);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OEN_USER,frame->ugpio_oen);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_IN_USER, frame->ugpio_in);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OUT_USER,frame->ugpio_out);
}
static IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
regs_frame[offset++] = *(uint32_t *)addr;
}
}
}
static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
*(uint32_t *)addr = regs_frame[offset++];
}
}
}
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void);
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void);
typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool);
static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep,
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save();
if ((frame->pmufunc & 0x3) == 0x1) {
REG_CLR_BIT(SLEEP_MODE_REG, BIT(0)); /* Tell rom to run light sleep wake stub */
REG_WRITE(LIGHT_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore);
return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
}
return ESP_OK;
}
esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool),
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
uint32_t mstatus = save_mstatus_and_disable_global_int();
/* wait cache idle */
Cache_Freeze_ICache_Enable(CACHE_FREEZE_ACK_BUSY);
Cache_Freeze_ICache_Disable();
cpu_domain_dev_regs_save(s_cpu_retention.retent.plic_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame);
RvCoreNonCriticalSleepFrame *frame = rv_core_noncritical_regs_save();
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
rv_core_noncritical_regs_restore(frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.plic_frame);
restore_mstatus(mstatus);
return err;
}
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
#if SOC_PM_SUPPORT_CPU_PD
esp_err_t esp_sleep_cpu_retention_init(void)
{
esp_err_t err = ESP_OK;
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
err = esp_sleep_cpu_pd_low_init();
#elif SOC_PM_CPU_RETENTION_BY_SW
err = esp_sleep_cpu_retention_init_impl();
#endif
return err;
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
esp_err_t err = ESP_OK;
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
err = esp_sleep_cpu_pd_low_deinit();
#elif SOC_PM_CPU_RETENTION_BY_SW
err = esp_sleep_cpu_retention_deinit_impl();
#endif
return err;
}
bool cpu_domain_pd_allowed(void)
{
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
return (s_cpu_retention.retent.cpu_pd_mem != NULL);
#elif SOC_PM_CPU_RETENTION_BY_SW
return (s_cpu_retention.retent.critical_frame != NULL) && \
(s_cpu_retention.retent.non_critical_frame != NULL) && \
(s_cpu_retention.retent.intpri_frame != NULL) && \
(s_cpu_retention.retent.cache_config_frame != NULL) && \
(s_cpu_retention.retent.plic_frame != NULL) && \
(s_cpu_retention.retent.clint_frame != NULL);
#else
return false;
#endif
}
#endif

View File

@ -0,0 +1,239 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "riscv/rvsleep-frames.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#if !CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_aon_reg.h"
#include "soc/extmem_reg.h"
#endif
.section .data1,"aw"
.global rv_core_critical_regs_frame
.type rv_core_critical_regs_frame,@object
.align 4
rv_core_critical_regs_frame:
.word 0
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to save the critical registers of the CPU
core to the internal RAM before sleep, and modify the PMU control flag to
indicate that the system needs to sleep. When the subroutine returns, it
will return the memory pointer that saves the context information of the CPU
critical registers.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_save
.type rv_core_critical_regs_save,@function
.align 4
rv_core_critical_regs_save:
/* arrived here in critical section. we need:
save riscv core critical registers to RvCoreCriticalSleepFrame
*/
csrw mscratch, t0 /* use mscratch as temp storage */
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
sw ra, RV_SLP_CTX_RA(t0)
sw sp, RV_SLP_CTX_SP(t0)
sw gp, RV_SLP_CTX_GP(t0)
sw tp, RV_SLP_CTX_TP(t0)
sw t1, RV_SLP_CTX_T1(t0)
sw t2, RV_SLP_CTX_T2(t0)
sw s0, RV_SLP_CTX_S0(t0)
sw s1, RV_SLP_CTX_S1(t0)
sw a0, RV_SLP_CTX_A0(t0)
/* !! WARNING, do not use the a0 register below, a0 carries important sleep
* information and will be returned as the return value !! */
mv a0, t0
sw a1, RV_SLP_CTX_A1(t0)
sw a2, RV_SLP_CTX_A2(t0)
sw a3, RV_SLP_CTX_A3(t0)
sw a4, RV_SLP_CTX_A4(t0)
sw a5, RV_SLP_CTX_A5(t0)
sw a6, RV_SLP_CTX_A6(t0)
sw a7, RV_SLP_CTX_A7(t0)
sw s2, RV_SLP_CTX_S2(t0)
sw s3, RV_SLP_CTX_S3(t0)
sw s4, RV_SLP_CTX_S4(t0)
sw s5, RV_SLP_CTX_S5(t0)
sw s6, RV_SLP_CTX_S6(t0)
sw s7, RV_SLP_CTX_S7(t0)
sw s8, RV_SLP_CTX_S8(t0)
sw s9, RV_SLP_CTX_S9(t0)
sw s10, RV_SLP_CTX_S10(t0)
sw s11, RV_SLP_CTX_S11(t0)
sw t3, RV_SLP_CTX_T3(t0)
sw t4, RV_SLP_CTX_T4(t0)
sw t5, RV_SLP_CTX_T5(t0)
sw t6, RV_SLP_CTX_T6(t0)
csrr t1, mstatus
sw t1, RV_SLP_CTX_MSTATUS(t0)
csrr t2, mtvec
sw t2, RV_SLP_CTX_MTVEC(t0)
csrr t3, mcause
sw t3, RV_SLP_CTX_MCAUSE(t0)
csrr t1, mtval
sw t1, RV_SLP_CTX_MTVAL(t0)
csrr t2, mie
sw t2, RV_SLP_CTX_MIE(t0)
csrr t3, mip
sw t3, RV_SLP_CTX_MIP(t0)
csrr t1, mepc
sw t1, RV_SLP_CTX_MEPC(t0)
/*
!!! Let idf knows it's going to sleep !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
li t1, ~0x3
lw t2, RV_SLP_CTX_PMUFUNC(t0)
and t2, t1, t2
ori t2, t2, 0x1
sw t2, RV_SLP_CTX_PMUFUNC(t0)
mv t3, t0
csrr t0, mscratch
sw t0, RV_SLP_CTX_T0(t3)
#if !CONFIG_IDF_TARGET_ESP32C6
/* writeback dcache is required here!!! */
la t0, EXTMEM_CACHE_SYNC_MAP_REG
li t1, 0x10
sw t1, 0x0(t0) /* set EXTMEM_CACHE_SYNC_MAP_REG bit 4 */
la t2, EXTMEM_CACHE_SYNC_ADDR_REG
sw zero, 0x0(t2) /* clear EXTMEM_CACHE_SYNC_ADDR_REG */
la t0, EXTMEM_CACHE_SYNC_SIZE_REG
sw zero, 0x0(t0) /* clear EXTMEM_CACHE_SYNC_SIZE_REG */
la t1, EXTMEM_CACHE_SYNC_CTRL_REG
lw t2, 0x0(t1)
ori t2, t2, 0x4
sw t2, 0x0(t1)
li t0, 0x10 /* SYNC_DONE bit */
wait_sync_done:
lw t2, 0x0(t1)
and t2, t0, t2
beqz t2, wait_sync_done
#endif
lw t0, RV_SLP_CTX_T0(t3)
lw t1, RV_SLP_CTX_T1(t3)
lw t2, RV_SLP_CTX_T2(t3)
lw t3, RV_SLP_CTX_T3(t3)
ret
.size rv_core_critical_regs_save, . - rv_core_critical_regs_save
#define CSR_PCER_U 0x800
#define CSR_PCMR_U 0x801
#define PCER_CYCLES (1<<0) /* count clock cycles */
#define PCMR_GLOBAL_EN (1<<0) /* enable count */
#define pcer CSR_PCER_U
#define pcmr CSR_PCMR_U
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to restore the CPU core critical register
context before sleep after system wakes up, modify the PMU control
information, and return the critical register context memory object pointer.
After the subroutine returns, continue to restore other modules of the
system.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_restore
.type rv_core_critical_regs_restore,@function
.align 4
rv_core_critical_regs_restore:
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
beqz t0, .skip_restore /* make sure we do not jump to zero address */
/*
!!! Let idf knows it's sleep awake. !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
lw t1, RV_SLP_CTX_PMUFUNC(t0)
ori t1, t1, 0x3
sw t1, RV_SLP_CTX_PMUFUNC(t0)
lw t2, RV_SLP_CTX_MEPC(t0)
csrw mepc, t2
lw t3, RV_SLP_CTX_MIP(t0)
csrw mip, t3
lw t1, RV_SLP_CTX_MIE(t0)
csrw mie, t1
lw t2, RV_SLP_CTX_MSTATUS(t0)
csrw mstatus, t2
lw t3, RV_SLP_CTX_MTVEC(t0)
csrw mtvec, t3
lw t1, RV_SLP_CTX_MCAUSE(t0)
csrw mcause, t1
lw t2, RV_SLP_CTX_MTVAL(t0)
csrw mtval, t2
lw t6, RV_SLP_CTX_T6(t0)
lw t5, RV_SLP_CTX_T5(t0)
lw t4, RV_SLP_CTX_T4(t0)
lw t3, RV_SLP_CTX_T3(t0)
lw s11, RV_SLP_CTX_S11(t0)
lw s10, RV_SLP_CTX_S10(t0)
lw s9, RV_SLP_CTX_S9(t0)
lw s8, RV_SLP_CTX_S8(t0)
lw s7, RV_SLP_CTX_S7(t0)
lw s6, RV_SLP_CTX_S6(t0)
lw s5, RV_SLP_CTX_S5(t0)
lw s4, RV_SLP_CTX_S4(t0)
lw s3, RV_SLP_CTX_S3(t0)
lw s2, RV_SLP_CTX_S2(t0)
lw a7, RV_SLP_CTX_A7(t0)
lw a6, RV_SLP_CTX_A6(t0)
lw a5, RV_SLP_CTX_A5(t0)
lw a4, RV_SLP_CTX_A4(t0)
lw a3, RV_SLP_CTX_A3(t0)
lw a2, RV_SLP_CTX_A2(t0)
lw a1, RV_SLP_CTX_A1(t0)
lw a0, RV_SLP_CTX_A0(t0)
lw s1, RV_SLP_CTX_S1(t0)
lw s0, RV_SLP_CTX_S0(t0)
lw t2, RV_SLP_CTX_T2(t0)
lw t1, RV_SLP_CTX_T1(t0)
lw tp, RV_SLP_CTX_TP(t0)
lw gp, RV_SLP_CTX_GP(t0)
lw sp, RV_SLP_CTX_SP(t0)
lw ra, RV_SLP_CTX_RA(t0)
lw t0, RV_SLP_CTX_T0(t0)
.skip_restore:
ret
.size rv_core_critical_regs_restore, . - rv_core_critical_regs_restore

View File

@ -20,10 +20,15 @@
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "hal/rtc_io_hal.h"
#if !SOC_PMU_SUPPORTED
#include "hal/rtc_hal.h"
#endif
#include "esp_private/gpio.h"
#include "esp_private/sleep_gpio.h"
#include "esp_private/spi_flash_os.h"
#include "esp_private/startup_internal.h"
#include "bootloader_flash.h"
static const char *TAG = "sleep";
@ -180,3 +185,15 @@ void esp_deep_sleep_wakeup_io_reset(void)
}
#endif
}
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
{
// Configure to isolate (disable the Input/Output/Pullup/Pulldown
// function of the pin) all GPIO pins in sleep state
esp_sleep_config_gpio_isolate();
// Enable automatic switching of GPIO configuration
esp_sleep_enable_gpio_switch(true);
return ESP_OK;
}
#endif

View File

@ -24,7 +24,11 @@
#include "soc/soc_caps.h"
#include "driver/rtc_io.h"
#include "hal/rtc_io_hal.h"
#if !SOC_PMU_SUPPORTED
#include "hal/rtc_cntl_ll.h"
#include "hal/rtc_hal.h"
#endif
#include "driver/uart.h"
@ -33,7 +37,6 @@
#include "regi2c_ctrl.h" //For `REGI2C_ANA_CALI_PD_WORKAROUND`, temp
#include "hal/wdt_hal.h"
#include "hal/rtc_hal.h"
#include "hal/uart_hal.h"
#if SOC_TOUCH_SENSOR_SUPPORTED
#include "hal/touch_sensor_hal.h"
@ -46,9 +49,8 @@
#include "esp_rom_uart.h"
#include "esp_rom_sys.h"
#include "esp_private/brownout.h"
#include "esp_private/sleep_retention.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/esp_clk.h"
#include "esp_private/startup_internal.h"
#include "esp_private/esp_task_wdt.h"
#ifdef CONFIG_IDF_TARGET_ESP32
@ -72,6 +74,8 @@
#include "esp32c2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/rtc.h"
#include "hal/lp_timer_hal.h"
#include "esp_private/esp_pmu.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/cache.h"
@ -87,6 +91,7 @@
// Cycles for RTC Timer clock source (internal oscillator) calibrate
#define RTC_CLK_SRC_CAL_CYCLES (10)
#define FAST_CLK_SRC_CAL_CYCLES (2000) /* ~ 127.4 us */
#ifdef CONFIG_IDF_TARGET_ESP32
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (212)
@ -107,8 +112,8 @@
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
#elif CONFIG_IDF_TARGET_ESP32C6
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)// TODO: IDF-5348
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56)
#elif CONFIG_IDF_TARGET_ESP32H2
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)// TODO: IDF-6267
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
@ -141,7 +146,12 @@ extern void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time
* Internal structure which holds all requested deep sleep parameters
*/
typedef struct {
esp_sleep_pd_option_t pd_options[ESP_PD_DOMAIN_MAX];
struct {
esp_sleep_pd_option_t pd_option;
int16_t refs;
uint16_t reserved; /* reserved for 4 bytes aligned */
} domain[ESP_PD_DOMAIN_MAX];
portMUX_TYPE lock;
uint64_t sleep_duration;
uint32_t wakeup_triggers : 15;
uint32_t ext1_trigger_mode : 1;
@ -154,6 +164,7 @@ typedef struct {
uint32_t ccount_ticks_record;
uint32_t sleep_time_overhead_out;
uint32_t rtc_clk_cal_period;
uint32_t fast_clk_cal_period;
uint64_t rtc_ticks_at_sleep_start;
} sleep_config_t;
@ -161,7 +172,13 @@ typedef struct {
_Static_assert(22 >= SOC_RTCIO_PIN_COUNT, "Chip has more RTCIOs than 22, should increase ext1_rtc_gpio_mask field size");
static sleep_config_t s_config = {
.pd_options = {[0 ... ESP_PD_DOMAIN_MAX - 1] = ESP_PD_OPTION_AUTO,},
.domain = {
[0 ... ESP_PD_DOMAIN_MAX - 1] = {
.pd_option = ESP_PD_OPTION_AUTO,
.refs = 0
}
},
.lock = portMUX_INITIALIZER_UNLOCKED,
.ccount_ticks_record = 0,
.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US,
.wakeup_triggers = 0
@ -169,9 +186,7 @@ static sleep_config_t s_config = {
/* Internal variable used to track if light sleep wakeup sources are to be
expected when determining wakeup cause. */
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static bool s_light_sleep_wakeup = false;
#endif
/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
is not thread-safe, so we need to disable interrupts before going to deep sleep. */
@ -194,13 +209,11 @@ static uint32_t get_power_down_flags(void);
static void ext0_wakeup_prepare(void);
static void ext1_wakeup_prepare(void);
#endif
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static void timer_wakeup_prepare(void);
#endif
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
static void touch_wakeup_prepare(void);
#endif
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
static void gpio_deep_sleep_wakeup_prepare(void);
#endif
@ -292,7 +305,6 @@ void esp_deep_sleep(uint64_t time_in_us)
}
// [refactor-todo] provide target logic for body of uart functions below
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static void IRAM_ATTR flush_uarts(void)
{
for (int i = 0; i < SOC_UART_NUM; ++i) {
@ -337,7 +349,6 @@ static void IRAM_ATTR resume_uarts(void)
uart_ll_force_xon(i);
}
}
#endif
/**
* These save-restore workaround should be moved to lower layer
@ -350,8 +361,8 @@ inline static void IRAM_ATTR misc_modules_sleep_prepare(void)
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_apply();
#endif
#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD
sleep_enable_memory_retention();
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
sleep_enable_cpu_retention();
#endif
#if REGI2C_ANA_CALI_PD_WORKAROUND
regi2c_analog_cali_reg_read();
@ -363,8 +374,8 @@ inline static void IRAM_ATTR misc_modules_sleep_prepare(void)
*/
inline static void IRAM_ATTR misc_modules_wake_prepare(void)
{
#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD
sleep_disable_memory_retention();
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
sleep_disable_cpu_retention();
#endif
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_unapply();
@ -377,7 +388,7 @@ inline static void IRAM_ATTR misc_modules_wake_prepare(void)
#endif
}
inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu);
inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp);
inline static bool is_light_sleep(uint32_t pd_flags)
{
@ -386,9 +397,6 @@ inline static bool is_light_sleep(uint32_t pd_flags)
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
{
#if CONFIG_IDF_TARGET_ESP32C6
return 0; // TODO: WIFI-5150
#else
// Stop UART output so that output is not lost due to APB frequency change.
// For light sleep, suspend UART output — it will resume after wakeup.
// For deep sleep, wait for the contents of UART FIFO to be sent.
@ -492,6 +500,12 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
}
// Enter sleep
#if SOC_PMU_SUPPORTED
pmu_sleep_config_t config;
pmu_sleep_init(pmu_sleep_config_default(&config, pd_flags, s_config.sleep_time_adjustment,
s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period,
deep_sleep), deep_sleep);
#else
rtc_sleep_config_t config;
rtc_sleep_get_default_config(sleep_flags, &config);
rtc_sleep_init(config);
@ -500,6 +514,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
if (!deep_sleep) {
rtc_sleep_low_init(s_config.rtc_clk_cal_period);
}
#endif
// Configure timer wakeup
if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) {
@ -513,6 +528,8 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
esp_sleep_isolate_digital_gpio();
#endif
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5349
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
extern char _rtc_text_start[];
#if CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM
@ -523,7 +540,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
size_t rtc_fast_length = (size_t)_rtc_force_fast_end - (size_t)_rtc_text_start;
#endif
esp_rom_set_rtc_wake_addr((esp_rom_wake_func_t)esp_wake_stub_entry, rtc_fast_length);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
#else
#if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
@ -531,14 +548,26 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
// RTC has no rtc memory, IDF-3901
set_rtc_memory_crc();
#endif
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
#else
result = ESP_OK;
#endif
} else {
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu);
#if SOC_PM_CPU_RETENTION_BY_SW
if (pd_flags & PMU_SLEEP_PD_CPU) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
} else {
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
#endif
}
// Restore CPU frequency
@ -553,13 +582,14 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
resume_uarts();
return result;
#endif
}
inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu)
inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp)
{
#ifdef CONFIG_IDF_TARGET_ESP32
return rtc_sleep_start(s_config.wakeup_triggers, reject_triggers);
#elif SOC_PMU_SUPPORTED
return pmu_sleep_start(s_config.wakeup_triggers, reject_triggers, lslp_mem_inf_fpu, dslp);
#else
return rtc_sleep_start(s_config.wakeup_triggers, reject_triggers, lslp_mem_inf_fpu);
#endif
@ -624,26 +654,23 @@ void IRAM_ATTR esp_deep_sleep_start(void)
* Helper function which handles entry to and exit from light sleep
* Placed into IRAM as flash may need some time to be powered on.
*/
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
uint32_t flash_enable_time_us,
rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline));
uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline));
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
uint32_t flash_enable_time_us,
rtc_vddsdio_config_t vddsdio_config)
uint32_t flash_enable_time_us)
{
#if CONFIG_IDF_TARGET_ESP32C6
return ESP_ERR_NOT_SUPPORTED; // TODO: WIFI-5150
#else
// Enter sleep
uint32_t reject = esp_sleep_start(pd_flags);
#if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
// If VDDSDIO regulator was controlled by RTC registers before sleep,
// restore the configuration.
if (vddsdio_config.force) {
rtc_vddsdio_set_config(vddsdio_config);
}
#endif
// If SPI flash was powered down, wait for it to become ready
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
@ -652,9 +679,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
}
return reject ? ESP_ERR_SLEEP_REJECT : ESP_OK;
#endif
}
#endif
/**
* vddsdio is used for power supply of spi flash
@ -665,18 +690,16 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
* x | 1 | pd flash with relaxed conditions(force_pd)
* 1 | 0 | pd flash with strict conditions(safe_pd)
*/
static inline bool can_power_down_vddsdio(const uint32_t vddsdio_pd_sleep_duration)
static inline bool can_power_down_vddsdio(uint32_t pd_flags, const uint32_t vddsdio_pd_sleep_duration)
{
bool force_pd = !(s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) || (s_config.sleep_duration > vddsdio_pd_sleep_duration);
bool safe_pd = (s_config.wakeup_triggers == RTC_TIMER_TRIG_EN) && (s_config.sleep_duration > vddsdio_pd_sleep_duration);
return (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] == ESP_PD_OPTION_OFF) ? force_pd : safe_pd;
return (pd_flags & RTC_SLEEP_PD_VDDSDIO) ? force_pd : safe_pd;
}
esp_err_t esp_light_sleep_start(void)
{
#if CONFIG_IDF_TARGET_ESP32C6
return ESP_ERR_NOT_SUPPORTED; // TODO: WIFI-5150
#else
s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
esp_err_t timerret = ESP_OK;
@ -684,9 +707,7 @@ esp_err_t esp_light_sleep_start(void)
timerret = esp_task_wdt_stop();
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&light_sleep_lock);
portENTER_CRITICAL(&s_config.lock);
/*
Note: We are about to stall the other CPU via the esp_ipc_isr_stall_other_cpu(). However, there is a chance of
deadlock if after stalling the other CPU, we attempt to take spinlocks already held by the other CPU that is.
@ -710,7 +731,11 @@ esp_err_t esp_light_sleep_start(void)
*/
esp_clk_private_lock();
#if SOC_LP_TIMER_SUPPORTED
s_config.rtc_ticks_at_sleep_start = lp_timer_hal_get_cycle_count(0);
#else
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
#endif
uint32_t ccount_at_sleep_start = esp_cpu_get_cycle_count();
uint64_t high_res_time_at_start = esp_timer_get_time();
uint32_t sleep_time_overhead_in = (ccount_at_sleep_start - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
@ -751,9 +776,16 @@ esp_err_t esp_light_sleep_start(void)
* 4. Code execution time which can be measured;
*/
#if SOC_PMU_SUPPORTED
s_config.fast_clk_cal_period = rtc_clk_cal(RTC_CAL_RC_FAST, FAST_CLK_SRC_CAL_CYCLES);
int sleep_time_sw_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US + sleep_time_overhead_in + s_config.sleep_time_overhead_out;
int sleep_time_hw_adjustment = pmu_sleep_calculate_hw_wait_time(pd_flags, s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period);
s_config.sleep_time_adjustment = sleep_time_sw_adjustment + sleep_time_hw_adjustment;
#else
uint32_t rtc_cntl_xtl_buf_wait_slp_cycles = rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, s_config.rtc_clk_cal_period);
s_config.sleep_time_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US + sleep_time_overhead_in + s_config.sleep_time_overhead_out
+ rtc_time_slowclk_to_us(rtc_cntl_xtl_buf_wait_slp_cycles + RTC_CNTL_CK8M_WAIT_SLP_CYCLES + RTC_CNTL_WAKEUP_DELAY_CYCLES, s_config.rtc_clk_cal_period);
#endif
// Decide if VDD_SDIO needs to be powered down;
// If it needs to be powered down, adjust sleep time.
@ -781,7 +813,7 @@ esp_err_t esp_light_sleep_start(void)
flash_enable_time_us + LIGHT_SLEEP_MIN_TIME_US + s_config.sleep_time_adjustment
+ rtc_time_slowclk_to_us(RTC_MODULE_SLEEP_PREPARE_CYCLES, s_config.rtc_clk_cal_period));
if (can_power_down_vddsdio(vddsdio_pd_sleep_duration)) {
if (can_power_down_vddsdio(pd_flags, vddsdio_pd_sleep_duration)) {
if (s_config.sleep_time_overhead_out < flash_enable_time_us) {
s_config.sleep_time_adjustment += flash_enable_time_us;
}
@ -799,8 +831,6 @@ esp_err_t esp_light_sleep_start(void)
periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in);
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
// Safety net: enable WDT in case exit from light sleep fails
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5653
wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &LP_WDT};
@ -829,14 +859,18 @@ esp_err_t esp_light_sleep_start(void)
err = ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION;
} else {
// Enter sleep, then wait for flash to be ready on wakeup
err = esp_light_sleep_inner(pd_flags, flash_enable_time_us, vddsdio_config);
err = esp_light_sleep_inner(pd_flags, flash_enable_time_us);
}
// light sleep wakeup flag only makes sense after a successful light sleep
s_light_sleep_wakeup = (err == ESP_OK);
// System timer has been stopped for the duration of the sleep, correct for that.
#if SOC_LP_TIMER_SUPPORTED
uint64_t rtc_ticks_at_end = lp_timer_hal_get_cycle_count(0);
#else
uint64_t rtc_ticks_at_end = rtc_time_get();
#endif
uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start, s_config.rtc_clk_cal_period);
/**
@ -856,8 +890,7 @@ esp_err_t esp_light_sleep_start(void)
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
portEXIT_CRITICAL(&light_sleep_lock);
s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
portEXIT_CRITICAL(&s_config.lock);
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
/* Restart the Task Watchdog timer as it was stopped before sleeping. */
@ -866,8 +899,8 @@ esp_err_t esp_light_sleep_start(void)
}
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
return err;
#endif
}
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)
@ -945,7 +978,6 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
return ESP_OK;
}
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static void timer_wakeup_prepare(void)
{
int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
@ -954,9 +986,13 @@ static void timer_wakeup_prepare(void)
}
int64_t ticks = rtc_time_us_to_slowclk(sleep_duration, s_config.rtc_clk_cal_period);
#if SOC_LP_TIMER_SUPPORTED
lp_timer_hal_set_alarm_target(0, s_config.rtc_ticks_at_sleep_start + ticks);
#else
rtc_hal_set_wakeup_timer(s_config.rtc_ticks_at_sleep_start + ticks);
}
#endif
}
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/* In deep sleep mode, only the sleep channel is supported, and other touch channels should be turned off. */
@ -1092,7 +1128,7 @@ static void ext1_wakeup_prepare(void)
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
// Pad configuration depends on RTC_PERIPH state in sleep mode
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
if (s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option != ESP_PD_OPTION_ON) {
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
// RTC_PERIPH will be powered down, so RTC_IO_ registers will
// loose their state. Lock pad configuration.
@ -1139,16 +1175,20 @@ uint64_t esp_sleep_get_ext1_wakeup_status(void)
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
uint64_t esp_sleep_get_gpio_wakeup_status(void)
{
#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5349
return 0;
#else
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_GPIO) {
return 0;
}
return rtc_hal_gpio_get_wakeup_status();
#endif
}
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: WIFI-5150
static void gpio_deep_sleep_wakeup_prepare(void)
{
#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5349
for (gpio_num_t gpio_idx = GPIO_NUM_0; gpio_idx < GPIO_NUM_MAX; gpio_idx++) {
if (((1ULL << gpio_idx) & s_config.gpio_wakeup_mask) == 0) {
continue;
@ -1164,8 +1204,8 @@ static void gpio_deep_sleep_wakeup_prepare(void)
}
// Clear state from previous wakeup
rtc_hal_gpio_clear_wakeup_status();
}
#endif
}
esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask, esp_deepsleep_gpio_wake_up_mode_t mode)
{
@ -1265,14 +1305,18 @@ esp_err_t esp_sleep_disable_bt_wakeup(void)
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
{
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5645
#if CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5645
return ESP_SLEEP_WAKEUP_UNDEFINED;
#else
if (esp_rom_get_reset_reason(0) != RESET_REASON_CORE_DEEP_SLEEP && !s_light_sleep_wakeup) {
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
#if SOC_PMU_SUPPORTED
uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU);
#else
uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause();
#endif
if (wakeup_cause & RTC_TIMER_TRIG_EN) {
return ESP_SLEEP_WAKEUP_TIMER;
@ -1314,13 +1358,20 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
#endif
}
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
esp_sleep_pd_option_t option)
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_t option)
{
if (domain >= ESP_PD_DOMAIN_MAX || option > ESP_PD_OPTION_AUTO) {
return ESP_ERR_INVALID_ARG;
}
s_config.pd_options[domain] = option;
portENTER_CRITICAL_SAFE(&s_config.lock);
int refs = (option == ESP_PD_OPTION_ON) ? s_config.domain[domain].refs++ \
: (option == ESP_PD_OPTION_OFF) ? --s_config.domain[domain].refs \
: s_config.domain[domain].refs;
if (refs == 0) {
s_config.domain[domain].pd_option = option;
}
portEXIT_CRITICAL_SAFE(&s_config.lock);
assert(refs >= 0);
return ESP_OK;
}
@ -1342,9 +1393,9 @@ static uint32_t get_power_down_flags(void)
*/
volatile size_t rtc_slow_mem_used = (size_t)&_rtc_slow_length;
if ((s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] == ESP_PD_OPTION_AUTO) &&
if ((s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option == ESP_PD_OPTION_AUTO) &&
(rtc_slow_mem_used > 0 || (s_config.wakeup_triggers & RTC_ULP_TRIG_EN))) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] = ESP_PD_OPTION_ON;
s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option = ESP_PD_OPTION_ON;
}
#endif
@ -1353,27 +1404,27 @@ static uint32_t get_power_down_flags(void)
/* RTC_FAST_MEM is needed for deep sleep stub.
If RTC_FAST_MEM is Auto, keep it powered on, so that deep sleep stub can run.
In the new chip revision, deep sleep stub will be optional, and this can be changed. */
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] == ESP_PD_OPTION_AUTO) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] = ESP_PD_OPTION_ON;
if (s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option == ESP_PD_OPTION_AUTO) {
s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option = ESP_PD_OPTION_ON;
}
#else
/* If RTC_FAST_MEM is used for heap, force RTC_FAST_MEM to be powered on. */
s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] = ESP_PD_OPTION_ON;
s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option = ESP_PD_OPTION_ON;
#endif
#endif
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
// RTC_PERIPH is needed for EXT0 wakeup and GPIO wakeup.
// If RTC_PERIPH is left auto (EXT0/GPIO aren't enabled), RTC_PERIPH will be powered off by default.
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] == ESP_PD_OPTION_AUTO) {
if (s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option == ESP_PD_OPTION_AUTO) {
if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN | RTC_GPIO_TRIG_EN)) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_ON;
s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option = ESP_PD_OPTION_ON;
}
#if CONFIG_IDF_TARGET_ESP32
else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) {
// On ESP32, forcing power up of RTC_PERIPH
// prevents ULP timer and touch FSMs from working correctly.
s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_OFF;
s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option = ESP_PD_OPTION_OFF;
}
#endif //CONFIG_IDF_TARGET_ESP32
}
@ -1381,56 +1432,9 @@ static uint32_t get_power_down_flags(void)
#if SOC_PM_SUPPORT_CPU_PD
if (!cpu_domain_pd_allowed()) {
s_config.pd_options[ESP_PD_DOMAIN_CPU] = ESP_PD_OPTION_ON;
s_config.domain[ESP_PD_DOMAIN_CPU].pd_option = ESP_PD_OPTION_ON;
}
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF;
#endif
const __attribute__((unused)) char *option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */};
/* This function is called from a critical section, log with ESP_EARLY_LOGD. */
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
ESP_EARLY_LOGD(TAG, "RTC_PERIPH: %s", option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH]]);
#endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
ESP_EARLY_LOGD(TAG, "RTC_SLOW_MEM: %s", option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM]]);
#endif
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
ESP_EARLY_LOGD(TAG, "RTC_FAST_MEM: %s", option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM]]);
#endif
// Prepare flags based on the selected options
uint32_t pd_flags = 0;
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM;
}
#endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_SLOW_MEM;
}
#endif
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
}
#endif
#if SOC_PM_SUPPORT_CPU_PD
if (s_config.pd_options[ESP_PD_DOMAIN_CPU] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_CPU;
}
#endif
if (s_config.pd_options[ESP_PD_DOMAIN_RC_FAST] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_INT_8M;
}
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_XTAL;
}
/**
* VDD_SDIO power domain shall be kept on during the light sleep
* when CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set and off when it is set.
@ -1440,15 +1444,80 @@ static uint32_t get_power_down_flags(void)
* In deep sleep mode, the power domain will be turned off, regardless the
* value of this field.
*/
if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] == ESP_PD_OPTION_AUTO) {
#if SOC_PM_SUPPORT_VDDSDIO_PD
if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option == ESP_PD_OPTION_AUTO) {
#ifndef CONFIG_ESP_SLEEP_POWER_DOWN_FLASH
s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] = ESP_PD_OPTION_ON;
s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option = ESP_PD_OPTION_ON;
#endif
}
#endif
if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] != ESP_PD_OPTION_ON) {
#if SOC_PM_SUPPORT_XTAL_PD
#ifdef CONFIG_IDF_TARGET_ESP32
s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option = ESP_PD_OPTION_OFF;
#endif
#endif
const __attribute__((unused)) char *option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */};
/* This function is called from a critical section, log with ESP_EARLY_LOGD. */
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
ESP_EARLY_LOGD(TAG, "RTC_PERIPH: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option]);
#endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
ESP_EARLY_LOGD(TAG, "RTC_SLOW_MEM: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option]);
#endif
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
ESP_EARLY_LOGD(TAG, "RTC_FAST_MEM: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option]);
#endif
// Prepare flags based on the selected options
uint32_t pd_flags = 0;
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
if (s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM;
}
#endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
if (s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_SLOW_MEM;
}
#endif
#if SOC_PM_SUPPORT_RTC_PERIPH_PD
if (s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
}
#endif
#if SOC_PM_SUPPORT_CPU_PD
if (s_config.domain[ESP_PD_DOMAIN_CPU].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_CPU;
}
#endif
#if SOC_PM_SUPPORT_XTAL32K_PD
if (s_config.domain[ESP_PD_DOMAIN_XTAL32K].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= PMU_SLEEP_PD_XTAL32K;
}
#endif
#if SOC_PM_SUPPORT_RC32K_PD
if (s_config.domain[ESP_PD_DOMAIN_RC32K].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= PMU_SLEEP_PD_RC32K;
}
#endif
#if SOC_PM_SUPPORT_RC_FAST_PD
if (s_config.domain[ESP_PD_DOMAIN_RC_FAST].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_INT_8M;
}
#endif
#if SOC_PM_SUPPORT_XTAL_PD
if (s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_XTAL;
}
#endif
#if SOC_PM_SUPPORT_VDDSDIO_PD
if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
}
#endif
#if ((defined CONFIG_RTC_CLK_SRC_EXT_CRYS) && (defined CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT) && (SOC_PM_SUPPORT_RTC_PERIPH_PD))
if ((s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) == 0) {
@ -1474,15 +1543,3 @@ void rtc_sleep_enable_ultra_low(bool enable)
{
s_ultra_low_enabled = enable;
}
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
{
// Configure to isolate (disable the Input/Output/Pullup/Pulldown
// function of the pin) all GPIO pins in sleep state
esp_sleep_config_gpio_isolate();
// Enable automatic switching of GPIO configuration
esp_sleep_enable_gpio_switch(true);
return ESP_OK;
}
#endif

View File

@ -1,219 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "soc/soc_caps.h"
#include "hal/rtc_hal.h"
#include "esp_private/sleep_retention.h"
#include "sdkconfig.h"
#ifdef CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep";
/**
* Internal structure which holds all requested light sleep memory retention parameters
*/
typedef struct {
rtc_cntl_sleep_retent_t retent;
} sleep_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_retention_t s_retention;
#if SOC_PM_SUPPORT_TAGMEM_PD
#if CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
static int cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t code_seg_size, uint32_t data_seg_vaddr, uint32_t data_seg_size)
{
int sets; /* i/d-cache total set counts */
int index; /* virtual address mapping i/d-cache row offset */
int waysgrp;
int icache_tagmem_blk_gs, dcache_tagmem_blk_gs;
struct cache_mode imode = { .icache = 1 };
struct cache_mode dmode = { .icache = 0 };
/* calculate/prepare i-cache tag memory retention parameters */
Cache_Get_Mode(&imode);
sets = imode.cache_size / imode.cache_ways / imode.cache_line_size;
index = (code_seg_vaddr / imode.cache_line_size) % sets;
waysgrp = imode.cache_ways >> 2;
code_seg_size = ALIGNUP(imode.cache_line_size, code_seg_size);
s_retention.retent.tagmem.icache.start_point = index;
s_retention.retent.tagmem.icache.size = (sets * waysgrp) & 0xff;
s_retention.retent.tagmem.icache.vld_size = s_retention.retent.tagmem.icache.size;
if (code_seg_size < imode.cache_size / imode.cache_ways) {
s_retention.retent.tagmem.icache.vld_size = (code_seg_size / imode.cache_line_size) * waysgrp;
}
s_retention.retent.tagmem.icache.enable = (code_seg_size != 0) ? 1 : 0;
icache_tagmem_blk_gs = s_retention.retent.tagmem.icache.vld_size ? s_retention.retent.tagmem.icache.vld_size : sets * waysgrp;
icache_tagmem_blk_gs = ALIGNUP(4, icache_tagmem_blk_gs);
ESP_LOGD(TAG, "I-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (imode.cache_size>>10),
imode.cache_line_size, imode.cache_ways, sets, index, icache_tagmem_blk_gs);
/* calculate/prepare d-cache tag memory retention parameters */
Cache_Get_Mode(&dmode);
sets = dmode.cache_size / dmode.cache_ways / dmode.cache_line_size;
index = (data_seg_vaddr / dmode.cache_line_size) % sets;
waysgrp = dmode.cache_ways >> 2;
data_seg_size = ALIGNUP(dmode.cache_line_size, data_seg_size);
s_retention.retent.tagmem.dcache.start_point = index;
s_retention.retent.tagmem.dcache.size = (sets * waysgrp) & 0x1ff;
s_retention.retent.tagmem.dcache.vld_size = s_retention.retent.tagmem.dcache.size;
#ifndef CONFIG_ESP32S3_DATA_CACHE_16KB
if (data_seg_size < dmode.cache_size / dmode.cache_ways) {
s_retention.retent.tagmem.dcache.vld_size = (data_seg_size / dmode.cache_line_size) * waysgrp;
}
s_retention.retent.tagmem.dcache.enable = (data_seg_size != 0) ? 1 : 0;
#else
s_retention.retent.tagmem.dcache.enable = 1;
#endif
dcache_tagmem_blk_gs = s_retention.retent.tagmem.dcache.vld_size ? s_retention.retent.tagmem.dcache.vld_size : sets * waysgrp;
dcache_tagmem_blk_gs = ALIGNUP(4, dcache_tagmem_blk_gs);
ESP_LOGD(TAG, "D-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (dmode.cache_size>>10),
dmode.cache_line_size, dmode.cache_ways, sets, index, dcache_tagmem_blk_gs);
/* For I or D cache tagmem retention, backup and restore are performed through
* RTC DMA (its bus width is 128 bits), For I/D Cache tagmem blocks (i-cache
* tagmem blocks = 92 bits, d-cache tagmem blocks = 88 bits), RTC DMA automatically
* aligns its bit width to 96 bits, therefore, 3 times RTC DMA can transfer 4
* i/d-cache tagmem blocks (128 bits * 3 = 96 bits * 4) */
return (((icache_tagmem_blk_gs + dcache_tagmem_blk_gs) << 2) * 3);
}
#endif // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
static esp_err_t esp_sleep_tagmem_pd_low_init(bool enable)
{
if (enable) {
#if CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
if (s_retention.retent.tagmem.link_addr == NULL) {
extern char _stext[], _etext[];
uint32_t code_start = (uint32_t)_stext;
uint32_t code_size = (uint32_t)(_etext - _stext);
#if !(CONFIG_SPIRAM && CONFIG_IDF_TARGET_ESP32S3)
extern char _rodata_start[], _rodata_reserved_end[];
uint32_t data_start = (uint32_t)_rodata_start;
uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else
uint32_t data_start = SOC_DROM_LOW;
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
#endif
ESP_LOGI(TAG, "Code start at %08x, total %.2f KiB, data start at %08x, total %.2f KiB",
code_start, (float)code_size/1024, data_start, (float)data_size/1024);
int tagmem_sz = cache_tagmem_retention_setup(code_start, code_size, data_start, data_size);
void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_TAGMEM_PD_DMA_ADDR_ALIGN,
tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
memset(buf, 0, tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE);
s_retention.retent.tagmem.link_addr = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, tagmem_sz, NULL);
} else {
s_retention.retent.tagmem.icache.enable = 0;
s_retention.retent.tagmem.dcache.enable = 0;
s_retention.retent.tagmem.link_addr = NULL;
return ESP_ERR_NO_MEM;
}
}
#else // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
s_retention.retent.tagmem.icache.enable = 0;
s_retention.retent.tagmem.dcache.enable = 0;
s_retention.retent.tagmem.link_addr = NULL;
#endif // CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
} else {
#if SOC_PM_SUPPORT_TAGMEM_PD
if (s_retention.retent.tagmem.link_addr) {
heap_caps_free(s_retention.retent.tagmem.link_addr);
s_retention.retent.tagmem.icache.enable = 0;
s_retention.retent.tagmem.dcache.enable = 0;
s_retention.retent.tagmem.link_addr = NULL;
}
#endif
}
return ESP_OK;
}
#endif // SOC_PM_SUPPORT_TAGMEM_PD
#if SOC_PM_SUPPORT_CPU_PD
esp_err_t esp_sleep_cpu_pd_low_init(bool enable)
{
if (enable) {
if (s_retention.retent.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN,
SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
memset(buf, 0, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE);
s_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
} else {
if (s_retention.retent.cpu_pd_mem) {
heap_caps_free(s_retention.retent.cpu_pd_mem);
s_retention.retent.cpu_pd_mem = NULL;
}
}
#if SOC_PM_SUPPORT_TAGMEM_PD
if (esp_sleep_tagmem_pd_low_init(enable) != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_init(false);
return ESP_ERR_NO_MEM;
#endif
}
#endif
return ESP_OK;
}
bool cpu_domain_pd_allowed(void)
{
return (s_retention.retent.cpu_pd_mem != NULL);
}
#endif // SOC_PM_SUPPORT_CPU_PD
#if SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD
void sleep_enable_memory_retention(void)
{
#if SOC_PM_SUPPORT_CPU_PD
rtc_cntl_hal_enable_cpu_retention(&s_retention.retent);
#endif
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_enable_tagmem_retention(&s_retention.retent);
#endif
}
void IRAM_ATTR sleep_disable_memory_retention(void)
{
#if SOC_PM_SUPPORT_CPU_PD
rtc_cntl_hal_disable_cpu_retention(&s_retention.retent);
#endif
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_disable_tagmem_retention(&s_retention.retent);
#endif
}
#endif // SOC_PM_SUPPORT_CPU_PD || SOC_PM_SUPPORT_TAGMEM_PD

View File

@ -15,9 +15,19 @@
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/soc_caps.h"
#include "hal/rtc_cntl_ll.h"
#include "hal/uart_ll.h"
#if SOC_LP_TIMER_SUPPORTED
#include "hal/lp_timer_ll.h"
#include "hal/lp_timer_hal.h"
#else
#include "hal/rtc_cntl_ll.h"
#endif
#if SOC_PMU_SUPPORTED
#include "hal/pmu_ll.h"
#endif
#include "sdkconfig.h"
#include "esp_rom_uart.h"
#include "esp_rom_sys.h"
@ -57,7 +67,12 @@ void RTC_IRAM_ATTR esp_wake_stub_sleep(esp_deep_sleep_wake_stub_fn_t new_stub)
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_MEM
// Go to sleep.
#if SOC_PMU_SUPPORTED
pmu_ll_hp_set_sleep_enable(&PMU);
#else
rtc_cntl_ll_sleep_enable();
#endif
// A few CPU cycles may be necessary for the sleep to start...
while (true) {};
// never reaches here.
@ -70,12 +85,23 @@ void RTC_IRAM_ATTR esp_wake_stub_uart_tx_wait_idle(uint8_t uart_no)
void RTC_IRAM_ATTR esp_wake_stub_set_wakeup_time(uint64_t time_in_us)
{
#if SOC_LP_TIMER_SUPPORTED
uint64_t rtc_count_delta = lp_timer_ll_time_to_count(time_in_us);
uint64_t rtc_curr_count = lp_timer_hal_get_cycle_count(0);
lp_timer_hal_set_alarm_target(0, rtc_curr_count + rtc_count_delta);
#else
uint64_t rtc_count_delta = rtc_cntl_ll_time_to_count(time_in_us);
uint64_t rtc_curr_count = rtc_cntl_ll_get_rtc_time();
rtc_cntl_ll_set_wakeup_timer(rtc_curr_count + rtc_count_delta);
#endif
}
uint32_t RTC_IRAM_ATTR esp_wake_stub_get_wakeup_cause(void)
{
#if SOC_PMU_SUPPORTED
return pmu_ll_hp_get_wakeup_cause(&PMU);
#else
return rtc_cntl_ll_get_wakeup_cause();
#endif
}

View File

@ -2,10 +2,10 @@ menu "Power Management"
config PM_ENABLE
bool "Support for power management"
# SMP FreeRTOS currently does not support power management IDF-4997
# ESP32C6 currently does not support power management IDF-5347 IDF-6270
# Note. Disabling this option for C6 will also cause all sdkconfig.release test cases run without pm enabled
# ORed with __DOXYGEN__ to pass C6 docs build, need to remove when pm is supported on C6
depends on (!FREERTOS_SMP && !IDF_TARGET_ESP32C6 && !IDF_TARGET_ESP32H2) || __DOXYGEN__
# ESP32H2 currently does not support power management IDF-6270
# Note. Disabling this option for H2 will also cause all sdkconfig.release test cases run without pm enabled
# ORed with __DOXYGEN__ to pass H2 docs build, need to remove when pm is supported on H2
depends on (!FREERTOS_SMP && !IDF_TARGET_ESP32H2) || __DOXYGEN__
default n
help
If enabled, application is compiled with support for power management.
@ -87,7 +87,7 @@ menu "Power Management"
config PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
bool "Power down CPU in light sleep"
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6
select PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP if ESP32S3_DATA_CACHE_16KB
default y
help

View File

@ -15,16 +15,17 @@ entries:
sleep_modes:esp_sleep_enable_timer_wakeup (noflash)
sleep_modes:timer_wakeup_prepare (noflash)
sleep_modes:get_power_down_flags (noflash)
rtc_init:rtc_vddsdio_get_config (noflash)
if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED:
rtc_init:rtc_vddsdio_get_config (noflash)
esp_clk:esp_clk_slowclk_cal_set (noflash)
esp_clk:esp_clk_slowclk_cal_get (noflash)
esp_clk:esp_rtc_get_time_us (noflash)
if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y:
sleep_gpio:gpio_sleep_mode_config_apply (noflash)
if SOC_PM_SUPPORT_CPU_PD = y || SOC_PM_SUPPORT_TAGMEM_PD = y:
sleep_retention:sleep_enable_memory_retention (noflash)
if SOC_PM_CPU_RETENTION_BY_RTCCNTL = y && (SOC_PM_SUPPORT_CPU_PD = y || SOC_PM_SUPPORT_TAGMEM_PD = y):
sleep_cpu:sleep_enable_cpu_retention (noflash)
if SOC_PM_SUPPORT_CPU_PD = y:
sleep_retention:cpu_domain_pd_allowed (noflash)
sleep_cpu:cpu_domain_pd_allowed (noflash)
[mapping:esp_system_pm]
archive: libesp_system.a
@ -86,7 +87,8 @@ entries:
gpio_hal_workaround:gpio_hal_sleep_pupd_config_unapply (noflash)
gpio_hal_workaround:gpio_hal_sleep_mode_setup_wrapper (noflash)
gpio_hal_workaround:gpio_hal_fun_pupd_restore (noflash)
if PM_SLP_IRAM_OPT = y && PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y:
rtc_cntl_hal:rtc_cntl_hal_enable_cpu_retention (noflash)
if PM_SLP_IRAM_OPT = y && PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP = y:
rtc_cntl_hal:rtc_cntl_hal_enable_tagmem_retention (noflash)
if SOC_PM_CPU_RETENTION_BY_RTCCNTL = y:
if PM_SLP_IRAM_OPT = y && PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y:
rtc_cntl_hal:rtc_cntl_hal_enable_cpu_retention (noflash)
if PM_SLP_IRAM_OPT = y && PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP = y:
rtc_cntl_hal:rtc_cntl_hal_enable_tagmem_retention (noflash)

View File

@ -288,6 +288,13 @@ esp_err_t esp_pm_configure(const void* vconfig)
*/
apb_max_freq = 80;
}
#elif CONFIG_IDF_TARGET_ESP32C6
/* Maximum SOC APB clock frequency is 40 MHz, maximum Modem (WiFi,
* Bluetooth, etc..) APB clock frequency is 80 MHz */
const int soc_apb_clk_freq = esp_clk_apb_freq() / MHZ;
const int modem_apb_clk_freq = MODEM_APB_CLK_FREQ / MHZ;
const int apb_clk_freq = MAX(soc_apb_clk_freq, modem_apb_clk_freq);
int apb_max_freq = MIN(max_freq_mhz, apb_clk_freq); /* CPU frequency in APB_MAX mode */
#else
int apb_max_freq = MIN(max_freq_mhz, 80); /* CPU frequency in APB_MAX mode */
#endif
@ -320,9 +327,12 @@ esp_err_t esp_pm_configure(const void* vconfig)
#endif
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_SUPPORT_CPU_PD
esp_err_t ret = esp_sleep_cpu_pd_low_init(config->light_sleep_enable);
if (config->light_sleep_enable && ret != ESP_OK) {
ESP_LOGW(TAG, "Failed to enable CPU power down during light sleep.");
if (config->light_sleep_enable) {
if (esp_sleep_cpu_retention_init() != ESP_OK) {
ESP_LOGW(TAG, "Failed to enable CPU power down during light sleep.");
}
} else {
esp_sleep_cpu_retention_deinit();
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -32,7 +32,7 @@ extern "C" {
* Please do not use reserved or used rtc memory or registers. *
* *
*************************************************************************************
* RTC Memory & Store Register usage
* LP Memory & Store Register usage
*************************************************************************************
* rtc memory addr type size usage
* 0x3f421000(0x50000000) Slow SIZE_CP Co-Processor code/Reset Entry
@ -42,25 +42,29 @@ extern "C" {
*
*************************************************************************************
* RTC store registers usage
* RTC_CNTL_STORE0_REG Reserved
* RTC_CNTL_STORE1_REG RTC_SLOW_CLK calibration value
* RTC_CNTL_STORE2_REG Boot time, low word
* RTC_CNTL_STORE3_REG Boot time, high word
* RTC_CNTL_STORE4_REG External XTAL frequency
* RTC_CNTL_STORE5_REG APB bus frequency
* RTC_CNTL_STORE6_REG FAST_RTC_MEMORY_ENTRY
* RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC
* LP_AON_STORE0_REG Reserved
* LP_AON_STORE1_REG RTC_SLOW_CLK calibration value
* LP_AON_STORE2_REG Boot time, low word
* LP_AON_STORE3_REG Boot time, high word
* LP_AON_STORE4_REG External XTAL frequency
* LP_AON_STORE5_REG FAST_RTC_MEMORY_LENGTH
* LP_AON_STORE6_REG FAST_RTC_MEMORY_ENTRY
* LP_AON_STORE7_REG FAST_RTC_MEMORY_CRC
* LP_AON_STORE8_REG Store light sleep wake stub addr
* LP_AON_STORE9_REG Store the sleep mode at bit[0] (0:light sleep 1:deep sleep)
*************************************************************************************
*/
#define RTC_SLOW_CLK_CAL_REG LP_AON_STORE1_REG
#define RTC_BOOT_TIME_LOW_REG LP_AON_STORE2_REG
#define RTC_BOOT_TIME_HIGH_REG LP_AON_STORE3_REG
#define RTC_XTAL_FREQ_REG LP_AON_STORE4_REG
#define RTC_APB_FREQ_REG LP_AON_STORE5_REG
#define RTC_ENTRY_ADDR_REG LP_AON_STORE6_REG
#define RTC_RESET_CAUSE_REG LP_AON_STORE6_REG
#define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG
#define RTC_SLOW_CLK_CAL_REG LP_AON_STORE1_REG
#define RTC_BOOT_TIME_LOW_REG LP_AON_STORE2_REG
#define RTC_BOOT_TIME_HIGH_REG LP_AON_STORE3_REG
#define RTC_XTAL_FREQ_REG LP_AON_STORE4_REG
#define RTC_ENTRY_LENGTH_REG LP_AON_STORE5_REG
#define RTC_ENTRY_ADDR_REG LP_AON_STORE6_REG
#define RTC_RESET_CAUSE_REG LP_AON_STORE6_REG
#define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG
#define LIGHT_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG
#define SLEEP_MODE_REG LP_AON_STORE9_REG
#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code.

View File

@ -23,6 +23,7 @@
#include "esp32c2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/rtc.h"
#include "esp_private/esp_pmu.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#endif
@ -72,6 +73,9 @@ void IRAM_ATTR bootloader_fill_random(void *buffer, size_t length)
void esp_clk_init(void)
{
s_warn();
#if SOC_PMU_SUPPORTED
pmu_init();
#endif
}
void esp_perip_clk_init(void)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -23,6 +23,7 @@
#include "esp_private/esp_modem_clock.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"
#include "esp_private/esp_pmu.h"
#include "esp_rom_uart.h"
#include "esp_rom_sys.h"
@ -42,13 +43,7 @@ static const char *TAG = "clk";
__attribute__((weak)) void esp_clk_init(void)
{
#if !CONFIG_IDF_ENV_FPGA
rtc_config_t cfg = RTC_CONFIG_DEFAULT();
soc_reset_reason_t rst_reas;
rst_reas = esp_rom_get_reset_reason(0);
if (rst_reas == RESET_REASON_CHIP_POWER_ON) {
cfg.cali_ocode = 1;
}
rtc_init(cfg);
pmu_init();
assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M);

View File

@ -17,7 +17,7 @@
100: esp_timer_startup_init in components/esp_timer/src/esp_timer.c on BIT(0)
# esp_sleep doesn't have init dependencies
105: esp_sleep_startup_init in components/esp_hw_support/sleep_modes.c on BIT(0)
105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
# app_trace has to be initialized before systemview
115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES

View File

@ -19,7 +19,6 @@
#include "soc/rtc.h" // for wakeup trigger defines
#include "soc/rtc_periph.h" // for read rtc registers directly (cause)
#include "soc/soc.h" // for direct register read macros
#include "hal/rtc_cntl_ll.h"
#include "esp_newlib.h"
#include "test_utils.h"
#include "sdkconfig.h"
@ -29,6 +28,12 @@
#include "esp_private/esp_clk.h"
#include "esp_random.h"
#if SOC_PMU_SUPPORTED
#include "esp_private/esp_pmu.h"
#else
#include "hal/rtc_cntl_ll.h"
#endif
#define ESP_EXT0_WAKEUP_LEVEL_LOW 0
#define ESP_EXT0_WAKEUP_LEVEL_HIGH 1
@ -445,7 +450,11 @@ __attribute__((unused)) static float get_time_ms(void)
__attribute__((unused)) static uint32_t get_cause(void)
{
#if SOC_PMU_SUPPORTED
uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU);
#else
uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause();
#endif
return wakeup_cause;
}
@ -590,4 +599,4 @@ TEST_CASE("wake up using GPIO (2 or 4 low)", "[deepsleep][ignore]")
}
#endif // SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2)
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) TODO: IDF-5348, IDF-5349
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) TODO: IDF-5349

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -33,7 +33,6 @@
#include "esp_phy_init.h"
#include "soc/rtc_cntl_periph.h"
#include "soc/rtc.h"
#include "esp_private/sleep_retention.h"
#include "phy_init_data.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"

View File

@ -118,6 +118,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "${target}/modem_clock_hal.c")
endif()
if(CONFIG_SOC_LP_TIMER_SUPPORTED)
list(APPEND srcs "${target}/lp_timer_hal.c")
endif()
if(CONFIG_SOC_BOD_SUPPORTED)
list(APPEND srcs "brownout_hal.c")
endif()
@ -138,6 +142,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "sdio_slave_hal.c")
endif()
if(CONFIG_SOC_PMU_SUPPORTED)
list(APPEND srcs "${target}/pmu_hal.c")
endif()
if(${target} STREQUAL "esp32")
list(APPEND srcs
"touch_sensor_hal.c"
@ -198,7 +206,6 @@ if(NOT BOOTLOADER_BUILD)
if(${target} STREQUAL "esp32c6")
list(APPEND srcs
"spi_flash_hal_gpspi.c"
"esp32c6/rtc_cntl_hal.c"
"hmac_hal.c"
"ds_hal.c")

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "soc/soc.h"
#include "hal/lp_timer_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief set alarm target value
*
* @param timer_id timer num of lp_timer, 0 or 1 for esp32c6
*
* @param value when counter reaches alarm value, alarm event will be triggered
*/
void lp_timer_hal_set_alarm_target(uint8_t timer_id, uint64_t value);
/**
* @brief get current counter value
*
* @param timer_id timer num of lp_timer, 0 or 1 for esp32c6
*/
uint64_t lp_timer_hal_get_cycle_count(uint8_t timer_id);
/**
* @brief clear alarm interrupt status
*/
void lp_timer_hal_clear_alarm_intr_status(void);
/**
* @brief clear overflow interrupt status
*/
void lp_timer_hal_clear_overflow_intr_status(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for ESP32-C6 LP_Timer register operations
#pragma once
#include <stdlib.h>
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/lp_timer_struct.h"
#include "soc/lp_aon_reg.h"
#include "hal/lp_timer_types.h"
#ifdef __cplusplus
extern "C" {
#endif
FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value)
{
dev->target[timer_id].hi.target_hi = (value >> 32) & 0xFFFF;
dev->target[timer_id].lo.target_lo = value & 0xFFFFFFFF;
}
FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en)
{
dev->target[timer_id].hi.enable = en;
}
FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t timer_id)
{
return dev->counter[timer_id].lo.counter_lo;
}
FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t timer_id)
{
return dev->counter[timer_id].hi.counter_hi;
}
FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev)
{
dev->update.update = 1;
}
FORCE_INLINE_ATTR void lp_timer_ll_clear_alarm_intr_status(lp_timer_dev_t *dev)
{
dev->int_clr.alarm = 1;
}
FORCE_INLINE_ATTR void lp_timer_ll_clear_overflow_intr_status(lp_timer_dev_t *dev)
{
dev->int_clr.overflow = 1;
}
FORCE_INLINE_ATTR uint64_t lp_timer_ll_time_to_count(uint64_t time_in_us)
{
uint32_t slow_clk_value = REG_READ(LP_AON_STORE1_REG);
return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for PMU
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#include "hal/pmu_ll.h"
#include "hal/pmu_types.h"
typedef struct {
pmu_dev_t *dev;
} pmu_hal_context_t;
void pmu_hal_hp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle);
uint32_t pmu_hal_hp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal);
void pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle);
uint32_t pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal);
void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal);
void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal);
void pmu_hal_hp_set_sleep_modem_backup_enable(pmu_hal_context_t *hal);
void pmu_hal_hp_set_sleep_modem_backup_disable(pmu_hal_context_t *hal);
void pmu_hal_hp_set_modem_active_backup_enable(pmu_hal_context_t *hal);
void pmu_hal_hp_set_modem_active_backup_disable(pmu_hal_context_t *hal);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,666 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for ESP32-C6 PMU register operations
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/pmu_struct.h"
#include "hal/pmu_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set the power domain that needs to be powered down in the digital power
*
* @param hw Beginning address of the peripheral registers.
* @param mode The pmu mode
* @param flag Digital power domain flag
*
* @return None
*/
FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_power(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t flag)
{
hw->hp_sys[mode].dig_power.val = flag;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_func(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t icg_func)
{
hw->hp_sys[mode].icg_func = icg_func;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_apb(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t bitmap)
{
hw->hp_sys[mode].icg_apb = bitmap;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_modem(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t code)
{
hw->hp_sys[mode].icg_modem.code = code;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_uart_wakeup_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool wakeup_en)
{
hw->hp_sys[mode].syscntl.uart_wakeup_en = wakeup_en;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_hold_all_lp_pad(pmu_dev_t *hw, pmu_hp_mode_t mode, bool hold_all)
{
hw->hp_sys[mode].syscntl.lp_pad_hold_all = hold_all;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_hold_all_hp_pad(pmu_dev_t *hw, pmu_hp_mode_t mode, bool hold_all)
{
hw->hp_sys[mode].syscntl.hp_pad_hold_all = hold_all;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_pad_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel)
{
hw->hp_sys[mode].syscntl.dig_pad_slp_sel = slp_sel;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_pause_watchdog(pmu_dev_t *hw, pmu_hp_mode_t mode, bool pause_wdt)
{
hw->hp_sys[mode].syscntl.dig_pause_wdt = pause_wdt;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_cpu_stall(pmu_dev_t *hw, pmu_hp_mode_t mode, bool cpu_stall)
{
hw->hp_sys[mode].syscntl.dig_cpu_stall = cpu_stall;
}
/**
* @brief Set the power domain that needs to be powered down in the clock power
*
* @param hw Beginning address of the peripheral registers.
* @param mode The pmu mode
* @param flag Clock power domain flag
*
* @return None
*/
FORCE_INLINE_ATTR void pmu_ll_hp_set_clk_power(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t xpd_flag)
{
hw->hp_sys[mode].clk_power.val = xpd_flag;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_xtal_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_xtal)
{
hw->hp_sys[mode].xtal.xpd_xtal = xpd_xtal;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd_bias)
{
hw->hp_sys[mode].bias.xpd_bias = xpd_bias;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_dbg_atten(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t value)
{
hw->hp_sys[mode].bias.dbg_atten = value;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_current_power_off(pmu_dev_t *hw, pmu_hp_mode_t mode, bool off)
{
hw->hp_sys[mode].bias.pd_cur = off;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_bias_sleep_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool en)
{
hw->hp_sys[mode].bias.bias_sleep = en;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_retention_param(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t param)
{
hw->hp_sys[mode].backup.val = param;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_active_backup_enable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_ACTIVE].backup.hp_sleep2active_backup_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_active_backup_disable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_ACTIVE].backup.hp_sleep2active_backup_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_active_backup_enable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_ACTIVE].backup.hp_modem2active_backup_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_active_backup_disable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_ACTIVE].backup.hp_modem2active_backup_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_modem_backup_enable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_MODEM].backup.hp_sleep2modem_backup_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_to_modem_backup_disable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_MODEM].backup.hp_sleep2modem_backup_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_active_to_sleep_backup_enable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_SLEEP].backup.hp_active2sleep_backup_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_active_to_sleep_backup_disable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_SLEEP].backup.hp_active2sleep_backup_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_sleep_backup_enable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_SLEEP].backup.hp_modem2sleep_backup_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_modem_to_sleep_backup_disable(pmu_dev_t *hw)
{
hw->hp_sys[PMU_MODE_HP_SLEEP].backup.hp_modem2sleep_backup_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_backup_icg_func(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t icg_func)
{
hw->hp_sys[mode].backup_clk = icg_func;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sysclk_nodiv(pmu_dev_t *hw, pmu_hp_mode_t mode, bool sysclk_nodiv)
{
hw->hp_sys[mode].sysclk.dig_sysclk_nodiv = sysclk_nodiv;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_sysclk_enable(pmu_dev_t *hw, pmu_hp_mode_t mode, bool icg_sysclk_en)
{
hw->hp_sys[mode].sysclk.icg_sysclk_en = icg_sysclk_en;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sysclk_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel)
{
hw->hp_sys[mode].sysclk.sysclk_slp_sel = slp_sel;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_icg_sysclk_slp_sel(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_sel)
{
hw->hp_sys[mode].sysclk.icg_slp_sel = slp_sel;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_sysclk(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t sysclk_sel)
{
hw->hp_sys[mode].sysclk.dig_sysclk_sel = sysclk_sel;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_logic_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_xpd)
{
hw->hp_sys[mode].regulator0.slp_logic_xpd = slp_xpd;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_memory_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool slp_xpd)
{
hw->hp_sys[mode].regulator0.slp_mem_xpd = slp_xpd;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_xpd(pmu_dev_t *hw, pmu_hp_mode_t mode, bool xpd)
{
hw->hp_sys[mode].regulator0.xpd = xpd;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_logic_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t slp_dbias)
{
hw->hp_sys[mode].regulator0.slp_logic_dbias = slp_dbias;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_sleep_memory_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t slp_dbias)
{
hw->hp_sys[mode].regulator0.slp_mem_dbias = slp_dbias;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_dbias(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t dbias)
{
hw->hp_sys[mode].regulator0.dbias = dbias;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_regulator_driver_bar(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t drv_b)
{
hw->hp_sys[mode].regulator1.drv_b = drv_b;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_slp_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool slp_xpd)
{
hw->lp_sys[mode].regulator0.slp_xpd = slp_xpd;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd)
{
hw->lp_sys[mode].regulator0.xpd = xpd;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_sleep_dbias(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t slp_dbias)
{
hw->lp_sys[mode].regulator0.slp_dbias = slp_dbias;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_dbias(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t dbias)
{
hw->lp_sys[mode].regulator0.dbias = dbias;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_regulator_driver_bar(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t drv_b)
{
hw->lp_sys[mode].regulator1.drv_b = drv_b;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_xtal_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd_xtal)
{
HAL_ASSERT(mode == PMU_MODE_LP_SLEEP);
hw->lp_sys[mode].xtal.xpd_xtal = xpd_xtal;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_dig_power(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t flag)
{
hw->lp_sys[mode].dig_power.val = flag;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_clk_power(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t xpd_flag)
{
hw->lp_sys[mode].clk_power.val = xpd_flag;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_clk_power(pmu_dev_t *hw, pmu_lp_mode_t mode)
{
return hw->lp_sys[mode].clk_power.val;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_bias_xpd(pmu_dev_t *hw, pmu_lp_mode_t mode, bool xpd_bias)
{
HAL_ASSERT(mode == PMU_MODE_LP_SLEEP);
hw->lp_sys[mode].bias.xpd_bias = xpd_bias;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_dbg_atten(pmu_dev_t *hw, pmu_lp_mode_t mode, uint32_t value)
{
HAL_ASSERT(mode == PMU_MODE_LP_SLEEP);
hw->lp_sys[mode].bias.dbg_atten = value;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_current_power_off(pmu_dev_t *hw, pmu_lp_mode_t mode, bool off)
{
HAL_ASSERT(mode == PMU_MODE_LP_SLEEP);
hw->lp_sys[mode].bias.pd_cur = off;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_bias_sleep_enable(pmu_dev_t *hw, pmu_lp_mode_t mode, bool en)
{
HAL_ASSERT(mode == PMU_MODE_LP_SLEEP);
hw->lp_sys[mode].bias.bias_sleep = en;
}
/****/
FORCE_INLINE_ATTR void pmu_ll_imm_set_clk_power(pmu_dev_t *hw, uint32_t flag)
{
hw->imm.clk_power.val = flag;
}
FORCE_INLINE_ATTR void pmu_ll_imm_set_icg_slp_sel(pmu_dev_t *hw, bool slp_sel)
{
if (slp_sel) {
hw->imm.sleep_sysclk.tie_high_icg_slp_sel = 1;
} else {
hw->imm.sleep_sysclk.tie_low_icg_slp_sel = 1;
}
}
FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_sysclk_sel(pmu_dev_t *hw, bool update)
{
hw->imm.sleep_sysclk.update_dig_sysclk_sel = update;
}
FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_switch(pmu_dev_t *hw, bool update)
{
hw->imm.sleep_sysclk.update_dig_icg_switch = update;
}
FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_func(pmu_dev_t *hw, bool icg_func_update)
{
hw->imm.hp_func_icg.update_dig_icg_func_en = icg_func_update;
}
FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_apb(pmu_dev_t *hw, bool icg_apb_update)
{
hw->imm.hp_apb_icg.update_dig_icg_apb_en = icg_apb_update;
}
FORCE_INLINE_ATTR void pmu_ll_imm_update_dig_icg_modem_code(pmu_dev_t *hw, bool icg_modem_update)
{
hw->imm.modem_icg.update_dig_icg_modem_en = icg_modem_update;
}
FORCE_INLINE_ATTR void pmu_ll_imm_set_lp_rootclk_sel(pmu_dev_t *hw, bool rootclk_sel)
{
if (rootclk_sel) {
hw->imm.lp_icg.tie_high_lp_rootclk_sel = 1;
} else {
hw->imm.lp_icg.tie_low_lp_rootclk_sel = 1;
}
}
FORCE_INLINE_ATTR void pmu_ll_imm_set_hp_pad_hold_all(pmu_dev_t *hw, bool hold_all)
{
if (hold_all) {
hw->imm.pad_hold_all.tie_high_hp_pad_hold_all = 1;
} else {
hw->imm.pad_hold_all.tie_low_hp_pad_hold_all = 1;
}
}
FORCE_INLINE_ATTR void pmu_ll_imm_set_lp_pad_hold_all(pmu_dev_t *hw, bool hold_all)
{
if (hold_all) {
hw->imm.pad_hold_all.tie_high_lp_pad_hold_all = 1;
} else {
hw->imm.pad_hold_all.tie_low_lp_pad_hold_all = 1;
}
}
/*** */
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_reset(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool rst)
{
hw->power.hp_pd[domain].force_reset = rst;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_isolate(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool iso)
{
hw->power.hp_pd[domain].force_iso = iso;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_power_up(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool fpu)
{
hw->power.hp_pd[domain].force_pu = fpu;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_no_reset(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool no_rst)
{
hw->power.hp_pd[domain].force_no_reset = no_rst;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_no_isolate(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool no_iso)
{
hw->power.hp_pd[domain].force_no_iso = no_iso;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_power_force_power_down(pmu_dev_t *hw, pmu_hp_power_domain_t domain, bool fpd)
{
hw->power.hp_pd[domain].force_pd = fpd;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_reset(pmu_dev_t *hw, bool rst)
{
hw->power.lp_peri.force_reset = rst;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_isolate(pmu_dev_t *hw, bool iso)
{
hw->power.lp_peri.force_iso = iso;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_power_up(pmu_dev_t *hw, bool fpu)
{
hw->power.lp_peri.force_pu = fpu;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_no_reset(pmu_dev_t *hw, bool no_rst)
{
hw->power.lp_peri.force_no_reset = no_rst;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_no_isolate(pmu_dev_t *hw, bool no_iso)
{
hw->power.lp_peri.force_no_iso = no_iso;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_power_force_power_down(pmu_dev_t *hw, bool fpd)
{
hw->power.lp_peri.force_pd = fpd;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_isolate(pmu_dev_t *hw, uint32_t iso)
{
hw->power.mem_cntl.force_hp_mem_iso = iso;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_power_down(pmu_dev_t *hw, uint32_t fpd)
{
hw->power.mem_cntl.force_hp_mem_pd = fpd;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_no_isolate(pmu_dev_t *hw, uint32_t no_iso)
{
hw->power.mem_cntl.force_hp_mem_no_iso = no_iso;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_memory_power_up(pmu_dev_t *hw, uint32_t fpu)
{
hw->power.mem_cntl.force_hp_mem_pu = fpu;
}
/*** */
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_enable(pmu_dev_t *hw)
{
hw->wakeup.cntl0.sleep_req = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_reject_enable(pmu_dev_t *hw, uint32_t reject)
{
hw->wakeup.cntl1.sleep_reject_ena = reject;
hw->wakeup.cntl1.slp_reject_en = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_reject_disable(pmu_dev_t *hw)
{
hw->wakeup.cntl1.slp_reject_en = 0;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_wakeup_enable(pmu_dev_t *hw, uint32_t wakeup)
{
hw->wakeup.cntl2 = wakeup;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode)
{
hw->wakeup.cntl3.sleep_prt_sel = mode;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle)
{
hw->wakeup.cntl3.hp_min_slp_val = slow_clk_cycle;
}
FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw)
{
hw->wakeup.cntl4.slp_reject_cause_clr = 1;
}
FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_wakeup(pmu_dev_t *hw)
{
return (hw->hp_ext.int_raw.wakeup == 1);
}
FORCE_INLINE_ATTR bool pmu_ll_hp_is_sleep_reject(pmu_dev_t *hw)
{
return (hw->hp_ext.int_raw.reject == 1);
}
FORCE_INLINE_ATTR void pmu_ll_hp_clear_wakeup_intr_status(pmu_dev_t *hw)
{
hw->hp_ext.int_clr.wakeup = 1;
}
FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw)
{
hw->hp_ext.int_clr.reject = 1;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_wakeup_cause(pmu_dev_t *hw)
{
return hw->wakeup.status0;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_reject_cause(pmu_dev_t *hw)
{
return hw->wakeup.status1;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle)
{
hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw)
{
return hw->hp_ext.clk_cntl.modify_icg_cntl_wait;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw)
{
return hw->hp_ext.clk_cntl.switch_icg_cntl_wait;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer0.powerdown_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_down_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer0.powerdown_timer;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer1.powerdown_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer1.powerdown_timer;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle)
{
hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw)
{
return hw->wakeup.cntl5.lp_ana_wait_target;
}
FORCE_INLINE_ATTR void pmu_ll_set_modem_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->wakeup.cntl5.modem_wait_target = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_get_modem_wait_target_cycle(pmu_dev_t *hw)
{
return hw->wakeup.cntl5.modem_wait_target;
}
FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.clk_wait.wait_xtal_stable = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw)
{
return hw->power.clk_wait.wait_xtal_stable;
}
FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.clk_wait.wait_pll_stable = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw)
{
return hw->power.clk_wait.wait_pll_stable;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer1.wait_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_supply_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer1.wait_timer;
}
FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_up_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer1.powerup_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer1.powerup_timer;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->wakeup.cntl7.ana_wait_target = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw)
{
return hw->wakeup.cntl7.ana_wait_target;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer0.wait_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_supply_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer0.wait_timer;
}
FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_up_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
{
hw->power.wait_timer0.powerup_timer = cycle;
}
FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_digital_power_up_wait_cycle(pmu_dev_t *hw)
{
return hw->power.wait_timer0.powerup_timer;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,89 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/lp_aon_reg.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t)
{
// TODO: IDF-5645
}
FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void)
{
// TODO: IDF-5645
return 0;
}
FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void)
{
// TODO: IDF-5645
}
FORCE_INLINE_ATTR void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr)
{
// TODO: IDF-5718 has removed the retention feature
}
FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention_clock(void)
{
// TODO: IDF-5718 has removed the retention feature
}
FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(void)
{
// TODO: IDF-5718 has removed the retention feature
}
FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void)
{
// TODO: IDF-5718 has removed the retention feature
}
FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void)
{
REG_SET_BIT(LP_AON_SYS_CFG_REG, LP_AON_HPSYS_SW_RESET);
}
FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no)
{
REG_SET_BIT(LP_AON_CPUCORE0_CFG_REG, LP_AON_CPU_CORE0_SW_RESET);
}
FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void)
{
// TODO: IDF-6064
}
FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void)
{
// TODO: IDF-6064
return 0;
}
FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us)
{
// TODO: IDF-6064
return 0;
}
FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void)
{
// TODO: IDF-6064
return 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -247,7 +247,7 @@ static inline void rtcio_ll_force_hold_disable(int rtcio_num)
*/
static inline void rtcio_ll_deep_sleep_hold_en_all(void)
{
PMU.imm_pad_hold_all.tie_high_lp_pad_hold_all = 1;
PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1;
}
/**
@ -255,7 +255,7 @@ static inline void rtcio_ll_deep_sleep_hold_en_all(void)
*/
static inline void rtcio_ll_deep_sleep_hold_dis_all(void)
{
PMU.imm_pad_hold_all.tie_low_lp_pad_hold_all = 1;
PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1;
}
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -76,7 +76,7 @@ typedef enum {
UART_INTR_RS485_FRM_ERR = (0x1 << 16),
UART_INTR_RS485_CLASH = (0x1 << 17),
UART_INTR_CMD_CHAR_DET = (0x1 << 18),
// UART_INTR_WAKEUP = (0x1 << 19), // TODO: Test UART wakeup while supporting sleep
UART_INTR_WAKEUP = (0x1 << 19),
} uart_intr_t;
/**

View File

@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "hal/lp_timer_ll.h"
static DRAM_ATTR struct {
lp_timer_dev_t *dev;
} lp_timer_context = { .dev = &LP_TIMER };
void IRAM_ATTR lp_timer_hal_set_alarm_target(uint8_t timer_id, uint64_t value)
{
lp_timer_ll_clear_alarm_intr_status(lp_timer_context.dev);
lp_timer_ll_set_alarm_target(lp_timer_context.dev, timer_id, value);
lp_timer_ll_set_target_enable(lp_timer_context.dev, timer_id, true);
}
uint64_t IRAM_ATTR lp_timer_hal_get_cycle_count(uint8_t timer_id)
{
lp_timer_ll_counter_snapshot(lp_timer_context.dev);
uint32_t lo = lp_timer_ll_get_counter_value_low(lp_timer_context.dev, timer_id);
uint32_t hi = lp_timer_ll_get_counter_value_high(lp_timer_context.dev, timer_id);
lp_timer_counter_value_t result = {
.lo = lo,
.hi = hi
};
return result.val;
}
void IRAM_ATTR lp_timer_hal_clear_alarm_intr_status(void)
{
lp_timer_ll_clear_alarm_intr_status(lp_timer_context.dev);
}
void IRAM_ATTR lp_timer_hal_clear_overflow_intr_status(void)
{
lp_timer_ll_clear_overflow_intr_status(lp_timer_context.dev);
}

View File

@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for PMU (ESP32-C6 specific part)
#include "soc/soc.h"
#include "esp_attr.h"
#include "hal/pmu_hal.h"
#include "hal/pmu_types.h"
void IRAM_ATTR pmu_hal_hp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle)
{
pmu_ll_hp_set_digital_power_supply_wait_cycle(hal->dev, power_supply_wait_cycle);
pmu_ll_hp_set_digital_power_up_wait_cycle(hal->dev, power_up_wait_cycle);
}
uint32_t IRAM_ATTR pmu_hal_hp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal)
{
uint32_t power_supply_wait_cycle = pmu_ll_hp_get_digital_power_supply_wait_cycle(hal->dev);
uint32_t power_up_wait_cycle = pmu_ll_hp_get_digital_power_up_wait_cycle(hal->dev);
return power_supply_wait_cycle + power_up_wait_cycle;
}
void IRAM_ATTR pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t power_supply_wait_cycle, uint32_t power_up_wait_cycle)
{
pmu_ll_lp_set_digital_power_supply_wait_cycle(hal->dev, power_supply_wait_cycle);
pmu_ll_lp_set_digital_power_up_wait_cycle(hal->dev, power_up_wait_cycle);
}
uint32_t IRAM_ATTR pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal)
{
uint32_t power_supply_wait_cycle = pmu_ll_lp_get_digital_power_supply_wait_cycle(hal->dev);
uint32_t power_up_wait_cycle = pmu_ll_lp_get_digital_power_up_wait_cycle(hal->dev);
return power_supply_wait_cycle + power_up_wait_cycle;
}
void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_active_to_sleep_backup_enable(hal->dev);
pmu_ll_hp_set_sleep_to_active_backup_enable(hal->dev);
}
void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_sleep_to_active_backup_disable(hal->dev);
pmu_ll_hp_set_active_to_sleep_backup_disable(hal->dev);
}
void pmu_hal_hp_set_sleep_modem_backup_enable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_sleep_to_modem_backup_enable(hal->dev);
}
void pmu_hal_hp_set_sleep_modem_backup_disable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_sleep_to_modem_backup_disable(hal->dev);
}
void pmu_hal_hp_set_modem_active_backup_enable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_modem_to_active_backup_enable(hal->dev);
}
void pmu_hal_hp_set_modem_active_backup_disable(pmu_hal_context_t *hal)
{
pmu_ll_hp_set_modem_to_active_backup_disable(hal->dev);
}

View File

@ -1,53 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for RTC CNTL (common part)
#include "soc/soc_caps.h"
#include "soc/lldesc.h"
#include "hal/dma_types.h"
#include "hal/rtc_hal.h"
#include "hal/assert.h"
#include "esp_attr.h"
#define RTC_CNTL_HAL_LINK_BUF_SIZE_MIN (SOC_RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE) /* The minimum size of dma link buffer */
typedef struct rtc_cntl_link_buf_conf {
uint32_t cfg[4]; /* 4 word for dma link buffer configuration */
} rtc_cntl_link_buf_conf_t;
void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next)
{
HAL_ASSERT(elem != NULL);
HAL_ASSERT(buff != NULL);
HAL_ASSERT(size >= RTC_CNTL_HAL_LINK_BUF_SIZE_MIN);
lldesc_t *plink = (lldesc_t *)elem;
plink->eof = next ? 0 : 1;
plink->owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
plink->size = size >> 4; /* in unit of 16 bytes */
plink->length = size >> 4;
plink->buf = buff;
plink->offset = 0;
plink->sosf = 0;
STAILQ_NEXT(plink, qe) = next;
return (void *)plink;
}
#if SOC_PM_SUPPORT_CPU_PD
void rtc_cntl_hal_enable_cpu_retention(void *addr)
{
// TODO: IDF-5718 has removed the retention feature
}
void IRAM_ATTR rtc_cntl_hal_disable_cpu_retention(void *addr)
{
// TODO: IDF-5718 has removed the retention feature
}
#endif // SOC_PM_SUPPORT_CPU_PD

View File

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "soc/soc_caps.h"
/**
* @brief The structure of the counter value in lower power timer
*/
typedef struct {
union {
struct {
uint32_t lo: SOC_LP_TIMER_BIT_WIDTH_LO; /*!< Low part of counter value */
uint32_t hi: SOC_LP_TIMER_BIT_WIDTH_HI; /*!< High part of counter value */
uint32_t reserved: 16;
};
uint64_t val; /*!< counter value */
};
} lp_timer_counter_value_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,166 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @brief PMU modes of HP system
*/
typedef enum {
PMU_MODE_HP_ACTIVE = 0, /*!< PMU in HP_ACTIVE mode */
PMU_MODE_HP_MODEM, /*!< PMU in HP_MODEM mode */
PMU_MODE_HP_SLEEP, /*!< PMU in HP_SLEEP mode */
PMU_MODE_HP_MAX,
} pmu_hp_mode_t;
/**
* @brief PMU modes of LP system
*/
typedef enum {
PMU_MODE_LP_ACTIVE = 0, /*!< PMU in LP_ACTIVE mode */
PMU_MODE_LP_SLEEP, /*!< PMU in LP_SLEEP mode */
PMU_MODE_LP_MAX,
} pmu_lp_mode_t;
typedef enum {
PMU_HP_PD_TOP = 0, /* Power domain of digital top */
PMU_HP_PD_AON, /* Power domain of always-on */
PMU_HP_PD_CPU, /* Power domain of HP CPU */
PMU_HP_PD_RESERVED, /* Reserved power domain*/
PMU_HP_PD_WIFI, /* Power domain of WIFI */
PMU_HP_PD_MAX
} pmu_hp_power_domain_t;
/* Software configuration instance type from pmu_struct.h */
typedef union {
struct {
uint32_t reserved0 : 21;
uint32_t vdd_spi_pd_en: 1;
uint32_t mem_dslp : 1;
uint32_t mem_pd_en : 4;
uint32_t wifi_pd_en : 1;
uint32_t reserved1 : 1;
uint32_t cpu_pd_en : 1;
uint32_t aon_pd_en : 1;
uint32_t top_pd_en : 1;
};
struct {
uint32_t reserved2 : 26;
uint32_t i2c_iso_en : 1;
uint32_t i2c_retention: 1;
uint32_t xpd_bb_i2c : 1;
uint32_t xpd_bbpll_i2c: 1;
uint32_t xpd_bbpll : 1;
uint32_t reserved3 : 1;
};
struct {
uint32_t reserved4 : 31;
uint32_t xpd_xtal : 1;
};
uint32_t val;
} pmu_hp_power_t;
typedef union {
struct {
uint32_t reserved0 : 30;
uint32_t mem_dslp : 1;
uint32_t peri_pd_en: 1;
};
struct {
uint32_t reserved1 : 28;
uint32_t xpd_xtal32k: 1;
uint32_t xpd_rc32k : 1;
uint32_t xpd_fosc : 1;
uint32_t pd_osc : 1;
};
struct {
uint32_t reserved2 : 31;
uint32_t xpd_xtal : 1;
};
uint32_t val;
} pmu_lp_power_t;
typedef struct {
struct {
uint32_t reserved0 : 25;
uint32_t xpd_bias : 1;
uint32_t dbg_atten : 4;
uint32_t pd_cur : 1;
uint32_t bias_sleep: 1;
};
struct {
uint32_t reserved1 : 16;
uint32_t slp_mem_xpd : 1;
uint32_t slp_logic_xpd : 1;
uint32_t xpd : 1;
uint32_t slp_mem_dbias : 4;
uint32_t slp_logic_dbias: 4;
uint32_t dbias : 5;
};
struct {
uint32_t reserved2: 8;
uint32_t drv_b : 24;
};
} pmu_hp_analog_t;
typedef struct {
struct {
uint32_t reserved0 : 25;
uint32_t xpd_bias : 1;
uint32_t dbg_atten : 4;
uint32_t pd_cur : 1;
uint32_t bias_sleep: 1;
};
struct {
uint32_t reserved1: 21;
uint32_t slp_xpd : 1;
uint32_t xpd : 1;
uint32_t slp_dbias: 4;
uint32_t dbias : 5;
};
struct {
uint32_t reserved2: 28;
uint32_t drv_b : 4;
};
} pmu_lp_analog_t;
typedef struct {
uint32_t modem_wakeup_wait_cycle;
uint16_t analog_wait_target_cycle;
uint16_t digital_power_down_wait_cycle;
uint16_t digital_power_supply_wait_cycle;
uint16_t digital_power_up_wait_cycle;
uint16_t pll_stable_wait_cycle;
uint8_t modify_icg_cntl_wait_cycle;
uint8_t switch_icg_cntl_wait_cycle;
uint8_t min_slp_slow_clk_cycle;
} pmu_hp_param_t;
typedef struct {
uint16_t digital_power_supply_wait_cycle;
uint8_t min_slp_slow_clk_cycle;
uint8_t analog_wait_target_cycle;
uint8_t digital_power_down_wait_cycle;
uint8_t digital_power_up_wait_cycle;
} pmu_lp_param_t;
typedef struct {
union {
uint16_t xtal_stable_wait_slow_clk_cycle;
uint16_t xtal_stable_wait_cycle;
};
} pmu_hp_lp_param_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __RVSLEEP_FRAMES_H__
#define __RVSLEEP_FRAMES_H__
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n) - 1) & -(n))
#ifdef STRUCT_BEGIN
#undef STRUCT_BEGIN
#undef STRUCT_FIELD
#undef STRUCT_AFIELD
#undef STRUCT_END
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#ifdef __clang__
#define STRUCT_BEGIN .set RV_STRUCT_OFFSET, 0
#define STRUCT_FIELD(ctype,size,asname,name) .set asname, RV_STRUCT_OFFSET; .set RV_STRUCT_OFFSET, asname + size
#define STRUCT_AFIELD(ctype,size,asname,name,n) .set asname, RV_STRUCT_OFFSET;\
.set RV_STRUCT_OFFSET, asname + (size)*(n);
#define STRUCT_END(sname) .set sname##Size, RV_STRUCT_OFFSET;
#else // __clang__
#define STRUCT_BEGIN .pushsection .text; .struct 0
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
#define STRUCT_END(sname) sname##Size:; .popsection
#endif // __clang__
#else
#define STRUCT_BEGIN typedef struct {
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
#define STRUCT_END(sname) } sname;
#endif
/*
* -------------------------------------------------------------------------------
* RISC-V CORE CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MEPC, mepc) /* Machine Exception Program Counter */
STRUCT_FIELD (long, 4, RV_SLP_CTX_RA, ra) /* Return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_SP, sp) /* Stack pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_GP, gp) /* Global pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_TP, tp) /* Thread pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T0, t0) /* Temporary/alternate link register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T1, t1) /* t1-2: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T2, t2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S0, s0) /* Saved register/frame pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S1, s1) /* Saved register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A0, a0) /* a0-1: Function arguments/return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A1, a1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A2, a2) /* a2-7: Function arguments */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A3, a3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A4, a4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A5, a5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A6, a6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A7, a7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S2, s2) /* s2-11: Saved registers */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S3, s3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S4, s4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S5, s5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S6, s6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S7, s7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S8, s8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S9, s9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S10, s10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S11, s11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T3, t3) /* t3-6: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T4, t4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T5, t5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T6, t6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSTATUS, mstatus) /* Machine Status */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MCAUSE, mcause) /* Machine Trap Cause */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVAL, mtval) /* Machine Trap Value */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIE, mie) /* Machine intr enable */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIP, mip) /* Machine intr pending */
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMUFUNC, pmufunc) /* A field is used to identify whether it is going
* to sleep or has just been awakened. We use the
* lowest 2 bits as indication infomation, 3 means
* being awakened, 1 means going to sleep */
STRUCT_END(RvCoreCriticalSleepFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define RV_SLEEP_CTX_SZ1 RvCoreCriticalSleepFrameSize
#else
#define RV_SLEEP_CTX_SZ1 sizeof(RvCoreCriticalSleepFrame)
#endif
/*
* Sleep stack frame size, after align up to 16 bytes boundary
*/
#define RV_SLEEP_CTX_FRMSZ (ALIGNUP(0x10, RV_SLEEP_CTX_SZ1))
/*
* -------------------------------------------------------------------------------
* RISC-V CORE NON-CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSCRATCH, mscratch)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIDELEG, mideleg)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MISA, misa)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TSELECT, tselect)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA1, tdata1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA2, tdata2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TCONTROL, tcontrol)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG0, pmpcfg0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG1, pmpcfg1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR0, pmpaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR1, pmpaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR2, pmpaddr2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR3, pmpaddr3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR4, pmpaddr4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR5, pmpaddr5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR6, pmpaddr6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR7, pmpaddr7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR8, pmpaddr8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR9, pmpaddr9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR10, pmpaddr10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR11, pmpaddr11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR12, pmpaddr12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR13, pmpaddr13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR14, pmpaddr14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR15, pmpaddr15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec)
STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UEPC, uepc)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UCAUSE, ucause)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCER, mpcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCMR, mpcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCCR, mpccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_CPU_TESTBUS_CTRL, cpu_testbus_ctrl)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCER, upcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCMR, upcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCCR, upccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OEN, ugpio_oen)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_IN, ugpio_in)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OUT, ugpio_out)
STRUCT_END(RvCoreNonCriticalSleepFrame)
#endif /* #ifndef __RVSLEEP_FRAMES_H__ */

View File

@ -743,6 +743,14 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
bool
default y
config SOC_CLK_APLL_SUPPORTED
bool
default y

View File

@ -373,6 +373,9 @@
#define SOC_PM_SUPPORT_RTC_FAST_MEM_PD (1)
#define SOC_PM_SUPPORT_RTC_SLOW_MEM_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_CONFIGURABLE_VDDSDIO_SUPPORTED (1)
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)

View File

@ -607,6 +607,10 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_CLK_RC_FAST_D256_SUPPORTED
bool
default y

View File

@ -722,37 +722,6 @@ typedef struct {
*/
void rtc_init(rtc_config_t cfg);
/**
* Structure describing vddsdio configuration
*/
typedef struct {
uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins.
uint32_t enable : 1; //!< Enable VDDSDIO regulator
uint32_t tieh : 1; //!< Select VDDSDIO voltage. One of RTC_VDDSDIO_TIEH_1_8V, RTC_VDDSDIO_TIEH_3_3V
uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator
} rtc_vddsdio_config_t;
/**
* Get current VDDSDIO configuration
* If VDDSDIO configuration is overridden by RTC, get values from RTC
* Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE
* Otherwise, use default values and the level of MTDI bootstrapping pin.
* @return currently used VDDSDIO configuration
*/
rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
/**
* Set new VDDSDIO configuration using RTC registers.
* If config.force == 1, this overrides configuration done using bootstrapping
* pins and EFUSE.
*
* @param config new VDDSDIO configuration
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.

View File

@ -289,6 +289,7 @@
#define SOC_PM_SUPPORT_WIFI_PD (0)
#define SOC_PM_SUPPORT_BT_PD (0)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
/*--------------------------- CLOCK SUBSYSTEM CAPS -------------------------- */
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)

View File

@ -863,6 +863,14 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_PM_CPU_RETENTION_BY_RTCCNTL
bool
default y
config SOC_CLK_RC_FAST_D256_SUPPORTED
bool
default y

View File

@ -764,37 +764,6 @@ typedef struct {
*/
void rtc_init(rtc_config_t cfg);
/**
* Structure describing vddsdio configuration
*/
typedef struct {
uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins.
uint32_t enable : 1; //!< Enable VDDSDIO regulator
uint32_t tieh : 1; //!< Select VDDSDIO voltage. One of RTC_VDDSDIO_TIEH_1_8V, RTC_VDDSDIO_TIEH_3_3V
uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator
} rtc_vddsdio_config_t;
/**
* Get current VDDSDIO configuration
* If VDDSDIO configuration is overridden by RTC, get values from RTC
* Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE
* Otherwise, use default values and the level of MTDI bootstrapping pin.
* @return currently used VDDSDIO configuration
*/
rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
/**
* Set new VDDSDIO configuration using RTC registers.
* If config.force == 1, this overrides configuration done using bootstrapping
* pins and EFUSE.
*
* @param config new VDDSDIO configuration
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.

View File

@ -383,6 +383,9 @@
#define SOC_PM_SUPPORT_WIFI_PD (1)
#define SOC_PM_SUPPORT_BT_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_PM_CPU_RETENTION_BY_RTCCNTL (1)
/*--------------------------- CLOCK SUBSYSTEM CAPS -------------------------- */
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)

View File

@ -147,6 +147,14 @@ config SOC_APM_SUPPORTED
bool
default y
config SOC_PMU_SUPPORTED
bool
default y
config SOC_LP_TIMER_SUPPORTED
bool
default y
config SOC_XTAL_SUPPORT_40M
bool
default y
@ -659,14 +667,6 @@ config SOC_MCPWM_CLK_SUPPORT_XTAL
bool
default y
config SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH
int
default 128
config SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM
int
default 108
config SOC_RSA_MAX_BIT_LEN
int
default 3072
@ -839,6 +839,14 @@ config SOC_SYSTIMER_SUPPORT_ETM
bool
default y
config SOC_LP_TIMER_BIT_WIDTH_LO
int
default 32
config SOC_LP_TIMER_BIT_WIDTH_HI
int
default 16
config SOC_TIMER_GROUPS
int
default 2
@ -963,6 +971,10 @@ config SOC_UART_SUPPORT_XTAL_CLK
bool
default y
config SOC_UART_SUPPORT_WAKEUP_INT
bool
default y
config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND
bool
default y
@ -991,11 +1003,7 @@ config SOC_PM_SUPPORT_CPU_PD
bool
default y
config SOC_PM_SUPPORT_WIFI_PD
bool
default y
config SOC_PM_SUPPORT_BT_PD
config SOC_PM_SUPPORT_MODEM_PD
bool
default y
@ -1011,10 +1019,18 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
bool
default y
config SOC_PM_CPU_RETENTION_BY_SW
bool
default y
config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
bool
default y

View File

@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,346 +10,99 @@
extern "C" {
#endif
/** Group: configure_register */
/** Type of tar0_low register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_low0 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_low0:32;
};
uint32_t val;
} lp_timer_tar0_low_reg_t;
typedef struct {
union {
struct {
uint32_t target_lo: 32;
};
uint32_t val;
} lo;
union {
struct {
uint32_t target_hi: 16;
uint32_t reserved0: 15;
uint32_t enable : 1;
};
uint32_t val;
} hi;
} lp_timer_target_reg_t;
/** Type of tar0_high register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_high0 : R/W; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_high0:16;
uint32_t reserved_16:15;
/** main_timer_tar_en0 : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_tar_en0:1;
};
uint32_t val;
} lp_timer_tar0_high_reg_t;
/** Type of tar1_low register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_low1 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_low1:32;
};
uint32_t val;
} lp_timer_tar1_low_reg_t;
/** Type of tar1_high register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_high1 : R/W; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_high1:16;
uint32_t reserved_16:15;
/** main_timer_tar_en1 : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_tar_en1:1;
};
uint32_t val;
} lp_timer_tar1_high_reg_t;
/** Type of update register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:28;
/** main_timer_update : WT; bitpos: [28]; default: 0;
* need_des
*/
uint32_t main_timer_update:1;
/** main_timer_xtal_off : R/W; bitpos: [29]; default: 0;
* need_des
*/
uint32_t main_timer_xtal_off:1;
/** main_timer_sys_stall : R/W; bitpos: [30]; default: 0;
* need_des
*/
uint32_t main_timer_sys_stall:1;
/** main_timer_sys_rst : R/W; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_sys_rst:1;
uint32_t reserved0: 28;
uint32_t update : 1;
uint32_t xtal_off : 1;
uint32_t sys_stall: 1;
uint32_t sys_rst : 1;
};
uint32_t val;
} lp_timer_update_reg_t;
/** Type of main_buf0_low register
* need_des
*/
typedef struct {
union {
struct {
uint32_t counter_lo: 32;
};
uint32_t val;
} lo;
union {
struct {
uint32_t counter_hi: 16;
uint32_t reserved0 : 16;
};
uint32_t val;
} hi;
} lp_timer_counter_reg_t;
typedef union {
struct {
/** main_timer_buf0_low : RO; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf0_low:32;
uint32_t reserved0: 31;
uint32_t trigger : 1;
};
uint32_t val;
} lp_timer_main_buf0_low_reg_t;
} lp_timer_overflow_reg_t;
/** Type of main_buf0_high register
* need_des
*/
typedef union {
struct {
/** main_timer_buf0_high : RO; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf0_high:16;
uint32_t reserved_16:16;
uint32_t reserved0: 30;
uint32_t overflow : 1;
uint32_t alarm : 1;
};
uint32_t val;
} lp_timer_main_buf0_high_reg_t;
} lp_timer_intr_reg_t;
/** Type of main_buf1_low register
* need_des
*/
typedef union {
struct {
/** main_timer_buf1_low : RO; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf1_low:32;
uint32_t reserved0: 30;
uint32_t overflow : 1;
uint32_t alarm : 1;
};
uint32_t val;
} lp_timer_main_buf1_low_reg_t;
} lp_timer_lp_intr_reg_t;
/** Type of main_buf1_high register
* need_des
*/
typedef union {
struct {
/** main_timer_buf1_high : RO; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf1_high:16;
uint32_t reserved_16:16;
};
uint32_t val;
} lp_timer_main_buf1_high_reg_t;
typedef volatile struct lp_timer_dev_t{
lp_timer_target_reg_t target[2];
lp_timer_update_reg_t update;
lp_timer_counter_reg_t counter[2];
lp_timer_overflow_reg_t overflow;
lp_timer_intr_reg_t int_raw;
lp_timer_intr_reg_t int_st;
lp_timer_intr_reg_t int_en;
lp_timer_intr_reg_t int_clr;
lp_timer_lp_intr_reg_t lp_int_raw;
lp_timer_lp_intr_reg_t lp_int_st;
lp_timer_lp_intr_reg_t lp_int_en;
lp_timer_lp_intr_reg_t lp_int_clr;
/** Type of main_overflow register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:31;
/** main_timer_alarm_load : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_alarm_load:1;
};
uint32_t val;
} lp_timer_main_overflow_reg_t;
uint32_t reserved[237];
/** Type of int_raw register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** overflow_raw : R/WTC/SS; bitpos: [30]; default: 0;
* need_des
*/
uint32_t overflow_raw:1;
/** soc_wakeup_int_raw : R/WTC/SS; bitpos: [31]; default: 0;
* need_des
*/
uint32_t soc_wakeup_int_raw:1;
};
uint32_t val;
} lp_timer_int_raw_reg_t;
/** Type of int_st register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** overflow_st : RO; bitpos: [30]; default: 0;
* need_des
*/
uint32_t overflow_st:1;
/** soc_wakeup_int_st : RO; bitpos: [31]; default: 0;
* need_des
*/
uint32_t soc_wakeup_int_st:1;
};
uint32_t val;
} lp_timer_int_st_reg_t;
/** Type of int_ena register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** overflow_ena : R/W; bitpos: [30]; default: 0;
* need_des
*/
uint32_t overflow_ena:1;
/** soc_wakeup_int_ena : R/W; bitpos: [31]; default: 0;
* need_des
*/
uint32_t soc_wakeup_int_ena:1;
};
uint32_t val;
} lp_timer_int_ena_reg_t;
/** Type of int_clr register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** overflow_clr : WT; bitpos: [30]; default: 0;
* need_des
*/
uint32_t overflow_clr:1;
/** soc_wakeup_int_clr : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t soc_wakeup_int_clr:1;
};
uint32_t val;
} lp_timer_int_clr_reg_t;
/** Type of lp_int_raw register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** main_timer_overflow_lp_int_raw : R/WTC/SS; bitpos: [30]; default: 0;
* need_des
*/
uint32_t main_timer_overflow_lp_int_raw:1;
/** main_timer_lp_int_raw : R/WTC/SS; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_lp_int_raw:1;
};
uint32_t val;
} lp_timer_lp_int_raw_reg_t;
/** Type of lp_int_st register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** main_timer_overflow_lp_int_st : RO; bitpos: [30]; default: 0;
* need_des
*/
uint32_t main_timer_overflow_lp_int_st:1;
/** main_timer_lp_int_st : RO; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_lp_int_st:1;
};
uint32_t val;
} lp_timer_lp_int_st_reg_t;
/** Type of lp_int_ena register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** main_timer_overflow_lp_int_ena : R/W; bitpos: [30]; default: 0;
* need_des
*/
uint32_t main_timer_overflow_lp_int_ena:1;
/** main_timer_lp_int_ena : R/W; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_lp_int_ena:1;
};
uint32_t val;
} lp_timer_lp_int_ena_reg_t;
/** Type of lp_int_clr register
* need_des
*/
typedef union {
struct {
uint32_t reserved_0:30;
/** main_timer_overflow_lp_int_clr : WT; bitpos: [30]; default: 0;
* need_des
*/
uint32_t main_timer_overflow_lp_int_clr:1;
/** main_timer_lp_int_clr : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_lp_int_clr:1;
};
uint32_t val;
} lp_timer_lp_int_clr_reg_t;
/** Type of date register
* need_des
*/
typedef union {
struct {
/** date : R/W; bitpos: [30:0]; default: 34672976;
* need_des
*/
uint32_t date:31;
/** clk_en : R/W; bitpos: [31]; default: 0;
* need_des
*/
uint32_t clk_en:1;
};
uint32_t val;
} lp_timer_date_reg_t;
typedef struct lp_timer_dev_t {
volatile lp_timer_tar0_low_reg_t tar0_low;
volatile lp_timer_tar0_high_reg_t tar0_high;
volatile lp_timer_tar1_low_reg_t tar1_low;
volatile lp_timer_tar1_high_reg_t tar1_high;
volatile lp_timer_update_reg_t update;
volatile lp_timer_main_buf0_low_reg_t main_buf0_low;
volatile lp_timer_main_buf0_high_reg_t main_buf0_high;
volatile lp_timer_main_buf1_low_reg_t main_buf1_low;
volatile lp_timer_main_buf1_high_reg_t main_buf1_high;
volatile lp_timer_main_overflow_reg_t main_overflow;
volatile lp_timer_int_raw_reg_t int_raw;
volatile lp_timer_int_st_reg_t int_st;
volatile lp_timer_int_ena_reg_t int_ena;
volatile lp_timer_int_clr_reg_t int_clr;
volatile lp_timer_lp_int_raw_reg_t lp_int_raw;
volatile lp_timer_lp_int_st_reg_t lp_int_st;
volatile lp_timer_lp_int_ena_reg_t lp_int_ena;
volatile lp_timer_lp_int_clr_reg_t lp_int_clr;
uint32_t reserved_048[237];
volatile lp_timer_date_reg_t date;
union {
struct {
uint32_t date : 31;
uint32_t clk_en: 1;
};
uint32_t val;
} date;
} lp_timer_dev_t;
extern lp_timer_dev_t LP_TIMER;

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ extern "C" {
/**
* @file rtc.h
* @brief Low-level RTC power, clock, and sleep functions.
* @brief Low-level RTC power, clock functions.
*
* Functions in this file facilitate configuration of ESP32's RTC_CNTL peripheral.
* RTC_CNTL peripheral handles many functions:
@ -514,204 +514,8 @@ bool rtc_dig_8m_enabled(void);
*/
uint32_t rtc_clk_freq_cal(uint32_t cal_val);
/**
* @brief Power down flags for rtc_sleep_pd function
*/
typedef struct {
uint32_t dig_fpu : 1; //!< Set to 1 to power UP digital part in sleep
uint32_t rtc_fpu : 1; //!< Set to 1 to power UP RTC memories in sleep
uint32_t cpu_fpu : 1; //!< Set to 1 to power UP digital memories and CPU in sleep
uint32_t i2s_fpu : 1; //!< Set to 1 to power UP I2S in sleep
uint32_t bb_fpu : 1; //!< Set to 1 to power UP WiFi in sleep
uint32_t nrx_fpu : 1; //!< Set to 1 to power UP WiFi in sleep
uint32_t fe_fpu : 1; //!< Set to 1 to power UP WiFi in sleep
uint32_t sram_fpu : 1; //!< Set to 1 to power UP SRAM in sleep
uint32_t rom_ram_fpu : 1; //!< Set to 1 to power UP ROM/IRAM0_DRAM0 in sleep
} rtc_sleep_pu_config_t;
/**
* Initializer for rtc_sleep_pu_config_t which sets all flags to the same value
*/
#define RTC_SLEEP_PU_CONFIG_ALL(val) {\
.dig_fpu = (val), \
.rtc_fpu = (val), \
.cpu_fpu = (val), \
.i2s_fpu = (val), \
.bb_fpu = (val), \
.nrx_fpu = (val), \
.fe_fpu = (val), \
.sram_fpu = (val), \
.rom_ram_fpu = (val), \
}
void rtc_sleep_pu(rtc_sleep_pu_config_t cfg);
/**
* @brief sleep configuration for rtc_sleep_init function
*/
typedef struct {
uint32_t lslp_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (digital domain memory)
uint32_t rtc_mem_inf_follow_cpu : 1;//!< keep low voltage in sleep mode (even if ULP/touch is used)
uint32_t rtc_fastmem_pd_en : 1; //!< power down RTC fast memory
uint32_t rtc_slowmem_pd_en : 1; //!< power down RTC slow memory
uint32_t rtc_peri_pd_en : 1; //!< power down RTC peripherals
uint32_t wifi_pd_en : 1; //!< power down WiFi
uint32_t bt_pd_en : 1; //!< power down BT
uint32_t cpu_pd_en : 1; //!< power down CPU, but not restart when lightsleep.
uint32_t int_8m_pd_en : 1; //!< Power down Internal 8M oscillator
uint32_t dig_peri_pd_en : 1; //!< power down digital peripherals
uint32_t deep_slp : 1; //!< power down digital domain
uint32_t wdt_flashboot_mod_en : 1; //!< enable WDT flashboot mode
uint32_t dig_dbias_wak : 5; //!< set bias for digital domain, in active mode
uint32_t dig_dbias_slp : 5; //!< set bias for digital domain, in sleep mode
uint32_t rtc_dbias_wak : 5; //!< set bias for RTC domain, in active mode
uint32_t rtc_dbias_slp : 5; //!< set bias for RTC domain, in sleep mode
uint32_t dbg_atten_monitor : 4; //!< voltage parameter, in monitor mode
uint32_t bias_sleep_monitor : 1; //!< circuit control parameter, in monitor mode
uint32_t dbg_atten_slp : 4; //!< voltage parameter, in sleep mode
uint32_t bias_sleep_slp : 1; //!< circuit control parameter, in sleep mode
uint32_t pd_cur_monitor : 1; //!< circuit control parameter, in monitor mode
uint32_t pd_cur_slp : 1; //!< circuit control parameter, in sleep mode
uint32_t vddsdio_pd_en : 1; //!< power down VDDSDIO regulator
uint32_t xtal_fpu : 1; //!< keep main XTAL powered up in sleep
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
#define RTC_SLEEP_PD_RTC_PERIPH BIT(1) //!< Power down RTC peripherals
#define RTC_SLEEP_PD_RTC_SLOW_MEM BIT(2) //!< Power down RTC SLOW memory
#define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) //!< Power down RTC FAST memory
#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) //!< RTC FAST and SLOW memories are automatically powered up and down along with the CPU
#define RTC_SLEEP_PD_VDDSDIO BIT(5) //!< Power down VDDSDIO regulator
#define RTC_SLEEP_PD_WIFI BIT(6) //!< Power down WIFI
#define RTC_SLEEP_PD_BT BIT(7) //!< Power down BT
#define RTC_SLEEP_PD_CPU BIT(8) //!< Power down CPU when in lightsleep, but not restart
#define RTC_SLEEP_PD_DIG_PERIPH BIT(9) //!< Power down DIG peripherals
#define RTC_SLEEP_PD_INT_8M BIT(10) //!< Power down Internal 8M oscillator
#define RTC_SLEEP_PD_XTAL BIT(11) //!< Power down main XTAL
//These flags are not power domains, but will affect some sleep parameters
#define RTC_SLEEP_DIG_USE_8M BIT(16)
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
/**
* Default initializer for rtc_sleep_config_t
*
* This initializer sets all fields to "reasonable" values (e.g. suggested for
* production use) based on a combination of RTC_SLEEP_PD_x flags.
*
* @param RTC_SLEEP_PD_x flags combined using bitwise OR
*/
void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_config);
/**
* @brief Prepare the chip to enter sleep mode
*
* This function configures various power control state machines to handle
* entry into light sleep or deep sleep mode, switches APB and CPU clock source
* (usually to XTAL), and sets bias voltages for digital and RTC power domains.
*
* This function does not actually enter sleep mode; this is done using
* rtc_sleep_start function. Software may do some other actions between
* rtc_sleep_init and rtc_sleep_start, such as set wakeup timer and configure
* wakeup sources.
* @param cfg sleep mode configuration
*/
void rtc_sleep_init(rtc_sleep_config_t cfg);
/**
* @brief Low level initialize for rtc state machine waiting cycles after waking up
*
* This function configures the cycles chip need to wait for internal 8MHz
* oscillator and external 40MHz crystal. As we configure fixed time for waiting
* crystal, we need to pass period to calculate cycles. Now this function only
* used in lightsleep mode.
*
* @param slowclk_period re-calibrated slow clock period
*/
void rtc_sleep_low_init(uint32_t slowclk_period);
/**
* @brief Set target value of RTC counter for RTC_TIMER_TRIG_EN wakeup source
* @param t value of RTC counter at which wakeup from sleep will happen;
* only the lower 48 bits are used
*/
void rtc_sleep_set_wakeup_time(uint64_t t);
#define RTC_GPIO_TRIG_EN BIT(2) //!< GPIO wakeup
#define RTC_TIMER_TRIG_EN BIT(3) //!< Timer wakeup
#define RTC_WIFI_TRIG_EN BIT(5) //!< WIFI wakeup (light sleep only)
#define RTC_UART0_TRIG_EN BIT(6) //!< UART0 wakeup (light sleep only)
#define RTC_UART1_TRIG_EN BIT(7) //!< UART1 wakeup (light sleep only)
#define RTC_BT_TRIG_EN BIT(10) //!< BT wakeup (light sleep only)
#define RTC_XTAL32K_DEAD_TRIG_EN BIT(12)
#define RTC_USB_TRIG_EN BIT(14)
#define RTC_BROWNOUT_DET_TRIG_EN BIT(16)
/**
* RTC_SLEEP_REJECT_MASK records sleep reject sources supported by chip
*/
#define RTC_SLEEP_REJECT_MASK (RTC_GPIO_TRIG_EN | \
RTC_TIMER_TRIG_EN | \
RTC_WIFI_TRIG_EN | \
RTC_UART0_TRIG_EN | \
RTC_UART1_TRIG_EN | \
RTC_BT_TRIG_EN | \
RTC_XTAL32K_DEAD_TRIG_EN | \
RTC_USB_TRIG_EN | \
RTC_BROWNOUT_DET_TRIG_EN)
/**
* @brief Enter deep or light sleep mode
*
* This function enters the sleep mode previously configured using rtc_sleep_init
* function. Before entering sleep, software should configure wake up sources
* appropriately (set up GPIO wakeup registers, timer wakeup registers,
* and so on).
*
* If deep sleep mode was configured using rtc_sleep_init, and sleep is not
* rejected by hardware (based on reject_opt flags), this function never returns.
* When the chip wakes up from deep sleep, CPU is reset and execution starts
* from ROM bootloader.
*
* If light sleep mode was configured using rtc_sleep_init, this function
* returns on wakeup, or if sleep is rejected by hardware.
*
* @param wakeup_opt bit mask wake up reasons to enable (RTC_xxx_TRIG_EN flags
* combined with OR)
* @param reject_opt bit mask of sleep reject reasons:
* - RTC_CNTL_GPIO_REJECT_EN
* - RTC_CNTL_SDIO_REJECT_EN
* These flags are used to prevent entering sleep when e.g.
* an external host is communicating via SDIO slave
* @return non-zero if sleep was rejected by hardware
*/
uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu);
/**
* @brief Enter deep sleep mode
*
* Similar to rtc_sleep_start(), but additionally uses hardware to calculate the CRC value
* of RTC FAST memory. On wake, this CRC is used to determine if a deep sleep wake
* stub is valid to execute (if a wake address is set).
*
* No RAM is accessed while calculating the CRC and going into deep sleep, which makes
* this function safe to use even if the caller's stack is in RTC FAST memory.
*
* @note If no deep sleep wake stub address is set then calling rtc_sleep_start() will
* have the same effect and takes less time as CRC calculation is skipped.
*
* @note This function should only be called after rtc_sleep_init() has been called to
* configure the system for deep sleep.
*
* @param wakeup_opt - same as for rtc_sleep_start
* @param reject_opt - same as for rtc_sleep_start
*
* @return non-zero if sleep was rejected by hardware
*/
uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt);
/**
* RTC power and clock control initialization settings
@ -754,37 +558,6 @@ typedef struct {
*/
void rtc_init(rtc_config_t cfg);
/**
* Structure describing vddsdio configuration
*/
typedef struct {
uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins.
uint32_t enable : 1; //!< Enable VDDSDIO regulator
uint32_t tieh : 1; //!< Select VDDSDIO voltage. One of RTC_VDDSDIO_TIEH_1_8V, RTC_VDDSDIO_TIEH_3_3V
uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator
} rtc_vddsdio_config_t;
/**
* Get current VDDSDIO configuration
* If VDDSDIO configuration is overridden by RTC, get values from RTC
* Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE
* Otherwise, use default values and the level of MTDI bootstrapping pin.
* @return currently used VDDSDIO configuration
*/
rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
/**
* Set new VDDSDIO configuration using RTC registers.
* If config.force == 1, this overrides configuration done using bootstrapping
* pins and EFUSE.
*
* @param config new VDDSDIO configuration
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.

View File

@ -141,6 +141,7 @@
#define EFUSE_CLK_FREQ_ROM ( 20*1000000)
#define CPU_CLK_FREQ APB_CLK_FREQ
#define APB_CLK_FREQ ( 40*1000000 )
#define MODEM_APB_CLK_FREQ ( 80*1000000 )
#define REF_CLK_FREQ ( 1000000 )
#define RTC_CLK_FREQ (20*1000000)
#define XTAL_CLK_FREQ (40*1000000)

View File

@ -63,6 +63,8 @@
#define SOC_SDIO_SLAVE_SUPPORTED 1
#define SOC_BOD_SUPPORTED 1
#define SOC_APM_SUPPORTED 1
#define SOC_PMU_SUPPORTED 1
#define SOC_LP_TIMER_SUPPORTED 1
/*-------------------------- XTAL CAPS ---------------------------------------*/
#define SOC_XTAL_SUPPORT_40M 1
@ -281,15 +283,6 @@
#define SOC_MCPWM_CLK_SUPPORT_PLL160M (1) ///< Support PLL160M as clock source
#define SOC_MCPWM_CLK_SUPPORT_XTAL (1) ///< Support XTAL as clock source
// TODO: IDF-5348 (Copy from esp32c3, need check)
/*-------------------------- RTC CAPS --------------------------------------*/
#define SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH (128)
#define SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM (108)
#define SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN (SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)
#define SOC_RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE (SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)
#define SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE (SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM * (SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3))
// TODO: IDF-5359 (Copy from esp32c3, need check)
/*--------------------------- RSA CAPS ---------------------------------------*/
#define SOC_RSA_MAX_BIT_LEN (3072)
@ -368,6 +361,10 @@
#define SOC_SYSTIMER_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SOC_SYSTIMER_SUPPORT_ETM 1 // Systimer comparator can generate ETM event
/*-------------------------- LP_TIMER CAPS ----------------------------------*/
#define SOC_LP_TIMER_BIT_WIDTH_LO 32 // Bit width of lp_timer low part
#define SOC_LP_TIMER_BIT_WIDTH_HI 16 // Bit width of lp_timer high part
/*--------------------------- TIMER GROUP CAPS ---------------------------------------*/
#define SOC_TIMER_GROUPS (2)
#define SOC_TIMER_GROUP_TIMERS_PER_GROUP (1U)
@ -410,14 +407,13 @@
// TODO: IDF-5338 (Copy from esp32c3, need check)
/*-------------------------- UART CAPS ---------------------------------------*/
// ESP32-C6 has 2 UARTs
#define SOC_UART_NUM (2)
#define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */
#define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */
#define SOC_UART_SUPPORT_PLL_F80M_CLK (1) /*!< Support PLL_DIV as the clock source */
#define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */
#define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */
// #define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ // TODO: Test UART wakeup while supporting sleep
#define SOC_UART_NUM (2)
#define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */
#define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */
#define SOC_UART_SUPPORT_PLL_F80M_CLK (1) /*!< Support PLL_DIV as the clock source */
#define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */
#define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */
#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ // TODO: Test UART wakeup while supporting sleep
// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled
#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1)
@ -438,14 +434,16 @@
#define SOC_PM_SUPPORT_WIFI_WAKEUP (1)
#define SOC_PM_SUPPORT_BT_WAKEUP (1)
#define SOC_PM_SUPPORT_CPU_PD (1)
#define SOC_PM_SUPPORT_WIFI_PD (1)
#define SOC_PM_SUPPORT_BT_PD (1)
#define SOC_PM_SUPPORT_MODEM_PD (1)
#define SOC_PM_SUPPORT_XTAL32K_PD (1)
#define SOC_PM_SUPPORT_RC32K_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!<Supports CRC only the stub code in RTC memory */
#define SOC_PM_CPU_RETENTION_BY_SW (1)
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1)
#define SOC_MODEM_CLOCK_IS_INDEPENDENT (1)

View File

@ -835,6 +835,14 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_PM_CPU_RETENTION_BY_RTCCNTL
bool
default y
config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
bool
default y

View File

@ -769,37 +769,6 @@ typedef struct {
*/
void rtc_init(rtc_config_t cfg);
/**
* Structure describing vddsdio configuration
*/
typedef struct {
uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins.
uint32_t enable : 1; //!< Enable VDDSDIO regulator
uint32_t tieh : 1; //!< Select VDDSDIO voltage. One of RTC_VDDSDIO_TIEH_1_8V, RTC_VDDSDIO_TIEH_3_3V
uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator
} rtc_vddsdio_config_t;
/**
* Get current VDDSDIO configuration
* If VDDSDIO configuration is overridden by RTC, get values from RTC
* Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE
* Otherwise, use default values and the level of MTDI bootstrapping pin.
* @return currently used VDDSDIO configuration
*/
rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
/**
* Set new VDDSDIO configuration using RTC registers.
* If config.force == 1, this overrides configuration done using bootstrapping
* pins and EFUSE.
*
* @param config new VDDSDIO configuration
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.
// Please use the declarations in soc/clk_tree_defs.h instead.

View File

@ -419,7 +419,8 @@
#define SOC_PM_SUPPORT_WIFI_PD (1)
#define SOC_PM_SUPPORT_BT_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_PM_CPU_RETENTION_BY_RTCCNTL (1)
#define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!<Supports CRC only the stub code in RTC memory */
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/

View File

@ -854,36 +854,6 @@ typedef struct {
*/
void rtc_init(rtc_config_t cfg);
/**
* Structure describing vddsdio configuration
*/
typedef struct {
uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins.
uint32_t enable : 1; //!< Enable VDDSDIO regulator
uint32_t tieh : 1; //!< Select VDDSDIO voltage. One of RTC_VDDSDIO_TIEH_1_8V, RTC_VDDSDIO_TIEH_3_3V
uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator
uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator
} rtc_vddsdio_config_t;
/**
* Get current VDDSDIO configuration
* If VDDSDIO configuration is overridden by RTC, get values from RTC
* Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE
* Otherwise, use default values and the level of MTDI bootstrapping pin.
* @return currently used VDDSDIO configuration
*/
rtc_vddsdio_config_t rtc_vddsdio_get_config(void);
/**
* Set new VDDSDIO configuration using RTC registers.
* If config.force == 1, this overrides configuration done using bootstrapping
* pins and EFUSE.
*
* @param config new VDDSDIO configuration
*/
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
/**
* Regulator config
*/

View File

@ -955,6 +955,14 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
bool
default y
config SOC_CLK_APLL_SUPPORTED
bool
default y

View File

@ -415,6 +415,9 @@
#define SOC_PM_SUPPORT_RTC_FAST_MEM_PD (1)
#define SOC_PM_SUPPORT_RTC_SLOW_MEM_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_CONFIGURABLE_VDDSDIO_SUPPORTED (1)
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)

View File

@ -1003,10 +1003,22 @@ config SOC_PM_SUPPORT_RC_FAST_PD
bool
default y
config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
bool
default y
config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
bool
default y
config SOC_PM_CPU_RETENTION_BY_RTCCNTL
bool
default y
config SOC_CLK_RC_FAST_D256_SUPPORTED
bool
default y

View File

@ -411,9 +411,13 @@
#define SOC_PM_SUPPORT_TAGMEM_PD (1)
#define SOC_PM_SUPPORT_RTC_PERIPH_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_CONFIGURABLE_VDDSDIO_SUPPORTED (1)
#define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!<Supports CRC only the stub code in RTC memory */
#define SOC_PM_CPU_RETENTION_BY_RTCCNTL (1)
/*--------------------------- CLOCK SUBSYSTEM CAPS -------------------------- */
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)
#define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1)

View File

@ -106,7 +106,7 @@ examples/system/ipc/ipc_isr:
examples/system/light_sleep:
disable:
- if: IDF_TARGET in ["esp32c2", "esp32c6", "esp32h2"]
- if: IDF_TARGET in ["esp32c2", "esp32h2"]
temporary: true
reason: target(s) not supported yet

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
# Light Sleep Example

View File

@ -12,7 +12,8 @@
/* Most development boards have "boot" button attached to GPIO0.
* You can also change this to another pin.
*/
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H4
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H4 \
|| CONFIG_IDF_TARGET_ESP32C6
#define BOOT_BUTTON_NUM 9
#else
#define BOOT_BUTTON_NUM 0

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import logging
@ -13,6 +13,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.generic
def test_light_sleep(dut: Dut) -> None:

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -27,6 +27,7 @@
#include "cmd_system.h"
#include "wifi_cmd.h"
#include "esp_wifi_he.h"
#include "esp_pm.h"
/*******************************************************
* Constants
@ -244,10 +245,7 @@ void app_main(void)
}
// TODO: WIFI-5150
#if CONFIG_PM_ENABLE
io_toggle_pmu_internal_signal_map_to_io_init();
io_toggle_gpio_init();
#if CONFIG_PM_ENABLE && 0
sleep_clock_system_retention_init();
sleep_clock_modem_retention_init();
sleep_peripheral_retention_init();

View File

@ -105,6 +105,8 @@ void app_main(void)
esp_pm_config_esp32s3_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32C2
esp_pm_config_esp32c2_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32C6
esp_pm_config_esp32c6_t pm_config = {
#endif
.max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
.min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,

View File

@ -156,3 +156,4 @@ components/espcoredump/include/port/xtensa/esp_core_dump_summary_port.h
components/riscv/include/esp_private/panic_reason.h
components/riscv/include/riscv/interrupt.h
components/riscv/include/riscv/rvruntime-frames.h
components/riscv/include/riscv/rvsleep-frames.h