feat(sleep): Increased/modified files for static sleep cpu retention buffer support

This commit is contained in:
Li Shuai
2025-08-27 09:51:51 +08:00
parent b43f0ddc70
commit d208a27ef5
20 changed files with 1915 additions and 785 deletions

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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -17,13 +17,8 @@
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "soc/soc_caps.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 "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h" #include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h" #include "esp_private/sleep_cpu.h"
@@ -33,38 +28,16 @@
#include "esp32c5/rom/rtc.h" #include "esp32c5/rom/rtc.h"
#include "esp32c5/rom/cache.h" #include "esp32c5/rom/cache.h"
#include "rvsleep-frames.h" #include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h" #include "esp_private/system_internal.h"
#include "hal/uart_hal.h" #include "hal/uart_hal.h"
#endif #endif
static __attribute__((unused)) const char *TAG = "sleep"; 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; static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_MTVT (0x307) #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; 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) FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{ {
return RV_READ_MSTATUS_AND_DISABLE_INTR(); 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) 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) 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) 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 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
@@ -17,13 +18,8 @@
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "soc/soc_caps.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 "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h" #include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h" #include "esp_private/sleep_cpu.h"
@@ -33,41 +29,13 @@
#include "esp32c6/rom/rtc.h" #include "esp32c6/rom/rtc.h"
#include "esp32c6/rom/cache.h" #include "esp32c6/rom/cache.h"
#include "rvsleep-frames.h" #include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h" #include "esp_private/system_internal.h"
#include "hal/uart_hal.h" #include "hal/uart_hal.h"
#endif #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_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1 #define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2 #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_HWLP 0x7f1
#define CUSTOM_CSR_CO_AIA 0x7f2 #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) static __attribute__((unused)) const char *TAG = "sleep";
{
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) static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
{
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]));
}
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) 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) 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) 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) 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -17,13 +17,8 @@
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "soc/soc_caps.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 "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h" #include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h" #include "esp_private/sleep_cpu.h"
@@ -33,6 +28,7 @@
#include "esp32c61/rom/rtc.h" #include "esp32c61/rom/rtc.h"
#include "esp32c61/rom/cache.h" #include "esp32c61/rom/cache.h"
#include "rvsleep-frames.h" #include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h" #include "esp_private/system_internal.h"
@@ -41,29 +37,6 @@
static __attribute__((unused)) const char *TAG = "sleep"; 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; 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; 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) FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{ {
return RV_READ_MSTATUS_AND_DISABLE_INTR(); 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) 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) 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) 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -18,13 +18,8 @@
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "soc/soc_caps.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 "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h" #include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h" #include "esp_private/sleep_cpu.h"
@@ -33,6 +28,7 @@
#include "esp32h2/rom/rtc.h" #include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/cache.h" #include "esp32h2/rom/cache.h"
#include "rvsleep-frames.h" #include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h" #include "esp_private/system_internal.h"
@@ -41,33 +37,9 @@
static __attribute__((unused)) const char *TAG = "sleep"; 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; static DRAM_ATTR sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_PCER_MACHINE 0x7e0 #define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1 #define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2 #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; 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) FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{ {
return RV_READ_MSTATUS_AND_DISABLE_INTR(); 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) 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) 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) 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -18,7 +18,6 @@
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "soc/clic_reg.h" #include "soc/clic_reg.h"
#include "soc/rtc_periph.h" #include "soc/rtc_periph.h"
@@ -32,6 +31,7 @@
#include "esp32p4/rom/ets_sys.h" #include "esp32p4/rom/ets_sys.h"
#include "esp32p4/rom/rtc.h" #include "esp32p4/rom/rtc.h"
#include "rvsleep-frames.h" #include "rvsleep-frames.h"
#include "sleep_cpu_retention.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h" #include "esp_private/system_internal.h"
@@ -40,142 +40,16 @@
#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE #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]; static TCM_DRAM_ATTR smp_retention_state_t s_smp_retention_state[portNUM_PROCESSORS];
#endif #endif
static __attribute__((unused)) const char *TAG = "sleep"; 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; static TCM_DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; 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) FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{ {
return RV_READ_MSTATUS_AND_DISABLE_INTR(); 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) 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) 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) 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;
}