diff --git a/components/hal/esp32c6/include/hal/etm_ll.h b/components/hal/esp32c6/include/hal/etm_ll.h index 22bc835177..a40dd68b12 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" #include "soc/pcr_struct.h" @@ -112,6 +113,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 93dc73a9f7..c212d33b9a 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_core_ll.h b/components/hal/esp32c6/include/hal/lp_core_ll.h index 36ac25ba11..c79830f5f0 100644 --- a/components/hal/esp32c6/include/hal/lp_core_ll.h +++ b/components/hal/esp32c6/include/hal/lp_core_ll.h @@ -109,6 +109,14 @@ static inline void lp_core_ll_set_wakeup_source(uint32_t flags) PMU.lp_ext.pwr1.wakeup_en = flags; } +/** + * @brief Get wake-up sources for the LP-core + */ +static inline uint32_t lp_core_ll_get_wakeup_source(void) +{ + return PMU.lp_ext.pwr1.wakeup_en; +} + #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 a99349240b..d04bccb559 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 15f39d10e4..2470f73247 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/hal/esp32p4/include/hal/etm_ll.h b/components/hal/esp32p4/include/hal/etm_ll.h index fa1dcae8c1..6904d170ac 100644 --- a/components/hal/esp32p4/include/hal/etm_ll.h +++ b/components/hal/esp32p4/include/hal/etm_ll.h @@ -121,6 +121,24 @@ 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; } +/** + * @brief Get the flag that marks whether LP CPU is awakened by ETM + * + * @return Return true if lpcore is woken up by soc etm flag + */ +static inline bool etm_ll_is_lpcore_wakeup_triggered(void) +{ + return SOC_ETM.task_st5.ulp_task_wakeup_cpu_st; +} + +/** + * @brief Clear the flag that marks whether LP CPU is awakened by ETM + */ +static inline void etm_ll_clear_lpcore_wakeup_status(void) +{ + SOC_ETM.task_st5_clr.ulp_task_wakeup_cpu_st_clr = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/lp_core_ll.h b/components/hal/esp32p4/include/hal/lp_core_ll.h index ed9ecdb3e5..73274fda12 100644 --- a/components/hal/esp32p4/include/hal/lp_core_ll.h +++ b/components/hal/esp32p4/include/hal/lp_core_ll.h @@ -111,6 +111,13 @@ static inline void lp_core_ll_set_wakeup_source(uint32_t flags) PMU.lp_cpu_pwr2.lp_cpu_wakeup_en = flags; } +/** + * @brief Get wake-up sources for the LP-core + */ +static inline uint32_t lp_core_ll_get_wakeup_source(void) +{ + return PMU.lp_cpu_pwr2.lp_cpu_wakeup_en; +} /** * @brief Set boot address for lp core diff --git a/components/hal/esp32p4/include/hal/lp_timer_ll.h b/components/hal/esp32p4/include/hal/lp_timer_ll.h index 75016c6282..81aecb30d1 100644 --- a/components/hal/esp32p4/include/hal/lp_timer_ll.h +++ b/components/hal/esp32p4/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_system_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.main_timer_lp_int_clr = 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_SYSTEM_REG_LP_STORE1_REG); diff --git a/components/hal/esp32p4/include/hal/pmu_ll.h b/components/hal/esp32p4/include/hal/pmu_ll.h new file mode 100644 index 0000000000..1b898aee31 --- /dev/null +++ b/components/hal/esp32p4/include/hal/pmu_ll.h @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for ESP32-C6 PMU register operations + +#pragma once + +#include +#include +#include "soc/soc.h" +#include "esp_attr.h" +#include "hal/assert.h" +#include "soc/pmu_struct.h" +#include "hal/pmu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_interrupt_raw(pmu_dev_t *hw) +{ + return hw->lp_int_raw.val; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) +{ + hw->lp_int_raw.val = mask; +} + +#ifdef __cplusplus +} +#endif 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 0078839731..bee3d6c574 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 @@ -13,6 +13,19 @@ extern "C" { #include #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 e094848e5a..a5cf8855b9 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 90d9c7f62f..5ed302ba31 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -9,6 +9,13 @@ #include "riscv/csr.h" #include "soc/soc.h" #include "soc/pmu_reg.h" +#include "hal/misc.h" +#include "hal/lp_core_ll.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 */ #if CONFIG_IDF_TARGET_ESP32C6 @@ -17,6 +24,46 @@ #define LP_CORE_CPU_FREQUENCY_HZ 20000000 #endif +static uint32_t lp_wakeup_cause = 0; + +void ulp_lp_core_update_wakeup_cause(void) +{ + if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_HP_CPU) \ + && (pmu_ll_lp_get_interrupt_raw(&PMU) & PMU_HP_SW_TRIGGER_INT_RAW)) { + lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_HP_CPU; + pmu_ll_lp_clear_intsts_mask(&PMU, PMU_HP_SW_TRIGGER_INT_CLR); + } + + if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_LP_UART) \ + && (uart_ll_get_intraw_mask(&LP_UART) & LP_UART_WAKEUP_INT_RAW)) { + lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_LP_UART; + uart_ll_clr_intsts_mask(&LP_UART, LP_UART_WAKEUP_INT_CLR); + } + + if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_LP_IO) \ + && rtcio_ll_get_interrupt_status()) { + lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_LP_IO; + rtcio_ll_clear_interrupt_status(); + } + + if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_ETM) \ + && etm_ll_is_lpcore_wakeup_triggered()) { + lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_ETM; + etm_ll_clear_lpcore_wakeup_status(); + } + + if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER) \ + && (lp_timer_ll_get_lp_intr_raw(&LP_TIMER) & LP_TIMER_MAIN_TIMER_LP_INT_RAW)) { + lp_wakeup_cause |= LP_CORE_LL_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. *