From 9b99fc90339e0d06e2f20c76bb7432ffc15100b6 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 11 Jan 2023 14:12:40 +0800 Subject: [PATCH] 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 --- components/esp_hw_support/CMakeLists.txt | 8 + .../include/esp_private/sleep_cpu.h | 8 + components/esp_hw_support/sleep_cpu.c | 429 +++++++++++++++++- components/esp_hw_support/sleep_cpu_asm.S | 239 ++++++++++ components/esp_rom/include/esp32c6/rom/rtc.h | 40 +- .../riscv/include/riscv/rvsleep-frames.h | 153 +++++++ tools/ci/check_public_headers_exceptions.txt | 1 + 7 files changed, 840 insertions(+), 38 deletions(-) create mode 100644 components/esp_hw_support/sleep_cpu_asm.S create mode 100644 components/riscv/include/riscv/rvsleep-frames.h diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 81a9e4d36f..fb5e8056fc 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -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() diff --git a/components/esp_hw_support/include/esp_private/sleep_cpu.h b/components/esp_hw_support/include/esp_private/sleep_cpu.h index 1e58100e30..0e05797443 100644 --- a/components/esp_hw_support/include/esp_private/sleep_cpu.h +++ b/components/esp_hw_support/include/esp_private/sleep_cpu.h @@ -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 diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index 472601babc..2f01bdc779 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -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 diff --git a/components/esp_hw_support/sleep_cpu_asm.S b/components/esp_hw_support/sleep_cpu_asm.S new file mode 100644 index 0000000000..c62756d889 --- /dev/null +++ b/components/esp_hw_support/sleep_cpu_asm.S @@ -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 diff --git a/components/esp_rom/include/esp32c6/rom/rtc.h b/components/esp_rom/include/esp32c6/rom/rtc.h index 844f010147..3fba551945 100644 --- a/components/esp_rom/include/esp32c6/rom/rtc.h +++ b/components/esp_rom/include/esp32c6/rom/rtc.h @@ -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. diff --git a/components/riscv/include/riscv/rvsleep-frames.h b/components/riscv/include/riscv/rvsleep-frames.h new file mode 100644 index 0000000000..06b2b75d8c --- /dev/null +++ b/components/riscv/include/riscv/rvsleep-frames.h @@ -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__ */ diff --git a/tools/ci/check_public_headers_exceptions.txt b/tools/ci/check_public_headers_exceptions.txt index acbbb06184..024e6b9eb6 100644 --- a/tools/ci/check_public_headers_exceptions.txt +++ b/tools/ci/check_public_headers_exceptions.txt @@ -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