Skip to content

Commit 9529c4e

Browse files
fix(esp_hw_support): fix mmu memory powered down issue by software backup and restore mmu table content
squash! fix(esp_hw_support): fix mmu memory powered down issue by software backup and restore mmu table content
1 parent a30ed69 commit 9529c4e

File tree

4 files changed

+171
-1
lines changed

4 files changed

+171
-1
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stddef.h>
8+
#include <string.h>
9+
#include <inttypes.h>
10+
11+
#include "esp_attr.h"
12+
#include "esp_check.h"
13+
#include "esp_sleep.h"
14+
#include "esp_log.h"
15+
#include "esp_heap_caps.h"
16+
#include "soc/soc_caps.h"
17+
#include "sdkconfig.h"
18+
#include "soc/spi_mem_reg.h"
19+
#include "esp_private/startup_internal.h"
20+
21+
static const char *TAG = "sleep_mmu";
22+
23+
typedef struct {
24+
uint32_t start;
25+
uint32_t end;
26+
} mmu_domain_dev_regs_region_t;
27+
28+
typedef struct {
29+
mmu_domain_dev_regs_region_t *region;
30+
int region_num;
31+
uint32_t *regs_frame;
32+
} mmu_domain_dev_sleep_frame_t;
33+
34+
/**
35+
* Internal structure which holds all requested light sleep mmu retention parameters
36+
*/
37+
typedef struct {
38+
struct {
39+
mmu_domain_dev_sleep_frame_t *mmu_table_frame;
40+
} retent;
41+
} sleep_mmu_retention_t;
42+
43+
static DRAM_ATTR __attribute__((unused)) sleep_mmu_retention_t s_mmu_retention;
44+
45+
static void * mmu_domain_dev_sleep_frame_alloc_and_init(const mmu_domain_dev_regs_region_t *regions, const int region_num)
46+
{
47+
const int region_sz = sizeof(mmu_domain_dev_regs_region_t) * region_num;
48+
int regs_frame_sz = 0;
49+
for (int num = 0; num < region_num; num++) {
50+
regs_frame_sz += regions[num].end - regions[num].start;
51+
}
52+
void *frame = heap_caps_malloc(sizeof(mmu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
53+
if (frame) {
54+
mmu_domain_dev_regs_region_t *region = (mmu_domain_dev_regs_region_t *)(frame + sizeof(mmu_domain_dev_sleep_frame_t));
55+
memcpy(region, regions, region_num * sizeof(mmu_domain_dev_regs_region_t));
56+
void *regs_frame = frame + sizeof(mmu_domain_dev_sleep_frame_t) + region_sz;
57+
memset(regs_frame, 0, regs_frame_sz);
58+
*(mmu_domain_dev_sleep_frame_t *)frame = (mmu_domain_dev_sleep_frame_t) {
59+
.region = region,
60+
.region_num = region_num,
61+
.regs_frame = (uint32_t *)regs_frame
62+
};
63+
}
64+
return frame;
65+
}
66+
67+
static inline void * mmu_domain_mmu_table_sleep_frame_alloc_and_init(void)
68+
{
69+
#define MMU_TABLE_SIZE (512 * 4)
70+
const static mmu_domain_dev_regs_region_t regions[] = {
71+
{ .start = SPI_MEM_MMU_ITEM_CONTENT_REG(0), .end = SPI_MEM_MMU_ITEM_CONTENT_REG(0) + MMU_TABLE_SIZE}
72+
};
73+
return mmu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
74+
}
75+
76+
static IRAM_ATTR void mmu_domain_dev_regs_save(mmu_domain_dev_sleep_frame_t *frame)
77+
{
78+
assert(frame);
79+
mmu_domain_dev_regs_region_t *region = frame->region;
80+
uint32_t *regs_frame = frame->regs_frame;
81+
82+
int offset = 0;
83+
for (int i = 0; i < frame->region_num; i++) {
84+
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
85+
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset);
86+
regs_frame[offset++] = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0));
87+
}
88+
}
89+
}
90+
91+
static IRAM_ATTR void mmu_domain_dev_regs_restore(mmu_domain_dev_sleep_frame_t *frame)
92+
{
93+
assert(frame);
94+
mmu_domain_dev_regs_region_t *region = frame->region;
95+
uint32_t *regs_frame = frame->regs_frame;
96+
97+
int offset = 0;
98+
for (int i = 0; i < frame->region_num; i++) {
99+
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
100+
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset);
101+
REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0),regs_frame[offset++]);
102+
}
103+
}
104+
}
105+
106+
IRAM_ATTR void esp_sleep_mmu_retention(bool backup_or_restore)
107+
{
108+
if (backup_or_restore) {
109+
mmu_domain_dev_regs_save(s_mmu_retention.retent.mmu_table_frame);
110+
} else {
111+
mmu_domain_dev_regs_restore(s_mmu_retention.retent.mmu_table_frame);
112+
}
113+
}
114+
115+
static esp_err_t esp_sleep_mmu_retention_deinit_impl(void)
116+
{
117+
if (s_mmu_retention.retent.mmu_table_frame) {
118+
heap_caps_free((void *)s_mmu_retention.retent.mmu_table_frame);
119+
s_mmu_retention.retent.mmu_table_frame = NULL;
120+
}
121+
return ESP_OK;
122+
}
123+
124+
static esp_err_t esp_sleep_mmu_retention_init_impl(void)
125+
{
126+
if (s_mmu_retention.retent.mmu_table_frame == NULL) {
127+
void *frame = mmu_domain_mmu_table_sleep_frame_alloc_and_init();
128+
if (frame == NULL) {
129+
goto err;
130+
}
131+
s_mmu_retention.retent.mmu_table_frame = (mmu_domain_dev_sleep_frame_t *)frame;
132+
}
133+
return ESP_OK;
134+
err:
135+
esp_sleep_mmu_retention_deinit();
136+
return ESP_ERR_NO_MEM;
137+
}
138+
139+
esp_err_t esp_sleep_mmu_retention_init(void)
140+
{
141+
return esp_sleep_mmu_retention_init_impl();
142+
}
143+
144+
esp_err_t esp_sleep_mmu_retention_deinit(void)
145+
{
146+
return esp_sleep_mmu_retention_deinit_impl();
147+
}
148+
149+
bool mmu_domain_pd_allowed(void)
150+
{
151+
return (s_mmu_retention.retent.mmu_table_frame != NULL);
152+
}
153+
154+
ESP_SYSTEM_INIT_FN(sleep_mmu_startup_init, SECONDARY, BIT(0), 108)
155+
{
156+
esp_err_t ret;
157+
ret = esp_sleep_mmu_retention_init();
158+
if (ret != ESP_OK) {
159+
ESP_EARLY_LOGW(TAG, "Failed to enable TOP power down during light sleep.");
160+
}
161+
return ESP_OK;
162+
}

components/esp_hw_support/sleep_modes.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@
189189
#endif
190190

191191
#if SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
192+
#if CONFIG_IDF_TARGET_ESP32C61
193+
#define SLEEP_MMU_TABLE_RETENTION_OVERHEAD_US (1232)
194+
#elif CONFIG_IDF_TARGET_ESP32C5
192195
#define SLEEP_MMU_TABLE_RETENTION_OVERHEAD_US (1220)
193196
#endif
194197
#endif

components/esp_system/system_init_fn.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/p
8787
SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32p4/sleep_clock.c on BIT(0)
8888
SECONDARY: 107: sleep_sys_periph_startup_init in components/esp_hw_support/sleep_system_peripheral.c on BIT(0)
8989
SECONDARY: 108: sleep_mmu_startup_init in components/esp_hw_support/lowpower/port/esp32c5/sleep_mmu.c on BIT(0)
90+
SECONDARY: 108: sleep_mmu_startup_init in components/esp_hw_support/lowpower/port/esp32c61/sleep_mmu.c on BIT(0)
9091

9192
# app_trace has to be initialized before systemview
9293
SECONDARY: 115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES

components/soc/esp32c61/include/soc/Kconfig.soc_caps.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,12 +849,16 @@ config SOC_PM_CPU_RETENTION_BY_SW
849849

850850
config SOC_PM_MODEM_RETENTION_BY_REGDMA
851851
bool
852-
default n
852+
default y
853853

854854
config SOC_EXT_MEM_CACHE_TAG_IN_CPU_DOMAIN
855855
bool
856856
default y
857857

858+
config SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
859+
bool
860+
default y
861+
858862
config SOC_PM_PAU_LINK_NUM
859863
int
860864
default 4

0 commit comments

Comments
 (0)