From 53afab3850f2c9fb886f5049fabb37ec2c347edc Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 12 Dec 2023 21:03:52 +0800 Subject: [PATCH] feat(ulp): add api to get lp_cpu wakeup cause and clear wakeup source at startup Closes https://github.com/espressif/esp-idf/issues/12651 --- components/hal/esp32c6/include/hal/etm_ll.h | 5 ++ .../hal/esp32c6/include/hal/lp_aon_ll.h | 18 +++++++ .../hal/esp32c6/include/hal/lp_timer_ll.h | 11 +++++ components/hal/esp32c6/include/hal/pmu_ll.h | 10 ++++ .../lp_core/include/ulp_lp_core_utils.h | 13 +++++ .../ulp/lp_core/lp_core/lp_core_startup.c | 2 + .../ulp/lp_core/lp_core/lp_core_utils.c | 47 +++++++++++++++++++ 7 files changed, 106 insertions(+) diff --git a/components/hal/esp32c6/include/hal/etm_ll.h b/components/hal/esp32c6/include/hal/etm_ll.h index 9d95b485c27..535a94eb2e8 100644 --- a/components/hal/esp32c6/include/hal/etm_ll.h +++ b/components/hal/esp32c6/include/hal/etm_ll.h @@ -11,6 +11,7 @@ #include #include "hal/assert.h" #include "hal/misc.h" +#include "hal/lp_aon_ll.h" #include "soc/soc_etm_struct.h" #ifdef __cplusplus @@ -98,6 +99,10 @@ static inline void etm_ll_channel_set_task(soc_etm_dev_t *hw, uint32_t chan, uin hw->channel[chan].task_id.task_id = task; } +#define etm_ll_is_lpcore_wakeup_triggered() lp_aon_ll_get_lpcore_etm_wakeup_flag() + +#define etm_ll_clear_lpcore_wakeup_status() lp_aon_ll_clear_lpcore_etm_wakeup_flag() + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/lp_aon_ll.h b/components/hal/esp32c6/include/hal/lp_aon_ll.h index 93dc73a9f73..c212d33b9ae 100644 --- a/components/hal/esp32c6/include/hal/lp_aon_ll.h +++ b/components/hal/esp32c6/include/hal/lp_aon_ll.h @@ -85,6 +85,24 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp) } } +/** + * @brief Get the flag that marks whether LP CPU is awakened by ETM + * + * @return Return true if lpcore is woken up by soc_etm + */ +static inline bool lp_aon_ll_get_lpcore_etm_wakeup_flag(void) +{ + return REG_GET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG); +} + +/** + * @brief Clear the flag that marks whether LP CPU is awakened by soc_etm + */ +static inline void lp_aon_ll_clear_lpcore_etm_wakeup_flag(void) +{ + REG_SET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG_CLR); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/lp_timer_ll.h b/components/hal/esp32c6/include/hal/lp_timer_ll.h index a99349240be..d04bccb5590 100644 --- a/components/hal/esp32c6/include/hal/lp_timer_ll.h +++ b/components/hal/esp32c6/include/hal/lp_timer_ll.h @@ -12,6 +12,7 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/lp_timer_struct.h" +#include "soc/lp_timer_reg.h" #include "soc/lp_aon_reg.h" #include "hal/lp_timer_types.h" #include "esp_attr.h" @@ -61,6 +62,16 @@ FORCE_INLINE_ATTR void lp_timer_ll_clear_lp_alarm_intr_status(lp_timer_dev_t *de dev->lp_int_clr.alarm = 1; } +FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_lp_intr_raw(lp_timer_dev_t *dev) +{ + return dev->lp_int_raw.val; +} + +FORCE_INLINE_ATTR void lp_timer_ll_clear_lp_intsts_mask(lp_timer_dev_t *dev, uint32_t mask) +{ + dev->lp_int_clr.val = mask; +} + FORCE_INLINE_ATTR uint64_t lp_timer_ll_time_to_count(uint64_t time_in_us) { uint32_t slow_clk_value = REG_READ(LP_AON_STORE1_REG); diff --git a/components/hal/esp32c6/include/hal/pmu_ll.h b/components/hal/esp32c6/include/hal/pmu_ll.h index 15f39d10e49..2470f73247c 100644 --- a/components/hal/esp32c6/include/hal/pmu_ll.h +++ b/components/hal/esp32c6/include/hal/pmu_ll.h @@ -531,6 +531,16 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_reject_cause(pmu_dev_t *hw) return hw->wakeup.status1; } +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_interrupt_raw(pmu_dev_t *hw) +{ + return hw->lp_ext.int_raw.val; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) +{ + hw->lp_ext.int_clr.val = mask; +} + FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h index ce47034df65..bbbd86d3f5e 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h @@ -12,6 +12,19 @@ extern "C" { #include +/** + * @brief Traverse all possible wake-up sources and update the wake-up cause so that + * ulp_lp_core_get_wakeup_cause can obtain the bitmap of the wake-up reasons. + */ +void ulp_lp_core_update_wakeup_cause(void); + +/** + * @brief Get the wakeup source which caused LP_CPU to wakeup from sleep + * + * @return Wakeup cause in bit map, for the meaning of each bit, refer + * to the definition of wakeup source in lp_core_ll.h + */ +uint32_t ulp_lp_core_get_wakeup_cause(void); /** * @brief Wakeup main CPU from sleep or deep sleep. diff --git a/components/ulp/lp_core/lp_core/lp_core_startup.c b/components/ulp/lp_core/lp_core/lp_core_startup.c index e094848e5ae..a5cf8855b92 100644 --- a/components/ulp/lp_core/lp_core/lp_core_startup.c +++ b/components/ulp/lp_core/lp_core/lp_core_startup.c @@ -14,6 +14,8 @@ extern void main(); /* Initialize lp core related system functions before calling user's main*/ void lp_core_startup() { + ulp_lp_core_update_wakeup_cause(); + main(); ulp_lp_core_memory_shared_cfg_t* shared_mem = ulp_lp_core_memory_shared_cfg_get(); diff --git a/components/ulp/lp_core/lp_core/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index e04b5c91155..fadccc92e7b 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -9,10 +9,57 @@ #include "riscv/csr.h" #include "soc/soc.h" #include "soc/pmu_reg.h" +#include "hal/misc.h" +#include "ulp_lp_core.h" +#include "hal/etm_ll.h" +#include "hal/lp_timer_ll.h" +#include "hal/pmu_ll.h" +#include "hal/uart_ll.h" +#include "hal/rtc_io_ll.h" /* LP_FAST_CLK is not very accurate, for now use a rough estimate */ #define LP_CORE_CPU_FREQUENCY_HZ 16000000 +static uint32_t lp_wakeup_cause = 0; + +void ulp_lp_core_update_wakeup_cause(void) +{ + if ((REG_GET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN) & ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU) \ + && (pmu_ll_lp_get_interrupt_raw(&PMU) & PMU_HP_SW_TRIGGER_INT_RAW)) { + lp_wakeup_cause |= ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU; + pmu_ll_lp_clear_intsts_mask(&PMU, PMU_HP_SW_TRIGGER_INT_CLR); + } + + if ((REG_GET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN) & ULP_LP_CORE_WAKEUP_SOURCE_LP_UART) \ + && REG_GET_BIT(LP_UART_INT_RAW_REG, LP_UART_WAKEUP_INT_RAW)) { + lp_wakeup_cause |= ULP_LP_CORE_WAKEUP_SOURCE_LP_UART; + REG_SET_BIT(LP_UART_INT_CLR_REG, LP_UART_WAKEUP_INT_CLR); + } + + if ((REG_GET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN) & ULP_LP_CORE_WAKEUP_SOURCE_LP_IO) \ + && rtcio_ll_get_interrupt_status()) { + lp_wakeup_cause |= ULP_LP_CORE_WAKEUP_SOURCE_LP_IO; + rtcio_ll_clear_interrupt_status(); + } + + if ((REG_GET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN) & ULP_LP_CORE_WAKEUP_SOURCE_ETM) \ + && etm_ll_is_lpcore_wakeup_triggered()) { + lp_wakeup_cause |= ULP_LP_CORE_WAKEUP_SOURCE_ETM; + etm_ll_clear_lpcore_wakeup_status(); + } + + if ((REG_GET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN) & ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER) \ + && (lp_timer_ll_get_lp_intr_raw(&LP_TIMER) & LP_TIMER_MAIN_TIMER_LP_INT_RAW)) { + lp_wakeup_cause |= ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER; + lp_timer_ll_clear_lp_intsts_mask(&LP_TIMER, LP_TIMER_MAIN_TIMER_LP_INT_CLR); + } +} + +uint32_t ulp_lp_core_get_wakeup_cause() +{ + return lp_wakeup_cause; +} + /** * @brief Wakeup main CPU from sleep or deep sleep. *