mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
cpu retention: software cpu retention support for esp32c6
cpu retention: add riscv core sleep critical and non-critical register layout structure definition cpu retention: add assembly subroutine for cpu critical register backup and restore cpu retention: add cpu core critical register context backup and restore support cpu retention: add cpu core non-critical register context backup and restore support cpu retention: add interrupt priority register context backup and restore support cpu retention: add cache config register context backup and restore support cpu retention: add plic interrupt register context backup and restore support cpu retention: add clint interrupt register context backup and restore support cpu retention: wait icache state idle before pmu enter sleep
This commit is contained in:
parent
1c39d64f95
commit
9b99fc9033
@ -73,6 +73,14 @@ if(NOT BOOTLOADER_BUILD)
|
||||
list(APPEND srcs "esp_ds.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)
|
||||
list(APPEND srcs "modem_clock.c")
|
||||
endif()
|
||||
|
@ -50,6 +50,14 @@ void sleep_disable_cpu_retention(void);
|
||||
|
||||
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_RTCCNTL
|
||||
|
||||
|
||||
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
|
||||
|
||||
esp_err_t 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);
|
||||
|
||||
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
@ -16,22 +17,55 @@
|
||||
#include "freertos/task.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/rtc_hal.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !SOC_PMU_SUPPORTED
|
||||
#include "hal/rtc_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"
|
||||
#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 {
|
||||
#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;
|
||||
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;
|
||||
#endif
|
||||
} sleep_cpu_retention_t;
|
||||
|
||||
@ -40,12 +74,12 @@ 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_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP
|
||||
static int cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t code_seg_size, uint32_t data_seg_vaddr, uint32_t data_seg_size)
|
||||
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)
|
||||
{
|
||||
int sets; /* i/d-cache total set counts */
|
||||
int index; /* virtual address mapping i/d-cache row offset */
|
||||
int waysgrp;
|
||||
int icache_tagmem_blk_gs, dcache_tagmem_blk_gs;
|
||||
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 };
|
||||
|
||||
@ -117,14 +151,13 @@ static esp_err_t esp_sleep_tagmem_pd_low_init(void)
|
||||
uint32_t data_start = SOC_DROM_LOW;
|
||||
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Code start at %08x, total %.2f KiB, data start at %08x, total %.2f KiB",
|
||||
code_start, (float)code_size/1024, data_start, (float)data_size/1024);
|
||||
int tagmem_sz = cache_tagmem_retention_setup(code_start, code_size, data_start, data_size);
|
||||
void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_TAGMEM_PD_DMA_ADDR_ALIGN,
|
||||
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) {
|
||||
memset(buf, 0, tagmem_sz + RTC_HAL_DMA_LINK_NODE_SIZE);
|
||||
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 {
|
||||
@ -161,11 +194,10 @@ static esp_err_t esp_sleep_tagmem_pd_low_deinit(void)
|
||||
esp_err_t esp_sleep_cpu_pd_low_init(void)
|
||||
{
|
||||
if (s_cpu_retention.retent.cpu_pd_mem == NULL) {
|
||||
void *buf = heap_caps_aligned_alloc(SOC_RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN,
|
||||
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) {
|
||||
memset(buf, 0, SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE);
|
||||
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 {
|
||||
@ -204,25 +236,371 @@ esp_err_t esp_sleep_cpu_pd_low_deinit(void)
|
||||
|
||||
void sleep_enable_cpu_retention(void)
|
||||
{
|
||||
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_REGDMA
|
||||
rtc_cntl_hal_enable_cpu_retention(&s_cpu_retention.retent);
|
||||
#endif
|
||||
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_REGDMA
|
||||
|
||||
#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)
|
||||
{
|
||||
#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_REGDMA
|
||||
rtc_cntl_hal_disable_cpu_retention(&s_cpu_retention.retent);
|
||||
#endif
|
||||
#if SOC_PM_SUPPORT_TAGMEM_PD && SOC_PM_CPU_RETENTION_BY_REGDMA
|
||||
|
||||
#if SOC_PM_SUPPORT_TAGMEM_PD
|
||||
rtc_cntl_hal_disable_tagmem_retention(&s_cpu_retention.retent);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_REGDMA
|
||||
#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
|
||||
#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 = EXTMEM_DCACHE_CTRL_REG, .end = EXTMEM_DCACHE_CTRL_REG + 4 },
|
||||
{ .start = EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, .end = EXTMEM_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;
|
||||
}
|
||||
|
||||
static inline IRAM_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;
|
||||
}
|
||||
|
||||
static inline IRAM_ATTR void restore_mstatus(uint32_t mstatus)
|
||||
{
|
||||
__asm__ __volatile__ ("csrw mstatus, %0\n" :: "r"(mstatus));
|
||||
}
|
||||
|
||||
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->pmpcfg0 = RV_READ_CSR(pmpcfg0);
|
||||
frame->pmpcfg1 = RV_READ_CSR(pmpcfg1);
|
||||
frame->pmpcfg2 = RV_READ_CSR(pmpcfg2);
|
||||
frame->pmpcfg3 = RV_READ_CSR(pmpcfg3);
|
||||
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->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(pmpcfg0, frame->pmpcfg0);
|
||||
RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1);
|
||||
RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2);
|
||||
RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3);
|
||||
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(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++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
REG_CLR_BIT(SLEEP_MODE_REG, BIT(0)); /* Tell rom to run light sleep wake stub */
|
||||
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);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32_t mstatus = save_mstatus_and_disable_global_int();
|
||||
|
||||
/* wait cache idle */
|
||||
Cache_Freeze_ICache_Enable(CACHE_FREEZE_ACK_BUSY);
|
||||
Cache_Freeze_ICache_Disable();
|
||||
|
||||
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();
|
||||
|
||||
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif // SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW
|
||||
|
||||
|
||||
#if SOC_PM_SUPPORT_CPU_PD
|
||||
@ -232,6 +610,8 @@ 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;
|
||||
}
|
||||
@ -241,6 +621,8 @@ 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;
|
||||
}
|
||||
@ -249,6 +631,13 @@ 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
|
||||
|
239
components/esp_hw_support/sleep_cpu_asm.S
Normal file
239
components/esp_hw_support/sleep_cpu_asm.S
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "riscv/rvsleep-frames.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32C6
|
||||
#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
|
||||
.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)
|
||||
sw a0, RV_SLP_CTX_A0(t0)
|
||||
|
||||
/* !! WARNING, do not use the a0 register below, a0 carries important sleep
|
||||
* information and will be returned as the return value !! */
|
||||
mv 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
|
||||
sw t0, RV_SLP_CTX_T0(t3)
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32C6
|
||||
/* 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)
|
||||
|
||||
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
|
||||
.type rv_core_critical_regs_restore,@function
|
||||
.align 4
|
||||
|
||||
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
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -32,7 +32,7 @@ extern "C" {
|
||||
* Please do not use reserved or used rtc memory or registers. *
|
||||
* *
|
||||
*************************************************************************************
|
||||
* RTC Memory & Store Register usage
|
||||
* LP Memory & Store Register usage
|
||||
*************************************************************************************
|
||||
* rtc memory addr type size usage
|
||||
* 0x3f421000(0x50000000) Slow SIZE_CP Co-Processor code/Reset Entry
|
||||
@ -42,25 +42,29 @@ extern "C" {
|
||||
*
|
||||
*************************************************************************************
|
||||
* RTC store registers usage
|
||||
* RTC_CNTL_STORE0_REG Reserved
|
||||
* RTC_CNTL_STORE1_REG RTC_SLOW_CLK calibration value
|
||||
* RTC_CNTL_STORE2_REG Boot time, low word
|
||||
* RTC_CNTL_STORE3_REG Boot time, high word
|
||||
* RTC_CNTL_STORE4_REG External XTAL frequency
|
||||
* RTC_CNTL_STORE5_REG APB bus frequency
|
||||
* RTC_CNTL_STORE6_REG FAST_RTC_MEMORY_ENTRY
|
||||
* RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC
|
||||
* LP_AON_STORE0_REG Reserved
|
||||
* LP_AON_STORE1_REG RTC_SLOW_CLK calibration value
|
||||
* LP_AON_STORE2_REG Boot time, low word
|
||||
* LP_AON_STORE3_REG Boot time, high word
|
||||
* LP_AON_STORE4_REG External XTAL frequency
|
||||
* LP_AON_STORE5_REG FAST_RTC_MEMORY_LENGTH
|
||||
* LP_AON_STORE6_REG FAST_RTC_MEMORY_ENTRY
|
||||
* LP_AON_STORE7_REG FAST_RTC_MEMORY_CRC
|
||||
* LP_AON_STORE8_REG Store light sleep wake stub addr
|
||||
* LP_AON_STORE9_REG Store the sleep mode at bit[0] (0:light sleep 1:deep sleep)
|
||||
*************************************************************************************
|
||||
*/
|
||||
|
||||
#define RTC_SLOW_CLK_CAL_REG LP_AON_STORE1_REG
|
||||
#define RTC_BOOT_TIME_LOW_REG LP_AON_STORE2_REG
|
||||
#define RTC_BOOT_TIME_HIGH_REG LP_AON_STORE3_REG
|
||||
#define RTC_XTAL_FREQ_REG LP_AON_STORE4_REG
|
||||
#define RTC_APB_FREQ_REG LP_AON_STORE5_REG
|
||||
#define RTC_ENTRY_ADDR_REG LP_AON_STORE6_REG
|
||||
#define RTC_RESET_CAUSE_REG LP_AON_STORE6_REG
|
||||
#define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG
|
||||
#define RTC_SLOW_CLK_CAL_REG LP_AON_STORE1_REG
|
||||
#define RTC_BOOT_TIME_LOW_REG LP_AON_STORE2_REG
|
||||
#define RTC_BOOT_TIME_HIGH_REG LP_AON_STORE3_REG
|
||||
#define RTC_XTAL_FREQ_REG LP_AON_STORE4_REG
|
||||
#define RTC_ENTRY_LENGTH_REG LP_AON_STORE5_REG
|
||||
#define RTC_ENTRY_ADDR_REG LP_AON_STORE6_REG
|
||||
#define RTC_RESET_CAUSE_REG LP_AON_STORE6_REG
|
||||
#define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG
|
||||
#define LIGHT_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG
|
||||
#define SLEEP_MODE_REG LP_AON_STORE9_REG
|
||||
|
||||
#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code.
|
||||
|
||||
|
153
components/riscv/include/riscv/rvsleep-frames.h
Normal file
153
components/riscv/include/riscv/rvsleep-frames.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RVSLEEP_FRAMES_H__
|
||||
#define __RVSLEEP_FRAMES_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 */
|
||||
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_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_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_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)
|
||||
STRUCT_END(RvCoreNonCriticalSleepFrame)
|
||||
|
||||
#endif /* #ifndef __RVSLEEP_FRAMES_H__ */
|
@ -156,3 +156,4 @@ 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user