mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
fix(esp_hw_support): fix mmu memory powered down issue by software backup and restore mmu table content
This commit is contained in:
parent
4a124913c4
commit
86e384b563
@ -759,6 +759,41 @@ esp_err_t esp_sleep_cpu_retention_init(void);
|
||||
esp_err_t esp_sleep_cpu_retention_deinit(void);
|
||||
#endif // ESP_SLEEP_POWER_DOWN_CPU
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
/**
|
||||
* @brief Backup or restore the MMU when the top domain is powered down.
|
||||
* @param backup_or_restore decide to backup mmu or restore mmu
|
||||
*/
|
||||
void esp_sleep_mmu_retention(bool backup_or_restore);
|
||||
|
||||
/**
|
||||
* @brief Mmu backup initialize when power down TOP domain
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM not enough retention memory
|
||||
*/
|
||||
esp_err_t esp_sleep_mmu_retention_init(void);
|
||||
|
||||
/**
|
||||
* @brief Mmu backup de-initialize when power down TOP domain
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*
|
||||
* Release system retention memory.
|
||||
*/
|
||||
esp_err_t esp_sleep_mmu_retention_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Whether to allow the top domain to be powered off due to mmu domain requiring retention.
|
||||
*
|
||||
* In light sleep mode, only when the system can provide enough memory
|
||||
* for mmu retention, the top power domain can be powered off.
|
||||
*/
|
||||
bool mmu_domain_pd_allowed(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configure to isolate all GPIO pins in sleep state
|
||||
*/
|
||||
|
@ -16,6 +16,10 @@ if(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP OR
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD AND CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
||||
list(APPEND srcs "cpu_retention/port/${target}/sleep_mmu.c")
|
||||
endif()
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")
|
||||
|
@ -452,7 +452,6 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
|
||||
/* Minus sizeof(long) is for bypass `frame_crc` field */
|
||||
update_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
|
||||
#endif
|
||||
|
||||
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
|
||||
|
||||
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
|
||||
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
|
||||
static const char *TAG = "sleep_mmu";
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} mmu_domain_dev_regs_region_t;
|
||||
|
||||
typedef struct {
|
||||
mmu_domain_dev_regs_region_t *region;
|
||||
int region_num;
|
||||
uint32_t *regs_frame;
|
||||
} mmu_domain_dev_sleep_frame_t;
|
||||
|
||||
/**
|
||||
* Internal structure which holds all requested light sleep mmu retention parameters
|
||||
*/
|
||||
typedef struct {
|
||||
struct {
|
||||
mmu_domain_dev_sleep_frame_t *mmu_table_frame;
|
||||
} retent;
|
||||
} sleep_mmu_retention_t;
|
||||
|
||||
static DRAM_ATTR __attribute__((unused)) sleep_mmu_retention_t s_mmu_retention;
|
||||
|
||||
static void * mmu_domain_dev_sleep_frame_alloc_and_init(const mmu_domain_dev_regs_region_t *regions, const int region_num)
|
||||
{
|
||||
const int region_sz = sizeof(mmu_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(mmu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
|
||||
if (frame) {
|
||||
mmu_domain_dev_regs_region_t *region = (mmu_domain_dev_regs_region_t *)(frame + sizeof(mmu_domain_dev_sleep_frame_t));
|
||||
memcpy(region, regions, region_num * sizeof(mmu_domain_dev_regs_region_t));
|
||||
void *regs_frame = frame + sizeof(mmu_domain_dev_sleep_frame_t) + region_sz;
|
||||
memset(regs_frame, 0, regs_frame_sz);
|
||||
*(mmu_domain_dev_sleep_frame_t *)frame = (mmu_domain_dev_sleep_frame_t) {
|
||||
.region = region,
|
||||
.region_num = region_num,
|
||||
.regs_frame = (uint32_t *)regs_frame
|
||||
};
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
static inline void * mmu_domain_mmu_table_sleep_frame_alloc_and_init(void)
|
||||
{
|
||||
#define MMU_TABLE_SIZE (512 * 4)
|
||||
const static mmu_domain_dev_regs_region_t regions[] = {
|
||||
{ .start = SPI_MEM_MMU_ITEM_CONTENT_REG(0), .end = SPI_MEM_MMU_ITEM_CONTENT_REG(0) + MMU_TABLE_SIZE}
|
||||
};
|
||||
return mmu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
|
||||
}
|
||||
|
||||
static IRAM_ATTR void mmu_domain_dev_regs_save(mmu_domain_dev_sleep_frame_t *frame)
|
||||
{
|
||||
assert(frame);
|
||||
mmu_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) {
|
||||
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset);
|
||||
regs_frame[offset++] = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void mmu_domain_dev_regs_restore(mmu_domain_dev_sleep_frame_t *frame)
|
||||
{
|
||||
assert(frame);
|
||||
mmu_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) {
|
||||
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset);
|
||||
REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0),regs_frame[offset++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void esp_sleep_mmu_retention(bool backup_or_restore)
|
||||
{
|
||||
if (backup_or_restore) {
|
||||
mmu_domain_dev_regs_save(s_mmu_retention.retent.mmu_table_frame);
|
||||
} else {
|
||||
mmu_domain_dev_regs_restore(s_mmu_retention.retent.mmu_table_frame);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t esp_sleep_mmu_retention_deinit_impl(void)
|
||||
{
|
||||
if (s_mmu_retention.retent.mmu_table_frame) {
|
||||
heap_caps_free((void *)s_mmu_retention.retent.mmu_table_frame);
|
||||
s_mmu_retention.retent.mmu_table_frame = NULL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_sleep_mmu_retention_init_impl(void)
|
||||
{
|
||||
if (s_mmu_retention.retent.mmu_table_frame == NULL) {
|
||||
void *frame = mmu_domain_mmu_table_sleep_frame_alloc_and_init();
|
||||
if (frame == NULL) {
|
||||
goto err;
|
||||
}
|
||||
s_mmu_retention.retent.mmu_table_frame = (mmu_domain_dev_sleep_frame_t *)frame;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
esp_sleep_mmu_retention_deinit();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_sleep_mmu_retention_init(void)
|
||||
{
|
||||
return esp_sleep_mmu_retention_init_impl();
|
||||
}
|
||||
|
||||
esp_err_t esp_sleep_mmu_retention_deinit(void)
|
||||
{
|
||||
return esp_sleep_mmu_retention_deinit_impl();
|
||||
}
|
||||
|
||||
bool mmu_domain_pd_allowed(void)
|
||||
{
|
||||
return (s_mmu_retention.retent.mmu_table_frame != NULL);
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(sleep_mmu_startup_init, SECONDARY, BIT(0), 108)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_sleep_mmu_retention_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGW(TAG, "Failed to enable TOP power down during light sleep.");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
@ -30,7 +30,7 @@
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
static const char *TAG = "sleep";
|
||||
static const char *TAG = "sleep_gpio";
|
||||
|
||||
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
|
||||
void gpio_sleep_mode_config_apply(void)
|
||||
|
@ -181,6 +181,10 @@
|
||||
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ)
|
||||
#endif
|
||||
|
||||
#if SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
#define SLEEP_MMU_TABLE_RETENTION_OVERHEAD_US (961)
|
||||
#endif
|
||||
|
||||
// Minimal amount of time we can sleep for
|
||||
#define LIGHT_SLEEP_MIN_TIME_US 200
|
||||
|
||||
@ -1005,6 +1009,12 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
if (pd_flags & PMU_SLEEP_PD_TOP) {
|
||||
esp_sleep_mmu_retention(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_PMU_SUPPORTED
|
||||
#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU
|
||||
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0);
|
||||
@ -1024,6 +1034,11 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m
|
||||
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
|
||||
#endif
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
if (pd_flags & PMU_SLEEP_PD_TOP) {
|
||||
esp_sleep_mmu_retention(false);
|
||||
}
|
||||
#endif
|
||||
/* Unhold the SPI CS pin */
|
||||
#if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND)
|
||||
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
|
||||
@ -1343,6 +1358,10 @@ esp_err_t esp_light_sleep_start(void)
|
||||
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;
|
||||
#if SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
int sleep_time_sw_mmu_table_restore = (pd_flags & PMU_SLEEP_PD_TOP) ? SLEEP_MMU_TABLE_RETENTION_OVERHEAD_US : 0;
|
||||
s_config.sleep_time_adjustment += sleep_time_sw_mmu_table_restore;
|
||||
#endif
|
||||
#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
|
||||
@ -2126,6 +2145,9 @@ FORCE_INLINE_ATTR bool top_domain_pd_allowed(void) {
|
||||
top_pd_allowed &= cpu_domain_pd_allowed();
|
||||
#else
|
||||
top_pd_allowed = false;
|
||||
#endif
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
top_pd_allowed &= mmu_domain_pd_allowed();
|
||||
#endif
|
||||
top_pd_allowed &= clock_domain_pd_allowed();
|
||||
top_pd_allowed &= peripheral_domain_pd_allowed();
|
||||
|
@ -82,6 +82,7 @@ SECONDARY: 103: esp_security_init in components/esp_security/src/init.c on BIT(0
|
||||
SECONDARY: 105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
|
||||
SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/sleep_clock.c on BIT(0)
|
||||
SECONDARY: 107: sleep_sys_periph_startup_init in components/esp_hw_support/sleep_system_peripheral.c on BIT(0)
|
||||
SECONDARY: 108: sleep_mmu_startup_init in components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_mmu.c on BIT(0)
|
||||
|
||||
# app_trace has to be initialized before systemview
|
||||
SECONDARY: 115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES
|
||||
|
@ -1247,6 +1247,10 @@ config SOC_PM_MODEM_RETENTION_BY_REGDMA
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PM_PAU_LINK_NUM
|
||||
int
|
||||
default 5
|
||||
|
@ -560,7 +560,7 @@
|
||||
|
||||
#define SOC_PM_CPU_RETENTION_BY_SW (1)
|
||||
#define SOC_PM_MODEM_RETENTION_BY_REGDMA (1)
|
||||
// #define SOC_PM_RETENTION_HAS_CLOCK_BUG (1)
|
||||
#define SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD (1)
|
||||
|
||||
#define SOC_PM_PAU_LINK_NUM (5)
|
||||
#define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1)
|
||||
|
Loading…
Reference in New Issue
Block a user