Power Management: added protection to the configuration of each power domain

This commit is contained in:
Li Shuai
2022-12-16 11:25:55 +08:00
committed by wuzhenghui
parent 0f6cda1dd3
commit 02f5df3b3e

View File

@@ -145,7 +145,12 @@ extern void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time
* Internal structure which holds all requested deep sleep parameters * Internal structure which holds all requested deep sleep parameters
*/ */
typedef struct { 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; uint64_t sleep_duration;
uint32_t wakeup_triggers : 15; uint32_t wakeup_triggers : 15;
uint32_t ext1_trigger_mode : 1; uint32_t ext1_trigger_mode : 1;
@@ -166,7 +171,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_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 = { 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, .ccount_ticks_record = 0,
.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US,
.wakeup_triggers = 0 .wakeup_triggers = 0
@@ -686,9 +697,7 @@ static inline bool can_power_down_vddsdio(uint32_t pd_flags, const uint32_t vdds
esp_err_t esp_light_sleep_start(void) esp_err_t esp_light_sleep_start(void)
{ {
#if CONFIG_IDF_TARGET_ESP32C6 s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
return ESP_ERR_NOT_SUPPORTED; // TODO: WIFI-5150
#else
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER #if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
esp_err_t timerret = ESP_OK; esp_err_t timerret = ESP_OK;
@@ -696,9 +705,7 @@ esp_err_t esp_light_sleep_start(void)
timerret = esp_task_wdt_stop(); timerret = esp_task_wdt_stop();
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER #endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
s_config.ccount_ticks_record = esp_cpu_get_cycle_count(); portENTER_CRITICAL(&s_config.lock);
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&light_sleep_lock);
/* /*
Note: We are about to stall the other CPU via the esp_ipc_isr_stall_other_cpu(). However, there is a chance of 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. deadlock if after stalling the other CPU, we attempt to take spinlocks already held by the other CPU that is.
@@ -878,8 +885,7 @@ esp_err_t esp_light_sleep_start(void)
wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx);
} }
portEXIT_CRITICAL(&light_sleep_lock); portEXIT_CRITICAL(&s_config.lock);
s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL);
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER #if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
/* Restart the Task Watchdog timer as it was stopped before sleeping. */ /* Restart the Task Watchdog timer as it was stopped before sleeping. */
@@ -888,6 +894,7 @@ esp_err_t esp_light_sleep_start(void)
} }
#endif // CONFIG_ESP_TASK_WDT_USE_ESP_TIMER #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; return err;
#endif #endif
} }
@@ -1114,7 +1121,7 @@ static void ext1_wakeup_prepare(void)
#if SOC_PM_SUPPORT_RTC_PERIPH_PD #if SOC_PM_SUPPORT_RTC_PERIPH_PD
// Pad configuration depends on RTC_PERIPH state in sleep mode // 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 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
// RTC_PERIPH will be powered down, so RTC_IO_ registers will // RTC_PERIPH will be powered down, so RTC_IO_ registers will
// loose their state. Lock pad configuration. // loose their state. Lock pad configuration.
@@ -1336,13 +1343,20 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
#endif #endif
} }
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_t option)
esp_sleep_pd_option_t option)
{ {
if (domain >= ESP_PD_DOMAIN_MAX || option > ESP_PD_OPTION_AUTO) { if (domain >= ESP_PD_DOMAIN_MAX || option > ESP_PD_OPTION_AUTO) {
return ESP_ERR_INVALID_ARG; 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; return ESP_OK;
} }
@@ -1364,9 +1378,9 @@ static uint32_t get_power_down_flags(void)
*/ */
volatile size_t rtc_slow_mem_used = (size_t)&_rtc_slow_length; 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))) { (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 #endif
@@ -1375,27 +1389,27 @@ static uint32_t get_power_down_flags(void)
/* RTC_FAST_MEM is needed for deep sleep stub. /* 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. 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. */ 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) { if (s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option == ESP_PD_OPTION_AUTO) {
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;
} }
#else #else
/* If RTC_FAST_MEM is used for heap, force RTC_FAST_MEM to be powered on. */ /* 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
#endif #endif
#if SOC_PM_SUPPORT_RTC_PERIPH_PD #if SOC_PM_SUPPORT_RTC_PERIPH_PD
// RTC_PERIPH is needed for EXT0 wakeup and GPIO wakeup. // 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 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)) { 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 #if CONFIG_IDF_TARGET_ESP32
else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) { else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) {
// On ESP32, forcing power up of RTC_PERIPH // On ESP32, forcing power up of RTC_PERIPH
// prevents ULP timer and touch FSMs from working correctly. // 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 #endif //CONFIG_IDF_TARGET_ESP32
} }
@@ -1403,7 +1417,7 @@ static uint32_t get_power_down_flags(void)
#if SOC_PM_SUPPORT_CPU_PD #if SOC_PM_SUPPORT_CPU_PD
if (!cpu_domain_pd_allowed()) { 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 #endif
/** /**
@@ -1416,66 +1430,66 @@ static uint32_t get_power_down_flags(void)
* value of this field. * value of this field.
*/ */
#if SOC_PM_SUPPORT_VDDSDIO_PD #if SOC_PM_SUPPORT_VDDSDIO_PD
if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] == ESP_PD_OPTION_AUTO) { if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option == ESP_PD_OPTION_AUTO) {
#ifndef CONFIG_ESP_SLEEP_POWER_DOWN_FLASH #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
} }
#endif #endif
#if SOC_PM_SUPPORT_XTAL_PD #if SOC_PM_SUPPORT_XTAL_PD
#ifdef CONFIG_IDF_TARGET_ESP32 #ifdef CONFIG_IDF_TARGET_ESP32
s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF; s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option = ESP_PD_OPTION_OFF;
#endif #endif
#endif #endif
const __attribute__((unused)) char *option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */}; 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. */ /* This function is called from a critical section, log with ESP_EARLY_LOGD. */
#if SOC_PM_SUPPORT_RTC_PERIPH_PD #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]]); ESP_EARLY_LOGD(TAG, "RTC_PERIPH: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_PERIPH].pd_option]);
#endif #endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD #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]]); ESP_EARLY_LOGD(TAG, "RTC_SLOW_MEM: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option]);
#endif #endif
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD #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]]); ESP_EARLY_LOGD(TAG, "RTC_FAST_MEM: %s", option_str[s_config.domain[ESP_PD_DOMAIN_RTC_FAST_MEM].pd_option]);
#endif #endif
// Prepare flags based on the selected options // Prepare flags based on the selected options
uint32_t pd_flags = 0; uint32_t pd_flags = 0;
#if SOC_PM_SUPPORT_RTC_FAST_MEM_PD #if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
if (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_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM; pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM;
} }
#endif #endif
#if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD #if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_RTC_SLOW_MEM].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_SLOW_MEM; pd_flags |= RTC_SLEEP_PD_RTC_SLOW_MEM;
} }
#endif #endif
#if SOC_PM_SUPPORT_RTC_PERIPH_PD #if SOC_PM_SUPPORT_RTC_PERIPH_PD
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) {
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH; pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
} }
#endif #endif
#if SOC_PM_SUPPORT_CPU_PD #if SOC_PM_SUPPORT_CPU_PD
if (s_config.pd_options[ESP_PD_DOMAIN_CPU] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_CPU].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_CPU; pd_flags |= RTC_SLEEP_PD_CPU;
} }
#endif #endif
#if SOC_PM_SUPPORT_XTAL32K_PD #if SOC_PM_SUPPORT_XTAL32K_PD
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL32K] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_XTAL32K].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= PMU_SLEEP_PD_XTAL32K; pd_flags |= PMU_SLEEP_PD_XTAL32K;
} }
#endif #endif
#if SOC_PM_SUPPORT_RC32K_PD #if SOC_PM_SUPPORT_RC32K_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RC32K] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_RC32K].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= PMU_SLEEP_PD_RC32K; pd_flags |= PMU_SLEEP_PD_RC32K;
} }
#endif #endif
#if SOC_PM_SUPPORT_RC_FAST_PD #if SOC_PM_SUPPORT_RC_FAST_PD
if (s_config.pd_options[ESP_PD_DOMAIN_RC_FAST] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_RC_FAST].pd_option != ESP_PD_OPTION_ON) {
#if CONFIG_IDF_TARGET_ESP32C6 #if CONFIG_IDF_TARGET_ESP32C6
pd_flags |= PMU_SLEEP_PD_FOSC; pd_flags |= PMU_SLEEP_PD_FOSC;
#else #else
@@ -1484,12 +1498,12 @@ static uint32_t get_power_down_flags(void)
} }
#endif #endif
#if SOC_PM_SUPPORT_XTAL_PD #if SOC_PM_SUPPORT_XTAL_PD
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_XTAL; pd_flags |= RTC_SLEEP_PD_XTAL;
} }
#endif #endif
#if SOC_PM_SUPPORT_VDDSDIO_PD #if SOC_PM_SUPPORT_VDDSDIO_PD
if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] != ESP_PD_OPTION_ON) { if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option != ESP_PD_OPTION_ON) {
#if CONFIG_IDF_TARGET_ESP32C6 #if CONFIG_IDF_TARGET_ESP32C6
pd_flags |= PMU_SLEEP_PD_VDDSDIO; pd_flags |= PMU_SLEEP_PD_VDDSDIO;
#else #else