refactor(esp_hw_support): split pd_cpu retention initialization by target

pull/13431/head
wuzhenghui 2024-02-05 14:26:30 +08:00
rodzic 81c49583ec
commit 03e5e4970d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 3EFEDECDEBA39BB9
16 zmienionych plików z 2330 dodań i 340 usunięć

Wyświetl plik

@ -48,11 +48,6 @@ if(NOT BOOTLOADER_BUILD)
if(CONFIG_SOC_ISP_SHARE_CSI_BRG)
list(APPEND srcs "mipi_csi_share_hw_ctrl.c")
endif()
if(CONFIG_SOC_PM_SUPPORT_CPU_PD)
list(APPEND srcs "sleep_cpu.c")
endif()
if(CONFIG_SOC_PAU_SUPPORTED)
list(APPEND srcs "sleep_retention.c" "sleep_system_peripheral.c" "sleep_clock.c")
endif()
@ -132,14 +127,6 @@ if(NOT BOOTLOADER_BUILD)
"port/regdma_link.c")
endif()
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
list(APPEND srcs "sleep_cpu_asm.S")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_save")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_restore")
endif()
if(CONFIG_SOC_MODEM_CLOCK_IS_INDEPENDENT AND CONFIG_SOC_MODEM_CLOCK_SUPPORTED)
list(APPEND srcs "modem_clock.c")
endif()
@ -164,13 +151,11 @@ if(NOT BOOTLOADER_BUILD)
if(CONFIG_IDF_TARGET_ESP32P4)
list(REMOVE_ITEM srcs
"sleep_cpu.c" # TODO: IDF-7528, IDF-7529
"sleep_wake_stub.c" # TODO: IDF-7529
)
endif()
if(CONFIG_IDF_TARGET_ESP32C5)
list(REMOVE_ITEM srcs
"sleep_cpu.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_modes.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_wake_stub.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
"sleep_gpio.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
@ -191,6 +176,7 @@ idf_component_register(SRCS ${srcs}
idf_build_get_property(target IDF_TARGET)
add_subdirectory(port/${target})
add_subdirectory(lowpower)
if(NOT BOOTLOADER_BUILD)
if(CONFIG_SPIRAM)

Wyświetl plik

@ -0,0 +1,25 @@
if(BOOTLOADER_BUILD)
return()
endif()
set(srcs)
if(CONFIG_SOC_PM_SUPPORT_CPU_PD)
list(APPEND srcs "cpu_retention/port/${target}/sleep_cpu.c")
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
list(APPEND srcs "cpu_retention/port/${target}/sleep_cpu_asm.S")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_save")
set_property(TARGET ${COMPONENT_LIB}
APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u rv_core_critical_regs_restore")
endif()
endif()
if(CONFIG_IDF_TARGET_ESP32C5)
list(REMOVE_ITEM srcs "cpu_retention/port/${target}/sleep_cpu.c" # TODO: [ESP32C5] IDF-8638, IDF-8640
)
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")

Wyświetl plik

@ -0,0 +1,113 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "hal/rtc_hal.h"
#include "soc/rtc_periph.h"
#include "soc/soc_caps.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/sleep_event.h"
#include "sdkconfig.h"
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 {
rtc_cntl_sleep_retent_t retent;
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
esp_err_t esp_sleep_cpu_pd_low_init(void)
{
if (s_cpu_retention.retent.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, 1,
SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_pd_low_deinit(void)
{
if (s_cpu_retention.retent.cpu_pd_mem) {
heap_caps_free(s_cpu_retention.retent.cpu_pd_mem);
s_cpu_retention.retent.cpu_pd_mem = NULL;
}
return ESP_OK;
}
void sleep_enable_cpu_retention(void)
{
rtc_cntl_hal_enable_cpu_retention(&s_cpu_retention.retent);
}
void IRAM_ATTR sleep_disable_cpu_retention(void)
{
rtc_cntl_hal_disable_cpu_retention(&s_cpu_retention.retent);
}
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_pd_low_init();
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_pd_low_deinit();
}
bool cpu_domain_pd_allowed(void)
{
return (s_cpu_retention.retent.cpu_pd_mem != NULL);
}
esp_err_t sleep_cpu_configure(bool light_sleep_enable)
{
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
if (light_sleep_enable) {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep.");
} else {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_deinit(), TAG, "Failed to release CPU retention memory");
}
#endif
return ESP_OK;
}

Wyświetl plik

@ -138,7 +138,6 @@ STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3)
#if SOC_CPU_HAS_PMA
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR0, pmaaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR1, pmaaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR2, pmaaddr2)
@ -171,7 +170,6 @@ STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG13, pmacfg13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG14, pmacfg14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG15, pmacfg15)
#endif // SOC_CPU_HAS_PMA
STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec)
STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus)

Wyświetl plik

@ -0,0 +1,544 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/sleep_event.h"
#include "sdkconfig.h"
#include "esp32c5/rom/rtc.h"
#include "esp32c5/rom/cache.h"
#include "rvsleep-frames.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
#include "hal/clk_gate_ll.h"
#include "hal/uart_hal.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep";
typedef struct {
uint32_t start;
uint32_t end;
} cpu_domain_dev_regs_region_t;
typedef struct {
cpu_domain_dev_regs_region_t *region;
int region_num;
uint32_t *regs_frame;
} cpu_domain_dev_sleep_frame_t;
/**
* Internal structure which holds all requested light sleep cpu retention parameters
*/
typedef struct {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *intpri_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *plic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
#define CUSTOM_CSR_CPU_TESTBUS_CTRL 0x7e3
#define CUSTOM_CSR_PCER_USER 0x800
#define CUSTOM_CSR_PCMR_USER 0x801
#define CUSTOM_CSR_PCCR_USER 0x802
#define CUSTOM_CSR_GPIO_OEN_USER 0x803
#define CUSTOM_CSR_GPIO_IN_USER 0x804
#define CUSTOM_CSR_GPIO_OUT_USER 0x805
#define CUSTOM_CSR_CO_EXCEPTION_CAUSE 0x7f0
#define CUSTOM_CSR_CO_HWLP 0x7f1
#define CUSTOM_CSR_CO_AIA 0x7f2
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num)
{
const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num;
int regs_frame_sz = 0;
for (int num = 0; num < region_num; num++) {
regs_frame_sz += regions[num].end - regions[num].start;
}
void *frame = heap_caps_malloc(sizeof(cpu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame) {
cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t));
memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t));
void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz;
memset(regs_frame, 0, regs_frame_sz);
*(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) {
.region = region,
.region_num = region_num,
.regs_frame = (uint32_t *)regs_frame
};
}
return frame;
}
static 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_CTRL_REG, .end = CACHE_L1_CACHE_CTRL_REG + 4 },
{ .start = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_plic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = PLIC_MXINT_ENABLE_REG, .end = PLIC_MXINT_CLAIM_REG + 4 },
{ .start = PLIC_MXINT_CONF_REG, .end = PLIC_MXINT_CONF_REG + 4 },
{ .start = PLIC_UXINT_ENABLE_REG, .end = PLIC_UXINT_CLAIM_REG + 4 },
{ .start = PLIC_UXINT_CONF_REG, .end = PLIC_UXINT_CONF_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clint_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_UINT_SIP_REG, .end = CLINT_UINT_UTIMECMP_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static esp_err_t esp_sleep_cpu_retention_init_impl(void)
{
if (s_cpu_retention.retent.critical_frame == NULL) {
void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.intpri_frame == NULL) {
void *frame = cpu_domain_intpri_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.plic_frame == NULL) {
void *frame = cpu_domain_plic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
static esp_err_t esp_sleep_cpu_retention_deinit_impl(void)
{
if (s_cpu_retention.retent.critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.critical_frame);
s_cpu_retention.retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (s_cpu_retention.retent.non_critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame);
s_cpu_retention.retent.non_critical_frame = NULL;
}
if (s_cpu_retention.retent.intpri_frame) {
heap_caps_free((void *)s_cpu_retention.retent.intpri_frame);
s_cpu_retention.retent.intpri_frame = NULL;
}
if (s_cpu_retention.retent.cache_config_frame) {
heap_caps_free((void *)s_cpu_retention.retent.cache_config_frame);
s_cpu_retention.retent.cache_config_frame = NULL;
}
if (s_cpu_retention.retent.plic_frame) {
heap_caps_free((void *)s_cpu_retention.retent.plic_frame);
s_cpu_retention.retent.plic_frame = NULL;
}
if (s_cpu_retention.retent.clint_frame) {
heap_caps_free((void *)s_cpu_retention.retent.clint_frame);
s_cpu_retention.retent.clint_frame = NULL;
}
return ESP_OK;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
}
FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val)
{
RV_WRITE_CSR(mstatus, mstatus_val);
}
static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void)
{
assert(s_cpu_retention.retent.non_critical_frame);
RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame;
frame->mscratch = RV_READ_CSR(mscratch);
frame->mideleg = RV_READ_CSR(mideleg);
frame->misa = RV_READ_CSR(misa);
frame->tselect = RV_READ_CSR(tselect);
frame->tdata1 = RV_READ_CSR(tdata1);
frame->tdata2 = RV_READ_CSR(tdata2);
frame->tcontrol = RV_READ_CSR(tcontrol);
frame->pmpaddr0 = RV_READ_CSR(pmpaddr0);
frame->pmpaddr1 = RV_READ_CSR(pmpaddr1);
frame->pmpaddr2 = RV_READ_CSR(pmpaddr2);
frame->pmpaddr3 = RV_READ_CSR(pmpaddr3);
frame->pmpaddr4 = RV_READ_CSR(pmpaddr4);
frame->pmpaddr5 = RV_READ_CSR(pmpaddr5);
frame->pmpaddr6 = RV_READ_CSR(pmpaddr6);
frame->pmpaddr7 = RV_READ_CSR(pmpaddr7);
frame->pmpaddr8 = RV_READ_CSR(pmpaddr8);
frame->pmpaddr9 = RV_READ_CSR(pmpaddr9);
frame->pmpaddr10 = RV_READ_CSR(pmpaddr10);
frame->pmpaddr11 = RV_READ_CSR(pmpaddr11);
frame->pmpaddr12 = RV_READ_CSR(pmpaddr12);
frame->pmpaddr13 = RV_READ_CSR(pmpaddr13);
frame->pmpaddr14 = RV_READ_CSR(pmpaddr14);
frame->pmpaddr15 = RV_READ_CSR(pmpaddr15);
frame->pmpcfg0 = RV_READ_CSR(pmpcfg0);
frame->pmpcfg1 = RV_READ_CSR(pmpcfg1);
frame->pmpcfg2 = RV_READ_CSR(pmpcfg2);
frame->pmpcfg3 = RV_READ_CSR(pmpcfg3);
frame->pmaaddr0 = RV_READ_CSR(CSR_PMAADDR(0));
frame->pmaaddr1 = RV_READ_CSR(CSR_PMAADDR(1));
frame->pmaaddr2 = RV_READ_CSR(CSR_PMAADDR(2));
frame->pmaaddr3 = RV_READ_CSR(CSR_PMAADDR(3));
frame->pmaaddr4 = RV_READ_CSR(CSR_PMAADDR(4));
frame->pmaaddr5 = RV_READ_CSR(CSR_PMAADDR(5));
frame->pmaaddr6 = RV_READ_CSR(CSR_PMAADDR(6));
frame->pmaaddr7 = RV_READ_CSR(CSR_PMAADDR(7));
frame->pmaaddr8 = RV_READ_CSR(CSR_PMAADDR(8));
frame->pmaaddr9 = RV_READ_CSR(CSR_PMAADDR(9));
frame->pmaaddr10 = RV_READ_CSR(CSR_PMAADDR(10));
frame->pmaaddr11 = RV_READ_CSR(CSR_PMAADDR(11));
frame->pmaaddr12 = RV_READ_CSR(CSR_PMAADDR(12));
frame->pmaaddr13 = RV_READ_CSR(CSR_PMAADDR(13));
frame->pmaaddr14 = RV_READ_CSR(CSR_PMAADDR(14));
frame->pmaaddr15 = RV_READ_CSR(CSR_PMAADDR(15));
frame->pmacfg0 = RV_READ_CSR(CSR_PMACFG(0));
frame->pmacfg1 = RV_READ_CSR(CSR_PMACFG(1));
frame->pmacfg2 = RV_READ_CSR(CSR_PMACFG(2));
frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(3));
frame->pmacfg4 = RV_READ_CSR(CSR_PMACFG(4));
frame->pmacfg5 = RV_READ_CSR(CSR_PMACFG(5));
frame->pmacfg6 = RV_READ_CSR(CSR_PMACFG(6));
frame->pmacfg7 = RV_READ_CSR(CSR_PMACFG(7));
frame->pmacfg8 = RV_READ_CSR(CSR_PMACFG(8));
frame->pmacfg9 = RV_READ_CSR(CSR_PMACFG(9));
frame->pmacfg10 = RV_READ_CSR(CSR_PMACFG(10));
frame->pmacfg11 = RV_READ_CSR(CSR_PMACFG(11));
frame->pmacfg12 = RV_READ_CSR(CSR_PMACFG(12));
frame->pmacfg13 = RV_READ_CSR(CSR_PMACFG(13));
frame->pmacfg14 = RV_READ_CSR(CSR_PMACFG(14));
frame->pmacfg15 = RV_READ_CSR(CSR_PMACFG(15));
frame->utvec = RV_READ_CSR(utvec);
frame->ustatus = RV_READ_CSR(ustatus);
frame->uepc = RV_READ_CSR(uepc);
frame->ucause = RV_READ_CSR(ucause);
frame->mpcer = RV_READ_CSR(CUSTOM_CSR_PCER_MACHINE);
frame->mpcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_MACHINE);
frame->mpccr = RV_READ_CSR(CUSTOM_CSR_PCCR_MACHINE);
frame->cpu_testbus_ctrl = RV_READ_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL);
frame->upcer = RV_READ_CSR(CUSTOM_CSR_PCER_USER);
frame->upcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_USER);
frame->upccr = RV_READ_CSR(CUSTOM_CSR_PCCR_USER);
frame->ugpio_oen = RV_READ_CSR(CUSTOM_CSR_GPIO_OEN_USER);
frame->ugpio_in = RV_READ_CSR(CUSTOM_CSR_GPIO_IN_USER);
frame->ugpio_out = RV_READ_CSR(CUSTOM_CSR_GPIO_OUT_USER);
return frame;
}
static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFrame *frame)
{
assert(frame);
RV_WRITE_CSR(mscratch, frame->mscratch);
RV_WRITE_CSR(mideleg, frame->mideleg);
RV_WRITE_CSR(misa, frame->misa);
RV_WRITE_CSR(tselect, frame->tselect);
RV_WRITE_CSR(tdata1, frame->tdata1);
RV_WRITE_CSR(tdata2, frame->tdata2);
RV_WRITE_CSR(tcontrol, frame->tcontrol);
RV_WRITE_CSR(pmpaddr0, frame->pmpaddr0);
RV_WRITE_CSR(pmpaddr1, frame->pmpaddr1);
RV_WRITE_CSR(pmpaddr2, frame->pmpaddr2);
RV_WRITE_CSR(pmpaddr3, frame->pmpaddr3);
RV_WRITE_CSR(pmpaddr4, frame->pmpaddr4);
RV_WRITE_CSR(pmpaddr5, frame->pmpaddr5);
RV_WRITE_CSR(pmpaddr6, frame->pmpaddr6);
RV_WRITE_CSR(pmpaddr7, frame->pmpaddr7);
RV_WRITE_CSR(pmpaddr8, frame->pmpaddr8);
RV_WRITE_CSR(pmpaddr9, frame->pmpaddr9);
RV_WRITE_CSR(pmpaddr10,frame->pmpaddr10);
RV_WRITE_CSR(pmpaddr11,frame->pmpaddr11);
RV_WRITE_CSR(pmpaddr12,frame->pmpaddr12);
RV_WRITE_CSR(pmpaddr13,frame->pmpaddr13);
RV_WRITE_CSR(pmpaddr14,frame->pmpaddr14);
RV_WRITE_CSR(pmpaddr15,frame->pmpaddr15);
RV_WRITE_CSR(pmpcfg0, frame->pmpcfg0);
RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1);
RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2);
RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3);
RV_WRITE_CSR(CSR_PMAADDR(0), frame->pmaaddr0);
RV_WRITE_CSR(CSR_PMAADDR(1), frame->pmaaddr1);
RV_WRITE_CSR(CSR_PMAADDR(2), frame->pmaaddr2);
RV_WRITE_CSR(CSR_PMAADDR(3), frame->pmaaddr3);
RV_WRITE_CSR(CSR_PMAADDR(4), frame->pmaaddr4);
RV_WRITE_CSR(CSR_PMAADDR(5), frame->pmaaddr5);
RV_WRITE_CSR(CSR_PMAADDR(6), frame->pmaaddr6);
RV_WRITE_CSR(CSR_PMAADDR(7), frame->pmaaddr7);
RV_WRITE_CSR(CSR_PMAADDR(8), frame->pmaaddr8);
RV_WRITE_CSR(CSR_PMAADDR(9), frame->pmaaddr9);
RV_WRITE_CSR(CSR_PMAADDR(10),frame->pmaaddr10);
RV_WRITE_CSR(CSR_PMAADDR(11),frame->pmaaddr11);
RV_WRITE_CSR(CSR_PMAADDR(12),frame->pmaaddr12);
RV_WRITE_CSR(CSR_PMAADDR(13),frame->pmaaddr13);
RV_WRITE_CSR(CSR_PMAADDR(14),frame->pmaaddr14);
RV_WRITE_CSR(CSR_PMAADDR(15),frame->pmaaddr15);
RV_WRITE_CSR(CSR_PMACFG(0), frame->pmacfg0);
RV_WRITE_CSR(CSR_PMACFG(1), frame->pmacfg1);
RV_WRITE_CSR(CSR_PMACFG(2), frame->pmacfg2);
RV_WRITE_CSR(CSR_PMACFG(3), frame->pmacfg3);
RV_WRITE_CSR(CSR_PMACFG(4), frame->pmacfg4);
RV_WRITE_CSR(CSR_PMACFG(5), frame->pmacfg5);
RV_WRITE_CSR(CSR_PMACFG(6), frame->pmacfg6);
RV_WRITE_CSR(CSR_PMACFG(7), frame->pmacfg7);
RV_WRITE_CSR(CSR_PMACFG(8), frame->pmacfg8);
RV_WRITE_CSR(CSR_PMACFG(9), frame->pmacfg9);
RV_WRITE_CSR(CSR_PMACFG(10), frame->pmacfg10);
RV_WRITE_CSR(CSR_PMACFG(11), frame->pmacfg11);
RV_WRITE_CSR(CSR_PMACFG(12), frame->pmacfg12);
RV_WRITE_CSR(CSR_PMACFG(13), frame->pmacfg13);
RV_WRITE_CSR(CSR_PMACFG(14), frame->pmacfg14);
RV_WRITE_CSR(CSR_PMACFG(15), frame->pmacfg15);
RV_WRITE_CSR(utvec, frame->utvec);
RV_WRITE_CSR(ustatus, frame->ustatus);
RV_WRITE_CSR(uepc, frame->uepc);
RV_WRITE_CSR(ucause, frame->ucause);
RV_WRITE_CSR(CUSTOM_CSR_PCER_MACHINE, frame->mpcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_MACHINE, frame->mpcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_MACHINE, frame->mpccr);
RV_WRITE_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL, frame->cpu_testbus_ctrl);
RV_WRITE_CSR(CUSTOM_CSR_PCER_USER, frame->upcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_USER, frame->upcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_USER, frame->upccr);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OEN_USER,frame->ugpio_oen);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_IN_USER, frame->ugpio_in);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OUT_USER,frame->ugpio_out);
}
static IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
regs_frame[offset++] = *(uint32_t *)addr;
}
}
}
static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
*(uint32_t *)addr = regs_frame[offset++];
}
}
}
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
*(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size);
}
static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
// resume uarts
for (int i = 0; i < SOC_UART_NUM; ++i) {
if (!uart_ll_is_enabled(i)) {
continue;
}
uart_ll_force_xon(i);
}
/* Since it is still in the critical now, use ESP_EARLY_LOG */
ESP_EARLY_LOGE(TAG, "Sleep retention frame is corrupted");
esp_restart_noos();
}
}
#endif
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void);
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void);
typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool);
static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep,
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save();
if ((frame->pmufunc & 0x3) == 0x1) {
esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_END, (void *)0);
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus 2 * sizeof(long) is for bypass `pmufunc` and `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
REG_WRITE(LIGHT_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore);
return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
}
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
else {
validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
}
#endif
return pmu_sleep_finish();
}
esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool),
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0);
uint32_t mstatus = save_mstatus_and_disable_global_int();
cpu_domain_dev_regs_save(s_cpu_retention.retent.plic_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame);
RvCoreNonCriticalSleepFrame *frame = rv_core_noncritical_regs_save();
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus sizeof(long) is for bypass `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
validate_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
rv_core_noncritical_regs_restore(frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.plic_frame);
restore_mstatus(mstatus);
return err;
}
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
}
bool cpu_domain_pd_allowed(void)
{
return (s_cpu_retention.retent.critical_frame != NULL) && \
(s_cpu_retention.retent.non_critical_frame != NULL) && \
(s_cpu_retention.retent.intpri_frame != NULL) && \
(s_cpu_retention.retent.cache_config_frame != NULL) && \
(s_cpu_retention.retent.plic_frame != NULL) && \
(s_cpu_retention.retent.clint_frame != NULL);
}
esp_err_t sleep_cpu_configure(bool light_sleep_enable)
{
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
if (light_sleep_enable) {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep.");
} else {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_deinit(), TAG, "Failed to release CPU retention memory");
}
#endif
return ESP_OK;
}

Wyświetl plik

@ -5,15 +5,10 @@
*/
#include "soc/soc.h"
#include "riscv/rvsleep-frames.h"
#include "rvsleep-frames.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5
#include "soc/lp_aon_reg.h"
#include "soc/extmem_reg.h"
#endif
.section .data1,"aw"
.global rv_core_critical_regs_frame
.type rv_core_critical_regs_frame,@object
@ -59,7 +54,6 @@ rv_core_critical_regs_save:
*/
mv a0, t0
sw a0, RV_SLP_CTX_A0(t0)
sw a1, RV_SLP_CTX_A1(t0)
sw a2, RV_SLP_CTX_A2(t0)
sw a3, RV_SLP_CTX_A3(t0)
@ -113,31 +107,6 @@ rv_core_critical_regs_save:
mv t3, t0
csrr t0, mscratch
sw t0, RV_SLP_CTX_T0(t3)
#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5
/* writeback dcache is required here!!! */
la t0, EXTMEM_CACHE_SYNC_MAP_REG
li t1, 0x10
sw t1, 0x0(t0) /* set EXTMEM_CACHE_SYNC_MAP_REG bit 4 */
la t2, EXTMEM_CACHE_SYNC_ADDR_REG
sw zero, 0x0(t2) /* clear EXTMEM_CACHE_SYNC_ADDR_REG */
la t0, EXTMEM_CACHE_SYNC_SIZE_REG
sw zero, 0x0(t0) /* clear EXTMEM_CACHE_SYNC_SIZE_REG */
la t1, EXTMEM_CACHE_SYNC_CTRL_REG
lw t2, 0x0(t1)
ori t2, t2, 0x4
sw t2, 0x0(t1)
li t0, 0x10 /* SYNC_DONE bit */
wait_sync_done:
lw t2, 0x0(t1)
and t2, t0, t2
beqz t2, wait_sync_done
#endif
lw t0, RV_SLP_CTX_T0(t3)
lw t1, RV_SLP_CTX_T1(t3)
lw t2, RV_SLP_CTX_T2(t3)
lw t3, RV_SLP_CTX_T3(t3)

Wyświetl plik

@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __RVSLEEP_FRAMES_H__
#define __RVSLEEP_FRAMES_H__
#include "sdkconfig.h"
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n) - 1) & -(n))
#ifdef STRUCT_BEGIN
#undef STRUCT_BEGIN
#undef STRUCT_FIELD
#undef STRUCT_AFIELD
#undef STRUCT_END
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#ifdef __clang__
#define STRUCT_BEGIN .set RV_STRUCT_OFFSET, 0
#define STRUCT_FIELD(ctype,size,asname,name) .set asname, RV_STRUCT_OFFSET; .set RV_STRUCT_OFFSET, asname + size
#define STRUCT_AFIELD(ctype,size,asname,name,n) .set asname, RV_STRUCT_OFFSET;\
.set RV_STRUCT_OFFSET, asname + (size)*(n);
#define STRUCT_END(sname) .set sname##Size, RV_STRUCT_OFFSET;
#else // __clang__
#define STRUCT_BEGIN .pushsection .text; .struct 0
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
#define STRUCT_END(sname) sname##Size:; .popsection
#endif // __clang__
#else
#define STRUCT_BEGIN typedef struct {
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
#define STRUCT_END(sname) } sname;
#endif
/*
* -------------------------------------------------------------------------------
* RISC-V CORE CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MEPC, mepc) /* Machine Exception Program Counter */
STRUCT_FIELD (long, 4, RV_SLP_CTX_RA, ra) /* Return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_SP, sp) /* Stack pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_GP, gp) /* Global pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_TP, tp) /* Thread pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T0, t0) /* Temporary/alternate link register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T1, t1) /* t1-2: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T2, t2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S0, s0) /* Saved register/frame pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S1, s1) /* Saved register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A0, a0) /* a0-1: Function arguments/return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A1, a1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A2, a2) /* a2-7: Function arguments */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A3, a3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A4, a4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A5, a5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A6, a6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A7, a7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S2, s2) /* s2-11: Saved registers */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S3, s3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S4, s4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S5, s5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S6, s6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S7, s7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S8, s8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S9, s9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S10, s10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S11, s11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T3, t3) /* t3-6: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T4, t4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T5, t5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T6, t6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSTATUS, mstatus) /* Machine Status */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MCAUSE, mcause) /* Machine Trap Cause */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVAL, mtval) /* Machine Trap Value */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIE, mie) /* Machine intr enable */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIP, mip) /* Machine intr pending */
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMUFUNC, pmufunc) /* A field is used to identify whether it is going
* to sleep or has just been awakened. We use the
* lowest 2 bits as indication infomation, 3 means
* being awakened, 1 means going to sleep */
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_CSF_CTX_CRC, frame_crc) /* Used to check RvCoreCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreCriticalSleepFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define RV_SLEEP_CTX_SZ1 RvCoreCriticalSleepFrameSize
#else
#define RV_SLEEP_CTX_SZ1 sizeof(RvCoreCriticalSleepFrame)
#endif
/*
* Sleep stack frame size, after align up to 16 bytes boundary
*/
#define RV_SLEEP_CTX_FRMSZ (ALIGNUP(0x10, RV_SLEEP_CTX_SZ1))
/*
* -------------------------------------------------------------------------------
* RISC-V CORE NON-CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSCRATCH, mscratch)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIDELEG, mideleg)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MISA, misa)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TSELECT, tselect)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA1, tdata1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA2, tdata2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TCONTROL, tcontrol)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR0, pmpaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR1, pmpaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR2, pmpaddr2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR3, pmpaddr3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR4, pmpaddr4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR5, pmpaddr5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR6, pmpaddr6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR7, pmpaddr7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR8, pmpaddr8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR9, pmpaddr9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR10, pmpaddr10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR11, pmpaddr11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR12, pmpaddr12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR13, pmpaddr13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR14, pmpaddr14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR15, pmpaddr15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG0, pmpcfg0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG1, pmpcfg1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR0, pmaaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR1, pmaaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR2, pmaaddr2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR3, pmaaddr3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR4, pmaaddr4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR5, pmaaddr5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR6, pmaaddr6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR7, pmaaddr7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR8, pmaaddr8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR9, pmaaddr9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR10, pmaaddr10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR11, pmaaddr11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR12, pmaaddr12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR13, pmaaddr13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR14, pmaaddr14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR15, pmaaddr15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG0, pmacfg0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG1, pmacfg1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG2, pmacfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG3, pmacfg3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG4, pmacfg4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG5, pmacfg5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG6, pmacfg6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG7, pmacfg7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG8, pmacfg8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG9, pmacfg9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG10, pmacfg10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG11, pmacfg11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG12, pmacfg12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG13, pmacfg13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG14, pmacfg14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG15, pmacfg15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec)
STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UEPC, uepc)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UCAUSE, ucause)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCER, mpcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCMR, mpcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCCR, mpccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_CPU_TESTBUS_CTRL, cpu_testbus_ctrl)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCER, upcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCMR, upcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCCR, upccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OEN, ugpio_oen)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_IN, ugpio_in)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OUT, ugpio_out)
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_NCSF_CTX_CRC, frame_crc) /* Used to check RvCoreNonCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreNonCriticalSleepFrame)
#endif /* #ifndef __RVSLEEP_FRAMES_H__ */

Wyświetl plik

@ -18,16 +18,21 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/sleep_event.h"
#include "sdkconfig.h"
#if SOC_PMU_SUPPORTED
#include "esp_private/esp_pmu.h"
#else
#include "hal/rtc_hal.h"
#endif
#include "esp32c6/rom/rtc.h"
#include "esp32c6/rom/cache.h"
#include "rvsleep-frames.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
@ -35,36 +40,6 @@
#include "hal/uart_hal.h"
#endif
#include "soc/rtc_periph.h"
#ifdef CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/rtc.h"
#include "riscv/rvsleep-frames.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "esp32c6/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C5
#include "esp32c5/rom/rtc.h"
#include "riscv/rvsleep-frames.h"
#include "soc/intpri_reg.h"
#include "soc/cache_reg.h"
#include "soc/clic_reg.h"
#include "soc/clint_reg.h"
#include "esp32c5/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#include "riscv/rvsleep-frames.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "esp32h2/rom/cache.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep";
typedef struct {
@ -82,9 +57,6 @@ typedef struct {
* Internal structure which holds all requested light sleep cpu retention parameters
*/
typedef struct {
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
rtc_cntl_sleep_retent_t retent;
#elif SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
@ -93,197 +65,10 @@ typedef struct {
cpu_domain_dev_sleep_frame_t *plic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
#endif
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
#if CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
static uint32_t cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t code_seg_size, uint32_t data_seg_vaddr, uint32_t data_seg_size)
{
uint32_t sets; /* i/d-cache total set counts */
uint32_t index; /* virtual address mapping i/d-cache row offset */
uint32_t waysgrp;
uint32_t icache_tagmem_blk_gs, dcache_tagmem_blk_gs;
struct cache_mode imode = { .icache = 1 };
struct cache_mode dmode = { .icache = 0 };
/* calculate/prepare i-cache tag memory retention parameters */
Cache_Get_Mode(&imode);
sets = imode.cache_size / imode.cache_ways / imode.cache_line_size;
index = (code_seg_vaddr / imode.cache_line_size) % sets;
waysgrp = imode.cache_ways >> 2;
code_seg_size = ALIGNUP(imode.cache_line_size, code_seg_size);
s_cpu_retention.retent.tagmem.icache.start_point = index;
s_cpu_retention.retent.tagmem.icache.size = (sets * waysgrp) & 0xff;
s_cpu_retention.retent.tagmem.icache.vld_size = s_cpu_retention.retent.tagmem.icache.size;
if (code_seg_size < imode.cache_size / imode.cache_ways) {
s_cpu_retention.retent.tagmem.icache.vld_size = (code_seg_size / imode.cache_line_size) * waysgrp;
}
s_cpu_retention.retent.tagmem.icache.enable = (code_seg_size != 0) ? 1 : 0;
icache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.icache.vld_size ? s_cpu_retention.retent.tagmem.icache.vld_size : sets * waysgrp;
icache_tagmem_blk_gs = ALIGNUP(4, icache_tagmem_blk_gs);
ESP_LOGD(TAG, "I-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (imode.cache_size>>10),
imode.cache_line_size, imode.cache_ways, sets, index, icache_tagmem_blk_gs);
/* calculate/prepare d-cache tag memory retention parameters */
Cache_Get_Mode(&dmode);
sets = dmode.cache_size / dmode.cache_ways / dmode.cache_line_size;
index = (data_seg_vaddr / dmode.cache_line_size) % sets;
waysgrp = dmode.cache_ways >> 2;
data_seg_size = ALIGNUP(dmode.cache_line_size, data_seg_size);
s_cpu_retention.retent.tagmem.dcache.start_point = index;
s_cpu_retention.retent.tagmem.dcache.size = (sets * waysgrp) & 0x1ff;
s_cpu_retention.retent.tagmem.dcache.vld_size = s_cpu_retention.retent.tagmem.dcache.size;
#ifndef CONFIG_ESP32S3_DATA_CACHE_16KB
if (data_seg_size < dmode.cache_size / dmode.cache_ways) {
s_cpu_retention.retent.tagmem.dcache.vld_size = (data_seg_size / dmode.cache_line_size) * waysgrp;
}
s_cpu_retention.retent.tagmem.dcache.enable = (data_seg_size != 0) ? 1 : 0;
#else
s_cpu_retention.retent.tagmem.dcache.enable = 1;
#endif
dcache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.dcache.vld_size ? s_cpu_retention.retent.tagmem.dcache.vld_size : sets * waysgrp;
dcache_tagmem_blk_gs = ALIGNUP(4, dcache_tagmem_blk_gs);
ESP_LOGD(TAG, "D-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (dmode.cache_size>>10),
dmode.cache_line_size, dmode.cache_ways, sets, index, dcache_tagmem_blk_gs);
/* For I or D cache tagmem retention, backup and restore are performed through
* RTC DMA (its bus width is 128 bits), For I/D Cache tagmem blocks (i-cache
* tagmem blocks = 92 bits, d-cache tagmem blocks = 88 bits), RTC DMA automatically
* aligns its bit width to 96 bits, therefore, 3 times RTC DMA can transfer 4
* i/d-cache tagmem blocks (128 bits * 3 = 96 bits * 4) */
return (((icache_tagmem_blk_gs + dcache_tagmem_blk_gs) << 2) * 3);
}
#endif // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
static esp_err_t esp_sleep_tagmem_pd_low_init(void)
{
#if CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
if (s_cpu_retention.retent.tagmem.link_addr == NULL) {
extern char _stext[], _etext[];
uint32_t code_start = (uint32_t)_stext;
uint32_t code_size = (uint32_t)(_etext - _stext);
#if !(CONFIG_SPIRAM && CONFIG_SOC_PM_SUPPORT_TAGMEM_PD)
extern char _rodata_start[], _rodata_reserved_end[];
uint32_t data_start = (uint32_t)_rodata_start;
uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else
uint32_t data_start = SOC_DROM_LOW;
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
#endif
ESP_LOGI(TAG, "Code start at 0x%08"PRIx32", total %"PRIu32", data start at 0x%08"PRIx32", total %"PRIu32" Bytes",
code_start, code_size, data_start, data_size);
uint32_t tagmem_sz = cache_tagmem_retention_setup(code_start, code_size, data_start, data_size);
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_TAGMEM_PD_DMA_ADDR_ALIGN, 1,
tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.tagmem.link_addr = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, tagmem_sz, NULL);
} else {
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
return ESP_ERR_NO_MEM;
}
}
#else // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
#endif // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
return ESP_OK;
}
static esp_err_t esp_sleep_tagmem_pd_low_deinit(void)
{
#if SOC_PM_SUPPORT_TAGMEM_PD
if (s_cpu_retention.retent.tagmem.link_addr) {
heap_caps_free(s_cpu_retention.retent.tagmem.link_addr);
s_cpu_retention.retent.tagmem.icache.enable = 0;
s_cpu_retention.retent.tagmem.dcache.enable = 0;
s_cpu_retention.retent.tagmem.link_addr = NULL;
}
#endif
return ESP_OK;
}
#endif // SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
esp_err_t esp_sleep_cpu_pd_low_init(void)
{
if (s_cpu_retention.retent.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, 1,
SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
if (esp_sleep_tagmem_pd_low_init() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
#endif
return ESP_OK;
}
esp_err_t esp_sleep_cpu_pd_low_deinit(void)
{
if (s_cpu_retention.retent.cpu_pd_mem) {
heap_caps_free(s_cpu_retention.retent.cpu_pd_mem);
s_cpu_retention.retent.cpu_pd_mem = NULL;
}
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
if (esp_sleep_tagmem_pd_low_deinit() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
#endif
return ESP_OK;
}
void sleep_enable_cpu_retention(void)
{
rtc_cntl_hal_enable_cpu_retention(&s_cpu_retention.retent);
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_enable_tagmem_retention(&s_cpu_retention.retent);
#endif
}
void IRAM_ATTR sleep_disable_cpu_retention(void)
{
rtc_cntl_hal_disable_cpu_retention(&s_cpu_retention.retent);
#if SOC_PM_SUPPORT_TAGMEM_PD
rtc_cntl_hal_disable_tagmem_retention(&s_cpu_retention.retent);
#endif
}
#endif
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
@ -334,13 +119,8 @@ static inline void * cpu_domain_intpri_sleep_frame_alloc_and_init(void)
static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
#if CONFIG_IDF_TARGET_ESP32C6
{ .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 }
#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5
{ .start = CACHE_L1_CACHE_CTRL_REG, .end = CACHE_L1_CACHE_CTRL_REG + 4 },
{ .start = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4 }
#endif
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
@ -446,20 +226,14 @@ static esp_err_t esp_sleep_cpu_retention_deinit_impl(void)
return ESP_OK;
}
static inline IRAM_ATTR uint32_t save_mstatus_and_disable_global_int(void)
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
uint32_t mstatus;
__asm__ __volatile__ (
"csrr %0, mstatus\n"
"csrci mstatus, 0x8\n"
: "=r"(mstatus)
);
return mstatus;
return RV_READ_MSTATUS_AND_DISABLE_INTR();
}
static inline IRAM_ATTR void restore_mstatus(uint32_t mstatus)
FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val)
{
__asm__ __volatile__ ("csrw mstatus, %0\n" :: "r"(mstatus));
RV_WRITE_CSR(mstatus, mstatus_val);
}
static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void)
@ -495,7 +269,6 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi
frame->pmpcfg2 = RV_READ_CSR(pmpcfg2);
frame->pmpcfg3 = RV_READ_CSR(pmpcfg3);
#if SOC_CPU_HAS_PMA
frame->pmaaddr0 = RV_READ_CSR(CSR_PMAADDR(0));
frame->pmaaddr1 = RV_READ_CSR(CSR_PMAADDR(1));
frame->pmaaddr2 = RV_READ_CSR(CSR_PMAADDR(2));
@ -528,7 +301,6 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi
frame->pmacfg13 = RV_READ_CSR(CSR_PMACFG(13));
frame->pmacfg14 = RV_READ_CSR(CSR_PMACFG(14));
frame->pmacfg15 = RV_READ_CSR(CSR_PMACFG(15));
#endif // SOC_CPU_HAS_PMA
frame->utvec = RV_READ_CSR(utvec);
frame->ustatus = RV_READ_CSR(ustatus);
@ -579,7 +351,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra
RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2);
RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3);
#if SOC_CPU_HAS_PMA
RV_WRITE_CSR(CSR_PMAADDR(0), frame->pmaaddr0);
RV_WRITE_CSR(CSR_PMAADDR(1), frame->pmaaddr1);
RV_WRITE_CSR(CSR_PMAADDR(2), frame->pmaaddr2);
@ -612,7 +383,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra
RV_WRITE_CSR(CSR_PMACFG(13), frame->pmacfg13);
RV_WRITE_CSR(CSR_PMACFG(14), frame->pmacfg14);
RV_WRITE_CSR(CSR_PMACFG(15), frame->pmacfg15);
#endif //SOC_CPU_HAS_PMA
RV_WRITE_CSR(utvec, frame->utvec);
RV_WRITE_CSR(ustatus, frame->ustatus);
@ -670,11 +440,9 @@ static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t
if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
// resume uarts
for (int i = 0; i < SOC_UART_NUM; ++i) {
#ifndef CONFIG_IDF_TARGET_ESP32
if (!uart_ll_is_enabled(i)) {
continue;
}
#endif
uart_ll_force_xon(i);
}
@ -743,47 +511,24 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
return err;
}
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
#if SOC_PM_SUPPORT_CPU_PD
esp_err_t esp_sleep_cpu_retention_init(void)
{
esp_err_t err = ESP_OK;
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
err = esp_sleep_cpu_pd_low_init();
#elif SOC_PM_CPU_RETENTION_BY_SW
err = esp_sleep_cpu_retention_init_impl();
#endif
return err;
return esp_sleep_cpu_retention_init_impl();
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
esp_err_t err = ESP_OK;
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
err = esp_sleep_cpu_pd_low_deinit();
#elif SOC_PM_CPU_RETENTION_BY_SW
err = esp_sleep_cpu_retention_deinit_impl();
#endif
return err;
return esp_sleep_cpu_retention_deinit_impl();
}
bool cpu_domain_pd_allowed(void)
{
#if SOC_PM_CPU_RETENTION_BY_RTCCNTL
return (s_cpu_retention.retent.cpu_pd_mem != NULL);
#elif SOC_PM_CPU_RETENTION_BY_SW
return (s_cpu_retention.retent.critical_frame != NULL) && \
(s_cpu_retention.retent.non_critical_frame != NULL) && \
(s_cpu_retention.retent.intpri_frame != NULL) && \
(s_cpu_retention.retent.cache_config_frame != NULL) && \
(s_cpu_retention.retent.plic_frame != NULL) && \
(s_cpu_retention.retent.clint_frame != NULL);
#else
return false;
#endif
}
esp_err_t sleep_cpu_configure(bool light_sleep_enable)
@ -797,5 +542,3 @@ esp_err_t sleep_cpu_configure(bool light_sleep_enable)
#endif
return ESP_OK;
}
#endif

Wyświetl plik

@ -0,0 +1,215 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "rvsleep-frames.h"
#include "sdkconfig.h"
.section .data1,"aw"
.global rv_core_critical_regs_frame
.type rv_core_critical_regs_frame,@object
.align 4
rv_core_critical_regs_frame:
.word 0
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to save the critical registers of the CPU
core to the internal RAM before sleep, and modify the PMU control flag to
indicate that the system needs to sleep. When the subroutine returns, it
will return the memory pointer that saves the context information of the CPU
critical registers.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_save
.type rv_core_critical_regs_save,@function
.align 4
rv_core_critical_regs_save:
/* arrived here in critical section. we need:
save riscv core critical registers to RvCoreCriticalSleepFrame
*/
csrw mscratch, t0 /* use mscratch as temp storage */
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
sw ra, RV_SLP_CTX_RA(t0)
sw sp, RV_SLP_CTX_SP(t0)
sw gp, RV_SLP_CTX_GP(t0)
sw tp, RV_SLP_CTX_TP(t0)
sw t1, RV_SLP_CTX_T1(t0)
sw t2, RV_SLP_CTX_T2(t0)
sw s0, RV_SLP_CTX_S0(t0)
sw s1, RV_SLP_CTX_S1(t0)
/* a0 is caller saved, so it does not need to be saved, but it should be the
pointer value of RvCoreCriticalSleepFrame for return.
*/
mv a0, t0
sw a0, RV_SLP_CTX_A0(t0)
sw a1, RV_SLP_CTX_A1(t0)
sw a2, RV_SLP_CTX_A2(t0)
sw a3, RV_SLP_CTX_A3(t0)
sw a4, RV_SLP_CTX_A4(t0)
sw a5, RV_SLP_CTX_A5(t0)
sw a6, RV_SLP_CTX_A6(t0)
sw a7, RV_SLP_CTX_A7(t0)
sw s2, RV_SLP_CTX_S2(t0)
sw s3, RV_SLP_CTX_S3(t0)
sw s4, RV_SLP_CTX_S4(t0)
sw s5, RV_SLP_CTX_S5(t0)
sw s6, RV_SLP_CTX_S6(t0)
sw s7, RV_SLP_CTX_S7(t0)
sw s8, RV_SLP_CTX_S8(t0)
sw s9, RV_SLP_CTX_S9(t0)
sw s10, RV_SLP_CTX_S10(t0)
sw s11, RV_SLP_CTX_S11(t0)
sw t3, RV_SLP_CTX_T3(t0)
sw t4, RV_SLP_CTX_T4(t0)
sw t5, RV_SLP_CTX_T5(t0)
sw t6, RV_SLP_CTX_T6(t0)
csrr t1, mstatus
sw t1, RV_SLP_CTX_MSTATUS(t0)
csrr t2, mtvec
sw t2, RV_SLP_CTX_MTVEC(t0)
csrr t3, mcause
sw t3, RV_SLP_CTX_MCAUSE(t0)
csrr t1, mtval
sw t1, RV_SLP_CTX_MTVAL(t0)
csrr t2, mie
sw t2, RV_SLP_CTX_MIE(t0)
csrr t3, mip
sw t3, RV_SLP_CTX_MIP(t0)
csrr t1, mepc
sw t1, RV_SLP_CTX_MEPC(t0)
/*
!!! Let idf knows it's going to sleep !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
li t1, ~0x3
lw t2, RV_SLP_CTX_PMUFUNC(t0)
and t2, t1, t2
ori t2, t2, 0x1
sw t2, RV_SLP_CTX_PMUFUNC(t0)
mv t3, t0
csrr t0, mscratch
lw t1, RV_SLP_CTX_T1(t3)
lw t2, RV_SLP_CTX_T2(t3)
lw t3, RV_SLP_CTX_T3(t3)
ret
.size rv_core_critical_regs_save, . - rv_core_critical_regs_save
#define CSR_PCER_U 0x800
#define CSR_PCMR_U 0x801
#define PCER_CYCLES (1<<0) /* count clock cycles */
#define PCMR_GLOBAL_EN (1<<0) /* enable count */
#define pcer CSR_PCER_U
#define pcmr CSR_PCMR_U
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to restore the CPU core critical register
context before sleep after system wakes up, modify the PMU control
information, and return the critical register context memory object pointer.
After the subroutine returns, continue to restore other modules of the
system.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_restore
.weak rv_core_critical_regs_restore
.type rv_core_critical_regs_restore,@function
.global _rv_core_critical_regs_restore
.type _rv_core_critical_regs_restore,@function
.align 4
_rv_core_critical_regs_restore: /* export a strong symbol to jump to here, used
* for a static callback */
nop
rv_core_critical_regs_restore:
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
beqz t0, .skip_restore /* make sure we do not jump to zero address */
/*
!!! Let idf knows it's sleep awake. !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
lw t1, RV_SLP_CTX_PMUFUNC(t0)
ori t1, t1, 0x3
sw t1, RV_SLP_CTX_PMUFUNC(t0)
lw t2, RV_SLP_CTX_MEPC(t0)
csrw mepc, t2
lw t3, RV_SLP_CTX_MIP(t0)
csrw mip, t3
lw t1, RV_SLP_CTX_MIE(t0)
csrw mie, t1
lw t2, RV_SLP_CTX_MSTATUS(t0)
csrw mstatus, t2
lw t3, RV_SLP_CTX_MTVEC(t0)
csrw mtvec, t3
lw t1, RV_SLP_CTX_MCAUSE(t0)
csrw mcause, t1
lw t2, RV_SLP_CTX_MTVAL(t0)
csrw mtval, t2
lw t6, RV_SLP_CTX_T6(t0)
lw t5, RV_SLP_CTX_T5(t0)
lw t4, RV_SLP_CTX_T4(t0)
lw t3, RV_SLP_CTX_T3(t0)
lw s11, RV_SLP_CTX_S11(t0)
lw s10, RV_SLP_CTX_S10(t0)
lw s9, RV_SLP_CTX_S9(t0)
lw s8, RV_SLP_CTX_S8(t0)
lw s7, RV_SLP_CTX_S7(t0)
lw s6, RV_SLP_CTX_S6(t0)
lw s5, RV_SLP_CTX_S5(t0)
lw s4, RV_SLP_CTX_S4(t0)
lw s3, RV_SLP_CTX_S3(t0)
lw s2, RV_SLP_CTX_S2(t0)
lw a7, RV_SLP_CTX_A7(t0)
lw a6, RV_SLP_CTX_A6(t0)
lw a5, RV_SLP_CTX_A5(t0)
lw a4, RV_SLP_CTX_A4(t0)
lw a3, RV_SLP_CTX_A3(t0)
lw a2, RV_SLP_CTX_A2(t0)
lw a1, RV_SLP_CTX_A1(t0)
lw a0, RV_SLP_CTX_A0(t0)
lw s1, RV_SLP_CTX_S1(t0)
lw s0, RV_SLP_CTX_S0(t0)
lw t2, RV_SLP_CTX_T2(t0)
lw t1, RV_SLP_CTX_T1(t0)
lw tp, RV_SLP_CTX_TP(t0)
lw gp, RV_SLP_CTX_GP(t0)
lw sp, RV_SLP_CTX_SP(t0)
lw ra, RV_SLP_CTX_RA(t0)
lw t0, RV_SLP_CTX_T0(t0)
.skip_restore:
ret
.size rv_core_critical_regs_restore, . - rv_core_critical_regs_restore

Wyświetl plik

@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __RVSLEEP_FRAMES_H__
#define __RVSLEEP_FRAMES_H__
#include "sdkconfig.h"
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n) - 1) & -(n))
#ifdef STRUCT_BEGIN
#undef STRUCT_BEGIN
#undef STRUCT_FIELD
#undef STRUCT_AFIELD
#undef STRUCT_END
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#ifdef __clang__
#define STRUCT_BEGIN .set RV_STRUCT_OFFSET, 0
#define STRUCT_FIELD(ctype,size,asname,name) .set asname, RV_STRUCT_OFFSET; .set RV_STRUCT_OFFSET, asname + size
#define STRUCT_AFIELD(ctype,size,asname,name,n) .set asname, RV_STRUCT_OFFSET;\
.set RV_STRUCT_OFFSET, asname + (size)*(n);
#define STRUCT_END(sname) .set sname##Size, RV_STRUCT_OFFSET;
#else // __clang__
#define STRUCT_BEGIN .pushsection .text; .struct 0
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
#define STRUCT_END(sname) sname##Size:; .popsection
#endif // __clang__
#else
#define STRUCT_BEGIN typedef struct {
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
#define STRUCT_END(sname) } sname;
#endif
/*
* -------------------------------------------------------------------------------
* RISC-V CORE CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MEPC, mepc) /* Machine Exception Program Counter */
STRUCT_FIELD (long, 4, RV_SLP_CTX_RA, ra) /* Return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_SP, sp) /* Stack pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_GP, gp) /* Global pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_TP, tp) /* Thread pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T0, t0) /* Temporary/alternate link register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T1, t1) /* t1-2: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T2, t2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S0, s0) /* Saved register/frame pointer */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S1, s1) /* Saved register */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A0, a0) /* a0-1: Function arguments/return address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A1, a1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A2, a2) /* a2-7: Function arguments */
STRUCT_FIELD (long, 4, RV_SLP_CTX_A3, a3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A4, a4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A5, a5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A6, a6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_A7, a7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S2, s2) /* s2-11: Saved registers */
STRUCT_FIELD (long, 4, RV_SLP_CTX_S3, s3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S4, s4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S5, s5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S6, s6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S7, s7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S8, s8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S9, s9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S10, s10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_S11, s11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T3, t3) /* t3-6: Temporaries */
STRUCT_FIELD (long, 4, RV_SLP_CTX_T4, t4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T5, t5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_T6, t6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSTATUS, mstatus) /* Machine Status */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MCAUSE, mcause) /* Machine Trap Cause */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVAL, mtval) /* Machine Trap Value */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIE, mie) /* Machine intr enable */
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIP, mip) /* Machine intr pending */
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMUFUNC, pmufunc) /* A field is used to identify whether it is going
* to sleep or has just been awakened. We use the
* lowest 2 bits as indication infomation, 3 means
* being awakened, 1 means going to sleep */
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_CSF_CTX_CRC, frame_crc) /* Used to check RvCoreCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreCriticalSleepFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define RV_SLEEP_CTX_SZ1 RvCoreCriticalSleepFrameSize
#else
#define RV_SLEEP_CTX_SZ1 sizeof(RvCoreCriticalSleepFrame)
#endif
/*
* Sleep stack frame size, after align up to 16 bytes boundary
*/
#define RV_SLEEP_CTX_FRMSZ (ALIGNUP(0x10, RV_SLEEP_CTX_SZ1))
/*
* -------------------------------------------------------------------------------
* RISC-V CORE NON-CRITICAL REGISTER CONTEXT LAYOUT FOR SLEEP
* -------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_MSCRATCH, mscratch)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MIDELEG, mideleg)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MISA, misa)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TSELECT, tselect)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA1, tdata1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA2, tdata2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_TCONTROL, tcontrol)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR0, pmpaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR1, pmpaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR2, pmpaddr2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR3, pmpaddr3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR4, pmpaddr4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR5, pmpaddr5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR6, pmpaddr6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR7, pmpaddr7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR8, pmpaddr8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR9, pmpaddr9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR10, pmpaddr10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR11, pmpaddr11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR12, pmpaddr12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR13, pmpaddr13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR14, pmpaddr14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR15, pmpaddr15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG0, pmpcfg0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG1, pmpcfg1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR0, pmaaddr0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR1, pmaaddr1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR2, pmaaddr2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR3, pmaaddr3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR4, pmaaddr4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR5, pmaaddr5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR6, pmaaddr6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR7, pmaaddr7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR8, pmaaddr8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR9, pmaaddr9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR10, pmaaddr10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR11, pmaaddr11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR12, pmaaddr12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR13, pmaaddr13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR14, pmaaddr14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR15, pmaaddr15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG0, pmacfg0)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG1, pmacfg1)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG2, pmacfg2)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG3, pmacfg3)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG4, pmacfg4)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG5, pmacfg5)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG6, pmacfg6)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG7, pmacfg7)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG8, pmacfg8)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG9, pmacfg9)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG10, pmacfg10)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG11, pmacfg11)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG12, pmacfg12)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG13, pmacfg13)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG14, pmacfg14)
STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG15, pmacfg15)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec)
STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UEPC, uepc)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UCAUSE, ucause)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCER, mpcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCMR, mpcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_MPCCR, mpccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_CPU_TESTBUS_CTRL, cpu_testbus_ctrl)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCER, upcer)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCMR, upcmr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UPCCR, upccr)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OEN, ugpio_oen)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_IN, ugpio_in)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OUT, ugpio_out)
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_NCSF_CTX_CRC, frame_crc) /* Used to check RvCoreNonCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreNonCriticalSleepFrame)
#endif /* #ifndef __RVSLEEP_FRAMES_H__ */

Wyświetl plik

@ -0,0 +1,544 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "riscv/csr.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/extmem_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "soc/rtc_periph.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/sleep_event.h"
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/cache.h"
#include "rvsleep-frames.h"
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
#include "hal/clk_gate_ll.h"
#include "hal/uart_hal.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep";
typedef struct {
uint32_t start;
uint32_t end;
} cpu_domain_dev_regs_region_t;
typedef struct {
cpu_domain_dev_regs_region_t *region;
int region_num;
uint32_t *regs_frame;
} cpu_domain_dev_sleep_frame_t;
/**
* Internal structure which holds all requested light sleep cpu retention parameters
*/
typedef struct {
struct {
RvCoreCriticalSleepFrame *critical_frame;
RvCoreNonCriticalSleepFrame *non_critical_frame;
cpu_domain_dev_sleep_frame_t *intpri_frame;
cpu_domain_dev_sleep_frame_t *cache_config_frame;
cpu_domain_dev_sleep_frame_t *plic_frame;
cpu_domain_dev_sleep_frame_t *clint_frame;
} retent;
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
#define CUSTOM_CSR_PCER_MACHINE 0x7e0
#define CUSTOM_CSR_PCMR_MACHINE 0x7e1
#define CUSTOM_CSR_PCCR_MACHINE 0x7e2
#define CUSTOM_CSR_CPU_TESTBUS_CTRL 0x7e3
#define CUSTOM_CSR_PCER_USER 0x800
#define CUSTOM_CSR_PCMR_USER 0x801
#define CUSTOM_CSR_PCCR_USER 0x802
#define CUSTOM_CSR_GPIO_OEN_USER 0x803
#define CUSTOM_CSR_GPIO_IN_USER 0x804
#define CUSTOM_CSR_GPIO_OUT_USER 0x805
#define CUSTOM_CSR_CO_EXCEPTION_CAUSE 0x7f0
#define CUSTOM_CSR_CO_HWLP 0x7f1
#define CUSTOM_CSR_CO_AIA 0x7f2
extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame;
static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num)
{
const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num;
int regs_frame_sz = 0;
for (int num = 0; num < region_num; num++) {
regs_frame_sz += regions[num].end - regions[num].start;
}
void *frame = heap_caps_malloc(sizeof(cpu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame) {
cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t));
memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t));
void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz;
memset(regs_frame, 0, regs_frame_sz);
*(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) {
.region = region,
.region_num = region_num,
.regs_frame = (uint32_t *)regs_frame
};
}
return frame;
}
static 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_CTRL_REG, .end = CACHE_L1_CACHE_CTRL_REG + 4 },
{ .start = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_plic_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = PLIC_MXINT_ENABLE_REG, .end = PLIC_MXINT_CLAIM_REG + 4 },
{ .start = PLIC_MXINT_CONF_REG, .end = PLIC_MXINT_CONF_REG + 4 },
{ .start = PLIC_UXINT_ENABLE_REG, .end = PLIC_UXINT_CLAIM_REG + 4 },
{ .start = PLIC_UXINT_CONF_REG, .end = PLIC_UXINT_CONF_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static inline void * cpu_domain_clint_sleep_frame_alloc_and_init(void)
{
const static cpu_domain_dev_regs_region_t regions[] = {
{ .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 },
{ .start = CLINT_UINT_SIP_REG, .end = CLINT_UINT_UTIMECMP_H_REG + 4 }
};
return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]));
}
static esp_err_t esp_sleep_cpu_retention_init_impl(void)
{
if (s_cpu_retention.retent.critical_frame == NULL) {
void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.critical_frame = (RvCoreCriticalSleepFrame *)frame;
rv_core_critical_regs_frame = (RvCoreCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.non_critical_frame == NULL) {
void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL);
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.non_critical_frame = (RvCoreNonCriticalSleepFrame *)frame;
}
if (s_cpu_retention.retent.intpri_frame == NULL) {
void *frame = cpu_domain_intpri_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.intpri_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.cache_config_frame == NULL) {
void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.plic_frame == NULL) {
void *frame = cpu_domain_plic_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.plic_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
if (s_cpu_retention.retent.clint_frame == NULL) {
void *frame = cpu_domain_clint_sleep_frame_alloc_and_init();
if (frame == NULL) {
goto err;
}
s_cpu_retention.retent.clint_frame = (cpu_domain_dev_sleep_frame_t *)frame;
}
return ESP_OK;
err:
esp_sleep_cpu_retention_deinit();
return ESP_ERR_NO_MEM;
}
static esp_err_t esp_sleep_cpu_retention_deinit_impl(void)
{
if (s_cpu_retention.retent.critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.critical_frame);
s_cpu_retention.retent.critical_frame = NULL;
rv_core_critical_regs_frame = NULL;
}
if (s_cpu_retention.retent.non_critical_frame) {
heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame);
s_cpu_retention.retent.non_critical_frame = NULL;
}
if (s_cpu_retention.retent.intpri_frame) {
heap_caps_free((void *)s_cpu_retention.retent.intpri_frame);
s_cpu_retention.retent.intpri_frame = NULL;
}
if (s_cpu_retention.retent.cache_config_frame) {
heap_caps_free((void *)s_cpu_retention.retent.cache_config_frame);
s_cpu_retention.retent.cache_config_frame = NULL;
}
if (s_cpu_retention.retent.plic_frame) {
heap_caps_free((void *)s_cpu_retention.retent.plic_frame);
s_cpu_retention.retent.plic_frame = NULL;
}
if (s_cpu_retention.retent.clint_frame) {
heap_caps_free((void *)s_cpu_retention.retent.clint_frame);
s_cpu_retention.retent.clint_frame = NULL;
}
return ESP_OK;
}
FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void)
{
return RV_READ_MSTATUS_AND_DISABLE_INTR();
}
FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val)
{
RV_WRITE_CSR(mstatus, mstatus_val);
}
static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void)
{
assert(s_cpu_retention.retent.non_critical_frame);
RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame;
frame->mscratch = RV_READ_CSR(mscratch);
frame->mideleg = RV_READ_CSR(mideleg);
frame->misa = RV_READ_CSR(misa);
frame->tselect = RV_READ_CSR(tselect);
frame->tdata1 = RV_READ_CSR(tdata1);
frame->tdata2 = RV_READ_CSR(tdata2);
frame->tcontrol = RV_READ_CSR(tcontrol);
frame->pmpaddr0 = RV_READ_CSR(pmpaddr0);
frame->pmpaddr1 = RV_READ_CSR(pmpaddr1);
frame->pmpaddr2 = RV_READ_CSR(pmpaddr2);
frame->pmpaddr3 = RV_READ_CSR(pmpaddr3);
frame->pmpaddr4 = RV_READ_CSR(pmpaddr4);
frame->pmpaddr5 = RV_READ_CSR(pmpaddr5);
frame->pmpaddr6 = RV_READ_CSR(pmpaddr6);
frame->pmpaddr7 = RV_READ_CSR(pmpaddr7);
frame->pmpaddr8 = RV_READ_CSR(pmpaddr8);
frame->pmpaddr9 = RV_READ_CSR(pmpaddr9);
frame->pmpaddr10 = RV_READ_CSR(pmpaddr10);
frame->pmpaddr11 = RV_READ_CSR(pmpaddr11);
frame->pmpaddr12 = RV_READ_CSR(pmpaddr12);
frame->pmpaddr13 = RV_READ_CSR(pmpaddr13);
frame->pmpaddr14 = RV_READ_CSR(pmpaddr14);
frame->pmpaddr15 = RV_READ_CSR(pmpaddr15);
frame->pmpcfg0 = RV_READ_CSR(pmpcfg0);
frame->pmpcfg1 = RV_READ_CSR(pmpcfg1);
frame->pmpcfg2 = RV_READ_CSR(pmpcfg2);
frame->pmpcfg3 = RV_READ_CSR(pmpcfg3);
frame->pmaaddr0 = RV_READ_CSR(CSR_PMAADDR(0));
frame->pmaaddr1 = RV_READ_CSR(CSR_PMAADDR(1));
frame->pmaaddr2 = RV_READ_CSR(CSR_PMAADDR(2));
frame->pmaaddr3 = RV_READ_CSR(CSR_PMAADDR(3));
frame->pmaaddr4 = RV_READ_CSR(CSR_PMAADDR(4));
frame->pmaaddr5 = RV_READ_CSR(CSR_PMAADDR(5));
frame->pmaaddr6 = RV_READ_CSR(CSR_PMAADDR(6));
frame->pmaaddr7 = RV_READ_CSR(CSR_PMAADDR(7));
frame->pmaaddr8 = RV_READ_CSR(CSR_PMAADDR(8));
frame->pmaaddr9 = RV_READ_CSR(CSR_PMAADDR(9));
frame->pmaaddr10 = RV_READ_CSR(CSR_PMAADDR(10));
frame->pmaaddr11 = RV_READ_CSR(CSR_PMAADDR(11));
frame->pmaaddr12 = RV_READ_CSR(CSR_PMAADDR(12));
frame->pmaaddr13 = RV_READ_CSR(CSR_PMAADDR(13));
frame->pmaaddr14 = RV_READ_CSR(CSR_PMAADDR(14));
frame->pmaaddr15 = RV_READ_CSR(CSR_PMAADDR(15));
frame->pmacfg0 = RV_READ_CSR(CSR_PMACFG(0));
frame->pmacfg1 = RV_READ_CSR(CSR_PMACFG(1));
frame->pmacfg2 = RV_READ_CSR(CSR_PMACFG(2));
frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(3));
frame->pmacfg4 = RV_READ_CSR(CSR_PMACFG(4));
frame->pmacfg5 = RV_READ_CSR(CSR_PMACFG(5));
frame->pmacfg6 = RV_READ_CSR(CSR_PMACFG(6));
frame->pmacfg7 = RV_READ_CSR(CSR_PMACFG(7));
frame->pmacfg8 = RV_READ_CSR(CSR_PMACFG(8));
frame->pmacfg9 = RV_READ_CSR(CSR_PMACFG(9));
frame->pmacfg10 = RV_READ_CSR(CSR_PMACFG(10));
frame->pmacfg11 = RV_READ_CSR(CSR_PMACFG(11));
frame->pmacfg12 = RV_READ_CSR(CSR_PMACFG(12));
frame->pmacfg13 = RV_READ_CSR(CSR_PMACFG(13));
frame->pmacfg14 = RV_READ_CSR(CSR_PMACFG(14));
frame->pmacfg15 = RV_READ_CSR(CSR_PMACFG(15));
frame->utvec = RV_READ_CSR(utvec);
frame->ustatus = RV_READ_CSR(ustatus);
frame->uepc = RV_READ_CSR(uepc);
frame->ucause = RV_READ_CSR(ucause);
frame->mpcer = RV_READ_CSR(CUSTOM_CSR_PCER_MACHINE);
frame->mpcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_MACHINE);
frame->mpccr = RV_READ_CSR(CUSTOM_CSR_PCCR_MACHINE);
frame->cpu_testbus_ctrl = RV_READ_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL);
frame->upcer = RV_READ_CSR(CUSTOM_CSR_PCER_USER);
frame->upcmr = RV_READ_CSR(CUSTOM_CSR_PCMR_USER);
frame->upccr = RV_READ_CSR(CUSTOM_CSR_PCCR_USER);
frame->ugpio_oen = RV_READ_CSR(CUSTOM_CSR_GPIO_OEN_USER);
frame->ugpio_in = RV_READ_CSR(CUSTOM_CSR_GPIO_IN_USER);
frame->ugpio_out = RV_READ_CSR(CUSTOM_CSR_GPIO_OUT_USER);
return frame;
}
static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFrame *frame)
{
assert(frame);
RV_WRITE_CSR(mscratch, frame->mscratch);
RV_WRITE_CSR(mideleg, frame->mideleg);
RV_WRITE_CSR(misa, frame->misa);
RV_WRITE_CSR(tselect, frame->tselect);
RV_WRITE_CSR(tdata1, frame->tdata1);
RV_WRITE_CSR(tdata2, frame->tdata2);
RV_WRITE_CSR(tcontrol, frame->tcontrol);
RV_WRITE_CSR(pmpaddr0, frame->pmpaddr0);
RV_WRITE_CSR(pmpaddr1, frame->pmpaddr1);
RV_WRITE_CSR(pmpaddr2, frame->pmpaddr2);
RV_WRITE_CSR(pmpaddr3, frame->pmpaddr3);
RV_WRITE_CSR(pmpaddr4, frame->pmpaddr4);
RV_WRITE_CSR(pmpaddr5, frame->pmpaddr5);
RV_WRITE_CSR(pmpaddr6, frame->pmpaddr6);
RV_WRITE_CSR(pmpaddr7, frame->pmpaddr7);
RV_WRITE_CSR(pmpaddr8, frame->pmpaddr8);
RV_WRITE_CSR(pmpaddr9, frame->pmpaddr9);
RV_WRITE_CSR(pmpaddr10,frame->pmpaddr10);
RV_WRITE_CSR(pmpaddr11,frame->pmpaddr11);
RV_WRITE_CSR(pmpaddr12,frame->pmpaddr12);
RV_WRITE_CSR(pmpaddr13,frame->pmpaddr13);
RV_WRITE_CSR(pmpaddr14,frame->pmpaddr14);
RV_WRITE_CSR(pmpaddr15,frame->pmpaddr15);
RV_WRITE_CSR(pmpcfg0, frame->pmpcfg0);
RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1);
RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2);
RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3);
RV_WRITE_CSR(CSR_PMAADDR(0), frame->pmaaddr0);
RV_WRITE_CSR(CSR_PMAADDR(1), frame->pmaaddr1);
RV_WRITE_CSR(CSR_PMAADDR(2), frame->pmaaddr2);
RV_WRITE_CSR(CSR_PMAADDR(3), frame->pmaaddr3);
RV_WRITE_CSR(CSR_PMAADDR(4), frame->pmaaddr4);
RV_WRITE_CSR(CSR_PMAADDR(5), frame->pmaaddr5);
RV_WRITE_CSR(CSR_PMAADDR(6), frame->pmaaddr6);
RV_WRITE_CSR(CSR_PMAADDR(7), frame->pmaaddr7);
RV_WRITE_CSR(CSR_PMAADDR(8), frame->pmaaddr8);
RV_WRITE_CSR(CSR_PMAADDR(9), frame->pmaaddr9);
RV_WRITE_CSR(CSR_PMAADDR(10),frame->pmaaddr10);
RV_WRITE_CSR(CSR_PMAADDR(11),frame->pmaaddr11);
RV_WRITE_CSR(CSR_PMAADDR(12),frame->pmaaddr12);
RV_WRITE_CSR(CSR_PMAADDR(13),frame->pmaaddr13);
RV_WRITE_CSR(CSR_PMAADDR(14),frame->pmaaddr14);
RV_WRITE_CSR(CSR_PMAADDR(15),frame->pmaaddr15);
RV_WRITE_CSR(CSR_PMACFG(0), frame->pmacfg0);
RV_WRITE_CSR(CSR_PMACFG(1), frame->pmacfg1);
RV_WRITE_CSR(CSR_PMACFG(2), frame->pmacfg2);
RV_WRITE_CSR(CSR_PMACFG(3), frame->pmacfg3);
RV_WRITE_CSR(CSR_PMACFG(4), frame->pmacfg4);
RV_WRITE_CSR(CSR_PMACFG(5), frame->pmacfg5);
RV_WRITE_CSR(CSR_PMACFG(6), frame->pmacfg6);
RV_WRITE_CSR(CSR_PMACFG(7), frame->pmacfg7);
RV_WRITE_CSR(CSR_PMACFG(8), frame->pmacfg8);
RV_WRITE_CSR(CSR_PMACFG(9), frame->pmacfg9);
RV_WRITE_CSR(CSR_PMACFG(10), frame->pmacfg10);
RV_WRITE_CSR(CSR_PMACFG(11), frame->pmacfg11);
RV_WRITE_CSR(CSR_PMACFG(12), frame->pmacfg12);
RV_WRITE_CSR(CSR_PMACFG(13), frame->pmacfg13);
RV_WRITE_CSR(CSR_PMACFG(14), frame->pmacfg14);
RV_WRITE_CSR(CSR_PMACFG(15), frame->pmacfg15);
RV_WRITE_CSR(utvec, frame->utvec);
RV_WRITE_CSR(ustatus, frame->ustatus);
RV_WRITE_CSR(uepc, frame->uepc);
RV_WRITE_CSR(ucause, frame->ucause);
RV_WRITE_CSR(CUSTOM_CSR_PCER_MACHINE, frame->mpcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_MACHINE, frame->mpcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_MACHINE, frame->mpccr);
RV_WRITE_CSR(CUSTOM_CSR_CPU_TESTBUS_CTRL, frame->cpu_testbus_ctrl);
RV_WRITE_CSR(CUSTOM_CSR_PCER_USER, frame->upcer);
RV_WRITE_CSR(CUSTOM_CSR_PCMR_USER, frame->upcmr);
RV_WRITE_CSR(CUSTOM_CSR_PCCR_USER, frame->upccr);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OEN_USER,frame->ugpio_oen);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_IN_USER, frame->ugpio_in);
RV_WRITE_CSR(CUSTOM_CSR_GPIO_OUT_USER,frame->ugpio_out);
}
static IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
regs_frame[offset++] = *(uint32_t *)addr;
}
}
}
static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *frame)
{
assert(frame);
cpu_domain_dev_regs_region_t *region = frame->region;
uint32_t *regs_frame = frame->regs_frame;
int offset = 0;
for (int i = 0; i < frame->region_num; i++) {
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) {
*(uint32_t *)addr = regs_frame[offset++];
}
}
}
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
*(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size);
}
static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
// resume uarts
for (int i = 0; i < SOC_UART_NUM; ++i) {
if (!uart_ll_is_enabled(i)) {
continue;
}
uart_ll_force_xon(i);
}
/* Since it is still in the critical now, use ESP_EARLY_LOG */
ESP_EARLY_LOGE(TAG, "Sleep retention frame is corrupted");
esp_restart_noos();
}
}
#endif
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void);
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void);
typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool);
static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep,
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save();
if ((frame->pmufunc & 0x3) == 0x1) {
esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_END, (void *)0);
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus 2 * sizeof(long) is for bypass `pmufunc` and `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
REG_WRITE(LIGHT_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore);
return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
}
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
else {
validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
}
#endif
return pmu_sleep_finish();
}
esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool),
uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp)
{
esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0);
uint32_t mstatus = save_mstatus_and_disable_global_int();
cpu_domain_dev_regs_save(s_cpu_retention.retent.plic_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame);
RvCoreNonCriticalSleepFrame *frame = rv_core_noncritical_regs_save();
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus sizeof(long) is for bypass `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
validate_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
rv_core_noncritical_regs_restore(frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.intpri_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.plic_frame);
restore_mstatus(mstatus);
return err;
}
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_retention_init_impl();
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_retention_deinit_impl();
}
bool cpu_domain_pd_allowed(void)
{
return (s_cpu_retention.retent.critical_frame != NULL) && \
(s_cpu_retention.retent.non_critical_frame != NULL) && \
(s_cpu_retention.retent.intpri_frame != NULL) && \
(s_cpu_retention.retent.cache_config_frame != NULL) && \
(s_cpu_retention.retent.plic_frame != NULL) && \
(s_cpu_retention.retent.clint_frame != NULL);
}
esp_err_t sleep_cpu_configure(bool light_sleep_enable)
{
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
if (light_sleep_enable) {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep.");
} else {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_deinit(), TAG, "Failed to release CPU retention memory");
}
#endif
return ESP_OK;
}

Wyświetl plik

@ -0,0 +1,216 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "rvsleep-frames.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
.section .data1,"aw"
.global rv_core_critical_regs_frame
.type rv_core_critical_regs_frame,@object
.align 4
rv_core_critical_regs_frame:
.word 0
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to save the critical registers of the CPU
core to the internal RAM before sleep, and modify the PMU control flag to
indicate that the system needs to sleep. When the subroutine returns, it
will return the memory pointer that saves the context information of the CPU
critical registers.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_save
.type rv_core_critical_regs_save,@function
.align 4
rv_core_critical_regs_save:
/* arrived here in critical section. we need:
save riscv core critical registers to RvCoreCriticalSleepFrame
*/
csrw mscratch, t0 /* use mscratch as temp storage */
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
sw ra, RV_SLP_CTX_RA(t0)
sw sp, RV_SLP_CTX_SP(t0)
sw gp, RV_SLP_CTX_GP(t0)
sw tp, RV_SLP_CTX_TP(t0)
sw t1, RV_SLP_CTX_T1(t0)
sw t2, RV_SLP_CTX_T2(t0)
sw s0, RV_SLP_CTX_S0(t0)
sw s1, RV_SLP_CTX_S1(t0)
/* a0 is caller saved, so it does not need to be saved, but it should be the
pointer value of RvCoreCriticalSleepFrame for return.
*/
mv a0, t0
sw a0, RV_SLP_CTX_A0(t0)
sw a1, RV_SLP_CTX_A1(t0)
sw a2, RV_SLP_CTX_A2(t0)
sw a3, RV_SLP_CTX_A3(t0)
sw a4, RV_SLP_CTX_A4(t0)
sw a5, RV_SLP_CTX_A5(t0)
sw a6, RV_SLP_CTX_A6(t0)
sw a7, RV_SLP_CTX_A7(t0)
sw s2, RV_SLP_CTX_S2(t0)
sw s3, RV_SLP_CTX_S3(t0)
sw s4, RV_SLP_CTX_S4(t0)
sw s5, RV_SLP_CTX_S5(t0)
sw s6, RV_SLP_CTX_S6(t0)
sw s7, RV_SLP_CTX_S7(t0)
sw s8, RV_SLP_CTX_S8(t0)
sw s9, RV_SLP_CTX_S9(t0)
sw s10, RV_SLP_CTX_S10(t0)
sw s11, RV_SLP_CTX_S11(t0)
sw t3, RV_SLP_CTX_T3(t0)
sw t4, RV_SLP_CTX_T4(t0)
sw t5, RV_SLP_CTX_T5(t0)
sw t6, RV_SLP_CTX_T6(t0)
csrr t1, mstatus
sw t1, RV_SLP_CTX_MSTATUS(t0)
csrr t2, mtvec
sw t2, RV_SLP_CTX_MTVEC(t0)
csrr t3, mcause
sw t3, RV_SLP_CTX_MCAUSE(t0)
csrr t1, mtval
sw t1, RV_SLP_CTX_MTVAL(t0)
csrr t2, mie
sw t2, RV_SLP_CTX_MIE(t0)
csrr t3, mip
sw t3, RV_SLP_CTX_MIP(t0)
csrr t1, mepc
sw t1, RV_SLP_CTX_MEPC(t0)
/*
!!! Let idf knows it's going to sleep !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
li t1, ~0x3
lw t2, RV_SLP_CTX_PMUFUNC(t0)
and t2, t1, t2
ori t2, t2, 0x1
sw t2, RV_SLP_CTX_PMUFUNC(t0)
mv t3, t0
csrr t0, mscratch
lw t1, RV_SLP_CTX_T1(t3)
lw t2, RV_SLP_CTX_T2(t3)
lw t3, RV_SLP_CTX_T3(t3)
ret
.size rv_core_critical_regs_save, . - rv_core_critical_regs_save
#define CSR_PCER_U 0x800
#define CSR_PCMR_U 0x801
#define PCER_CYCLES (1<<0) /* count clock cycles */
#define PCMR_GLOBAL_EN (1<<0) /* enable count */
#define pcer CSR_PCER_U
#define pcmr CSR_PCMR_U
/*
--------------------------------------------------------------------------------
This assembly subroutine is used to restore the CPU core critical register
context before sleep after system wakes up, modify the PMU control
information, and return the critical register context memory object pointer.
After the subroutine returns, continue to restore other modules of the
system.
--------------------------------------------------------------------------------
*/
.section .iram1,"ax"
.global rv_core_critical_regs_restore
.weak rv_core_critical_regs_restore
.type rv_core_critical_regs_restore,@function
.global _rv_core_critical_regs_restore
.type _rv_core_critical_regs_restore,@function
.align 4
_rv_core_critical_regs_restore: /* export a strong symbol to jump to here, used
* for a static callback */
nop
rv_core_critical_regs_restore:
la t0, rv_core_critical_regs_frame
lw t0, 0(t0) /* t0 pointer to RvCoreCriticalSleepFrame object */
beqz t0, .skip_restore /* make sure we do not jump to zero address */
/*
!!! Let idf knows it's sleep awake. !!!
RV_SLP_STK_PMUFUNC field is used to identify whether it is going to sleep or
has just been awakened. We use the lowest 2 bits as indication information,
3 means being awakened, 1 means going to sleep.
*/
lw t1, RV_SLP_CTX_PMUFUNC(t0)
ori t1, t1, 0x3
sw t1, RV_SLP_CTX_PMUFUNC(t0)
lw t2, RV_SLP_CTX_MEPC(t0)
csrw mepc, t2
lw t3, RV_SLP_CTX_MIP(t0)
csrw mip, t3
lw t1, RV_SLP_CTX_MIE(t0)
csrw mie, t1
lw t2, RV_SLP_CTX_MSTATUS(t0)
csrw mstatus, t2
lw t3, RV_SLP_CTX_MTVEC(t0)
csrw mtvec, t3
lw t1, RV_SLP_CTX_MCAUSE(t0)
csrw mcause, t1
lw t2, RV_SLP_CTX_MTVAL(t0)
csrw mtval, t2
lw t6, RV_SLP_CTX_T6(t0)
lw t5, RV_SLP_CTX_T5(t0)
lw t4, RV_SLP_CTX_T4(t0)
lw t3, RV_SLP_CTX_T3(t0)
lw s11, RV_SLP_CTX_S11(t0)
lw s10, RV_SLP_CTX_S10(t0)
lw s9, RV_SLP_CTX_S9(t0)
lw s8, RV_SLP_CTX_S8(t0)
lw s7, RV_SLP_CTX_S7(t0)
lw s6, RV_SLP_CTX_S6(t0)
lw s5, RV_SLP_CTX_S5(t0)
lw s4, RV_SLP_CTX_S4(t0)
lw s3, RV_SLP_CTX_S3(t0)
lw s2, RV_SLP_CTX_S2(t0)
lw a7, RV_SLP_CTX_A7(t0)
lw a6, RV_SLP_CTX_A6(t0)
lw a5, RV_SLP_CTX_A5(t0)
lw a4, RV_SLP_CTX_A4(t0)
lw a3, RV_SLP_CTX_A3(t0)
lw a2, RV_SLP_CTX_A2(t0)
lw a1, RV_SLP_CTX_A1(t0)
lw a0, RV_SLP_CTX_A0(t0)
lw s1, RV_SLP_CTX_S1(t0)
lw s0, RV_SLP_CTX_S0(t0)
lw t2, RV_SLP_CTX_T2(t0)
lw t1, RV_SLP_CTX_T1(t0)
lw tp, RV_SLP_CTX_TP(t0)
lw gp, RV_SLP_CTX_GP(t0)
lw sp, RV_SLP_CTX_SP(t0)
lw ra, RV_SLP_CTX_RA(t0)
lw t0, RV_SLP_CTX_T0(t0)
.skip_restore:
ret
.size rv_core_critical_regs_restore, . - rv_core_critical_regs_restore

Wyświetl plik

@ -0,0 +1,243 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_ipc_isr.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_crc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "soc/rtc_periph.h"
#include "soc/soc_caps.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/sleep_event.h"
#include "sdkconfig.h"
#include "hal/rtc_hal.h"
#include "esp32s3/rom/cache.h"
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 {
rtc_cntl_sleep_retent_t retent;
} sleep_cpu_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention;
#if CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
static rtc_cntl_sleep_cache_tag_retent_t *s_tag_mem = &s_cpu_retention.retent.tagmem;
static uint32_t cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t code_seg_size, uint32_t data_seg_vaddr, uint32_t data_seg_size)
{
uint32_t sets; /* i/d-cache total set counts */
uint32_t index; /* virtual address mapping i/d-cache row offset */
uint32_t waysgrp;
uint32_t icache_tagmem_blk_gs, dcache_tagmem_blk_gs;
struct cache_mode imode = { .icache = 1 };
struct cache_mode dmode = { .icache = 0 };
/* calculate/prepare i-cache tag memory retention parameters */
Cache_Get_Mode(&imode);
sets = imode.cache_size / imode.cache_ways / imode.cache_line_size;
index = (code_seg_vaddr / imode.cache_line_size) % sets;
waysgrp = imode.cache_ways >> 2;
code_seg_size = ALIGNUP(imode.cache_line_size, code_seg_size);
s_tag_mem->icache.start_point = index;
s_tag_mem->icache.size = (sets * waysgrp) & 0xff;
s_tag_mem->icache.vld_size = s_tag_mem->icache.size;
if (code_seg_size < imode.cache_size / imode.cache_ways) {
s_tag_mem->icache.vld_size = (code_seg_size / imode.cache_line_size) * waysgrp;
}
s_tag_mem->icache.enable = (code_seg_size != 0) ? 1 : 0;
icache_tagmem_blk_gs = s_tag_mem->icache.vld_size ? s_tag_mem->icache.vld_size : sets * waysgrp;
icache_tagmem_blk_gs = ALIGNUP(4, icache_tagmem_blk_gs);
ESP_LOGD(TAG, "I-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (imode.cache_size>>10),
imode.cache_line_size, imode.cache_ways, sets, index, icache_tagmem_blk_gs);
/* calculate/prepare d-cache tag memory retention parameters */
Cache_Get_Mode(&dmode);
sets = dmode.cache_size / dmode.cache_ways / dmode.cache_line_size;
index = (data_seg_vaddr / dmode.cache_line_size) % sets;
waysgrp = dmode.cache_ways >> 2;
data_seg_size = ALIGNUP(dmode.cache_line_size, data_seg_size);
s_tag_mem->dcache.start_point = index;
s_tag_mem->dcache.size = (sets * waysgrp) & 0x1ff;
s_tag_mem->dcache.vld_size = s_tag_mem->dcache.size;
#ifndef CONFIG_ESP32S3_DATA_CACHE_16KB
if (data_seg_size < dmode.cache_size / dmode.cache_ways) {
s_tag_mem->dcache.vld_size = (data_seg_size / dmode.cache_line_size) * waysgrp;
}
s_tag_mem->dcache.enable = (data_seg_size != 0) ? 1 : 0;
#else
s_tag_mem->dcache.enable = 1;
#endif
dcache_tagmem_blk_gs = s_tag_mem->dcache.vld_size ? s_tag_mem->dcache.vld_size : sets * waysgrp;
dcache_tagmem_blk_gs = ALIGNUP(4, dcache_tagmem_blk_gs);
ESP_LOGD(TAG, "D-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (dmode.cache_size>>10),
dmode.cache_line_size, dmode.cache_ways, sets, index, dcache_tagmem_blk_gs);
/* For I or D cache tagmem retention, backup and restore are performed through
* RTC DMA (its bus width is 128 bits), For I/D Cache tagmem blocks (i-cache
* tagmem blocks = 92 bits, d-cache tagmem blocks = 88 bits), RTC DMA automatically
* aligns its bit width to 96 bits, therefore, 3 times RTC DMA can transfer 4
* i/d-cache tagmem blocks (128 bits * 3 = 96 bits * 4) */
return (((icache_tagmem_blk_gs + dcache_tagmem_blk_gs) << 2) * 3);
}
#endif // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
static esp_err_t esp_sleep_tagmem_pd_low_init(void)
{
#if CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
if (s_tag_mem->link_addr == NULL) {
extern char _stext[], _etext[];
uint32_t code_start = (uint32_t)_stext;
uint32_t code_size = (uint32_t)(_etext - _stext);
#if !(CONFIG_SPIRAM && CONFIG_SOC_PM_SUPPORT_TAGMEM_PD)
extern char _rodata_start[], _rodata_reserved_end[];
uint32_t data_start = (uint32_t)_rodata_start;
uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else
uint32_t data_start = SOC_DROM_LOW;
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
#endif
ESP_LOGI(TAG, "Code start at 0x%08"PRIx32", total %"PRIu32", data start at 0x%08"PRIx32", total %"PRIu32" Bytes",
code_start, code_size, data_start, data_size);
uint32_t tagmem_sz = cache_tagmem_retention_setup(code_start, code_size, data_start, data_size);
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_TAGMEM_PD_DMA_ADDR_ALIGN, 1,
tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_tag_mem->link_addr = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, tagmem_sz, NULL);
} else {
s_tag_mem->icache.enable = 0;
s_tag_mem->dcache.enable = 0;
s_tag_mem->link_addr = NULL;
return ESP_ERR_NO_MEM;
}
}
#else // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
s_tag_mem->icache.enable = 0;
s_tag_mem->dcache.enable = 0;
s_tag_mem->link_addr = NULL;
#endif // CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP
return ESP_OK;
}
static esp_err_t esp_sleep_tagmem_pd_low_deinit(void)
{
if (s_tag_mem->link_addr) {
heap_caps_free(s_tag_mem->link_addr);
s_tag_mem->icache.enable = 0;
s_tag_mem->dcache.enable = 0;
s_tag_mem->link_addr = NULL;
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_pd_low_init(void)
{
if (s_cpu_retention.retent.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_calloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, 1,
SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION);
if (buf) {
s_cpu_retention.retent.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf + RTC_HAL_DMA_LINK_NODE_SIZE, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
if (esp_sleep_tagmem_pd_low_init() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
return ESP_OK;
}
esp_err_t esp_sleep_cpu_pd_low_deinit(void)
{
if (s_cpu_retention.retent.cpu_pd_mem) {
heap_caps_free(s_cpu_retention.retent.cpu_pd_mem);
s_cpu_retention.retent.cpu_pd_mem = NULL;
}
if (esp_sleep_tagmem_pd_low_deinit() != ESP_OK) {
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
esp_sleep_cpu_pd_low_deinit();
return ESP_ERR_NO_MEM;
#endif
}
return ESP_OK;
}
void sleep_enable_cpu_retention(void)
{
rtc_cntl_hal_enable_cpu_retention(&s_cpu_retention.retent);
rtc_cntl_hal_enable_tagmem_retention(&s_cpu_retention.retent);
}
void IRAM_ATTR sleep_disable_cpu_retention(void)
{
rtc_cntl_hal_disable_cpu_retention(&s_cpu_retention.retent);
rtc_cntl_hal_disable_tagmem_retention(&s_cpu_retention.retent);
}
esp_err_t esp_sleep_cpu_retention_init(void)
{
return esp_sleep_cpu_pd_low_init();
}
esp_err_t esp_sleep_cpu_retention_deinit(void)
{
return esp_sleep_cpu_pd_low_deinit();
}
bool cpu_domain_pd_allowed(void)
{
return (s_cpu_retention.retent.cpu_pd_mem != NULL);
}
esp_err_t sleep_cpu_configure(bool light_sleep_enable)
{
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
if (light_sleep_enable) {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep.");
} else {
ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_deinit(), TAG, "Failed to release CPU retention memory");
}
#endif
return ESP_OK;
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -28,26 +28,30 @@
extern "C" {
#endif
#if SOC_PM_SUPPORT_TAGMEM_PD
typedef struct rtc_cntl_sleep_cache_tag_retent {
void *link_addr; /* Internal ram address for tagmem retention */
struct {
uint32_t start_point: 8, /* the row of start for i-cache tag memory */
vld_size: 8, /* valid size of i-cache tag memory, unit: 4 i-cache tagmem blocks */
size: 8, /* i-cache tag memory size, unit: 4 i-cache tagmem blocks */
enable: 1; /* enable or disable i-cache tagmem retention */
} icache;
struct {
uint32_t start_point: 9, /* the row of start for d-cache tag memory */
vld_size: 9, /* valid size of d-cache tag memory, unit: 4 d-cache tagmem blocks */
size: 9, /* d-cache tag memory size, unit: 4 d-cache tagmem blocks */
enable: 1; /* enable or disable d-cache tagmem retention */
} dcache;
} rtc_cntl_sleep_cache_tag_retent_t;
#endif
typedef struct rtc_cntl_sleep_retent {
#if SOC_PM_SUPPORT_CPU_PD
void *cpu_pd_mem; /* Internal ram address for cpu retention */
void *cpu_pd_mem; /* Internal ram address for cpu retention */
#endif // SOC_PM_SUPPORT_CPU_PD
#if SOC_PM_SUPPORT_TAGMEM_PD
struct {
void *link_addr; /* Internal ram address for tagmem retention */
struct {
uint32_t start_point: 8, /* the row of start for i-cache tag memory */
vld_size: 8, /* valid size of i-cache tag memory, unit: 4 i-cache tagmem blocks */
size: 8, /* i-cache tag memory size, unit: 4 i-cache tagmem blocks */
enable: 1; /* enable or disable i-cache tagmem retention */
} icache;
struct {
uint32_t start_point: 9, /* the row of start for d-cache tag memory */
vld_size: 9, /* valid size of d-cache tag memory, unit: 4 d-cache tagmem blocks */
size: 9, /* d-cache tag memory size, unit: 4 d-cache tagmem blocks */
enable: 1; /* enable or disable d-cache tagmem retention */
} dcache;
} tagmem;
rtc_cntl_sleep_cache_tag_retent_t tagmem; /* I/D Cache tag memory retention information */
#endif // SOC_PM_SUPPORT_TAGMEM_PD
} rtc_cntl_sleep_retent_t;

Wyświetl plik

@ -182,6 +182,9 @@ extern "C" {
#define RV_SET_CSR_FIELD(_r, _f, _v) ({ (RV_WRITE_CSR((_r),((RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S)))));})
#define RV_CLEAR_CSR_FIELD(_r, _f) ({ (RV_WRITE_CSR((_r),(RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))));})
#define RV_READ_MSTATUS_AND_DISABLE_INTR() ({ unsigned long __tmp; \
asm volatile ("csrrci %0, mstatus, 0x8" : "=r"(__tmp)); __tmp; })
#define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */
#ifdef __cplusplus

Wyświetl plik

@ -146,4 +146,3 @@ components/espcoredump/include/port/xtensa/esp_core_dump_summary_port.h
components/riscv/include/esp_private/panic_reason.h
components/riscv/include/riscv/interrupt.h
components/riscv/include/riscv/rvruntime-frames.h
components/riscv/include/riscv/rvsleep-frames.h