From 909573f8e7b9dff91677ade64fad1bef5f953b24 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Tue, 19 Aug 2025 11:10:44 +0800 Subject: [PATCH 01/13] Revert "change(esp_hw_support): comment out for ci pass in esp32h4beta5" This reverts commit 9f4a5681639022430bde7666c40994f512b5e417. --- components/soc/esp32h4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32h4/include/soc/soc_caps.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 035e132b26..ca6afb1647 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -847,6 +847,10 @@ config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 7cf25e5666..5b1cce4213 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -488,7 +488,7 @@ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) -// #define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ // #define SOC_UART_WAKEUP_CHARS_SEQ_MAX_LEN 5 #define SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE (1) From bc4c9952bbf594562576c6059400a142ad80abf1 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 7 Jul 2025 14:32:52 +0800 Subject: [PATCH 02/13] change(esp_hw_support): support cpu domain power down and cpu retention for esp32h4 beta5 --- .../lowpower/port/esp32h4/rvsleep-frames.h | 214 +++++ .../lowpower/port/esp32h4/sleep_cpu.c | 753 ++++++++++++++++++ .../lowpower/port/esp32h4/sleep_cpu_asm.S | 255 ++++++ components/esp_hw_support/sleep_modes.c | 4 +- components/esp_system/system_init_fn.txt | 1 + .../hal/esp32h4/include/hal/clk_gate_ll.h | 92 +++ .../esp32h4/include/soc/Kconfig.soc_caps.in | 8 + components/soc/esp32h4/include/soc/soc_caps.h | 4 +- 8 files changed, 1327 insertions(+), 4 deletions(-) create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S create mode 100644 components/hal/esp32h4/include/hal/clk_gate_ll.h diff --git a/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h b/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h new file mode 100644 index 0000000000..e7521996e0 --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h @@ -0,0 +1,214 @@ +/* + * SPDX-FileCopyrightText: 2025 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 information, 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_MISA, misa) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MSCRATCHCSW, mscratchcsw) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MSCRATCHCSW1, mscratchcsw1) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MCYCLEH, mcycleh) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MINSTRET, minstret) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MINSTRETH, minstreth) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MCOUNTEREN, mcounteren) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MCOUNTINHIBIT, mcountinhibit) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER8, mhpmcounter8) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER9, mhpmcounter9) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER13, mhpmcounter13) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER8H, mhpmcounter8h) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER9H, mhpmcounter9h) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMCOUNTER13H, mhpmcounter13h) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMEVENT8, mhpmevent8) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMEVENT9, mhpmevent9) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHPMEVENT13, mhpmevent13) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MCONTEXT, mcontext) + STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus) + STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec) + STRUCT_FIELD (long, 4, RV_SLP_CTX_USCRATCH, uscratch) + STRUCT_FIELD (long, 4, RV_SLP_CTX_UCAUSE, ucause) + STRUCT_FIELD (long, 4, RV_SLP_CTX_UINTTHRESH, uintthresh) + + 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_TDATA3, tdata3) + 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) + +#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) + 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) +#endif // SOC_CPU_HAS_PMA + + STRUCT_FIELD (long, 4, RV_SLP_CTX_MCYCLE, mcycle) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVT, mtvt) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MINTTHRESH, mintthresh) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MXSTATUS, mxstatus) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHCR, mhcr) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MHINT, mhint) + STRUCT_FIELD (long, 4, RV_SLP_CTX_MEXSTATUS, mexstatus) + STRUCT_FIELD (long, 4, RV_SLP_CTX_JVT, jvt) + +#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__ */ diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c new file mode 100644 index 0000000000..0801d8e84e --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c @@ -0,0 +1,753 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#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 "soc/soc_caps.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 + +#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 + +#include "soc/rtc_periph.h" + +#include "esp32h4/rom/rtc.h" +#include "rvsleep-frames.h" +#include "soc/intpri_reg.h" +#include "soc/cache_reg.h" +#include "soc/clint_reg.h" +#include "esp32h4/rom/cache.h" +#include "esp_ipc_isr.h" +#include "soc/pcr_reg.h" + +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#include +#include "soc/hp_system_reg.h" +typedef enum { + SMP_IDLE, + SMP_BACKUP_START, + SMP_BACKUP_DONE, + SMP_RESTORE_START, + SMP_RESTORE_DONE, + SMP_SKIP_RETENTION, +} smp_retention_state_t; + +static DRAM_ATTR smp_retention_state_t s_smp_retention_state[portNUM_PROCESSORS]; +#endif + +static __attribute__((unused)) const char *TAG = "sleep"; + +typedef struct { + uint32_t start; + uint32_t end; +} cpu_domain_dev_regs_region_t; + +typedef struct { + cpu_domain_dev_regs_region_t *region; + int region_num; + uint32_t *regs_frame; +} cpu_domain_dev_sleep_frame_t; + +/** + * Internal structure which holds all requested light sleep cpu retention parameters + */ +typedef struct { + struct { + RvCoreCriticalSleepFrame *critical_frame[portNUM_PROCESSORS]; + RvCoreNonCriticalSleepFrame *non_critical_frame[portNUM_PROCESSORS]; + cpu_domain_dev_sleep_frame_t *cache_config_frame; + cpu_domain_dev_sleep_frame_t *clint_frame[portNUM_PROCESSORS]; + cpu_domain_dev_sleep_frame_t *clic_frame[portNUM_PROCESSORS]; + } retent; +} sleep_cpu_retention_t; + +static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention; + + +#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW + +#define CUSTOM_CSR_MTVT (0x307) +#define CUSTOM_CSR_MNXTI (0x345) +#define CUSTOM_CSR_MINTTHRESH (0x347) +#define CUSTOM_CSR_MSCRATCHCSW (0x348) +#define CUSTOM_CSR_MSCRATCHCSW1 (0x349) +#define CUSTOM_CSR_UINTTHRESH (0x047) +#define CUSTOM_CSR_UINTSTATUS (0xCB1) +#define CUSTOM_CSR_MXSTATUS (0x7c0) +#define CUSTOM_CSR_MHCR (0x7c1) +#define CUSTOM_CSR_MHINT (0x7c5) +#define CUSTOM_CSR_MEXSTATUS (0x7e1) +#define CUSTOM_CSR_JVT (0x017) + +extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; + +static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num) +{ + const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num; + int regs_frame_sz = 0; + for (int num = 0; num < region_num; num++) { + regs_frame_sz += regions[num].end - regions[num].start; + } + void *frame = heap_caps_malloc(sizeof(cpu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame) { + cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t)); + memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t)); + void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz; + memset(regs_frame, 0, regs_frame_sz); + *(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) { + .region = region, + .region_num = region_num, + .regs_frame = (uint32_t *)regs_frame + }; + } + return frame; +} + +static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void) +{ + const static cpu_domain_dev_regs_region_t regions[] = { + { .start = CACHE_L1_ICACHE_CTRL_REG, .end = CACHE_L1_DCACHE_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_clint_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][3] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_SIP_REG + 4 }, + { .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_TIMECTL_REG + 4 }, + { .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }, + } + }; + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t)); +} + +static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][4] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 }, + { .start = CLIC_INT_CTRL_REG(3), .end = CLIC_INT_CTRL_REG(3) + 4 }, + { .start = CLIC_INT_CTRL_REG(7), .end = CLIC_INT_CTRL_REG(7) + 4 }, + { .start = CLIC_INT_CTRL_REG(16), .end = CLIC_INT_CTRL_REG(47) + 4 }, + } + }; + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t)); +} + +static esp_err_t esp_sleep_cpu_retention_init_impl(void) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (s_cpu_retention.retent.critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + s_cpu_retention.retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + } + if (s_cpu_retention.retent.non_critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + s_cpu_retention.retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame; + } + if (s_cpu_retention.retent.clic_frame[core_id] == NULL) { + void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + s_cpu_retention.retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + if (s_cpu_retention.retent.clint_frame[core_id] == NULL) { + void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + s_cpu_retention.retent.clint_frame[core_id] = (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 CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + atomic_init(&s_smp_retention_state[core_id], SMP_IDLE); + } +#endif + return ESP_OK; +err: + esp_sleep_cpu_retention_deinit(); + return ESP_ERR_NO_MEM; +} + +static esp_err_t esp_sleep_cpu_retention_deinit_impl(void) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (s_cpu_retention.retent.critical_frame[core_id]) { + heap_caps_free((void *)s_cpu_retention.retent.critical_frame[core_id]); + s_cpu_retention.retent.critical_frame[core_id] = NULL; + rv_core_critical_regs_frame[core_id] = NULL; + } + if (s_cpu_retention.retent.non_critical_frame[core_id]) { + heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame[core_id]); + s_cpu_retention.retent.non_critical_frame[core_id] = NULL; + } + if (s_cpu_retention.retent.clic_frame[core_id]) { + heap_caps_free((void *)s_cpu_retention.retent.clic_frame[core_id]); + s_cpu_retention.retent.clic_frame[core_id] = NULL; + } + if (s_cpu_retention.retent.clint_frame[core_id]) { + heap_caps_free((void *)s_cpu_retention.retent.clint_frame[core_id]); + s_cpu_retention.retent.clint_frame[core_id] = 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; + } + 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) +{ + RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[esp_cpu_get_core_id()]; + + frame->mscratch = RV_READ_CSR(mscratch); + 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->tdata3 = RV_READ_CSR(tdata3); + frame->tcontrol = RV_READ_CSR(tcontrol); + frame->mscratchcsw = RV_READ_CSR(CUSTOM_CSR_MSCRATCHCSW); + frame->mscratchcsw1 = RV_READ_CSR(CUSTOM_CSR_MSCRATCHCSW1); + frame->mcycleh = RV_READ_CSR(mcycleh); + frame->minstret = RV_READ_CSR(minstret); + frame->minstreth = RV_READ_CSR(minstreth); + frame->mcounteren = RV_READ_CSR(mcounteren); + frame->mcountinhibit = RV_READ_CSR(mcountinhibit); + frame->mhpmcounter8 = RV_READ_CSR(mhpmcounter8); + frame->mhpmcounter9 = RV_READ_CSR(mhpmcounter9); + frame->mhpmcounter13 = RV_READ_CSR(mhpmcounter13); + frame->mhpmcounter8h = RV_READ_CSR(mhpmcounter8h); + frame->mhpmcounter9h = RV_READ_CSR(mhpmcounter9h); + frame->mhpmcounter13h = RV_READ_CSR(mhpmcounter13h); + frame->mhpmevent8 = RV_READ_CSR(mhpmevent8); + frame->mhpmevent9 = RV_READ_CSR(mhpmevent9); + frame->mhpmevent13 = RV_READ_CSR(mhpmevent13); + frame->mcontext = RV_READ_CSR(mcontext); + frame->ustatus = RV_READ_CSR(ustatus); + frame->utvec = RV_READ_CSR(utvec); + frame->uscratch = RV_READ_CSR(uscratch); + frame->ucause = RV_READ_CSR(ucause); + frame->uintthresh = RV_READ_CSR(CUSTOM_CSR_UINTTHRESH); + + 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); + +#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)); + 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)); +#endif // SOC_CPU_HAS_PMA + + frame->mcycle = RV_READ_CSR(mcycle); + frame->mtvt = RV_READ_CSR(CUSTOM_CSR_MTVT); + frame->mintthresh = RV_READ_CSR(CUSTOM_CSR_MINTTHRESH); + frame->mxstatus = RV_READ_CSR(CUSTOM_CSR_MXSTATUS); + frame->mhcr = RV_READ_CSR(CUSTOM_CSR_MHCR); + frame->mhint = RV_READ_CSR(CUSTOM_CSR_MHINT); + frame->mexstatus = RV_READ_CSR(CUSTOM_CSR_MEXSTATUS); + frame->jvt = RV_READ_CSR(CUSTOM_CSR_JVT); + return frame; +} + +static IRAM_ATTR void rv_core_noncritical_regs_restore(void) +{ + RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[esp_cpu_get_core_id()]; + + RV_WRITE_CSR(mscratch, frame->mscratch); + 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(tdata3, frame->tdata3); + RV_WRITE_CSR(tcontrol, frame->tcontrol); + RV_WRITE_CSR(CUSTOM_CSR_MSCRATCHCSW, frame->mscratchcsw); + RV_WRITE_CSR(CUSTOM_CSR_MSCRATCHCSW1, frame->mscratchcsw1); + RV_WRITE_CSR(mcycleh, frame->mcycleh); + RV_WRITE_CSR(minstret, frame->minstret); + RV_WRITE_CSR(minstreth, frame->minstreth); + RV_WRITE_CSR(mcounteren, frame->mcounteren); + RV_WRITE_CSR(mcountinhibit, frame->mcountinhibit); + RV_WRITE_CSR(mhpmcounter8, frame->mhpmcounter8); + RV_WRITE_CSR(mhpmcounter9, frame->mhpmcounter9); + RV_WRITE_CSR(mhpmcounter13, frame->mhpmcounter13); + RV_WRITE_CSR(mhpmcounter8h, frame->mhpmcounter8h); + RV_WRITE_CSR(mhpmcounter9h, frame->mhpmcounter9h); + RV_WRITE_CSR(mhpmcounter13h, frame->mhpmcounter13h); + RV_WRITE_CSR(mhpmevent8, frame->mhpmevent8); + RV_WRITE_CSR(mhpmevent9, frame->mhpmevent9); + RV_WRITE_CSR(mhpmevent13, frame->mhpmevent13); + RV_WRITE_CSR(mcontext, frame->mcontext); + RV_WRITE_CSR(ustatus, frame->ustatus); + RV_WRITE_CSR(utvec, frame->utvec); + RV_WRITE_CSR(uscratch, frame->uscratch); + RV_WRITE_CSR(ucause, frame->ucause); + RV_WRITE_CSR(CUSTOM_CSR_UINTTHRESH, frame->uintthresh); + + 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); + +#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); + 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); +#endif //SOC_CPU_HAS_PMA + + RV_WRITE_CSR(mcycle, frame->mcycle); + + RV_WRITE_CSR(CUSTOM_CSR_MTVT, frame->mtvt); + RV_WRITE_CSR(CUSTOM_CSR_MINTTHRESH, frame->mintthresh); + RV_WRITE_CSR(CUSTOM_CSR_MXSTATUS, frame->mxstatus); + RV_WRITE_CSR(CUSTOM_CSR_MHCR, frame->mhcr); + RV_WRITE_CSR(CUSTOM_CSR_MHINT, frame->mhint); + RV_WRITE_CSR(CUSTOM_CSR_MEXSTATUS, frame->mexstatus); + RV_WRITE_CSR(CUSTOM_CSR_JVT, frame->jvt); +} + +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) { +#ifndef CONFIG_IDF_TARGET_ESP32 + if (!uart_ll_is_enabled(i)) { + continue; + } +#endif + 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) +{ + __attribute__((unused)) uint8_t core_id = esp_cpu_get_core_id(); + 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(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); + +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE + atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_DONE); + while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_BACKUP_DONE) { + ; + } +#endif + + 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(dslp); +} + +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(); + uint8_t core_id = esp_cpu_get_core_id(); +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE + atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_START); +#endif + + cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame[core_id]); + cpu_domain_dev_regs_save(s_cpu_retention.retent.clic_frame[core_id]); + cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame); + rv_core_noncritical_regs_save(); + +#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME + RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[core_id]; + /* 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 + +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE + // Start core1 + if (core_id == 0) { + REG_SET_BIT(PCR_CORE1_CONF_REG, PCR_CORE1_CLK_EN); + REG_CLR_BIT(PCR_CORE1_CONF_REG, PCR_CORE1_RST_EN); + } + + atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_START); +#endif + + rv_core_noncritical_regs_restore(); + cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame); + cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame[core_id]); + cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame[core_id]); + restore_mstatus(mstatus); + +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE + atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_DONE); +#endif + 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_SW + err = esp_sleep_cpu_retention_init_impl(); +#endif + return err; +} + +esp_err_t esp_sleep_cpu_retention_deinit(void) +{ + esp_err_t err = ESP_OK; +#if SOC_PM_CPU_RETENTION_BY_SW + err = esp_sleep_cpu_retention_deinit_impl(); +#endif + return err; +} + + +bool cpu_domain_pd_allowed(void) +{ + bool allowed = true; + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + allowed &= (s_cpu_retention.retent.critical_frame[core_id] != NULL); + allowed &= (s_cpu_retention.retent.non_critical_frame[core_id] != NULL); + } + allowed &= (s_cpu_retention.retent.cache_config_frame != NULL); + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + allowed &= (s_cpu_retention.retent.clic_frame[core_id] != NULL); + allowed &= (s_cpu_retention.retent.clint_frame[core_id] != NULL); + } + return allowed; +} + +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; +} + +#endif + +#if !CONFIG_FREERTOS_UNICORE +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +static IRAM_ATTR void smp_core_do_retention(void) +{ + uint8_t core_id = esp_cpu_get_core_id(); + + if (core_id == 0) { + WRITE_PERI_REG(INTPRI_CPU_INTR_FROM_CPU_2_REG, 0); + } else { + WRITE_PERI_REG(INTPRI_CPU_INTR_FROM_CPU_3_REG, 0); + } + + // Wait another core start to do retention + bool smp_skip_retention = false; + smp_retention_state_t another_core_state; + while (1) { + another_core_state = atomic_load(&s_smp_retention_state[!core_id]); + if (another_core_state == SMP_SKIP_RETENTION) { + // If another core skips the retention, the current core should also have to skip it. + smp_skip_retention = true; + break; + } else if (another_core_state == SMP_BACKUP_START) { + break; + } + } + + if (!smp_skip_retention) { + atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_START); + uint32_t mstatus = save_mstatus_and_disable_global_int(); + rv_core_noncritical_regs_save(); + cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame[core_id]); + cpu_domain_dev_regs_save(s_cpu_retention.retent.clic_frame[core_id]); + rv_core_critical_regs_save(); + RvCoreCriticalSleepFrame *frame_critical = s_cpu_retention.retent.critical_frame[core_id]; + if ((frame_critical->pmufunc & 0x3) == 0x1) { + + atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_DONE); + // wait another core trigger sleep and wakeup + while (1) { + // If another core's sleep request is rejected by the hardware, jumps out of blocking. + another_core_state = atomic_load(&s_smp_retention_state[!core_id]); + if (another_core_state == SMP_SKIP_RETENTION) { + break; + } + } + } else { + + // Start core1 + if (core_id == 0) { + REG_SET_BIT(PCR_CORE1_CONF_REG, PCR_CORE1_CLK_EN); + REG_CLR_BIT(PCR_CORE1_CONF_REG, PCR_CORE1_RST_EN); + } + atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_START); + cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame[core_id]); + cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame[core_id]); + rv_core_noncritical_regs_restore(); + restore_mstatus(mstatus); + atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_DONE); + } + } + // wait another core out sleep + while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_IDLE) { + ; + } + atomic_store(&s_smp_retention_state[core_id], SMP_IDLE); +} + + +IRAM_ATTR void esp_sleep_cpu_skip_retention(void) { + atomic_store(&s_smp_retention_state[esp_cpu_get_core_id()], SMP_SKIP_RETENTION); +} +#endif + +void sleep_smp_cpu_sleep_prepare(void) +{ +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP + while (atomic_load(&s_smp_retention_state[!esp_cpu_get_core_id()]) != SMP_IDLE) { + ; + } + esp_ipc_isr_call((esp_ipc_isr_func_t)smp_core_do_retention, NULL); +#else + esp_ipc_isr_stall_other_cpu(); +#endif +} + +void sleep_smp_cpu_wakeup_prepare(void) +{ +#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP + uint8_t core_id = esp_cpu_get_core_id(); + if (atomic_load(&s_smp_retention_state[core_id]) == SMP_RESTORE_DONE) { + while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_RESTORE_DONE) { + ; + } + } + atomic_store(&s_smp_retention_state[core_id], SMP_IDLE); +#else + esp_ipc_isr_release_other_cpu(); +#endif +} +#endif //!CONFIG_FREERTOS_UNICORE diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S new file mode 100644 index 0000000000..31a6f32832 --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S @@ -0,0 +1,255 @@ +/* + * SPDX-FileCopyrightText: 2025 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" +#include "freertos/FreeRTOSConfig.h" +#define MTVT (0x307) +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5 && !CONFIG_IDF_TARGET_ESP32H4 +#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: + .rept (portNUM_PROCESSORS) + .word 0 + .endr + +/* +-------------------------------------------------------------------------------- + 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 a0, rv_core_critical_regs_frame + csrr t1, mhartid + slli t1, t1, 2 + add a0, a0, t1 + lw t0, 0(a0) /* 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 + sw t0, RV_SLP_CTX_T0(t3) + +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5 && !CONFIG_IDF_TARGET_ESP32H4 + /* 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 + .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 + csrr t1, mhartid + slli t1, t1, 2 + add t0, t0, t1 + 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_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index d5e99cb43e..63a175682f 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -195,8 +195,8 @@ #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #elif CONFIG_IDF_TARGET_ESP32H4 -#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) -#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) +#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) +#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) #elif CONFIG_IDF_TARGET_ESP32P4 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (324) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (240) diff --git a/components/esp_system/system_init_fn.txt b/components/esp_system/system_init_fn.txt index f5b74cd689..2d6238b0c5 100644 --- a/components/esp_system/system_init_fn.txt +++ b/components/esp_system/system_init_fn.txt @@ -86,6 +86,7 @@ SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/p SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32c61/sleep_clock.c on BIT(0) SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32h2/sleep_clock.c on BIT(0) SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32h21/sleep_clock.c on BIT(0) +SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c on BIT(0) SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32p4/sleep_clock.c on BIT(0) SECONDARY: 107: sleep_sys_periph_startup_init in components/esp_hw_support/sleep_system_peripheral.c on BIT(0) SECONDARY: 108: sleep_mmu_startup_init in components/esp_hw_support/lowpower/port/esp32c5/sleep_mmu.c on BIT(0) diff --git a/components/hal/esp32h4/include/hal/clk_gate_ll.h b/components/hal/esp32h4/include/hal/clk_gate_ll.h new file mode 100644 index 0000000000..dbce34f14f --- /dev/null +++ b/components/hal/esp32h4/include/hal/clk_gate_ll.h @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "esp_attr.h" +#include "soc/pcr_struct.h" + +/** + * Enable or disable the clock gate for ref_8m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_8m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_8m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_8m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_8m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_16m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_16m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_16m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_16m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_16m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_32m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_32m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_32m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_32m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_32m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_48m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_48m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_48m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_48m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_48m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_64m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_64m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_64m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_64m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_64m_clk_en(__VA_ARGS__) + +/** + * Enable or disable the clock gate for ref_96m. + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_ref_96m_clk_en(bool enable) +{ + PCR.pll_div_clk_en.pll_96m_clk_en = enable; +} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define clk_gate_ll_ref_96m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_96m_clk_en(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index ca6afb1647..3384598489 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -883,6 +883,10 @@ config SOC_PM_SUPPORT_TOUCH_WAKEUP bool default y +config SOC_PM_SUPPORT_CPU_PD + bool + default y + config SOC_PM_SUPPORT_XTAL32K_PD bool default y @@ -907,6 +911,10 @@ config SOC_PM_SUPPORT_MAC_BB_PD bool default y +config SOC_PM_CPU_RETENTION_BY_SW + bool + default y + config SOC_PM_PAU_LINK_NUM int default 4 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 5b1cce4213..8c6671edcc 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -516,7 +516,7 @@ // #define SOC_PM_SUPPORT_EXT1_WAKEUP (1) // #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*! Date: Wed, 9 Jul 2025 15:36:47 +0800 Subject: [PATCH 03/13] change(esp_hw_support): support light sleep with modem domain power down for esp32h4beta5 --- .../lowpower/port/esp32h4/sleep_clock.c | 108 ++++++++++++++++++ .../port/esp32h4/rtc_clk_init.c | 35 ++++++ .../test_apps/sleep_retention/README.md | 4 +- .../hal/esp32h4/include/hal/modem_lpcon_ll.h | 48 ++++++++ .../hal/esp32h4/include/hal/regi2c_ctrl_ll.h | 3 +- components/hal/esp32h4/modem_clock_hal.c | 76 ++++++++++++ .../esp32h4/include/soc/Kconfig.soc_caps.in | 8 ++ components/soc/esp32h4/include/soc/soc_caps.h | 6 +- 8 files changed, 282 insertions(+), 6 deletions(-) create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c new file mode 100644 index 0000000000..9f4b09edc8 --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c @@ -0,0 +1,108 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_private/sleep_clock.h" +#include "soc/pcr_reg.h" +#include "modem/modem_syscon_reg.h" +#include "modem/modem_lpcon_reg.h" + + +static const char *TAG = "sleep_clock"; + +esp_err_t sleep_clock_system_retention_init(void *arg) +{ + #define N_REGS_PCR() (((PCR_ZERO_DET_CLK_CONF_REG - DR_REG_PCR_BASE) / 4) + 1) + + const static sleep_retention_entries_config_t pcr_regs_retention[] = { + /* Clock configuration retention */ + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(0x0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(0x2), PCR_BUS_CLK_UPDATE_REG, PCR_BUS_CLOCK_UPDATE, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(0x3), PCR_BUS_CLK_UPDATE_REG, 0x0, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } + }; + + esp_err_t err = sleep_retention_entries_create(pcr_regs_retention, ARRAY_SIZE(pcr_regs_retention), REGDMA_LINK_PRI_SYS_CLK, SLEEP_RETENTION_MODULE_CLOCK_SYSTEM); + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for system (PCR) retention"); + ESP_LOGI(TAG, "System Power, Clock and Reset sleep retention initialization"); + return ESP_OK; + + #undef N_REGS_PCR +} + +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE +esp_err_t sleep_clock_modem_retention_init(void *arg) +{ + #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_RF2_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) + + const static sleep_retention_entries_config_t modem_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + }; + + esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for modem (SYSCON) retention, 1 level priority"); + ESP_LOGI(TAG, "Modem Power, Clock and Reset sleep retention initialization"); + return ESP_OK; + + #undef N_REGS_SYSCON +} +#endif + +bool clock_domain_pd_allowed(void) +{ + const sleep_retention_module_bitmap_t inited_modules = sleep_retention_get_inited_modules(); + const sleep_retention_module_bitmap_t created_modules = sleep_retention_get_created_modules(); + const sleep_retention_module_bitmap_t sys_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap[SLEEP_RETENTION_MODULE_SYS_PERIPH >> 5] = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH % 32) }; + + /* The clock and reset of MODEM (WiFi, BLE and 15.4) modules are managed + * through MODEM_SYSCON, when one or more MODEMs are initialized, it is + * necessary to check the state of CLOCK_MODEM to determine MODEM domain on + * or off. The clock and reset of digital peripherals are managed through + * PCR, with TOP domain similar to MODEM domain. */ + sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; +#if SOC_BT_SUPPORTED + modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BLE_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC % 32); + modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); +#endif +#if SOC_IEEE802154_SUPPORTED + modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_802154_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_802154_MAC % 32); + modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); +#endif + + const sleep_retention_module_bitmap_t null_module = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; + + sleep_retention_module_bitmap_t mask = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; + const sleep_retention_module_bitmap_t system_modules = sleep_retention_module_bitmap_and(inited_modules, sys_clk_dep_modules); + if (!sleep_retention_module_bitmap_eq(system_modules, null_module)) { + mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_SYSTEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM % 32); + } +#if SOC_BT_SUPPORTED || SOC_IEEE802154_SUPPORTED + const sleep_retention_module_bitmap_t modem_modules = sleep_retention_module_bitmap_and(inited_modules, modem_clk_dep_modules); + if (!sleep_retention_module_bitmap_eq(modem_modules, null_module)) { + mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); + } +#endif + + const sleep_retention_module_bitmap_t clock_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask); + const sleep_retention_module_bitmap_t clock_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask); + return sleep_retention_module_bitmap_eq(clock_domain_inited_modules, clock_domain_created_modules); +} + +ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, SECONDARY, BIT(0), 106) +{ + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = sleep_clock_system_retention_init, .arg = NULL } }, + .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE + }; + sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM, &init_param); + +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE + init_param = (sleep_retention_module_init_param_t) { + .cbs = { .create = { .handle = sleep_clock_modem_retention_init, .arg = NULL } }, + .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE + }; + sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_MODEM, &init_param); +#endif + return ESP_OK; +} diff --git a/components/esp_hw_support/port/esp32h4/rtc_clk_init.c b/components/esp_hw_support/port/esp32h4/rtc_clk_init.c index c391e8593c..f8ffb8b300 100644 --- a/components/esp_hw_support/port/esp32h4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32h4/rtc_clk_init.c @@ -19,14 +19,49 @@ #include "hal/clk_tree_ll.h" #include "hal/pmu_ll.h" #include "soc/pmu_reg.h" +#if SOC_MODEM_CLOCK_SUPPORTED +#include "hal/modem_syscon_ll.h" +#include "hal/modem_lpcon_ll.h" +#endif #include "pmu_param.h" static const char *TAG = "rtc_clk_init"; +/** + * Initialize the ICG map of some modem clock domains in the PMU_ACTIVE state + * + * A pre-initialization interface is used to initialize the ICG map of the + * MODEM_APB, I2C_MST and LP_APB clock domains in the PMU_ACTIVE state, and + * disable the clock gating of these clock domains in the PMU_ACTIVE state, + * because the system clock source (PLL) in the system boot up process needs + * to use the i2c master peripheral. + * + * ICG map of all modem clock domains under different power states (PMU_ACTIVE, + * PMU_MODEM and PMU_SLEEP) will be initialized in esp_perip_clk_init(). + */ +static void rtc_clk_modem_clock_domain_active_state_icg_map_preinit(void) +{ + /* Configure modem ICG code in PMU_ACTIVE state */ + pmu_ll_hp_set_icg_modem(&PMU, PMU_MODE_HP_ACTIVE, PMU_HP_ICG_MODEM_CODE_ACTIVE); + +#if SOC_MODEM_CLOCK_SUPPORTED + /* Disable clock gating for MODEM_APB, I2C_MST and LP_APB clock domains in PMU_ACTIVE state */ + modem_syscon_ll_set_modem_apb_icg_bitmap(&MODEM_SYSCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); + modem_lpcon_ll_set_i2c_master_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); + modem_lpcon_ll_set_lp_apb_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); +#endif + + /* Software trigger force update modem ICG code and ICG switch */ + pmu_ll_imm_update_dig_icg_modem_code(&PMU, true); + pmu_ll_imm_update_dig_icg_switch(&PMU, true); +} + void rtc_clk_init(rtc_clk_config_t cfg) { rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_modem_clock_domain_active_state_icg_map_preinit(); + /* Set tuning parameters for RC_FAST and RC_SLOW clocks. * Note: this doesn't attempt to set the clocks to precise frequencies. * Instead, we calibrate these clocks against XTAL frequency later, when necessary. diff --git a/components/esp_hw_support/test_apps/sleep_retention/README.md b/components/esp_hw_support/test_apps/sleep_retention/README.md index 77eda1867c..a688c01bf6 100644 --- a/components/esp_hw_support/test_apps/sleep_retention/README.md +++ b/components/esp_hw_support/test_apps/sleep_retention/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | -| ----------------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | +| ----------------- | -------- | -------- | --------- | -------- | -------- | -------- | diff --git a/components/hal/esp32h4/include/hal/modem_lpcon_ll.h b/components/hal/esp32h4/include/hal/modem_lpcon_ll.h index 20afd4a53e..0a09a3c241 100644 --- a/components/hal/esp32h4/include/hal/modem_lpcon_ll.h +++ b/components/hal/esp32h4/include/hal/modem_lpcon_ll.h @@ -92,6 +92,54 @@ static inline void modem_lpcon_ll_reset_all(modem_lpcon_dev_t *hw) hw->rst_conf.val = 0; } +__attribute__((always_inline)) +static inline uint32_t modem_lpcon_ll_get_wifipwr_icg_bitmap(modem_lpcon_dev_t *hw) +{ + return hw->clk_conf_power_st.clk_wifipwr_st_map; +} + +__attribute__((always_inline)) +static inline void modem_lpcon_ll_set_wifipwr_icg_bitmap(modem_lpcon_dev_t *hw, uint32_t bitmap) +{ + hw->clk_conf_power_st.clk_wifipwr_st_map = bitmap; +} + +__attribute__((always_inline)) +static inline uint32_t modem_lpcon_ll_get_coex_icg_bitmap(modem_lpcon_dev_t *hw) +{ + return hw->clk_conf_power_st.clk_coex_st_map; +} + +__attribute__((always_inline)) +static inline void modem_lpcon_ll_set_coex_icg_bitmap(modem_lpcon_dev_t *hw, uint32_t bitmap) +{ + hw->clk_conf_power_st.clk_coex_st_map = bitmap; +} + +__attribute__((always_inline)) +static inline uint32_t modem_lpcon_ll_get_i2c_master_icg_bitmap(modem_lpcon_dev_t *hw) +{ + return hw->clk_conf_power_st.clk_i2c_mst_st_map; +} + +__attribute__((always_inline)) +static inline void modem_lpcon_ll_set_i2c_master_icg_bitmap(modem_lpcon_dev_t *hw, uint32_t bitmap) +{ + hw->clk_conf_power_st.clk_i2c_mst_st_map = bitmap; +} + +__attribute__((always_inline)) +static inline uint32_t modem_lpcon_ll_get_lp_apb_icg_bitmap(modem_lpcon_dev_t *hw) +{ + return hw->clk_conf_power_st.clk_lp_apb_st_map; +} + +__attribute__((always_inline)) +static inline void modem_lpcon_ll_set_lp_apb_icg_bitmap(modem_lpcon_dev_t *hw, uint32_t bitmap) +{ + hw->clk_conf_power_st.clk_lp_apb_st_map = bitmap; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h4/include/hal/regi2c_ctrl_ll.h b/components/hal/esp32h4/include/hal/regi2c_ctrl_ll.h index ee3c7c94bc..319c8bfde8 100644 --- a/components/hal/esp32h4/include/hal/regi2c_ctrl_ll.h +++ b/components/hal/esp32h4/include/hal/regi2c_ctrl_ll.h @@ -12,6 +12,7 @@ #include "soc/i2c_ana_mst_reg.h" #include "soc/pmu_reg.h" #include "modem/modem_lpcon_struct.h" +#include "modem/modem_syscon_struct.h" #ifdef __cplusplus extern "C" { @@ -65,7 +66,7 @@ static inline __attribute__((always_inline)) void regi2c_ctrl_ll_master_force_en */ static inline __attribute__((always_inline)) void regi2c_ctrl_ll_master_configure_clock(void) { - // Nothing to configure + MODEM_SYSCON.clk_conf.clk_i2c_mst_sel_160m = 1; } /** diff --git a/components/hal/esp32h4/modem_clock_hal.c b/components/hal/esp32h4/modem_clock_hal.c index 30d180fe03..bc1a70861c 100644 --- a/components/hal/esp32h4/modem_clock_hal.c +++ b/components/hal/esp32h4/modem_clock_hal.c @@ -13,6 +13,82 @@ #include "hal/modem_clock_types.h" #include "hal/assert.h" +typedef enum { + MODEM_CLOCK_XTAL32K_CODE = 0, + MODEM_CLOCK_RC32K_CODE = 1, + MODEM_CLOCK_EXT32K_CODE = 2 +} modem_clock_32k_clk_src_code_t; + +void IRAM_ATTR modem_clock_hal_set_clock_domain_icg_bitmap(modem_clock_hal_context_t *hal, modem_clock_domain_t domain, uint32_t bitmap) +{ + HAL_ASSERT(domain < MODEM_CLOCK_DOMAIN_MAX); + switch (domain) + { + case MODEM_CLOCK_DOMAIN_MODEM_APB: + modem_syscon_ll_set_modem_apb_icg_bitmap(hal->syscon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_MODEM_PERIPH: + modem_syscon_ll_set_modem_periph_icg_bitmap(hal->syscon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_BT: + modem_syscon_ll_set_bt_icg_bitmap(hal->syscon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_MODEM_FE: + modem_syscon_ll_set_fe_icg_bitmap(hal->syscon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_IEEE802154: + modem_syscon_ll_set_ieee802154_icg_bitmap(hal->syscon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_LP_APB: + modem_lpcon_ll_set_lp_apb_icg_bitmap(hal->lpcon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_I2C_MASTER: + modem_lpcon_ll_set_i2c_master_icg_bitmap(hal->lpcon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_COEX: + modem_lpcon_ll_set_coex_icg_bitmap(hal->lpcon_dev, bitmap); + break; + case MODEM_CLOCK_DOMAIN_WIFIPWR: + modem_lpcon_ll_set_wifipwr_icg_bitmap(hal->lpcon_dev, bitmap); + break; + default: + HAL_ASSERT(0); + } +} + +uint32_t IRAM_ATTR modem_clock_hal_get_clock_domain_icg_bitmap(modem_clock_hal_context_t *hal, modem_clock_domain_t domain) +{ + HAL_ASSERT(domain < MODEM_CLOCK_DOMAIN_MAX); + uint32_t bitmap = 0; + switch (domain) + { + case MODEM_CLOCK_DOMAIN_MODEM_APB: + bitmap = modem_syscon_ll_get_modem_apb_icg_bitmap(hal->syscon_dev); + break; + case MODEM_CLOCK_DOMAIN_MODEM_PERIPH: + bitmap = modem_syscon_ll_get_modem_periph_icg_bitmap(hal->syscon_dev); + break; + case MODEM_CLOCK_DOMAIN_BT: + bitmap = modem_syscon_ll_get_bt_icg_bitmap(hal->syscon_dev); + break; + case MODEM_CLOCK_DOMAIN_MODEM_FE: + bitmap = modem_syscon_ll_get_fe_icg_bitmap(hal->syscon_dev); + break; + case MODEM_CLOCK_DOMAIN_IEEE802154: + bitmap = modem_syscon_ll_get_ieee802154_icg_bitmap(hal->syscon_dev); + break; + case MODEM_CLOCK_DOMAIN_LP_APB: + bitmap = modem_lpcon_ll_get_lp_apb_icg_bitmap(hal->lpcon_dev); + break; + case MODEM_CLOCK_DOMAIN_I2C_MASTER: + bitmap = modem_lpcon_ll_get_i2c_master_icg_bitmap(hal->lpcon_dev); + break; + default: + HAL_ASSERT(0); + } + return bitmap; +} + void IRAM_ATTR modem_clock_hal_enable_modem_common_fe_clock(modem_clock_hal_context_t *hal, bool enable) { modem_syscon_ll_enable_fe_apb_clock(hal->syscon_dev, enable); diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 3384598489..714455f3d5 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -887,6 +887,10 @@ config SOC_PM_SUPPORT_CPU_PD bool default y +config SOC_PM_SUPPORT_MODEM_PD + bool + default y + config SOC_PM_SUPPORT_XTAL32K_PD bool default y @@ -915,6 +919,10 @@ config SOC_PM_CPU_RETENTION_BY_SW bool default y +config SOC_PM_MODEM_RETENTION_BY_REGDMA + bool + default y + config SOC_PM_PAU_LINK_NUM int default 4 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 8c6671edcc..b49d9f1bf9 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -517,7 +517,7 @@ // #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*! Date: Thu, 10 Jul 2025 17:21:43 +0800 Subject: [PATCH 04/13] fix(esp_hw_support): esp32h4 beta5 i2c config retention when pd modem refer to PM-487 --- .../lowpower/port/esp32h4/sleep_clock.c | 22 +++++++++++++++---- .../esp32h4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32h4/include/soc/soc_caps.h | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c index 9f4b09edc8..845d258f37 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c @@ -31,13 +31,15 @@ esp_err_t sleep_clock_system_retention_init(void *arg) #undef N_REGS_PCR } -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_RETENTION_WORKROUND esp_err_t sleep_clock_modem_retention_init(void *arg) { #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_RF2_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) + #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) const static sleep_retention_entries_config_t modem_regs_retention[] = { [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK(0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) } /* MODEM LPCON */ }; esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); @@ -45,6 +47,7 @@ esp_err_t sleep_clock_modem_retention_init(void *arg) ESP_LOGI(TAG, "Modem Power, Clock and Reset sleep retention initialization"); return ESP_OK; + #undef N_REGS_LPCON #undef N_REGS_SYSCON } #endif @@ -60,7 +63,7 @@ bool clock_domain_pd_allowed(void) * necessary to check the state of CLOCK_MODEM to determine MODEM domain on * or off. The clock and reset of digital peripherals are managed through * PCR, with TOP domain similar to MODEM domain. */ - sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; + __attribute__((unused)) sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; #if SOC_BT_SUPPORTED modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BLE_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC % 32); modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); @@ -83,7 +86,9 @@ bool clock_domain_pd_allowed(void) mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); } #endif - +#if SOC_PM_MODEM_CLK_RETENTION_WORKROUND + mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); +#endif const sleep_retention_module_bitmap_t clock_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask); const sleep_retention_module_bitmap_t clock_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask); return sleep_retention_module_bitmap_eq(clock_domain_inited_modules, clock_domain_created_modules); @@ -97,12 +102,21 @@ ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, SECONDARY, BIT(0), 106) }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM, &init_param); -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_RETENTION_WORKROUND init_param = (sleep_retention_module_init_param_t) { .cbs = { .create = { .handle = sleep_clock_modem_retention_init, .arg = NULL } }, +#if !SOC_PM_MODEM_CLK_RETENTION_WORKROUND .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE +#endif }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_MODEM, &init_param); #endif +#if SOC_PM_MODEM_CLK_RETENTION_WORKROUND + if (sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_CLOCK_MODEM) != ESP_OK) { + // even though the modem clock retention module create failed, sleep process can be executed without pd the modem domain, so just warning here + ESP_LOGW(TAG, "create retention link failed on modem clock, modem power domain won't be turned off during sleep"); + } +#endif + return ESP_OK; } diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 714455f3d5..f3b3e025c5 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -923,6 +923,10 @@ config SOC_PM_MODEM_RETENTION_BY_REGDMA bool default y +config SOC_PM_MODEM_CLK_RETENTION_WORKROUND + bool + default y + config SOC_PM_PAU_LINK_NUM int default 4 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index b49d9f1bf9..4c4e9512f8 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -533,7 +533,7 @@ #define SOC_PM_CPU_RETENTION_BY_SW (1) #define SOC_PM_MODEM_RETENTION_BY_REGDMA (1) -// #define SOC_PM_RETENTION_SW_TRIGGER_REGDMA (1) /*!< In esp32H2, regdma will power off when entering sleep */ +#define SOC_PM_MODEM_CLK_RETENTION_WORKROUND (1) /*!< In esp32H4, i2c lpcon is placed in modem domain*/ #define SOC_PM_PAU_LINK_NUM (4) #define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1) From 6078f64be43bd6a286ca9177583edc221929dee9 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 11 Jul 2025 11:32:36 +0800 Subject: [PATCH 05/13] change(esp_hw_support): update pau regdma register driver for esp32h4beta5 --- components/hal/esp32h4/include/hal/lp_aon_ll.h | 15 +++++++++++++++ components/hal/esp32h4/include/hal/lp_timer_ll.h | 6 ++++++ components/hal/esp32h4/include/hal/pau_ll.h | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/components/hal/esp32h4/include/hal/lp_aon_ll.h b/components/hal/esp32h4/include/hal/lp_aon_ll.h index d034ec8a77..ffb2c67986 100644 --- a/components/hal/esp32h4/include/hal/lp_aon_ll.h +++ b/components/hal/esp32h4/include/hal/lp_aon_ll.h @@ -91,6 +91,21 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp) REG_CLR_BIT(RTC_SLEEP_MODE_REG, BIT(0)); /* Tell rom to run light sleep wake stub */ } } + +/** + * @brief Set the maximum number of linked lists supported by REGDMA + * @param count: the maximum number of regdma link + */ +static inline void lp_aon_ll_set_regdma_link_count(int count) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.backup_dma_cfg0, aon_branch_link_length_aon, count); +} + +static inline void lp_aon_ll_set_regdma_link_addr(uint32_t addr) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.backup_dma_cfg2, aon_link_addr_aon, addr); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h4/include/hal/lp_timer_ll.h b/components/hal/esp32h4/include/hal/lp_timer_ll.h index adc5dbaa05..47346122da 100644 --- a/components/hal/esp32h4/include/hal/lp_timer_ll.h +++ b/components/hal/esp32h4/include/hal/lp_timer_ll.h @@ -77,6 +77,12 @@ FORCE_INLINE_ATTR void lp_timer_ll_lp_alarm_intr_enable(lp_timer_dev_t *dev, boo dev->lp_int_ena.main_timer_lp_int_ena = enable; } +/* Record the start and finish times for one-time regdma work */ +FORCE_INLINE_ATTR void lp_timer_ll_record_regdma_work_time_enable(lp_timer_dev_t *dev, bool en) +{ + dev->update.main_timer_regdma_work = en; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h4/include/hal/pau_ll.h b/components/hal/esp32h4/include/hal/pau_ll.h index c158e404e3..4f7bbf7716 100644 --- a/components/hal/esp32h4/include/hal/pau_ll.h +++ b/components/hal/esp32h4/include/hal/pau_ll.h @@ -84,6 +84,11 @@ static inline void pau_ll_set_regdma_timeout_read_mode_try_time(pau_dev_t *dev, REG_SET_FIELD(LP_AON_BACKUP_DMA_CFG1_REG, LP_AON_LINK_WAIT_TOUT_THRES_AON, thres); } +static inline void pau_ll_set_regdma_branch_max_link(pau_dev_t *dev, uint32_t max_link_len) +{ + REG_SET_FIELD(LP_AON_BACKUP_DMA_CFG1_REG, LP_AON_BRANCH_LINK_LENGTH_AON, max_link_len); +} + static inline uint32_t pau_ll_get_regdma_current_link_addr(pau_dev_t *dev) { return dev->regdma_current_link_addr.val; From 0f04aa2359e353d681b69d3eb67408ca7dec3be3 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 11 Jul 2025 11:33:10 +0800 Subject: [PATCH 06/13] change(esp_hw_support): support light sleep with top domain power down for esp32h4beta5 --- .../esp32h4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32h4/include/soc/soc_caps.h | 2 +- .../include/soc/system_periph_retention.h | 82 +++++++++++++ .../hw_ver_beta5/soc/interrupt_matrix_reg.h | 2 + .../soc/esp32h4/system_retention_periph.c | 110 ++++++++++++++++++ 5 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 components/soc/esp32h4/include/soc/system_periph_retention.h create mode 100644 components/soc/esp32h4/system_retention_periph.c diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index f3b3e025c5..98c656f67e 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -907,6 +907,10 @@ config SOC_PM_SUPPORT_VDDSDIO_PD bool default y +config SOC_PM_SUPPORT_TOP_PD + bool + default y + config SOC_PM_SUPPORT_HP_AON_PD bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 4c4e9512f8..c2fbbd7931 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -522,7 +522,7 @@ #define SOC_PM_SUPPORT_RC32K_PD (1) #define SOC_PM_SUPPORT_RC_FAST_PD (1) #define SOC_PM_SUPPORT_VDDSDIO_PD (1) -// #define SOC_PM_SUPPORT_TOP_PD (1) +#define SOC_PM_SUPPORT_TOP_PD (1) #define SOC_PM_SUPPORT_HP_AON_PD (1) #define SOC_PM_SUPPORT_MAC_BB_PD (1) // #define SOC_PM_SUPPORT_RTC_PERIPH_PD (1) // TODO: [ESP32H4] PM-484 diff --git a/components/soc/esp32h4/include/soc/system_periph_retention.h b/components/soc/esp32h4/include/soc/system_periph_retention.h new file mode 100644 index 0000000000..e93a52855d --- /dev/null +++ b/components/soc/esp32h4/include/soc/system_periph_retention.h @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc_caps.h" +#include "soc/regdma.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Provide access to interrupt matrix configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define INT_MTX_RETENTION_LINK_LEN 2 +extern const regdma_entries_config_t intr_matrix_regs_retention[INT_MTX_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to hp_system configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define HP_SYSTEM_RETENTION_LINK_LEN 2 +extern const regdma_entries_config_t hp_system_regs_retention[HP_SYSTEM_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to TEE_APM configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define TEE_APM_RETENTION_LINK_LEN 3 +extern const regdma_entries_config_t tee_apm_regs_retention[TEE_APM_RETENTION_LINK_LEN]; +#define TEE_APM_HIGH_PRI_RETENTION_LINK_LEN 1 +extern const regdma_entries_config_t tee_apm_highpri_regs_retention[TEE_APM_HIGH_PRI_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to IOMUX configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define IOMUX_RETENTION_LINK_LEN 5 +extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to spimem configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define SPIMEM_RETENTION_LINK_LEN 5 +extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to systimer configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define SYSTIMER_RETENTION_LINK_LEN 19 +extern const regdma_entries_config_t systimer_regs_retention[SYSTIMER_RETENTION_LINK_LEN]; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/register/hw_ver_beta5/soc/interrupt_matrix_reg.h b/components/soc/esp32h4/register/hw_ver_beta5/soc/interrupt_matrix_reg.h index 54ccf9f7c7..6c20c9b756 100644 --- a/components/soc/esp32h4/register/hw_ver_beta5/soc/interrupt_matrix_reg.h +++ b/components/soc/esp32h4/register/hw_ver_beta5/soc/interrupt_matrix_reg.h @@ -10,6 +10,8 @@ extern "C" { #endif +#define DR_REG_INTERRUPT_BASE(i) (DR_REG_INTMTX0_BASE + (i) * 0x1000) + /** INTERRUPT_CORE0_WIFI_MAC_INTR_MAP_REG register * WIFI_MAC_INTR mapping register */ diff --git a/components/soc/esp32h4/system_retention_periph.c b/components/soc/esp32h4/system_retention_periph.c new file mode 100644 index 0000000000..97baa156ce --- /dev/null +++ b/components/soc/esp32h4/system_retention_periph.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/regdma.h" +#include "soc/system_periph_retention.h" +#include "soc/timer_periph.h" +#include "soc/uart_reg.h" +#include "soc/systimer_reg.h" +#include "soc/timer_group_reg.h" +#include "soc/spi_mem_reg.h" +#include "soc/hp_system_reg.h" +#include "soc/tee_reg.h" +#include "soc/hp_apm_reg.h" +#include "soc/gpio_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/interrupt_matrix_reg.h" +#include "soc/clic_reg.h" + +/* Interrupt Matrix Registers Context */ +#define N_REGS_INTR_MATRIX(i) (((INTERRUPT_CORE0_CLOCK_GATE_REG(i) - (DR_REG_INTERRUPT_CORE0_BASE + (i) * 0x1000)) / 4) + 1) +const regdma_entries_config_t intr_matrix_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_INTMTX_LINK(0), DR_REG_INTERRUPT_CORE0_BASE, DR_REG_INTERRUPT_CORE0_BASE, N_REGS_INTR_MATRIX(0), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* intr matrix */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_INTMTX_LINK(1), DR_REG_INTERRUPT_CORE1_BASE, DR_REG_INTERRUPT_CORE1_BASE, N_REGS_INTR_MATRIX(1), 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* intr matrix */ +}; +_Static_assert(ARRAY_SIZE(intr_matrix_regs_retention) == INT_MTX_RETENTION_LINK_LEN, "Inconsistent INT_MTX retention link length definitions"); + +/* HP System Registers Context */ +#define N_REGS_HP_SYSTEM_0() (((HP_SYSTEM_CORE_DEBUG_RUNSTALL_CONF_REG - DR_REG_HP_SYSTEM_BASE) / 4) + 1) +#define N_REGS_HP_SYSTEM_1() (((HP_SYSTEM_AXI_MST_PRI_REG - HP_SYSTEM_SPROM_CTRL_REG) / 4) + 1) +const regdma_entries_config_t hp_system_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_HPSYS_LINK(0x0), DR_REG_HP_SYSTEM_BASE, DR_REG_HP_SYSTEM_BASE, N_REGS_HP_SYSTEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_HPSYS_LINK(0x1), HP_SYSTEM_SPROM_CTRL_REG, HP_SYSTEM_SPROM_CTRL_REG, N_REGS_HP_SYSTEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; +_Static_assert(ARRAY_SIZE(hp_system_regs_retention) == HP_SYSTEM_RETENTION_LINK_LEN, "Inconsistent HP_SYSTEM retention link length definitions"); + +/* TEE/APM Registers Context */ +#define N_REGS_TEE_0() (((TEE_ZERO_DET_CTRL_REG - DR_REG_TEE_BASE) / 4) + 1) +#define N_REGS_TEE_1() (((TEE_CLOCK_GATE_REG - TEE_BUS_ERR_CONF_REG) / 4) + 1) +#define N_REGS_APM() (((HP_APM_INT_EN_REG - DR_REG_HP_APM_BASE) / 4) + 1) +const regdma_entries_config_t tee_apm_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TEEAPM_LINK(0), DR_REG_HP_APM_BASE, DR_REG_HP_APM_BASE, N_REGS_APM(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* apm */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TEEAPM_LINK(1), DR_REG_TEE_BASE, DR_REG_TEE_BASE, N_REGS_TEE_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* tee */ + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TEEAPM_LINK(2), TEE_BUS_ERR_CONF_REG, TEE_BUS_ERR_CONF_REG, N_REGS_TEE_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* tee */ + +}; +const regdma_entries_config_t tee_apm_highpri_regs_retention[] = { + [0] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TEEAPM_LINK(3), TEE_M4_MODE_CTRL_REG, 0x0, 0xffffffff, 1, 0), .owner = ENTRY(2) } +}; +_Static_assert((ARRAY_SIZE(tee_apm_regs_retention) == TEE_APM_RETENTION_LINK_LEN) && (ARRAY_SIZE(tee_apm_highpri_regs_retention) == TEE_APM_HIGH_PRI_RETENTION_LINK_LEN), "Inconsistent TEE_APM retention link length definitions"); + +/* IO MUX Registers Context */ +#define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_U_PAD_GPIO39 - REG_IO_MUX_BASE) / 4) + 1) +#define N_REGS_IOMUX_1() (((GPIO_FUNC39_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) +#define N_REGS_IOMUX_2() (((GPIO_FUNC189_IN_SEL_CFG_REG - GPIO_FUNC0_IN_SEL_CFG_REG) / 4) + 1) +#define N_REGS_IOMUX_3() (((GPIO_PIN39_REG - GPIO_PIN0_REG) / 4) + 1) +#define N_REGS_IOMUX_4() (((GPIO_STATUS1_REG - GPIO_OUT_REG) / 4) + 1) +const regdma_entries_config_t iomux_regs_retention[] = { + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* io_mux */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), GPIO_FUNC0_OUT_SEL_CFG_REG, GPIO_FUNC0_OUT_SEL_CFG_REG, N_REGS_IOMUX_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x02), GPIO_FUNC0_IN_SEL_CFG_REG, GPIO_FUNC0_IN_SEL_CFG_REG, N_REGS_IOMUX_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x03), GPIO_PIN0_REG, GPIO_PIN0_REG, N_REGS_IOMUX_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x04), GPIO_OUT_REG, GPIO_OUT_REG, N_REGS_IOMUX_4(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } +}; +_Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "Inconsistent IOMUX retention link length definitions"); + +/* Memory SPI Registers Context */ +const regdma_entries_config_t flash_spimem_regs_retention[] = { + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SPIMEM_LINK(0x00), SPI_MEM_CMD_REG(0), SPI_MEM_CMD_REG(0), 47, 0, 0, 0x3fa9fd, 0x10000, 0xa5ffffff, 0x100), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SPIMEM_LINK(0x01), SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLOCK_GATE_REG(0), 9, 0, 0, 0x1, 0x0, 0x870001, 0xe), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x02), SPI_MEM_TIMING_CALI_REG(0), SPI_MEM_TIMING_CALI_REG(0), 8, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x03), SPI_MEM_TIMING_CALI_REG(0), SPI_MEM_TIMING_CALI_UPDATE, SPI_MEM_TIMING_CALI_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [4] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SPIMEM_LINK(0x04), SPI_MEM_CMD_REG(1), SPI_MEM_CMD_REG(1), 17, 0, 0, 0xafff, 0x1, 0x2000000, 0x2000000), .owner = ENTRY(0) | ENTRY(2) }, +}; +_Static_assert(ARRAY_SIZE(flash_spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); + +/* Systimer Registers Context */ +#define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1) +const regdma_entries_config_t systimer_regs_retention[] = { + [0] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x00), SYSTIMER_UNIT0_OP_REG, SYSTIMER_TIMER_UNIT0_UPDATE_M, SYSTIMER_TIMER_UNIT0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer */ + [1] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_SYSTIMER_LINK(0x01), SYSTIMER_UNIT0_OP_REG, SYSTIMER_TIMER_UNIT0_VALUE_VALID, SYSTIMER_TIMER_UNIT0_VALUE_VALID, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x02), SYSTIMER_UNIT0_VALUE_HI_REG, SYSTIMER_UNIT0_LOAD_HI_REG, 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x03), SYSTIMER_UNIT0_LOAD_REG, SYSTIMER_TIMER_UNIT0_LOAD_M, SYSTIMER_TIMER_UNIT0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [4] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x04), SYSTIMER_UNIT1_OP_REG, SYSTIMER_TIMER_UNIT1_UPDATE_M, SYSTIMER_TIMER_UNIT1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_SYSTIMER_LINK(0x05), SYSTIMER_UNIT1_OP_REG, SYSTIMER_TIMER_UNIT1_VALUE_VALID, SYSTIMER_TIMER_UNIT1_VALUE_VALID, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x06), SYSTIMER_UNIT1_VALUE_HI_REG, SYSTIMER_UNIT1_LOAD_HI_REG, 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [7] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x07), SYSTIMER_UNIT1_LOAD_REG, SYSTIMER_TIMER_UNIT1_LOAD_M, SYSTIMER_TIMER_UNIT1_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [8] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x08), SYSTIMER_TARGET0_HI_REG, SYSTIMER_TARGET0_HI_REG, N_REGS_SYSTIMER_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer target value & period */ + + [9] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x09), SYSTIMER_COMP0_LOAD_REG, SYSTIMER_TIMER_COMP0_LOAD, SYSTIMER_TIMER_COMP0_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [10] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0a), SYSTIMER_COMP1_LOAD_REG, SYSTIMER_TIMER_COMP1_LOAD, SYSTIMER_TIMER_COMP1_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [11] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0b), SYSTIMER_COMP2_LOAD_REG, SYSTIMER_TIMER_COMP2_LOAD, SYSTIMER_TIMER_COMP2_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [12] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0c), SYSTIMER_TARGET0_CONF_REG, 0, SYSTIMER_TARGET0_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [13] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0d), SYSTIMER_TARGET0_CONF_REG, SYSTIMER_TARGET0_PERIOD_MODE_M, SYSTIMER_TARGET0_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [14] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0e), SYSTIMER_TARGET1_CONF_REG, 0, SYSTIMER_TARGET1_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [15] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x0f), SYSTIMER_TARGET1_CONF_REG, SYSTIMER_TARGET1_PERIOD_MODE_M, SYSTIMER_TARGET1_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [16] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SYSTIMER_LINK(0x10), SYSTIMER_TARGET2_CONF_REG, 0, SYSTIMER_TARGET2_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + + [17] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x11), SYSTIMER_CONF_REG, SYSTIMER_CONF_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer work enable */ + [18] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x12), SYSTIMER_INT_ENA_REG, SYSTIMER_INT_ENA_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* Systimer intr enable */ +}; +_Static_assert(ARRAY_SIZE(systimer_regs_retention) == SYSTIMER_RETENTION_LINK_LEN, "Inconsistent Systimer retention link length definitions"); From ea2aaea88ca91d9644f010b2a6b3c37d8d298912 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 11 Jul 2025 15:01:08 +0800 Subject: [PATCH 07/13] change(hal): update lpperiph structure file and support rtcio for esp32h4beta5 --- .../soc/esp32h4/register/soc/lp_gpio_reg.h | 50 +++++++++---------- .../soc/esp32h4/register/soc/lp_iomux_reg.h | 14 +++--- .../soc/esp32h4/register/soc/lp_timer_reg.h | 36 ++++++------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/components/soc/esp32h4/register/soc/lp_gpio_reg.h b/components/soc/esp32h4/register/soc/lp_gpio_reg.h index 60b0d0921c..3ee708e0ef 100644 --- a/components/soc/esp32h4/register/soc/lp_gpio_reg.h +++ b/components/soc/esp32h4/register/soc/lp_gpio_reg.h @@ -14,7 +14,7 @@ extern "C" { /** LP_GPIO_OUT_REG register * LP_GPIO output register */ -#define LP_GPIO_OUT_REG (DR_REG_LP_BASE + 0x4) +#define LP_GPIO_OUT_REG (DR_REG_LP_GPIO_BASE + 0x4) /** LP_GPIO_OUT_DATA_ORIG : R/W/WTC; bitpos: [5:0]; default: 0; * Configures the output value of LP_GPIO0 ~ 5 output in simple LP_GPIO output mode. * 0: Low level @@ -30,7 +30,7 @@ extern "C" { /** LP_GPIO_OUT_W1TS_REG register * LP_GPIO output set register */ -#define LP_GPIO_OUT_W1TS_REG (DR_REG_LP_BASE + 0x8) +#define LP_GPIO_OUT_W1TS_REG (DR_REG_LP_GPIO_BASE + 0x8) /** LP_GPIO_OUT_W1TS : WT; bitpos: [5:0]; default: 0; * Configures whether or not to set the output register LP_GPIO_OUT_REG of LP_GPIO0 ~ * LP_GPIO5. @@ -47,7 +47,7 @@ extern "C" { /** LP_GPIO_OUT_W1TC_REG register * LP_GPIO output clear register */ -#define LP_GPIO_OUT_W1TC_REG (DR_REG_LP_BASE + 0xc) +#define LP_GPIO_OUT_W1TC_REG (DR_REG_LP_GPIO_BASE + 0xc) /** LP_GPIO_OUT_W1TC : WT; bitpos: [5:0]; default: 0; * Configures whether or not to clear the output register LP_GPIO_OUT_REG of LP_GPIO0 * ~ LP_GPIO5 output. @@ -64,7 +64,7 @@ extern "C" { /** LP_GPIO_ENABLE_REG register * LP_GPIO output enable register */ -#define LP_GPIO_ENABLE_REG (DR_REG_LP_BASE + 0x10) +#define LP_GPIO_ENABLE_REG (DR_REG_LP_GPIO_BASE + 0x10) /** LP_GPIO_ENABLE_DATA : R/W/WTC; bitpos: [5:0]; default: 0; * Configures whether or not to enable the output of LP_GPIO0 ~ LP_GPIO5. * 0: Not enable @@ -79,7 +79,7 @@ extern "C" { /** LP_GPIO_ENABLE_W1TS_REG register * LP_GPIO output enable set register */ -#define LP_GPIO_ENABLE_W1TS_REG (DR_REG_LP_BASE + 0x14) +#define LP_GPIO_ENABLE_W1TS_REG (DR_REG_LP_GPIO_BASE + 0x14) /** LP_GPIO_ENABLE_W1TS : WT; bitpos: [5:0]; default: 0; * Configures whether or not to set the output enable register LP_GPIO_ENABLE_REG of * LP_GPIO0 ~ LP_GPIO5. @@ -96,7 +96,7 @@ extern "C" { /** LP_GPIO_ENABLE_W1TC_REG register * LP_GPIO output enable clear register */ -#define LP_GPIO_ENABLE_W1TC_REG (DR_REG_LP_BASE + 0x18) +#define LP_GPIO_ENABLE_W1TC_REG (DR_REG_LP_GPIO_BASE + 0x18) /** LP_GPIO_ENABLE_W1TC : WT; bitpos: [5:0]; default: 0; * Configures whether or not to clear the output enable register LP_GPIO_ENABLE_REG of * LP_GPIO0 ~ LP_GPIO5. @@ -113,7 +113,7 @@ extern "C" { /** LP_GPIO_IN_REG register * LP_GPIO input register */ -#define LP_GPIO_IN_REG (DR_REG_LP_BASE + 0x1c) +#define LP_GPIO_IN_REG (DR_REG_LP_GPIO_BASE + 0x1c) /** LP_GPIO_IN_DATA_NEXT : RO; bitpos: [5:0]; default: 0; * Represents the input value of LP_GPIO0 ~ LP_GPIO5. Each bit represents a pin input * value: @@ -129,7 +129,7 @@ extern "C" { /** LP_GPIO_STATUS_REG register * LP_GPIO interrupt status register */ -#define LP_GPIO_STATUS_REG (DR_REG_LP_BASE + 0x20) +#define LP_GPIO_STATUS_REG (DR_REG_LP_GPIO_BASE + 0x20) /** LP_GPIO_STATUS_INTERRUPT : R/W/WTC; bitpos: [5:0]; default: 0; * The interrupt status of LP_GPIO0 ~ LP_GPIO5, can be configured by the software. * @@ -150,7 +150,7 @@ extern "C" { /** LP_GPIO_STATUS_W1TS_REG register * LP_GPIO interrupt status set register */ -#define LP_GPIO_STATUS_W1TS_REG (DR_REG_LP_BASE + 0x24) +#define LP_GPIO_STATUS_W1TS_REG (DR_REG_LP_GPIO_BASE + 0x24) /** LP_GPIO_STATUS_W1TS : WT; bitpos: [5:0]; default: 0; * Configures whether or not to set the interrupt status register * LP_GPIO_STATUS_INTERRUPT of LP_GPIO0 ~ LP_GPIO5. @@ -168,7 +168,7 @@ extern "C" { /** LP_GPIO_STATUS_W1TC_REG register * LP_GPIO interrupt status clear register */ -#define LP_GPIO_STATUS_W1TC_REG (DR_REG_LP_BASE + 0x28) +#define LP_GPIO_STATUS_W1TC_REG (DR_REG_LP_GPIO_BASE + 0x28) /** LP_GPIO_STATUS_W1TC : WT; bitpos: [5:0]; default: 0; * Configures whether or not to clear the interrupt status register * LP_GPIO_STATUS_INTERRUPT of LP_GPIO0 ~ LP_GPIO5. @@ -186,7 +186,7 @@ extern "C" { /** LP_GPIO_STATUS_NEXT_REG register * LP_GPIO interrupt source register */ -#define LP_GPIO_STATUS_NEXT_REG (DR_REG_LP_BASE + 0x2c) +#define LP_GPIO_STATUS_NEXT_REG (DR_REG_LP_GPIO_BASE + 0x2c) /** LP_GPIO_STATUS_INTERRUPT_NEXT : RO; bitpos: [5:0]; default: 0; * Represents the interrupt source signal of LP_GPIO0 ~ LP_GPIO5. * Bit0 ~ bit24 are corresponding to LP_GPIO0 ~ LP_GPIO5. Bitxx ~ bitxx is invalid. @@ -204,7 +204,7 @@ extern "C" { /** LP_GPIO_PIN0_REG register * LP_GPIO0 configuration register */ -#define LP_GPIO_PIN0_REG (DR_REG_LP_BASE + 0x30) +#define LP_GPIO_PIN0_REG (DR_REG_LP_GPIO_BASE + 0x30) /** LP_GPIO_PIN0_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -272,7 +272,7 @@ extern "C" { /** LP_GPIO_PIN1_REG register * LP_GPIO1 configuration register */ -#define LP_GPIO_PIN1_REG (DR_REG_LP_BASE + 0x34) +#define LP_GPIO_PIN1_REG (DR_REG_LP_GPIO_BASE + 0x34) /** LP_GPIO_PIN1_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -340,7 +340,7 @@ extern "C" { /** LP_GPIO_PIN2_REG register * LP_GPIO2 configuration register */ -#define LP_GPIO_PIN2_REG (DR_REG_LP_BASE + 0x38) +#define LP_GPIO_PIN2_REG (DR_REG_LP_GPIO_BASE + 0x38) /** LP_GPIO_PIN2_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -408,7 +408,7 @@ extern "C" { /** LP_GPIO_PIN3_REG register * LP_GPIO3 configuration register */ -#define LP_GPIO_PIN3_REG (DR_REG_LP_BASE + 0x3c) +#define LP_GPIO_PIN3_REG (DR_REG_LP_GPIO_BASE + 0x3c) /** LP_GPIO_PIN3_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -476,7 +476,7 @@ extern "C" { /** LP_GPIO_PIN4_REG register * LP_GPIO4 configuration register */ -#define LP_GPIO_PIN4_REG (DR_REG_LP_BASE + 0x40) +#define LP_GPIO_PIN4_REG (DR_REG_LP_GPIO_BASE + 0x40) /** LP_GPIO_PIN4_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -544,7 +544,7 @@ extern "C" { /** LP_GPIO_PIN5_REG register * LP_GPIO5 configuration register */ -#define LP_GPIO_PIN5_REG (DR_REG_LP_BASE + 0x44) +#define LP_GPIO_PIN5_REG (DR_REG_LP_GPIO_BASE + 0x44) /** LP_GPIO_PIN5_SYNC2_BYPASS : R/W; bitpos: [1:0]; default: 0; * Configures whether or not to synchronize LP_GPIO input data on either edge of LP IO * MUX operating clock for the second-level synchronization. @@ -612,7 +612,7 @@ extern "C" { /** LP_GPIO_FUNC0_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO0 output */ -#define LP_GPIO_FUNC0_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2b0) +#define LP_GPIO_FUNC0_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2b0) /** LP_GPIO_FUNC0_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -635,7 +635,7 @@ extern "C" { /** LP_GPIO_FUNC1_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO1 output */ -#define LP_GPIO_FUNC1_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2b4) +#define LP_GPIO_FUNC1_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2b4) /** LP_GPIO_FUNC1_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -658,7 +658,7 @@ extern "C" { /** LP_GPIO_FUNC2_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO2 output */ -#define LP_GPIO_FUNC2_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2b8) +#define LP_GPIO_FUNC2_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2b8) /** LP_GPIO_FUNC2_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -681,7 +681,7 @@ extern "C" { /** LP_GPIO_FUNC3_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO3 output */ -#define LP_GPIO_FUNC3_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2bc) +#define LP_GPIO_FUNC3_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2bc) /** LP_GPIO_FUNC3_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -704,7 +704,7 @@ extern "C" { /** LP_GPIO_FUNC4_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO4 output */ -#define LP_GPIO_FUNC4_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2c0) +#define LP_GPIO_FUNC4_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2c0) /** LP_GPIO_FUNC4_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -727,7 +727,7 @@ extern "C" { /** LP_GPIO_FUNC5_OUT_SEL_CFG_REG register * Configuration register for LP_GPIO5 output */ -#define LP_GPIO_FUNC5_OUT_SEL_CFG_REG (DR_REG_LP_BASE + 0x2c4) +#define LP_GPIO_FUNC5_OUT_SEL_CFG_REG (DR_REG_LP_GPIO_BASE + 0x2c4) /** LP_GPIO_FUNC5_OUT_INV_SEL : R/W; bitpos: [0]; default: 0; * Configures whether or not to invert the output value. * 0: Not invert @@ -750,7 +750,7 @@ extern "C" { /** LP_GPIO_CLOCK_GATE_REG register * LP_GPIO clock gate register */ -#define LP_GPIO_CLOCK_GATE_REG (DR_REG_LP_BASE + 0x3f8) +#define LP_GPIO_CLOCK_GATE_REG (DR_REG_LP_GPIO_BASE + 0x3f8) /** LP_GPIO_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether or not to enable clock gate. * 0: Not enable @@ -764,7 +764,7 @@ extern "C" { /** LP_GPIO_DATE_REG register * LP_GPIO version register */ -#define LP_GPIO_DATE_REG (DR_REG_LP_BASE + 0x3fc) +#define LP_GPIO_DATE_REG (DR_REG_LP_GPIO_BASE + 0x3fc) /** LP_GPIO_DATE : R/W; bitpos: [27:0]; default: 37769744; * Version control register. */ diff --git a/components/soc/esp32h4/register/soc/lp_iomux_reg.h b/components/soc/esp32h4/register/soc/lp_iomux_reg.h index d9557af304..bdbaf40728 100644 --- a/components/soc/esp32h4/register/soc/lp_iomux_reg.h +++ b/components/soc/esp32h4/register/soc/lp_iomux_reg.h @@ -14,7 +14,7 @@ extern "C" { /** LP_IO_MUX_GPIO0_REG register * LP IO MUX configuration register for LP_GPIO0 */ -#define LP_IO_MUX_GPIO0_REG (DR_REG_LP_BASE + 0x0) +#define LP_IO_MUX_GPIO0_REG (DR_REG_LP_IO_MUX_BASE + 0x0) /** LP_IO_MUX_GPIO0_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO0 in sleep mode. * 0: Disable @@ -151,7 +151,7 @@ extern "C" { /** LP_IO_MUX_GPIO1_REG register * LP IO MUX configuration register for LP_GPIO1 */ -#define LP_IO_MUX_GPIO1_REG (DR_REG_LP_BASE + 0x4) +#define LP_IO_MUX_GPIO1_REG (DR_REG_LP_IO_MUX_BASE + 0x4) /** LP_IO_MUX_GPIO1_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO1 in sleep mode. * 0: Disable @@ -288,7 +288,7 @@ extern "C" { /** LP_IO_MUX_GPIO2_REG register * LP IO MUX configuration register for LP_GPIO2 */ -#define LP_IO_MUX_GPIO2_REG (DR_REG_LP_BASE + 0x8) +#define LP_IO_MUX_GPIO2_REG (DR_REG_LP_IO_MUX_BASE + 0x8) /** LP_IO_MUX_GPIO2_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO2 in sleep mode. * 0: Disable @@ -425,7 +425,7 @@ extern "C" { /** LP_IO_MUX_GPIO3_REG register * LP IO MUX configuration register for LP_GPIO3 */ -#define LP_IO_MUX_GPIO3_REG (DR_REG_LP_BASE + 0xc) +#define LP_IO_MUX_GPIO3_REG (DR_REG_LP_IO_MUX_BASE + 0xc) /** LP_IO_MUX_GPIO3_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO3 in sleep mode. * 0: Disable @@ -562,7 +562,7 @@ extern "C" { /** LP_IO_MUX_GPIO4_REG register * LP IO MUX configuration register for LP_GPIO4 */ -#define LP_IO_MUX_GPIO4_REG (DR_REG_LP_BASE + 0x10) +#define LP_IO_MUX_GPIO4_REG (DR_REG_LP_IO_MUX_BASE + 0x10) /** LP_IO_MUX_GPIO4_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO4 in sleep mode. * 0: Disable @@ -699,7 +699,7 @@ extern "C" { /** LP_IO_MUX_GPIO5_REG register * LP IO MUX configuration register for LP_GPIO5 */ -#define LP_IO_MUX_GPIO5_REG (DR_REG_LP_BASE + 0x14) +#define LP_IO_MUX_GPIO5_REG (DR_REG_LP_IO_MUX_BASE + 0x14) /** LP_IO_MUX_GPIO5_MCU_OE : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable the output of LP_GPIO5 in sleep mode. * 0: Disable @@ -836,7 +836,7 @@ extern "C" { /** LP_IO_MUX_DATE_REG register * Version control register */ -#define LP_IO_MUX_DATE_REG (DR_REG_LP_BASE + 0x1fc) +#define LP_IO_MUX_DATE_REG (DR_REG_LP_IO_MUX_BASE + 0x1fc) /** LP_IO_MUX_REG_DATE : R/W; bitpos: [27:0]; default: 37769744; * Version control register */ diff --git a/components/soc/esp32h4/register/soc/lp_timer_reg.h b/components/soc/esp32h4/register/soc/lp_timer_reg.h index 98181a1c2e..c81fdbfb41 100644 --- a/components/soc/esp32h4/register/soc/lp_timer_reg.h +++ b/components/soc/esp32h4/register/soc/lp_timer_reg.h @@ -14,7 +14,7 @@ extern "C" { /** LP_TIMER_TAR0_LOW_REG register * RTC timer threshold low bits register0 */ -#define LP_TIMER_TAR0_LOW_REG (DR_REG_LP_BASE + 0x0) +#define LP_TIMER_TAR0_LOW_REG (DR_REG_LP_TIMER_BASE + 0x0) /** LP_TIMER_MAIN_TIMER_TAR_LOW0 : R/W; bitpos: [31:0]; default: 0; * Configures the lower 32 bits of the trigger threshold for the RTC timer compare0. */ @@ -26,7 +26,7 @@ extern "C" { /** LP_TIMER_TAR0_HIGH_REG register * RTC timer enable register0 */ -#define LP_TIMER_TAR0_HIGH_REG (DR_REG_LP_BASE + 0x4) +#define LP_TIMER_TAR0_HIGH_REG (DR_REG_LP_TIMER_BASE + 0x4) /** LP_TIMER_MAIN_TIMER_TAR_HIGH0 : R/W; bitpos: [15:0]; default: 0; * Configures the higher 16 bits of the trigger threshold for the RTC timer compare0 */ @@ -47,7 +47,7 @@ extern "C" { /** LP_TIMER_TAR1_LOW_REG register * RTC timer threshold low bits register1 */ -#define LP_TIMER_TAR1_LOW_REG (DR_REG_LP_BASE + 0x8) +#define LP_TIMER_TAR1_LOW_REG (DR_REG_LP_TIMER_BASE + 0x8) /** LP_TIMER_MAIN_TIMER_TAR_LOW1 : R/W; bitpos: [31:0]; default: 0; * Configures the lower 32 bits of the trigger threshold for the RTC timer compare1. */ @@ -59,7 +59,7 @@ extern "C" { /** LP_TIMER_TAR1_HIGH_REG register * RTC timer threshold high bits register0 */ -#define LP_TIMER_TAR1_HIGH_REG (DR_REG_LP_BASE + 0xc) +#define LP_TIMER_TAR1_HIGH_REG (DR_REG_LP_TIMER_BASE + 0xc) /** LP_TIMER_MAIN_TIMER_TAR_HIGH1 : R/W; bitpos: [15:0]; default: 0; * Configures the higher 16 bits of the trigger threshold for the RTC timer compare1 */ @@ -80,7 +80,7 @@ extern "C" { /** LP_TIMER_UPDATE_REG register * RTC timer update control register */ -#define LP_TIMER_UPDATE_REG (DR_REG_LP_BASE + 0x10) +#define LP_TIMER_UPDATE_REG (DR_REG_LP_TIMER_BASE + 0x10) /** LP_TIMER_MAIN_TIMER_UPDATE : WT; bitpos: [27]; default: 0; * Triggers timer by software */ @@ -123,7 +123,7 @@ extern "C" { /** LP_TIMER_MAIN_BUF0_LOW_REG register * RTC timer buffer0 low bits register */ -#define LP_TIMER_MAIN_BUF0_LOW_REG (DR_REG_LP_BASE + 0x14) +#define LP_TIMER_MAIN_BUF0_LOW_REG (DR_REG_LP_TIMER_BASE + 0x14) /** LP_TIMER_MAIN_TIMER_BUF0_LOW : RO; bitpos: [31:0]; default: 0; * RTC timer buffer0 low bits register */ @@ -135,7 +135,7 @@ extern "C" { /** LP_TIMER_MAIN_BUF0_HIGH_REG register * RTC timer buffer0 high bits register */ -#define LP_TIMER_MAIN_BUF0_HIGH_REG (DR_REG_LP_BASE + 0x18) +#define LP_TIMER_MAIN_BUF0_HIGH_REG (DR_REG_LP_TIMER_BASE + 0x18) /** LP_TIMER_MAIN_TIMER_BUF0_HIGH : RO; bitpos: [15:0]; default: 0; * RTC timer buffer0 high bits register */ @@ -147,7 +147,7 @@ extern "C" { /** LP_TIMER_MAIN_BUF1_LOW_REG register * RTC timer buffer1 low bits register */ -#define LP_TIMER_MAIN_BUF1_LOW_REG (DR_REG_LP_BASE + 0x1c) +#define LP_TIMER_MAIN_BUF1_LOW_REG (DR_REG_LP_TIMER_BASE + 0x1c) /** LP_TIMER_MAIN_TIMER_BUF1_LOW : RO; bitpos: [31:0]; default: 0; * RTC timer buffer1 low bits register */ @@ -159,7 +159,7 @@ extern "C" { /** LP_TIMER_MAIN_BUF1_HIGH_REG register * RTC timer buffer1 high bits register */ -#define LP_TIMER_MAIN_BUF1_HIGH_REG (DR_REG_LP_BASE + 0x20) +#define LP_TIMER_MAIN_BUF1_HIGH_REG (DR_REG_LP_TIMER_BASE + 0x20) /** LP_TIMER_MAIN_TIMER_BUF1_HIGH : RO; bitpos: [15:0]; default: 0; * RTC timer buffer1 high bits register */ @@ -171,7 +171,7 @@ extern "C" { /** LP_TIMER_INT_RAW_REG register * RTC timer interrupt raw register */ -#define LP_TIMER_INT_RAW_REG (DR_REG_LP_BASE + 0x28) +#define LP_TIMER_INT_RAW_REG (DR_REG_LP_TIMER_BASE + 0x28) /** LP_TIMER_OVERFLOW_RAW : R/WTC/SS; bitpos: [30]; default: 0; * Triggered when counter register of RTC main timer overflow. */ @@ -190,7 +190,7 @@ extern "C" { /** LP_TIMER_INT_ST_REG register * RTC timer interrupt status register */ -#define LP_TIMER_INT_ST_REG (DR_REG_LP_BASE + 0x2c) +#define LP_TIMER_INT_ST_REG (DR_REG_LP_TIMER_BASE + 0x2c) /** LP_TIMER_OVERFLOW_ST : RO; bitpos: [30]; default: 0; * Status of RTC main timer overflow interrupt . */ @@ -209,7 +209,7 @@ extern "C" { /** LP_TIMER_INT_ENA_REG register * RTC timer interrupt enable register */ -#define LP_TIMER_INT_ENA_REG (DR_REG_LP_BASE + 0x30) +#define LP_TIMER_INT_ENA_REG (DR_REG_LP_TIMER_BASE + 0x30) /** LP_TIMER_OVERFLOW_ENA : R/W; bitpos: [30]; default: 0; * Enable the RTC main timer overflow interrupt.. * 0 : Disable @@ -232,7 +232,7 @@ extern "C" { /** LP_TIMER_INT_CLR_REG register * RTC timer interrupt clear register */ -#define LP_TIMER_INT_CLR_REG (DR_REG_LP_BASE + 0x34) +#define LP_TIMER_INT_CLR_REG (DR_REG_LP_TIMER_BASE + 0x34) /** LP_TIMER_OVERFLOW_CLR : WT; bitpos: [30]; default: 0; * Clear the RTC main timer overflow raw interrupt.. */ @@ -251,7 +251,7 @@ extern "C" { /** LP_TIMER_LP_INT_RAW_REG register * RTC timer interrupt raw register(For ULP) */ -#define LP_TIMER_LP_INT_RAW_REG (DR_REG_LP_BASE + 0x38) +#define LP_TIMER_LP_INT_RAW_REG (DR_REG_LP_TIMER_BASE + 0x38) /** LP_TIMER_MAIN_TIMER_OVERFLOW_LP_INT_RAW : R/WTC/SS; bitpos: [30]; default: 0; * Triggered when counter register of RTC main timer overflow */ @@ -270,7 +270,7 @@ extern "C" { /** LP_TIMER_LP_INT_ST_REG register * RTC timer interrupt status register(For ULP) */ -#define LP_TIMER_LP_INT_ST_REG (DR_REG_LP_BASE + 0x3c) +#define LP_TIMER_LP_INT_ST_REG (DR_REG_LP_TIMER_BASE + 0x3c) /** LP_TIMER_MAIN_TIMER_OVERFLOW_LP_INT_ST : RO; bitpos: [30]; default: 0; * Status of RTC main timer overflow interrupt . */ @@ -289,7 +289,7 @@ extern "C" { /** LP_TIMER_LP_INT_ENA_REG register * RTC timer interrupt enable register(For ULP) */ -#define LP_TIMER_LP_INT_ENA_REG (DR_REG_LP_BASE + 0x40) +#define LP_TIMER_LP_INT_ENA_REG (DR_REG_LP_TIMER_BASE + 0x40) /** LP_TIMER_MAIN_TIMER_OVERFLOW_LP_INT_ENA : R/W; bitpos: [30]; default: 0; * Enable the RTC main timer overflow interrupt.. * 0 : Disable @@ -312,7 +312,7 @@ extern "C" { /** LP_TIMER_LP_INT_CLR_REG register * RTC timer interrupt clear register(For ULP) */ -#define LP_TIMER_LP_INT_CLR_REG (DR_REG_LP_BASE + 0x44) +#define LP_TIMER_LP_INT_CLR_REG (DR_REG_LP_TIMER_BASE + 0x44) /** LP_TIMER_MAIN_TIMER_OVERFLOW_LP_INT_CLR : WT; bitpos: [30]; default: 0; * Clear the RTC main timer overflow clear interrupt.. */ @@ -331,7 +331,7 @@ extern "C" { /** LP_TIMER_DATE_REG register * Date register */ -#define LP_TIMER_DATE_REG (DR_REG_LP_BASE + 0x3fc) +#define LP_TIMER_DATE_REG (DR_REG_LP_TIMER_BASE + 0x3fc) /** LP_TIMER_DATE : R/W; bitpos: [30:0]; default: 36769936; * Version data */ From 88fb8703462fef0c705db796b32708f4129a19c4 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 11 Jul 2025 17:56:36 +0800 Subject: [PATCH 08/13] change(soc): support xtal32k in esp32h4beta5 --- components/esp_system/port/soc/esp32h4/clk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/soc/esp32h4/clk.c b/components/esp_system/port/soc/esp32h4/clk.c index b75cb404d3..4bc1bf69cf 100644 --- a/components/esp_system/port/soc/esp32h4/clk.c +++ b/components/esp_system/port/soc/esp32h4/clk.c @@ -24,6 +24,7 @@ #include "esp_private/esp_pmu.h" #include "esp_rom_serial_output.h" #include "esp_rom_sys.h" +#include "esp_sleep.h" /* Number of cycles to wait from the 32k XTAL oscillator to consider it running. * Larger values increase startup delay. Smaller values may cause false positive @@ -181,5 +182,9 @@ void rtc_clk_select_rtc_slow_clk(void) */ __attribute__((weak)) void esp_perip_clk_init(void) { - ESP_EARLY_LOGW(TAG, "esp_perip_clk_init() has not been implemented yet"); + soc_rtc_slow_clk_src_t rtc_slow_clk_src = rtc_clk_slow_src_get(); + esp_sleep_pd_domain_t pu_domain = (esp_sleep_pd_domain_t)(\ + (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? ESP_PD_DOMAIN_XTAL32K \ + : ESP_PD_DOMAIN_MAX); + esp_sleep_pd_config(pu_domain, ESP_PD_OPTION_ON); } From b0c8bd723688bb118c5579c6ea978a54c50e10e8 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 14 Jul 2025 14:12:46 +0800 Subject: [PATCH 09/13] change(esp_hw_support): optimize sleep retated parameters in esp32h4beta5 --- .../port/esp32h4/private_include/pmu_param.h | 12 ++++++------ components/esp_hw_support/sleep_modes.c | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h index 0ba3f8ef0f..6c8d5a1e11 100644 --- a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h @@ -527,8 +527,8 @@ typedef struct pmu_sleep_machine_constant { .lp = { \ .min_slp_time_us = 450, \ .wakeup_wait_cycle = 4, \ - .analog_wait_time_us = 400, \ - .xtal_wait_stable_time_us = 2000, \ + .analog_wait_time_us = 130, \ + .xtal_wait_stable_time_us = 160, \ .clk_switch_cycle = 1, \ .clk_power_on_wait_cycle = 1, \ .isolate_wait_time_us = 1, \ @@ -540,18 +540,18 @@ typedef struct pmu_sleep_machine_constant { .min_slp_time_us = 450, \ .clock_domain_sync_time_us = 150, \ .system_dfs_up_work_time_us = 124, \ - .analog_wait_time_us = 800, \ + .analog_wait_time_us = 2200, \ .isolate_wait_time_us = 1, \ .reset_wait_time_us = 1, \ .power_supply_wait_time_us = 2, \ .power_up_wait_time_us = 2, \ .regdma_s2m_work_time_us = 172, \ - .regdma_s2a_work_time_us = 480, \ + .regdma_s2a_work_time_us = 280, \ .regdma_m2a_work_time_us = 278, \ - .regdma_a2s_work_time_us = 382, \ + .regdma_a2s_work_time_us = 220, \ .regdma_rf_on_work_time_us = 70, \ .regdma_rf_off_work_time_us = 23, \ - .xtal_wait_stable_time_us = 2000, \ + .xtal_wait_stable_time_us = 160, \ .pll_wait_stable_time_us = 1 \ } \ } diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 63a175682f..e89f51e2a7 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -195,8 +195,8 @@ #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #elif CONFIG_IDF_TARGET_ESP32H4 -#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) -#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) +#define DEFAULT_SLEEP_OUT_OVERHEAD_US (130) +#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #elif CONFIG_IDF_TARGET_ESP32P4 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (324) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (240) @@ -1172,7 +1172,6 @@ static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t cl { rtc_clk_cpu_freq_set_config(&cpu_freq_config); } - esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CLK_READY, (void *)0); if (!deep_sleep) { From 752ca902f608c80df7a1e1ace1737f582a4b1140 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Wed, 16 Jul 2025 21:29:41 +0800 Subject: [PATCH 10/13] feat(esp_hw_support): support rtcio & extio wakeup in esp32h4 beta5 --- .../soc/esp32h4/include/soc/Kconfig.soc_caps.in | 12 ++++++++++++ components/soc/esp32h4/include/soc/soc_caps.h | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 98c656f67e..1d1643b29e 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -83,6 +83,10 @@ config SOC_LP_TIMER_SUPPORTED bool default y +config SOC_LP_AON_SUPPORTED + bool + default y + config SOC_REG_I2C_SUPPORTED bool default y @@ -879,6 +883,14 @@ config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 +config SOC_PM_SUPPORT_EXT1_WAKEUP + bool + default y + +config SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN + bool + default y + config SOC_PM_SUPPORT_TOUCH_WAKEUP bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index c2fbbd7931..589407ab77 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -74,7 +74,7 @@ #define SOC_PMU_SUPPORTED 1 // TODO: [ESP32H4] IDF-12286 #define SOC_PAU_SUPPORTED 1 #define SOC_LP_TIMER_SUPPORTED 1 -// #define SOC_LP_AON_SUPPORTED 1 +#define SOC_LP_AON_SUPPORTED 1 // #define SOC_LP_PERIPHERALS_SUPPORTED 1 // #define SOC_LP_I2C_SUPPORTED 1 // TODO: [ESP32H4] IDF-12449 // #define SOC_ULP_LP_UART_SUPPORTED 1 // TODO: [ESP32H4] IDF-12445 IDF-12451 @@ -513,8 +513,8 @@ // TODO: IDF-12286 (inherit from verify code, need check) /*-------------------------- Power Management CAPS ----------------------------*/ // #define SOC_PM_SUPPORT_BT_WAKEUP (1) -// #define SOC_PM_SUPPORT_EXT1_WAKEUP (1) -// #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*! Date: Thu, 28 Aug 2025 21:51:40 +0800 Subject: [PATCH 11/13] change(esp_hw_support): update wait pll calibration done in sleep_clock --- .../lowpower/port/esp32h4/sleep_clock.c | 46 +++++++++++++------ .../esp32h4/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32h4/include/soc/soc_caps.h | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c index 845d258f37..2ec104f269 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c @@ -8,19 +8,21 @@ #include "soc/pcr_reg.h" #include "modem/modem_syscon_reg.h" #include "modem/modem_lpcon_reg.h" - +#include "soc/i2c_ana_mst_reg.h" +#include "soc/pmu_reg.h" +#include "soc/lp_analog_peri_reg.h" static const char *TAG = "sleep_clock"; esp_err_t sleep_clock_system_retention_init(void *arg) { #define N_REGS_PCR() (((PCR_ZERO_DET_CLK_CONF_REG - DR_REG_PCR_BASE) / 4) + 1) - const static sleep_retention_entries_config_t pcr_regs_retention[] = { /* Clock configuration retention */ - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(0x0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(0x2), PCR_BUS_CLK_UPDATE_REG, PCR_BUS_CLOCK_UPDATE, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(0x3), PCR_BUS_CLK_UPDATE_REG, 0x0, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(1), PCR_RESET_EVENT_BYPASS_REG, PCR_RESET_EVENT_BYPASS_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(2), PCR_BUS_CLK_UPDATE_REG, PCR_BUS_CLOCK_UPDATE, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(3), PCR_BUS_CLK_UPDATE_REG, 0x0, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; esp_err_t err = sleep_retention_entries_create(pcr_regs_retention, ARRAY_SIZE(pcr_regs_retention), REGDMA_LINK_PRI_SYS_CLK, SLEEP_RETENTION_MODULE_CLOCK_SYSTEM); @@ -31,15 +33,29 @@ esp_err_t sleep_clock_system_retention_init(void *arg) #undef N_REGS_PCR } -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_RETENTION_WORKROUND +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_CONF_RETENTION esp_err_t sleep_clock_modem_retention_init(void *arg) { #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_RF2_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) + /* In ESP32H4, the I2C control registers (syscon, lpcon) are placed in the modem domain, + and the BBPL requires I2C for calibration. This is the reason why the code for the BPLL enableq + section needs to be placed in this function.*/ const static sleep_retention_entries_config_t modem_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK(0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) } /* MODEM LPCON */ + /* SYSCON LPCON configuration retention */ + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK (0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM LPCON */ + /* Enable i2c master clock */ + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(1), MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN, MODEM_LPCON_CLK_I2C_MST_EN_M, 1, 0), .owner = ENTRY(0) }, + /* Start BBPLL self-calibration */ + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(2), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(3), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, + /* Wait calibration done */ + [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_MODEMSYSCON_LINK(4), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE, I2C_MST_BBPLL_CAL_DONE, 1, 0), .owner = ENTRY(0) }, + /* Stop BBPLL self-calibration */ + [6] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(5), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, + [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(6), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, }; esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); @@ -58,12 +74,14 @@ bool clock_domain_pd_allowed(void) const sleep_retention_module_bitmap_t created_modules = sleep_retention_get_created_modules(); const sleep_retention_module_bitmap_t sys_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap[SLEEP_RETENTION_MODULE_SYS_PERIPH >> 5] = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH % 32) }; - /* The clock and reset of MODEM (WiFi, BLE and 15.4) modules are managed + /* The clock and reset of MODEM (BLE and 15.4) modules are managed * through MODEM_SYSCON, when one or more MODEMs are initialized, it is * necessary to check the state of CLOCK_MODEM to determine MODEM domain on * or off. The clock and reset of digital peripherals are managed through * PCR, with TOP domain similar to MODEM domain. */ - __attribute__((unused)) sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; +#if SOC_BLE_SUPPORTED || SOC_IEEE802154_SUPPORTED + sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; +#endif #if SOC_BT_SUPPORTED modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BLE_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC % 32); modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); @@ -86,7 +104,7 @@ bool clock_domain_pd_allowed(void) mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); } #endif -#if SOC_PM_MODEM_CLK_RETENTION_WORKROUND +#if SOC_PM_MODEM_CLK_CONF_RETENTION mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); #endif const sleep_retention_module_bitmap_t clock_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask); @@ -102,16 +120,16 @@ ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, SECONDARY, BIT(0), 106) }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM, &init_param); -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_RETENTION_WORKROUND +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_CONF_RETENTION init_param = (sleep_retention_module_init_param_t) { .cbs = { .create = { .handle = sleep_clock_modem_retention_init, .arg = NULL } }, -#if !SOC_PM_MODEM_CLK_RETENTION_WORKROUND +#if !SOC_PM_MODEM_CLK_CONF_RETENTION .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE #endif }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_MODEM, &init_param); #endif -#if SOC_PM_MODEM_CLK_RETENTION_WORKROUND +#if SOC_PM_MODEM_CLK_CONF_RETENTION if (sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_CLOCK_MODEM) != ESP_OK) { // even though the modem clock retention module create failed, sleep process can be executed without pd the modem domain, so just warning here ESP_LOGW(TAG, "create retention link failed on modem clock, modem power domain won't be turned off during sleep"); diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 1d1643b29e..1035b0ed60 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -939,7 +939,7 @@ config SOC_PM_MODEM_RETENTION_BY_REGDMA bool default y -config SOC_PM_MODEM_CLK_RETENTION_WORKROUND +config SOC_PM_MODEM_CLK_CONF_RETENTION bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 589407ab77..8630a0e2f1 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -533,7 +533,7 @@ #define SOC_PM_CPU_RETENTION_BY_SW (1) #define SOC_PM_MODEM_RETENTION_BY_REGDMA (1) -#define SOC_PM_MODEM_CLK_RETENTION_WORKROUND (1) /*!< In esp32H4, i2c lpcon is placed in modem domain*/ +#define SOC_PM_MODEM_CLK_CONF_RETENTION (1) /*!< In esp32H4, i2c lpcon is placed in modem domain*/ #define SOC_PM_PAU_LINK_NUM (4) #define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1) From cfecbc99ce45749b5a74fddefcf244dbfdfee3e4 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 29 Aug 2025 11:09:24 +0800 Subject: [PATCH 12/13] change(esp_hw_support): update sleep cpu flow --- .../lowpower/port/esp32c5/sleep_cpu_static.c | 8 +- .../lowpower/port/esp32h4/rvsleep-frames.h | 2 - .../lowpower/port/esp32h4/sleep_cpu.c | 277 +++--------------- .../lowpower/port/esp32h4/sleep_cpu_asm.S | 46 +-- .../lowpower/port/esp32h4/sleep_cpu_dynamic.c | 199 +++++++++++++ .../port/esp32h4/sleep_cpu_retention.h | 59 ++++ .../lowpower/port/esp32h4/sleep_cpu_static.c | 237 +++++++++++++++ .../soc/esp32h4/register/soc/cache_reg.h | 1 - 8 files changed, 544 insertions(+), 285 deletions(-) create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_dynamic.c create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_retention.h create mode 100644 components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_static.c diff --git a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_static.c b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_static.c index fa3f5c4cb3..e78b6335d0 100644 --- a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_static.c +++ b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_static.c @@ -97,10 +97,10 @@ static void * cache_sleep_frame_init(void) static void * clint_sleep_frame_init(void) { const static cpu_domain_dev_regs_region_t regions[] = { - { .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_SIP_REG + 4 }, - { .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_MTIMECMP_H_REG + 4 }, - { .start = CLINT_MINT_TIMECTL_REG, .end = CLINT_MINT_TIMECTL_REG + 4 }, - { .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 } + { .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 }, + { .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }, + { .start = CPU_DOMAIN_DEV_START_ADDR2, .end = CPU_DOMAIN_DEV_END_ADDR2 }, + { .start = CPU_DOMAIN_DEV_START_ADDR3, .end = CPU_DOMAIN_DEV_END_ADDR3 } }; static uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4))); return cpu_domain_dev_sleep_frame_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame); diff --git a/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h b/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h index e7521996e0..95cffbef85 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h +++ b/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h @@ -162,7 +162,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) @@ -195,7 +194,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_MCYCLE, mcycle) STRUCT_FIELD (long, 4, RV_SLP_CTX_MTVT, mtvt) diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c index 0801d8e84e..6cfb020a7d 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c @@ -12,86 +12,44 @@ #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 "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" +#include "riscv/csr.h" #include "soc/soc_caps.h" +#include "soc/intpri_reg.h" +#include "soc/cache_reg.h" +#include "soc/clint_reg.h" +#include "soc/clic_reg.h" +#include "soc/pcr_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 "esp32h4/rom/rtc.h" +#include "esp32h4/rom/cache.h" +#include "rvsleep-frames.h" +#include "sleep_cpu_retention.h" #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME #include "esp_private/system_internal.h" -#include "hal/clk_gate_ll.h" #include "hal/uart_hal.h" #endif -#include "soc/rtc_periph.h" - -#include "esp32h4/rom/rtc.h" -#include "rvsleep-frames.h" -#include "soc/intpri_reg.h" -#include "soc/cache_reg.h" -#include "soc/clint_reg.h" -#include "esp32h4/rom/cache.h" -#include "esp_ipc_isr.h" -#include "soc/pcr_reg.h" - -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE -#include -#include "soc/hp_system_reg.h" -typedef enum { - SMP_IDLE, - SMP_BACKUP_START, - SMP_BACKUP_DONE, - SMP_RESTORE_START, - SMP_RESTORE_DONE, - SMP_SKIP_RETENTION, -} smp_retention_state_t; - +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE static DRAM_ATTR smp_retention_state_t s_smp_retention_state[portNUM_PROCESSORS]; #endif static __attribute__((unused)) const char *TAG = "sleep"; -typedef struct { - uint32_t start; - uint32_t end; -} cpu_domain_dev_regs_region_t; - -typedef struct { - cpu_domain_dev_regs_region_t *region; - int region_num; - uint32_t *regs_frame; -} cpu_domain_dev_sleep_frame_t; - -/** - * Internal structure which holds all requested light sleep cpu retention parameters - */ -typedef struct { - struct { - RvCoreCriticalSleepFrame *critical_frame[portNUM_PROCESSORS]; - RvCoreNonCriticalSleepFrame *non_critical_frame[portNUM_PROCESSORS]; - cpu_domain_dev_sleep_frame_t *cache_config_frame; - cpu_domain_dev_sleep_frame_t *clint_frame[portNUM_PROCESSORS]; - cpu_domain_dev_sleep_frame_t *clic_frame[portNUM_PROCESSORS]; - } retent; -} sleep_cpu_retention_t; - static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention; - -#if SOC_PM_SUPPORT_CPU_PD && SOC_PM_CPU_RETENTION_BY_SW - #define CUSTOM_CSR_MTVT (0x307) #define CUSTOM_CSR_MNXTI (0x345) #define CUSTOM_CSR_MINTTHRESH (0x347) @@ -107,155 +65,14 @@ static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention; extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; -static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num) +FORCE_INLINE_ATTR uint32_t save_mstatus_and_disable_global_int(void) { - 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; + return RV_READ_MSTATUS_AND_DISABLE_INTR(); } -static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void) +FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val) { - const static cpu_domain_dev_regs_region_t regions[] = { - { .start = CACHE_L1_ICACHE_CTRL_REG, .end = CACHE_L1_DCACHE_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_clint_sleep_frame_alloc_and_init(uint8_t core_id) -{ - const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][3] = { - [0 ... portNUM_PROCESSORS - 1] = { - { .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_SIP_REG + 4 }, - { .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_TIMECTL_REG + 4 }, - { .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }, - } - }; - return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t)); -} - -static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(uint8_t core_id) -{ - const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][4] = { - [0 ... portNUM_PROCESSORS - 1] = { - { .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 }, - { .start = CLIC_INT_CTRL_REG(3), .end = CLIC_INT_CTRL_REG(3) + 4 }, - { .start = CLIC_INT_CTRL_REG(7), .end = CLIC_INT_CTRL_REG(7) + 4 }, - { .start = CLIC_INT_CTRL_REG(16), .end = CLIC_INT_CTRL_REG(47) + 4 }, - } - }; - return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(cpu_domain_dev_regs_region_t)); -} - -static esp_err_t esp_sleep_cpu_retention_init_impl(void) -{ - for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { - if (s_cpu_retention.retent.critical_frame[core_id] == NULL) { - void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); - if (frame == NULL) { - goto err; - } - s_cpu_retention.retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; - rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; - } - if (s_cpu_retention.retent.non_critical_frame[core_id] == NULL) { - void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); - if (frame == NULL) { - goto err; - } - s_cpu_retention.retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame; - } - if (s_cpu_retention.retent.clic_frame[core_id] == NULL) { - void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); - if (frame == NULL) { - goto err; - } - s_cpu_retention.retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; - } - if (s_cpu_retention.retent.clint_frame[core_id] == NULL) { - void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); - if (frame == NULL) { - goto err; - } - s_cpu_retention.retent.clint_frame[core_id] = (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 CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE - for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { - atomic_init(&s_smp_retention_state[core_id], SMP_IDLE); - } -#endif - return ESP_OK; -err: - esp_sleep_cpu_retention_deinit(); - return ESP_ERR_NO_MEM; -} - -static esp_err_t esp_sleep_cpu_retention_deinit_impl(void) -{ - for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { - if (s_cpu_retention.retent.critical_frame[core_id]) { - heap_caps_free((void *)s_cpu_retention.retent.critical_frame[core_id]); - s_cpu_retention.retent.critical_frame[core_id] = NULL; - rv_core_critical_regs_frame[core_id] = NULL; - } - if (s_cpu_retention.retent.non_critical_frame[core_id]) { - heap_caps_free((void *)s_cpu_retention.retent.non_critical_frame[core_id]); - s_cpu_retention.retent.non_critical_frame[core_id] = NULL; - } - if (s_cpu_retention.retent.clic_frame[core_id]) { - heap_caps_free((void *)s_cpu_retention.retent.clic_frame[core_id]); - s_cpu_retention.retent.clic_frame[core_id] = NULL; - } - if (s_cpu_retention.retent.clint_frame[core_id]) { - heap_caps_free((void *)s_cpu_retention.retent.clint_frame[core_id]); - s_cpu_retention.retent.clint_frame[core_id] = 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; - } - 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)); + RV_WRITE_CSR(mstatus, mstatus_val); } static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) @@ -313,7 +130,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)); @@ -346,7 +162,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->mcycle = RV_READ_CSR(mcycle); frame->mtvt = RV_READ_CSR(CUSTOM_CSR_MTVT); @@ -414,7 +229,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(void) 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); @@ -447,7 +261,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(void) 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(mcycle, frame->mcycle); @@ -491,12 +304,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * #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); + *(frame_crc_ptr) = esp_rom_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)){ + if(*(frame_crc_ptr) != esp_rom_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 @@ -522,7 +335,11 @@ 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) { __attribute__((unused)) uint8_t core_id = esp_cpu_get_core_id(); - RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save(); + /* mstatus is core privated CSR, do it near the core critical regs restore */ + uint32_t mstatus = save_mstatus_and_disable_global_int(); + rv_core_critical_regs_save(); + + RvCoreCriticalSleepFrame * frame = s_cpu_retention.retent.critical_frame[core_id]; 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 @@ -531,7 +348,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_DONE); while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_BACKUP_DONE) { ; @@ -545,7 +362,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif - + restore_mstatus(mstatus); return pmu_sleep_finish(dslp); } @@ -553,9 +370,8 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin 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(); uint8_t core_id = esp_cpu_get_core_id(); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_START); #endif @@ -576,7 +392,7 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin validate_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE // Start core1 if (core_id == 0) { REG_SET_BIT(PCR_CORE1_CONF_REG, PCR_CORE1_CLK_EN); @@ -590,38 +406,27 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame); cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame[core_id]); cpu_domain_dev_regs_restore(s_cpu_retention.retent.clint_frame[core_id]); - restore_mstatus(mstatus); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_DONE); #endif 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_SW - err = esp_sleep_cpu_retention_init_impl(); +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE + return esp_sleep_cpu_retention_init_impl(& s_cpu_retention, s_smp_retention_state); +#else + return esp_sleep_cpu_retention_init_impl(& s_cpu_retention); #endif - return err; } esp_err_t esp_sleep_cpu_retention_deinit(void) { - esp_err_t err = ESP_OK; -#if SOC_PM_CPU_RETENTION_BY_SW - err = esp_sleep_cpu_retention_deinit_impl(); -#endif - return err; + return esp_sleep_cpu_retention_deinit_impl(& s_cpu_retention); } - bool cpu_domain_pd_allowed(void) { bool allowed = true; @@ -639,7 +444,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { @@ -649,10 +454,8 @@ esp_err_t sleep_cpu_configure(bool light_sleep_enable) return ESP_OK; } -#endif - #if !CONFIG_FREERTOS_UNICORE -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU static IRAM_ATTR void smp_core_do_retention(void) { uint8_t core_id = esp_cpu_get_core_id(); @@ -726,7 +529,7 @@ IRAM_ATTR void esp_sleep_cpu_skip_retention(void) { void sleep_smp_cpu_sleep_prepare(void) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU while (atomic_load(&s_smp_retention_state[!esp_cpu_get_core_id()]) != SMP_IDLE) { ; } @@ -738,7 +541,7 @@ void sleep_smp_cpu_sleep_prepare(void) void sleep_smp_cpu_wakeup_prepare(void) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU uint8_t core_id = esp_cpu_get_core_id(); if (atomic_load(&s_smp_retention_state[core_id]) == SMP_RESTORE_DONE) { while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_RESTORE_DONE) { diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S index 31a6f32832..4fece9393a 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_asm.S @@ -6,14 +6,11 @@ #include "soc/soc.h" #include "rvsleep-frames.h" -#include "soc/soc_caps.h" -#include "sdkconfig.h" #include "freertos/FreeRTOSConfig.h" -#define MTVT (0x307) -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5 && !CONFIG_IDF_TARGET_ESP32H4 -#include "soc/lp_aon_reg.h" -#include "soc/extmem_reg.h" -#endif +#include "sdkconfig.h" + +#include "soc/cache_reg.h" +#define CACHE_MAP_L1_CACHE_MASK (BIT(0) | BIT(1) | BIT(4)) .section .data1,"aw" .global rv_core_critical_regs_frame @@ -24,6 +21,7 @@ rv_core_critical_regs_frame: .word 0 .endr + /* -------------------------------------------------------------------------------- This assembly subroutine is used to save the critical registers of the CPU @@ -65,7 +63,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) @@ -120,30 +117,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 && !CONFIG_IDF_TARGET_ESP32H4 - /* 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) @@ -152,14 +125,6 @@ wait_sync_done: .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 @@ -183,7 +148,6 @@ _rv_core_critical_regs_restore: /* export a strong symbol to jump to here, used nop rv_core_critical_regs_restore: - la t0, rv_core_critical_regs_frame csrr t1, mhartid slli t1, t1, 2 diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_dynamic.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_dynamic.c new file mode 100644 index 0000000000..e606633cc1 --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_dynamic.c @@ -0,0 +1,199 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/cache_reg.h" +#include "soc/clint_reg.h" +#include "soc/clic_reg.h" +#include "esp_sleep.h" + +#include "rvsleep-frames.h" +#include "sleep_cpu_retention.h" + +extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; + +static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num) +{ + const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num; + int regs_frame_sz = 0; + for (int num = 0; num < region_num; num++) { + regs_frame_sz += regions[num].end - regions[num].start; + } + void *frame = heap_caps_malloc(sizeof(cpu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame) { + cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t)); + memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t)); + void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz; + memset(regs_frame, 0, regs_frame_sz); + *(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) { + .region = region, + .region_num = region_num, + .regs_frame = (uint32_t *)regs_frame + }; + } + return frame; +} + +static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void) +{ + const static cpu_domain_dev_regs_region_t regions[] = { + { .start = CACHE_L1_ICACHE_CTRL_REG, .end = CACHE_L1_DCACHE_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_clint_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][3] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CLINT_MINT_SIP_REG, .end = CLINT_MINT_SIP_REG + 4 }, + { .start = CLINT_MINT_MTIMECMP_L_REG, .end = CLINT_MINT_TIMECTL_REG + 4 }, + { .start = CLINT_MINT_MTIME_L_REG, .end = CLINT_MINT_MTIME_H_REG + 4 }, + } + }; + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(regions[core_id][0])); +} + +static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][4] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 }, + { .start = CLIC_INT_CTRL_REG(3), .end = CLIC_INT_CTRL_REG(3) + 4 }, + { .start = CLIC_INT_CTRL_REG(7), .end = CLIC_INT_CTRL_REG(7) + 4 }, + { .start = CLIC_INT_CTRL_REG(16), .end = CLIC_INT_CTRL_REG(47) + 4 }, + } + }; + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(regions[core_id][0])); +} + +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE +esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) { + void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id] == NULL) { + void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) { + void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init(); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame; + } + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + atomic_init(&s_smp_retention_state[core_id], SMP_IDLE); + } + return ESP_OK; +err: + esp_sleep_cpu_retention_deinit(); + return ESP_ERR_NO_MEM; +} +#else +esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, RV_SLEEP_CTX_FRMSZ, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *)frame; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) { + void *frame = heap_caps_calloc(1, sizeof(RvCoreNonCriticalSleepFrame), MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)frame; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) { + void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id] == NULL) { + void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) { + void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init(); + if (frame == NULL) { + goto err; + } + sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame; + } + return ESP_OK; +err: + esp_sleep_cpu_retention_deinit(); + return ESP_ERR_NO_MEM; +} +#endif + +esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id]) { + heap_caps_free((void *)sleep_cpu_retention_ptr->retent.critical_frame[core_id]); + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = NULL; + rv_core_critical_regs_frame[core_id] = NULL; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]) { + heap_caps_free((void *)sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]); + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = NULL; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id]) { + heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clic_frame[core_id]); + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = NULL; + } + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id]) { + heap_caps_free((void *)sleep_cpu_retention_ptr->retent.clint_frame[core_id]); + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = NULL; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame) { + heap_caps_free((void *)sleep_cpu_retention_ptr->retent.cache_config_frame); + sleep_cpu_retention_ptr->retent.cache_config_frame = NULL; + } + return ESP_OK; +} diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_retention.h b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_retention.h new file mode 100644 index 0000000000..7d31580212 --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_retention.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SLEEP_CPU_RETENTION_H__ +#define __SLEEP_CPU_RETENTION_H__ + +#include "rvsleep-frames.h" +#include "freertos/FreeRTOS.h" +#include "esp_err.h" + +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE +#include +#include "soc/hp_system_reg.h" +typedef enum { + SMP_IDLE, + SMP_BACKUP_START, + SMP_BACKUP_DONE, + SMP_RESTORE_START, + SMP_RESTORE_DONE, + SMP_SKIP_RETENTION, +} smp_retention_state_t; +#endif + +typedef struct { + uint32_t start; + uint32_t end; +} cpu_domain_dev_regs_region_t; + +typedef struct { + cpu_domain_dev_regs_region_t *region; + int region_num; + uint32_t *regs_frame; +} cpu_domain_dev_sleep_frame_t; + +/** + * Internal structure which holds all requested light sleep cpu retention parameters + */ +typedef struct { + struct { + RvCoreCriticalSleepFrame *critical_frame[portNUM_PROCESSORS]; + RvCoreNonCriticalSleepFrame *non_critical_frame[portNUM_PROCESSORS]; + cpu_domain_dev_sleep_frame_t *cache_config_frame; + cpu_domain_dev_sleep_frame_t *clic_frame[portNUM_PROCESSORS]; + cpu_domain_dev_sleep_frame_t *clint_frame[portNUM_PROCESSORS]; + } retent; +} sleep_cpu_retention_t; + +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE + esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state); +#else + esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr); +#endif + +esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr); + +#endif /* #ifndef __SLEEP_CPU_RETENTION_H__ */ diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_static.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_static.c new file mode 100644 index 0000000000..2ee118750d --- /dev/null +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu_static.c @@ -0,0 +1,237 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/cache_reg.h" +#include "soc/clint_reg.h" +#include "soc/clic_reg.h" +#include "esp_sleep.h" + +#include "rvsleep-frames.h" +#include "sleep_cpu_retention.h" + + +extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; + +#define R_CONCAT(s1, s2) _R_CONCAT(s1, s2) +#define _R_CONCAT(s1, s2) s1 ## s2 + +#define CPU_DOMAIN_DEV_SZ0 (CPU_DOMAIN_DEV_END_ADDR0 - CPU_DOMAIN_DEV_START_ADDR0) +#define CPU_DOMAIN_DEV_SZ1 (CPU_DOMAIN_DEV_END_ADDR1 - CPU_DOMAIN_DEV_START_ADDR1) +#define CPU_DOMAIN_DEV_SZ2 (CPU_DOMAIN_DEV_END_ADDR2 - CPU_DOMAIN_DEV_START_ADDR2) +#define CPU_DOMAIN_DEV_SZ3 (CPU_DOMAIN_DEV_END_ADDR3 - CPU_DOMAIN_DEV_START_ADDR3) +#define CPU_DOMAIN_DEV_SZ4 (CPU_DOMAIN_DEV_END_ADDR4 - CPU_DOMAIN_DEV_START_ADDR4) +#define CPU_DOMAIN_DEV_SZ5 (CPU_DOMAIN_DEV_END_ADDR5 - CPU_DOMAIN_DEV_START_ADDR5) +#define CPU_DOMAIN_DEV_SZ6 (CPU_DOMAIN_DEV_END_ADDR6 - CPU_DOMAIN_DEV_START_ADDR6) +#define CPU_DOMAIN_DEV_SZ7 (CPU_DOMAIN_DEV_END_ADDR7 - CPU_DOMAIN_DEV_START_ADDR7) + +#define CPU_DOMAIN_DEV_TOTAL_SZ(n) (R_CONCAT(__TOTAL_SZ, n)) + +#define __TOTAL_SZ0 (sizeof(cpu_domain_dev_sleep_frame_t)) +#define __TOTAL_SZ1 ((__TOTAL_SZ0) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ0) +#define __TOTAL_SZ2 ((__TOTAL_SZ1) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ1) +#define __TOTAL_SZ3 ((__TOTAL_SZ2) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ2) +#define __TOTAL_SZ4 ((__TOTAL_SZ3) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ3) +#define __TOTAL_SZ5 ((__TOTAL_SZ4) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ4) +#define __TOTAL_SZ6 ((__TOTAL_SZ5) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ5) +#define __TOTAL_SZ7 ((__TOTAL_SZ6) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ6) +#define __TOTAL_SZ8 ((__TOTAL_SZ7) + (sizeof(cpu_domain_dev_regs_region_t)) + CPU_DOMAIN_DEV_SZ7) + +static void * cpu_domain_dev_sleep_frame_alloc_and_init(const cpu_domain_dev_regs_region_t *regions, const int region_num, void * frame) +{ + const int region_sz = sizeof(cpu_domain_dev_regs_region_t) * region_num; + int regs_frame_sz = 0; + for (int num = 0; num < region_num; num++) { + regs_frame_sz += regions[num].end - regions[num].start; + } + if (frame) { + cpu_domain_dev_regs_region_t *region = (cpu_domain_dev_regs_region_t *)(frame + sizeof(cpu_domain_dev_sleep_frame_t)); + memcpy(region, regions, region_num * sizeof(cpu_domain_dev_regs_region_t)); + void *regs_frame = frame + sizeof(cpu_domain_dev_sleep_frame_t) + region_sz; + memset(regs_frame, 0, regs_frame_sz); + *(cpu_domain_dev_sleep_frame_t *)frame = (cpu_domain_dev_sleep_frame_t) { + .region = region, + .region_num = region_num, + .regs_frame = (uint32_t *)regs_frame + }; + } + return frame; +} + +#undef CPU_DOMAIN_DEV_START_ADDR0 +#undef CPU_DOMAIN_DEV_END_ADDR0 +#undef CPU_DOMAIN_DEV_START_ADDR1 +#undef CPU_DOMAIN_DEV_END_ADDR1 + +#define CPU_DOMAIN_DEV_START_ADDR0 (CACHE_L1_ICACHE_CTRL_REG) +#define CPU_DOMAIN_DEV_END_ADDR0 (CACHE_L1_DCACHE_CTRL_REG + 4) +#define CPU_DOMAIN_DEV_START_ADDR1 (CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG) +#define CPU_DOMAIN_DEV_END_ADDR1 (CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4) + +static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void) +{ + const static cpu_domain_dev_regs_region_t regions[] = { + { .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 }, + { .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 } + }; + static uint8_t sleep_frame[CPU_DOMAIN_DEV_TOTAL_SZ(2)] __attribute__((aligned(4))); + return cpu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0]), sleep_frame); +} + +#undef CPU_DOMAIN_DEV_START_ADDR0 +#undef CPU_DOMAIN_DEV_END_ADDR0 +#undef CPU_DOMAIN_DEV_START_ADDR1 +#undef CPU_DOMAIN_DEV_END_ADDR1 +#undef CPU_DOMAIN_DEV_START_ADDR2 +#undef CPU_DOMAIN_DEV_END_ADDR2 + +#define CPU_DOMAIN_DEV_START_ADDR0 (CLINT_MINT_SIP_REG) +#define CPU_DOMAIN_DEV_END_ADDR0 (CLINT_MINT_SIP_REG + 4) +#define CPU_DOMAIN_DEV_START_ADDR1 (CLINT_MINT_MTIMECMP_L_REG) +#define CPU_DOMAIN_DEV_END_ADDR1 (CLINT_MINT_TIMECTL_REG + 4) +#define CPU_DOMAIN_DEV_START_ADDR2 (CLINT_MINT_MTIME_L_REG) +#define CPU_DOMAIN_DEV_END_ADDR2 (CLINT_MINT_MTIME_H_REG + 4) + +static inline void * cpu_domain_clint_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][3] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CPU_DOMAIN_DEV_START_ADDR0, .end = CPU_DOMAIN_DEV_END_ADDR0 }, + { .start = CPU_DOMAIN_DEV_START_ADDR1, .end = CPU_DOMAIN_DEV_END_ADDR1 }, + { .start = CPU_DOMAIN_DEV_START_ADDR2, .end = CPU_DOMAIN_DEV_END_ADDR2 }, + } + }; + static DRAM_ATTR uint8_t sleep_frame[portNUM_PROCESSORS][CPU_DOMAIN_DEV_TOTAL_SZ(3)] __attribute__((aligned(4))); + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(regions[core_id][0]), sleep_frame[core_id]); +} + +#undef CPU_DOMAIN_DEV_START_ADDR0 +#undef CPU_DOMAIN_DEV_END_ADDR0 +#undef CPU_DOMAIN_DEV_START_ADDR1 +#undef CPU_DOMAIN_DEV_END_ADDR1 +#undef CPU_DOMAIN_DEV_START_ADDR2 +#undef CPU_DOMAIN_DEV_END_ADDR2 +#undef CPU_DOMAIN_DEV_START_ADDR3 +#undef CPU_DOMAIN_DEV_END_ADDR3 + +#define CPU_DOMAIN_DEV_START_ADDR0 (CLIC_INT_CONFIG_REG) +#define CPU_DOMAIN_DEV_END_ADDR0 (CLIC_INT_THRESH_REG + 4) +#define CPU_DOMAIN_DEV_START_ADDR1 (CLIC_INT_CTRL_REG(3)) +#define CPU_DOMAIN_DEV_END_ADDR1 (CLIC_INT_CTRL_REG(3) + 4) +#define CPU_DOMAIN_DEV_START_ADDR2 (CLIC_INT_CTRL_REG(7)) +#define CPU_DOMAIN_DEV_END_ADDR2 (CLIC_INT_CTRL_REG(7) + 4) +#define CPU_DOMAIN_DEV_START_ADDR3 (CLIC_INT_CTRL_REG(16)) +#define CPU_DOMAIN_DEV_END_ADDR3 (CLIC_INT_CTRL_REG(47) + 4) + +static inline void * cpu_domain_clic_sleep_frame_alloc_and_init(uint8_t core_id) +{ + const static cpu_domain_dev_regs_region_t regions[portNUM_PROCESSORS][4] = { + [0 ... portNUM_PROCESSORS - 1] = { + { .start = CLIC_INT_CONFIG_REG, .end = CLIC_INT_THRESH_REG + 4 }, + { .start = CLIC_INT_CTRL_REG(3), .end = CLIC_INT_CTRL_REG(3) + 4 }, + { .start = CLIC_INT_CTRL_REG(7), .end = CLIC_INT_CTRL_REG(7) + 4 }, + { .start = CLIC_INT_CTRL_REG(16), .end = CLIC_INT_CTRL_REG(47) + 4 }, + } + }; + static DRAM_ATTR uint8_t sleep_frame[portNUM_PROCESSORS][CPU_DOMAIN_DEV_TOTAL_SZ(4)] __attribute__((aligned(4))); + return cpu_domain_dev_sleep_frame_alloc_and_init(regions[core_id], sizeof(regions[core_id]) / sizeof(regions[core_id][0]), sleep_frame[core_id]); +} + +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE +esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr, smp_retention_state_t *s_smp_retention_state) +{ + static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ * portNUM_PROCESSORS] __attribute__((aligned(4))); + static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)* portNUM_PROCESSORS] __attribute__((aligned(4))); + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) { + void * regs = rv_core_critical_regs + core_id * RV_SLEEP_CTX_FRMSZ; + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *) regs; + rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *) regs; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) { + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)(rv_core_non_critical_regs+core_id * sizeof(RvCoreNonCriticalSleepFrame)); + } + } + + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id] == NULL) { + void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) { + void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) { + void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init(); + sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame; + } + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + atomic_init(&s_smp_retention_state[core_id], SMP_IDLE); + } + return ESP_OK; +} +#else +esp_err_t esp_sleep_cpu_retention_init_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr) +{ + static DRAM_ATTR uint8_t rv_core_critical_regs[RV_SLEEP_CTX_FRMSZ * portNUM_PROCESSORS] __attribute__((aligned(4))); + static DRAM_ATTR uint8_t rv_core_non_critical_regs[sizeof(RvCoreNonCriticalSleepFrame)* portNUM_PROCESSORS] __attribute__((aligned(4))); + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id] == NULL) { + void * regs = rv_core_critical_regs + core_id * RV_SLEEP_CTX_FRMSZ; + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = (RvCoreCriticalSleepFrame *) regs; + rv_core_critical_regs_frame[core_id] = (RvCoreCriticalSleepFrame *) regs; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] == NULL) { + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = (RvCoreNonCriticalSleepFrame *)(rv_core_non_critical_regs+core_id * sizeof(RvCoreNonCriticalSleepFrame)); + } + } + + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id] == NULL) { + void *frame = cpu_domain_clint_sleep_frame_alloc_and_init(core_id); + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id] == NULL) { + void *frame = cpu_domain_clic_sleep_frame_alloc_and_init(core_id); + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame == NULL) { + void *frame = cpu_domain_cache_config_sleep_frame_alloc_and_init(); + sleep_cpu_retention_ptr->retent.cache_config_frame = (cpu_domain_dev_sleep_frame_t *)frame; + } + return ESP_OK; +} +#endif + +esp_err_t esp_sleep_cpu_retention_deinit_impl(sleep_cpu_retention_t *sleep_cpu_retention_ptr) +{ + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.critical_frame[core_id]) { + sleep_cpu_retention_ptr->retent.critical_frame[core_id] = NULL; + rv_core_critical_regs_frame[core_id] = NULL; + } + if (sleep_cpu_retention_ptr->retent.non_critical_frame[core_id]) { + sleep_cpu_retention_ptr->retent.non_critical_frame[core_id] = NULL; + } + } + for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { + if (sleep_cpu_retention_ptr->retent.clint_frame[core_id]) { + sleep_cpu_retention_ptr->retent.clint_frame[core_id] = NULL; + } + if (sleep_cpu_retention_ptr->retent.clic_frame[core_id]) { + sleep_cpu_retention_ptr->retent.clic_frame[core_id] = NULL; + } + } + if (sleep_cpu_retention_ptr->retent.cache_config_frame) { + sleep_cpu_retention_ptr->retent.cache_config_frame = NULL; + } + return ESP_OK; +} diff --git a/components/soc/esp32h4/register/soc/cache_reg.h b/components/soc/esp32h4/register/soc/cache_reg.h index df662576b0..19e563df05 100644 --- a/components/soc/esp32h4/register/soc/cache_reg.h +++ b/components/soc/esp32h4/register/soc/cache_reg.h @@ -5,7 +5,6 @@ */ #pragma once -#include #include "soc/soc.h" #ifdef __cplusplus extern "C" { From 852aab4b6426d716c2399dbdbf29b3482ed335c0 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 29 Aug 2025 12:22:58 +0800 Subject: [PATCH 13/13] change(esp_hw_support): replace pmu reg operation with pmu ll layer code --- components/esp_hw_support/port/esp32h4/rtc_clk_init.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/esp_hw_support/port/esp32h4/rtc_clk_init.c b/components/esp_hw_support/port/esp32h4/rtc_clk_init.c index f8ffb8b300..106e80e917 100644 --- a/components/esp_hw_support/port/esp32h4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32h4/rtc_clk_init.c @@ -73,10 +73,11 @@ void rtc_clk_init(rtc_clk_config_t cfg) REG_SET_FIELD(LP_CLKRST_FOSC_CNTL_REG, LP_CLKRST_FOSC_DFREQ, cfg.clk_8m_dfreq); REG_SET_FIELD(LP_CLKRST_RC32K_CNTL_REG, LP_CLKRST_RC32K_DFREQ, cfg.slow_clk_dcap); // h4 specific workaround (RC32K_DFREQ is used for RC_SLOW clock tuning) TODO: IDF-12313 - uint32_t hp_cali_dbias = get_act_hp_dbias(); - uint32_t lp_cali_dbias = get_act_lp_dbias(); - REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, hp_cali_dbias); - REG_SET_FIELD(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, lp_cali_dbias); + uint32_t hp_dbias = get_act_hp_dbias(); + uint32_t lp_dbias = get_act_lp_dbias(); + pmu_ll_hp_set_regulator_xpd(&PMU, PMU_MODE_HP_ACTIVE, true); + pmu_ll_hp_set_regulator_dbias(&PMU, PMU_MODE_HP_ACTIVE, hp_dbias); + pmu_ll_lp_set_regulator_dbias(&PMU, PMU_MODE_LP_ACTIVE, lp_dbias); // XTAL freq can be directly informed from register field PCR_CLK_XTAL_FREQ