diff --git a/components/esp_hw_support/lowpower/port/esp32c5/rvsleep-frames.h b/components/esp_hw_support/lowpower/port/esp32c5/rvsleep-frames.h index e0275af06d..6261ead95c 100644 --- a/components/esp_hw_support/lowpower/port/esp32c5/rvsleep-frames.h +++ b/components/esp_hw_support/lowpower/port/esp32c5/rvsleep-frames.h @@ -83,6 +83,7 @@ STRUCT_BEGIN 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_MINTTHRESH, mintthresh) /* Machine intr threshold */ 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 @@ -173,7 +174,6 @@ STRUCT_BEGIN 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_MINTSTATUS, mintstatus) STRUCT_FIELD (long, 4, RV_SLP_CTX_MXSTATUS, mxstatus) STRUCT_FIELD (long, 4, RV_SLP_CTX_MHCR, mhcr) diff --git a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu.c index 8815cd3803..c87a9416b8 100644 --- a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu.c @@ -60,6 +60,20 @@ FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val) RV_WRITE_CSR(mstatus, mstatus_val); } +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND +FORCE_INLINE_ATTR uint32_t save_mintthresh_and_disable_global_int(void) +{ + /* Due to the reason described in IDF-14279, when mie is set to 0, mintthresh needs to be set to 0xff. */ + // TODO: IDF-14279 DIG-661 + return RV_READ_MINTTHRESH_AND_DISABLE_INTR(); +} + +FORCE_INLINE_ATTR void restore_mintthresh(uint32_t mintthresh_val) +{ + RV_RESTORE_MINTTHRESH(mintthresh_val); +} +#endif + static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) { assert(s_cpu_retention.retent.non_critical_frame); @@ -128,7 +142,6 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi 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); @@ -203,7 +216,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra 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); @@ -275,14 +287,14 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif @@ -294,6 +306,9 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin { esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0); uint32_t mstatus = save_mstatus_and_disable_global_int(); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + uint32_t mintthresh = save_mintthresh_and_disable_global_int(); +#endif cpu_domain_dev_regs_save(s_cpu_retention.retent.clic_frame); cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame); @@ -314,6 +329,9 @@ 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.clint_frame); cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + restore_mintthresh(mintthresh); +#endif restore_mstatus(mstatus); return err; } diff --git a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_asm.S index bfb6cf894d..bf5718b52e 100644 --- a/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_asm.S +++ b/components/esp_hw_support/lowpower/port/esp32c5/sleep_cpu_asm.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include "rvsleep-frames.h" #include "soc/soc_caps.h" #include "sdkconfig.h" +#include "riscv/csr_clic.h" .section .data1,"aw" .global rv_core_critical_regs_frame @@ -91,6 +92,8 @@ rv_core_critical_regs_save: sw t3, RV_SLP_CTX_MIP(t0) csrr t1, mepc sw t1, RV_SLP_CTX_MEPC(t0) + csrr t2, MINTTHRESH_CSR + sw t2, RV_SLP_CTX_MINTTHRESH(t0) /* !!! Let idf knows it's going to sleep !!! @@ -162,6 +165,8 @@ rv_core_critical_regs_restore: ori t1, t1, 0x3 sw t1, RV_SLP_CTX_PMUFUNC(t0) + lw t2, RV_SLP_CTX_MINTTHRESH(t0) + csrw MINTTHRESH_CSR, t2 lw t2, RV_SLP_CTX_MEPC(t0) csrw mepc, t2 lw t3, RV_SLP_CTX_MIP(t0) diff --git a/components/esp_hw_support/lowpower/port/esp32c6/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32c6/sleep_cpu.c index ddecd997f0..3d6ffba5f2 100644 --- a/components/esp_hw_support/lowpower/port/esp32c6/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32c6/sleep_cpu.c @@ -295,14 +295,14 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif diff --git a/components/esp_hw_support/lowpower/port/esp32c61/rvsleep-frames.h b/components/esp_hw_support/lowpower/port/esp32c61/rvsleep-frames.h index e0275af06d..6261ead95c 100644 --- a/components/esp_hw_support/lowpower/port/esp32c61/rvsleep-frames.h +++ b/components/esp_hw_support/lowpower/port/esp32c61/rvsleep-frames.h @@ -83,6 +83,7 @@ STRUCT_BEGIN 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_MINTTHRESH, mintthresh) /* Machine intr threshold */ 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 @@ -173,7 +174,6 @@ STRUCT_BEGIN 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_MINTSTATUS, mintstatus) STRUCT_FIELD (long, 4, RV_SLP_CTX_MXSTATUS, mxstatus) STRUCT_FIELD (long, 4, RV_SLP_CTX_MHCR, mhcr) diff --git a/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu.c index 809034cfa3..b00035e2bf 100644 --- a/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu.c @@ -60,6 +60,20 @@ FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val) RV_WRITE_CSR(mstatus, mstatus_val); } +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND +FORCE_INLINE_ATTR uint32_t save_mintthresh_and_disable_global_int(void) +{ + /* Due to the reason described in IDF-14279, when mie is set to 0, mintthresh needs to be set to 0xff. */ + // TODO: IDF-14279 DIG-661 + return RV_READ_MINTTHRESH_AND_DISABLE_INTR(); +} + +FORCE_INLINE_ATTR void restore_mintthresh(uint32_t mintthresh_val) +{ + RV_RESTORE_MINTTHRESH(mintthresh_val); +} +#endif + static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) { assert(s_cpu_retention.retent.non_critical_frame); @@ -128,7 +142,6 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi 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); @@ -203,7 +216,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra 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); @@ -275,14 +287,14 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif @@ -294,6 +306,9 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin { esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0); uint32_t mstatus = save_mstatus_and_disable_global_int(); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + uint32_t mintthresh = save_mintthresh_and_disable_global_int(); +#endif cpu_domain_dev_regs_save(s_cpu_retention.retent.clic_frame); cpu_domain_dev_regs_save(s_cpu_retention.retent.clint_frame); @@ -314,6 +329,9 @@ 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.clint_frame); cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + restore_mintthresh(mintthresh); +#endif restore_mstatus(mstatus); return err; } diff --git a/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu_asm.S index 934384cb78..bf5718b52e 100644 --- a/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu_asm.S +++ b/components/esp_hw_support/lowpower/port/esp32c61/sleep_cpu_asm.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include "rvsleep-frames.h" #include "soc/soc_caps.h" #include "sdkconfig.h" +#include "riscv/csr_clic.h" .section .data1,"aw" .global rv_core_critical_regs_frame @@ -91,6 +92,8 @@ rv_core_critical_regs_save: sw t3, RV_SLP_CTX_MIP(t0) csrr t1, mepc sw t1, RV_SLP_CTX_MEPC(t0) + csrr t2, MINTTHRESH_CSR + sw t2, RV_SLP_CTX_MINTTHRESH(t0) /* !!! Let idf knows it's going to sleep !!! @@ -162,6 +165,8 @@ rv_core_critical_regs_restore: ori t1, t1, 0x3 sw t1, RV_SLP_CTX_PMUFUNC(t0) + lw t2, RV_SLP_CTX_MINTTHRESH(t0) + csrw MINTTHRESH_CSR, t2 lw t2, RV_SLP_CTX_MEPC(t0) csrw mepc, t2 lw t3, RV_SLP_CTX_MIP(t0) diff --git a/components/esp_hw_support/lowpower/port/esp32h2/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32h2/sleep_cpu.c index fa24e9d959..3bd4bd5c15 100644 --- a/components/esp_hw_support/lowpower/port/esp32h2/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32h2/sleep_cpu.c @@ -295,14 +295,14 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif diff --git a/components/esp_hw_support/lowpower/port/esp32h21/sleep_cpu.c b/components/esp_hw_support/lowpower/port/esp32h21/sleep_cpu.c index 7467ecfd43..cf278ac485 100644 --- a/components/esp_hw_support/lowpower/port/esp32h21/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32h21/sleep_cpu.c @@ -294,14 +294,14 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif 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 95cffbef85..d6364a7759 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h +++ b/components/esp_hw_support/lowpower/port/esp32h4/rvsleep-frames.h @@ -83,6 +83,7 @@ STRUCT_BEGIN 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_MINTTHRESH, mintthresh) /* Machine intr threshold */ 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 @@ -197,7 +198,6 @@ STRUCT_BEGIN 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) 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 8f10c24e47..f7d662c48d 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_cpu.c @@ -71,6 +71,20 @@ FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val) RV_WRITE_CSR(mstatus, mstatus_val); } +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND +FORCE_INLINE_ATTR uint32_t save_mintthresh_and_disable_global_int(void) +{ + /* Due to the reason described in IDF-14279, when mie is set to 0, mintthresh needs to be set to 0xff. */ + // TODO: IDF-14279 DIG-661 + return RV_READ_MINTTHRESH_AND_DISABLE_INTR(); +} + +FORCE_INLINE_ATTR void restore_mintthresh(uint32_t mintthresh_val) +{ + RV_RESTORE_MINTTHRESH(mintthresh_val); +} +#endif + static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) { RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[esp_cpu_get_core_id()]; @@ -161,7 +175,6 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi 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); @@ -261,7 +274,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(void) 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); @@ -333,6 +345,9 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, __attribute__((unused)) uint8_t core_id = esp_cpu_get_core_id(); /* mstatus is core privated CSR, do it near the core critical regs restore */ uint32_t mstatus = save_mstatus_and_disable_global_int(); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + uint32_t mintthresh = save_mintthresh_and_disable_global_int(); +#endif rv_core_critical_regs_save(); RvCoreCriticalSleepFrame * frame = s_cpu_retention.retent.critical_frame[core_id]; @@ -340,7 +355,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, 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)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); @@ -355,8 +370,11 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #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)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } +#endif +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + restore_mintthresh(mintthresh); #endif restore_mstatus(mstatus); return pmu_sleep_finish(dslp); @@ -481,6 +499,9 @@ static IRAM_ATTR void smp_core_do_retention(void) if (!smp_skip_retention) { atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_START); uint32_t mstatus = save_mstatus_and_disable_global_int(); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + uint32_t mintthresh = save_mintthresh_and_disable_global_int(); +#endif 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]); @@ -508,6 +529,9 @@ static IRAM_ATTR void smp_core_do_retention(void) 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(); +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND + restore_mintthresh(mintthresh); +#endif restore_mstatus(mstatus); atomic_store(&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 4fece9393a..ee60496643 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 @@ -8,7 +8,7 @@ #include "rvsleep-frames.h" #include "freertos/FreeRTOSConfig.h" #include "sdkconfig.h" - +#include "riscv/csr_clic.h" #include "soc/cache_reg.h" #define CACHE_MAP_L1_CACHE_MASK (BIT(0) | BIT(1) | BIT(4)) @@ -100,6 +100,8 @@ rv_core_critical_regs_save: sw t3, RV_SLP_CTX_MIP(t0) csrr t1, mepc sw t1, RV_SLP_CTX_MEPC(t0) + csrr t2, MINTTHRESH_CSR + sw t2, RV_SLP_CTX_MINTTHRESH(t0) /* !!! Let idf knows it's going to sleep !!! @@ -166,6 +168,8 @@ rv_core_critical_regs_restore: ori t1, t1, 0x3 sw t1, RV_SLP_CTX_PMUFUNC(t0) + lw t2, RV_SLP_CTX_MINTTHRESH(t0) + csrw MINTTHRESH_CSR, t2 lw t2, RV_SLP_CTX_MEPC(t0) csrw mepc, t2 lw t3, RV_SLP_CTX_MIP(t0) diff --git a/components/riscv/include/riscv/csr.h b/components/riscv/include/riscv/csr.h index 0e9d71b4be..1eb2c3fe11 100644 --- a/components/riscv/include/riscv/csr.h +++ b/components/riscv/include/riscv/csr.h @@ -37,6 +37,9 @@ extern "C" { #include #include "encoding.h" #include "esp_assert.h" +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND +#include "riscv/csr_clic.h" +#endif /******************************************************** Physical Memory Attributes (PMA) register fields @@ -224,6 +227,16 @@ extern "C" { #define RV_READ_MSTATUS_AND_DISABLE_INTR() ({ unsigned long __tmp; \ asm volatile ("csrrci %0, mstatus, 0x8" : "=r"(__tmp)); __tmp; }) +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND +#define RV_READ_MINTTHRESH_AND_DISABLE_INTR() ({ unsigned long __tmp; \ + asm volatile ( \ + "li t0, 0xff\n\t" \ + "csrrw %0, %1, t0" : "=r"(__tmp) : "i"(MINTTHRESH_CSR) : "t0", "memory"); __tmp; }) + +#define RV_RESTORE_MINTTHRESH(val) \ + asm volatile ("csrw %0, %1" :: "i"(MINTTHRESH_CSR), "r"(val) : "memory") +#endif + #define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */ #ifdef __cplusplus diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index d7e822869c..a933fde2ab 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -182,7 +182,7 @@ .endm .macro mintthresh_csr_disable reg -#if __riscv_zcmp && INTTHRESH_STANDARD +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND /* Workaround for triggering an interrupt even when mstatus.mie is 0, when cm.push is called. */ li t0, 0xff csrrw \reg, MINTTHRESH_CSR, t0 @@ -190,7 +190,7 @@ .endm .macro mintthresh_csr_restore reg -#if __riscv_zcmp && INTTHRESH_STANDARD +#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND csrw MINTTHRESH_CSR, \reg #endif .endm diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 9a9cb551b6..6c7cac4940 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -483,6 +483,10 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_ZCMP_WORKAROUND + bool + default y + config SOC_DS_SIGNATURE_MAX_BIT_LEN int default 3072 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index fbed2753cb..6ae6518c4c 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -182,6 +182,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_ZCMP_WORKAROUND 1 + /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ #define SOC_DS_SIGNATURE_MAX_BIT_LEN (3072) diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 2d30ff80ab..7c3e574238 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -371,6 +371,10 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_ZCMP_WORKAROUND + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index ccead5f87f..e156c5daef 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -149,6 +149,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_ZCMP_WORKAROUND 1 + /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 1798d3c751..c23b67815d 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -239,6 +239,10 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_ZCMP_WORKAROUND + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index e151884293..3724366db6 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -175,6 +175,8 @@ #define SOC_HP_CPU_HAS_MULTIPLE_CORES 1 // Convenience boolean macro used to determine if a target has multiple cores. #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_ZCMP_WORKAROUND 1 + /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */