Merge branch 'feat/static_sleep_cpu_retention_buffer_support' into 'master'

Support static sleep cpu retention

See merge request espressif/esp-idf!40778
This commit is contained in:
Li Shuai
2025-08-28 09:47:59 +08:00
22 changed files with 1945 additions and 785 deletions

View File

@@ -9,6 +9,11 @@ set(srcs)
if(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP OR
(CONFIG_SOC_CPU_IN_TOP_DOMAIN AND CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP))
list(APPEND srcs "port/${target}/sleep_cpu.c")
if(CONFIG_PM_CPU_RETENTION_DYNAMIC)
list(APPEND srcs "port/${target}/sleep_cpu_dynamic.c")
elseif(CONFIG_PM_CPU_RETENTION_STATIC)
list(APPEND srcs "port/${target}/sleep_cpu_static.c")
endif()
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
list(APPEND srcs "port/${target}/sleep_cpu_asm.S")
set_property(TARGET ${COMPONENT_LIB}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,13 +17,8 @@
#include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
@@ -33,38 +28,16 @@
#include "esp32c5/rom/rtc.h"
#include "esp32c5/rom/cache.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
#include "hal/uart_hal.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 {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *clic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_MTVT (0x307)
@@ -77,127 +50,6 @@ static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
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_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CACHE_L1_CACHE_AUTOLOAD_CTRL_REG, .end = CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_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_SIP_REG + 4 },
{ .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 },
{ .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 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.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.clic_frame == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clic_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.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.clic_frame) {
heap_caps_free((void *)s_cpu_retention.retent.clic_frame);
s_cpu_retention.retent.clic_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;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
@@ -468,12 +320,12 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention);
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention);
}
bool cpu_domain_pd_allowed(void)

View File

@@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "esp_sleep.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
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_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CACHE_L1_CACHE_AUTOLOAD_CTRL_REG, .end = CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_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_SIP_REG + 4 },
{ .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 },
{ .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 4 },
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->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;
}
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clic_frame == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame);
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame);
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.cache_config_frame);
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clic_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clic_frame);
sleep_cpu_retention_ptr->retent.clic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clint_frame);
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SLEEP_CPU_RETENTION_H__
#define __SLEEP_CPU_RETENTION_H__
#include "rvsleep-frames.h"
#include "esp_err.h"
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 {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *clic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */

View File

@@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2)
#define _R_CONCAT(s1, s2) s1 ## s2
#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0)
#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1)
#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2)
#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3)
#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4)
#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5)
#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6)
#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7)
#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n))
#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t))
#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0)
#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1)
#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2)
#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3)
#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4)
#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5)
#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6)
#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7)
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
static void * cpu_domain_dev_sleep_frame_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame)
{
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;
}
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;
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#define CPU_DOMAIN_DEV_START_ADDR0 (CACHE_L1_CACHE_AUTOLOAD_CTRL_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_REG + 4)
static void * cache_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
};
static uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(1)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#undef CPU_DOMAIN_DEV_START_ADDR2
#undef CPU_DOMAIN_DEV_END_ADDR2
#undef CPU_DOMAIN_DEV_START_ADDR3
#undef CPU_DOMAIN_DEV_END_ADDR3
#define CPU_DOMAIN_DEV_START_ADDR0 (CLINT_MINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLINT_MINT_SIP_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLINT_MINT_MTIMECMP_L_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (CLINT_MINT_MTIMECMP_H_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR2 (CLINT_MINT_TIMECTL_REG)
#define CPU_DOMAIN_DEV_END_ADDR2 (CLINT_MINT_TIMECTL_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR3 (CLINT_MINT_MTIME_L_REG)
#define CPU_DOMAIN_DEV_END_ADDR3 (CLINT_MINT_MTIME_H_REG + 4)
static void * clint_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_SIP_REG + 4 },
{ .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 },
{ .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }
};
static uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (CLIC_INT_CONFIG_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLIC_INT_THRESH_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLIC_INT_CTRL_REG(0))
#define CPU_DOMAIN_DEV_END_ADDR1 (CLIC_INT_CTRL_REG(47) + 4)
static void * clic_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
};
static uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame == NULL) {
static uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
static uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *) rv_core_non_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cache_sleep_frame_init();
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clic_frame == NULL) {
void *frame = clic_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = clint_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clic_frame) {
sleep_cpu_retention_ptr->retent.clic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -1,9 +1,10 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
@@ -17,13 +18,8 @@
#include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
@@ -33,41 +29,13 @@
#include "esp32c6/rom/rtc.h"
#include "esp32c6/rom/cache.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
#include "hal/uart_hal.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 {
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;
} sleep_cpu_retention_t;
static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
@@ -82,148 +50,11 @@ static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#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 __attribute__((unused)) const char *TAG = "sleep";
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 DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = EXTMEM_L1_CACHE_CTRL_REG, .end = EXTMEM_L1_CACHE_CTRL_REG + 4 },
{ .start = EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = EXTMEM_L1_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;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
@@ -512,12 +343,12 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention);
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention);
}
bool cpu_domain_pd_allowed(void)

View File

@@ -0,0 +1,160 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "esp_sleep.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
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_L1_CACHE_CTRL_REG, .end = EXTMEM_L1_CACHE_CTRL_REG + 4 },
{ .start = EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = EXTMEM_L1_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]));
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->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;
}
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame == NULL) {
void *frame = cpu_domain_intpri_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.plic_frame == NULL) {
void *frame = cpu_domain_plic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t * sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame);
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame);
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.intpri_frame);
sleep_cpu_retention_ptr->retent.intpri_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.cache_config_frame);
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.plic_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.plic_frame);
sleep_cpu_retention_ptr->retent.plic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clint_frame);
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SLEEP_CPU_RETENTION_H__
#define __SLEEP_CPU_RETENTION_H__
#include "rvsleep-frames.h"
#include "esp_err.h"
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 {
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;
} sleep_cpu_retention_t;
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */

View File

@@ -0,0 +1,207 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2)
#define _R_CONCAT(s1, s2) s1 ## s2
#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0)
#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1)
#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2)
#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3)
#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4)
#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5)
#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6)
#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7)
#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n))
#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t))
#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0)
#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1)
#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2)
#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3)
#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4)
#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5)
#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6)
#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7)
static void * cpu_domain_dev_sleep_frame_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame)
{
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;
}
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;
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (INTPRI_CORE0_CPU_INT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (INTPRI_RND_ECO_LOW_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (INTPRI_RND_ECO_HIGH_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (INTPRI_RND_ECO_HIGH_REG + 4)
static void * intpri_sleep_frame_init(void)
{
static const cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (EXTMEM_L1_CACHE_CTRL_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (EXTMEM_L1_CACHE_CTRL_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG + 4)
static void * cache_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#undef CPU_DOMAIN_DEV_START_ADDR2
#undef CPU_DOMAIN_DEV_END_ADDR2
#undef CPU_DOMAIN_DEV_START_ADDR3
#undef CPU_DOMAIN_DEV_END_ADDR3
#define CPU_DOMAIN_DEV_START_ADDR0 (PLIC_MXINT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (PLIC_MXINT_CLAIM_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (PLIC_MXINT_CONF_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (PLIC_MXINT_CONF_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR2 (PLIC_UXINT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR2 (PLIC_UXINT_CLAIM_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR3 (PLIC_UXINT_CONF_REG)
#define CPU_DOMAIN_DEV_END_ADDR3 (PLIC_UXINT_CONF_REG + 4)
static void * plic_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
{ .start = CPU_DOMAIN_DEV_START_ADDR2, .end = CPU_DOMAIN_DEV_END_ADDR2 },
{ .start = CPU_DOMAIN_DEV_START_ADDR3, .end = CPU_DOMAIN_DEV_END_ADDR3 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (CLINT_MINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLINT_MINT_MTIMECMP_H_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLINT_UINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (CLINT_UINT_UTIMECMP_H_REG + 4)
static void * clint_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *) rv_core_non_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame == NULL) {
void *frame = intpri_sleep_frame_init();
sleep_cpu_retention_ptr->retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cache_sleep_frame_init();
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.plic_frame == NULL) {
void *frame = plic_sleep_frame_init();
sleep_cpu_retention_ptr->retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = clint_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame) {
sleep_cpu_retention_ptr->retent.intpri_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.plic_frame) {
sleep_cpu_retention_ptr->retent.plic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,13 +17,8 @@
#include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
@@ -33,6 +28,7 @@
#include "esp32c61/rom/rtc.h"
#include "esp32c61/rom/cache.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
@@ -41,29 +37,6 @@
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 {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *clic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
@@ -77,127 +50,6 @@ static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
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_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CACHE_L1_CACHE_AUTOLOAD_CTRL_REG, .end = CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_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_SIP_REG + 4 },
{ .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 },
{ .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 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.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.clic_frame == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clic_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.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.clic_frame) {
heap_caps_free((void *)s_cpu_retention.retent.clic_frame);
s_cpu_retention.retent.clic_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;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
@@ -468,12 +320,12 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention);
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention);
}
bool cpu_domain_pd_allowed(void)

View File

@@ -0,0 +1,141 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "esp_sleep.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
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_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CACHE_L1_CACHE_AUTOLOAD_CTRL_REG, .end = CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_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_SIP_REG + 4 },
{ .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 },
{ .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 4 },
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->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;
}
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clic_frame == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame);
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame);
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.cache_config_frame);
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clic_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clic_frame);
sleep_cpu_retention_ptr->retent.clic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clint_frame);
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SLEEP_CPU_RETENTION_H__
#define __SLEEP_CPU_RETENTION_H__
#include "rvsleep-frames.h"
#include "esp_err.h"
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 {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *clic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */

View File

@@ -0,0 +1,176 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2)
#define _R_CONCAT(s1, s2) s1 ## s2
#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0)
#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1)
#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2)
#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3)
#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4)
#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5)
#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6)
#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7)
#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n))
#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t))
#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0)
#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1)
#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2)
#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3)
#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4)
#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5)
#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6)
#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7)
static void * cpu_domain_dev_sleep_frame_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame)
{
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;
}
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;
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#define CPU_DOMAIN_DEV_START_ADDR0 (CACHE_L1_CACHE_AUTOLOAD_CTRL_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CACHE_L1_CACHE_AUTOLOAD_SCT1_SIZE_REG + 4)
static void * cache_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(1)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#undef CPU_DOMAIN_DEV_START_ADDR2
#undef CPU_DOMAIN_DEV_END_ADDR2
#undef CPU_DOMAIN_DEV_START_ADDR3
#undef CPU_DOMAIN_DEV_END_ADDR3
#define CPU_DOMAIN_DEV_START_ADDR0 (CLINT_MINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLINT_MINT_SIP_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLINT_MINT_MTIMECMP_L_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (CLINT_MINT_MTIMECMP_H_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR2 (CLINT_MINT_TIMECTL_REG)
#define CPU_DOMAIN_DEV_END_ADDR2 (CLINT_MINT_TIMECTL_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR3 (CLINT_MINT_MTIME_L_REG)
#define CPU_DOMAIN_DEV_END_ADDR3 (CLINT_MINT_MTIME_H_REG + 4)
static void * clint_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
{ .start = CPU_DOMAIN_DEV_START_ADDR2, .end = CPU_DOMAIN_DEV_END_ADDR2 },
{ .start = CPU_DOMAIN_DEV_START_ADDR3, .end = CPU_DOMAIN_DEV_END_ADDR3 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (CLIC_INT_CONFIG_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLIC_INT_THRESH_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLIC_INT_CTRL_REG(0))
#define CPU_DOMAIN_DEV_END_ADDR1 (CLIC_INT_CTRL_REG(47) + 4)
static void * clic_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *)rv_core_critical_regs;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)rv_core_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *) rv_core_non_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cache_sleep_frame_init();
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clic_frame == NULL) {
void *frame = clic_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = clint_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clic_frame) {
sleep_cpu_retention_ptr->retent.clic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,13 +18,8 @@
#include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
@@ -33,6 +28,7 @@
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/cache.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
@@ -41,33 +37,9 @@
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 {
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;
} sleep_cpu_retention_t;
static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
@@ -84,146 +56,6 @@ static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
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 = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_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;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
@@ -511,12 +343,12 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention);
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention);
}
bool cpu_domain_pd_allowed(void)

View File

@@ -0,0 +1,161 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "esp_sleep.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
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 = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_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]));
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->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;
}
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame == NULL) {
void *frame = cpu_domain_intpri_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.plic_frame == NULL) {
void *frame = cpu_domain_plic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame);
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame);
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.intpri_frame);
sleep_cpu_retention_ptr->retent.intpri_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.cache_config_frame);
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.plic_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.plic_frame);
sleep_cpu_retention_ptr->retent.plic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clint_frame);
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SLEEP_CPU_RETENTION_H__
#define __SLEEP_CPU_RETENTION_H__
#include "rvsleep-frames.h"
#include "esp_err.h"
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 {
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;
} sleep_cpu_retention_t;
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */

View File

@@ -0,0 +1,204 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2)
#define _R_CONCAT(s1, s2) s1 ## s2
#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0)
#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1)
#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2)
#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3)
#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4)
#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5)
#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6)
#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7)
#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n))
#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t))
#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0)
#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1)
#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2)
#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3)
#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4)
#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5)
#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6)
#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7)
static void * cpu_domain_dev_sleep_frame_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame)
{
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;
}
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;
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (INTPRI_CORE0_CPU_INT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (INTPRI_RND_ECO_LOW_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (INTPRI_RND_ECO_HIGH_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (INTPRI_RND_ECO_HIGH_REG + 4)
static void * intpri_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#define CPU_DOMAIN_DEV_START_ADDR0 (CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4)
static void * cache_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(1)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#undef CPU_DOMAIN_DEV_START_ADDR2
#undef CPU_DOMAIN_DEV_END_ADDR2
#undef CPU_DOMAIN_DEV_START_ADDR3
#undef CPU_DOMAIN_DEV_END_ADDR3
#define CPU_DOMAIN_DEV_START_ADDR0 (PLIC_MXINT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (PLIC_MXINT_CLAIM_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (PLIC_MXINT_CONF_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (PLIC_MXINT_CONF_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR2 (PLIC_UXINT_ENABLE_REG)
#define CPU_DOMAIN_DEV_END_ADDR2 (PLIC_UXINT_CLAIM_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR3 (PLIC_UXINT_CONF_REG)
#define CPU_DOMAIN_DEV_END_ADDR3 (PLIC_UXINT_CONF_REG + 4)
static void * plic_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
{ .start = CPU_DOMAIN_DEV_START_ADDR2, .end = CPU_DOMAIN_DEV_END_ADDR2 },
{ .start = CPU_DOMAIN_DEV_START_ADDR3, .end = CPU_DOMAIN_DEV_END_ADDR3 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (CLINT_MINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLINT_MINT_MTIMECMP_H_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLINT_UINT_SIP_REG)
#define CPU_DOMAIN_DEV_END_ADDR1 (CLINT_UINT_UTIMECMP_H_REG + 4)
static void * clint_sleep_frame_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }
};
static DRAM_ATTR uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame);
}
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.critical_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *) rv_core_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame == NULL) {
static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)] __attribute__((aligned(4)));
sleep_cpu_retention_ptr->retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *) rv_core_non_critical_regs;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame == NULL) {
void *frame = intpri_sleep_frame_init();
sleep_cpu_retention_ptr->retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) {
void *frame = cache_sleep_frame_init();
sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.plic_frame == NULL) {
void *frame = plic_sleep_frame_init();
sleep_cpu_retention_ptr->retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (sleep_cpu_retention_ptr->retent.clint_frame == NULL) {
void *frame = clint_sleep_frame_init();
sleep_cpu_retention_ptr->retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
if (sleep_cpu_retention_ptr->retent.critical_frame) {
sleep_cpu_retention_ptr->retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame) {
sleep_cpu_retention_ptr->retent.non_critical_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.intpri_frame) {
sleep_cpu_retention_ptr->retent.intpri_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.cache_config_frame) {
sleep_cpu_retention_ptr->retent.cache_config_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.plic_frame) {
sleep_cpu_retention_ptr->retent.plic_frame = NULL;
}
if (sleep_cpu_retention_ptr->retent.clint_frame) {
sleep_cpu_retention_ptr->retent.clint_frame = NULL;
}
return ESP_OK;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,7 +18,6 @@
#include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/clic_reg.h"
#include "soc/rtc_periph.h"
@@ -32,6 +31,7 @@
#include "esp32p4/rom/ets_sys.h"
#include "esp32p4/rom/rtc.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
@@ -40,142 +40,16 @@
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
#include <stdatomic.h>
#include "soc/hp_system_reg.h"
typedef enum {
SMP_IDLE,
SMP_BACKUP_START,
SMP_BACKUP_DONE,
SMP_RESTORE_START,
SMP_RESTORE_DONE,
SMP_SKIP_RETENTION,
} smp_retention_state_t;
static TCM_DRAM_ATTR smp_retention_state_t s_smp_retention_state[portNUM_PROCESSORS];
#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 {
struct {
RvCoreCriticalSleepFrame *critical_frame[portNUM_PROCESSORS];
RvCoreNonCriticalSleepFrame *non_critical_frame[portNUM_PROCESSORS];
cpu_domain_dev_sleep_frame_t *clic_frame[portNUM_PROCESSORS];
} retent;
} sleep_cpu_retention_t;
static TCM_DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS];
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_clic_sleep_frame_alloc_and_init(uint8_t core_id)
{
const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][2] = {
[0 ... portNUM_PROCESSORS - 1] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 4 },
}
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t));
}
static esp_err_t esp_sleep_cpu_retention_init_impl(void)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (s_cpu_retention.retent.critical_frame[core_id] == 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[core_id] = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.non_critical_frame[core_id] == 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[core_id] = (RvCoreNonCriticalSleepFrame *)frame;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (s_cpu_retention.retent.clic_frame[core_id] == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame;
}
}
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
atomic_init(&s_smp_retention_state[core_id], SMP_IDLE);
}
#endif
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)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (s_cpu_retention.retent.critical_frame[core_id]) {
heap_caps_free((void *)s_cpu_retention.retent.critical_frame[core_id]);
s_cpu_retention.retent.critical_frame[core_id] = NULL;
rv_core_critical_regs_frame[core_id] = NULL;
}
if (s_cpu_retention.retent.non_critical_frame[core_id]) {
heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame[core_id]);
s_cpu_retention.retent.non_critical_frame[core_id] = NULL;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (s_cpu_retention.retent.clic_frame[core_id]) {
heap_caps_free((void *)s_cpu_retention.retent.clic_frame[core_id]);
s_cpu_retention.retent.clic_frame[core_id] = NULL;
}
}
return ESP_OK;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
@@ -457,12 +331,16 @@ esp_err_t TCM_IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t,
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention, s_smp_retention_state);
#else
return esp_sleep_cpu_retention_init_impl(& s_cpu_retention);
#endif
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention);
}
bool cpu_domain_pd_allowed(void)

View File

@@ -0,0 +1,146 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/clic_reg.h"
#include "esp_sleep.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS];
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_clic_sleep_frame_alloc_and_init(uint8_t core_id)
{
const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][2] = {
[0 ... portNUM_PROCESSORS - 1] = {
{ .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 },
{ .start = CLIC_INT_CTRL_REG(0), .end = CLIC_INT_CTRL_REG(47) + 4 },
}
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t));
}
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) {
void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
atomic_init(&s_smp_retention_state[core_id], SMP_IDLE);
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
#else
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) {
void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id);
if (frame == NULL) {
goto err;
}
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame;
}
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
#endif
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id]) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame[core_id]);
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = NULL;
rv_core_critical_regs_frame[core_id] = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]);
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = NULL;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id]) {
heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clic_frame[core_id]);
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = NULL;
}
}
return ESP_OK;
}

View File

@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SLEEP_CPU_RETENTION_H__
#define __SLEEP_CPU_RETENTION_H__
#include "rvsleep-frames.h"
#include "freertos/FreeRTOS.h"
#include "esp_err.h"
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
#include <stdatomic.h>
#include "soc/hp_system_reg.h"
typedef enum {
SMP_IDLE,
SMP_BACKUP_START,
SMP_BACKUP_DONE,
SMP_RESTORE_START,
SMP_RESTORE_DONE,
SMP_SKIP_RETENTION,
} smp_retention_state_t;
#endif
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 {
struct {
RvCoreCriticalSleepFrame *critical_frame[portNUM_PROCESSORS];
RvCoreNonCriticalSleepFrame *non_critical_frame[portNUM_PROCESSORS];
cpu_domain_dev_sleep_frame_t *clic_frame[portNUM_PROCESSORS];
} retent;
} sleep_cpu_retention_t;
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state);
#else
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr);
#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */

View File

@@ -0,0 +1,155 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "soc/clic_reg.h"
#include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS];
#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2)
#define _R_CONCAT(s1, s2) s1 ## s2
#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0)
#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1)
#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2)
#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3)
#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4)
#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5)
#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6)
#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7)
#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n))
#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t))
#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0)
#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1)
#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2)
#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3)
#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4)
#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5)
#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6)
#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7)
static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame)
{
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;
}
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;
}
#undef CPU_DOMAIN_DEV_START_ADDR0
#undef CPU_DOMAIN_DEV_END_ADDR0
#undef CPU_DOMAIN_DEV_START_ADDR1
#undef CPU_DOMAIN_DEV_END_ADDR1
#define CPU_DOMAIN_DEV_START_ADDR0 (CLIC_INT_CONFIG_REG)
#define CPU_DOMAIN_DEV_END_ADDR0 (CLIC_INT_THRESH_REG + 4)
#define CPU_DOMAIN_DEV_START_ADDR1 (CLIC_INT_CTRL_REG(0))
#define CPU_DOMAIN_DEV_END_ADDR1 (CLIC_INT_CTRL_REG(47) + 4)
static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(uint8_t core_id)
{
static DRAM_ATTR cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][2] = {
[0 ... portNUM_PROCESSORS - 1] = {
{ .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 },
{ .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 },
}
};
static DRAM_ATTR uint8_t sleep_frame[portNUM_PROCESSORS][CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4)));
return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(regions[core_id][0]), sleep_frame[core_id]);
}
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state)
{
static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ * portNUM_PROCESSORS] __attribute__((aligned(4)));
static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)* portNUM_PROCESSORS] __attribute__((aligned(4)));
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) {
void * regs = rv_core_critical_regs + core_id * RV_SLEEP_CTX_FRMSZ;
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *) regs;
rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *) regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) {
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)(rv_core_non_critical_regs+core_id * sizeof(RvCoreNonCriticalSleepFrame));
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id);
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
atomic_init(&s_smp_retention_state[core_id], SMP_IDLE);
}
return ESP_OK;
}
#else
esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ * portNUM_PROCESSORS] __attribute__((aligned(4)));
static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)* portNUM_PROCESSORS] __attribute__((aligned(4)));
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) {
void * regs = rv_core_critical_regs + core_id * RV_SLEEP_CTX_FRMSZ;
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *) regs;
rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *) regs;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) {
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)(rv_core_non_critical_regs+core_id * sizeof(RvCoreNonCriticalSleepFrame));
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) {
void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id);
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame;
}
}
return ESP_OK;
}
#endif
esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr)
{
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.critical_frame[core_id]) {
sleep_cpu_retention_ptr->retent.critical_frame[core_id] = NULL;
rv_core_critical_regs_frame[core_id] = NULL;
}
if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]) {
sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = NULL;
}
}
for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) {
if (sleep_cpu_retention_ptr->retent.clic_frame[core_id]) {
sleep_cpu_retention_ptr->retent.clic_frame[core_id] = NULL;
}
}
return ESP_OK;
}

View File

@@ -130,6 +130,31 @@ menu "Power Management"
On esp32s3 soc, enabling this option will consume 8.58 KB of internal RAM
and will reduce sleep current consumption by about 650 uA.
choice
bool "Retentive memory alloaction strategy for light sleep"
depends on SOC_PM_CPU_RETENTION_BY_SW && \
(PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP || (PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_CPU_IN_TOP_DOMAIN))
default PM_CPU_RETENTION_DYNAMIC
help
In light sleep mode, certain CPU states and data need to be preserved in memory while cpu domain
is powered down. This configuration determines how the required memory resources are allocated.
The PM_CPU_RETENTION_DYNAMIC option allows more flexible runtime memory management by
supporting access to larger memory. However, it carries the risk of insufficient memory
when the chip enters the light-sleep mode, even resulting in retention failure.
In contrast, the PM_CPU_RETENTION_STATIC option ensures reliable sleep CPU retention during the
system initialization, but reduces the memory available during runtime.
config PM_CPU_RETENTION_DYNAMIC
bool "Dynamically allocate memory"
help
Allocate memory for retention data only when preparing to enter light sleep.
config PM_CPU_RETENTION_STATIC
bool "Statically allocate memory"
help
Pre-allocate all required retention memory during system initialization.
endchoice
config PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
bool "Restore I/D-cache tag memory after power down CPU light sleep"
depends on IDF_TARGET_ESP32S3 && PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP