diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 4abb2814c3..a2636af286 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -144,10 +144,7 @@ if(NOT BOOTLOADER_BUILD) if(CONFIG_IDF_TARGET_ESP32C61) # TODO: [ESP32C61] IDF-9245, IDF-9247, IDF-9248 list(REMOVE_ITEM srcs "sleep_cpu.c" - "sleep_modem.c" - "sleep_modes.c" "sleep_wake_stub.c" - "sleep_gpio.c" ) endif() else() diff --git a/components/esp_hw_support/port/esp32c61/CMakeLists.txt b/components/esp_hw_support/port/esp32c61/CMakeLists.txt index b368a3db17..45cdcebb73 100644 --- a/components/esp_hw_support/port/esp32c61/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c61/CMakeLists.txt @@ -20,7 +20,6 @@ endif() # TODO: [ESP32C61] IDF-9250 if(CONFIG_IDF_TARGET_ESP32C61) list(REMOVE_ITEM srcs - "pmu_sleep.c" "sar_periph_ctrl.c" ) endif() diff --git a/components/esp_hw_support/port/esp32c61/pmu_sleep.c b/components/esp_hw_support/port/esp32c61/pmu_sleep.c new file mode 100644 index 0000000000..cddc01697a --- /dev/null +++ b/components/esp_hw_support/port/esp32c61/pmu_sleep.c @@ -0,0 +1,313 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/pmu_struct.h" +#include "hal/lp_aon_hal.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_private/esp_pmu.h" +#include "pmu_param.h" + +#define HP(state) (PMU_MODE_HP_ ## state) +#define LP(state) (PMU_MODE_LP_ ## state) + + +static bool s_pmu_sleep_regdma_backup_enabled; + +void pmu_sleep_enable_regdma_backup(void) +{ + if(!s_pmu_sleep_regdma_backup_enabled){ + assert(PMU_instance()->hal); + /* entry 0, 1, 2 is used by pmu HP_SLEEP and HP_ACTIVE, HP_SLEEP + * and HP_MODEM or HP_MODEM and HP_ACTIVE states switching, + * respectively. entry 3 is reserved, not used yet! */ + pmu_hal_hp_set_sleep_active_backup_enable(PMU_instance()->hal); + pmu_hal_hp_set_sleep_modem_backup_enable(PMU_instance()->hal); + pmu_hal_hp_set_modem_active_backup_enable(PMU_instance()->hal); + s_pmu_sleep_regdma_backup_enabled = true; + } +} + +void pmu_sleep_disable_regdma_backup(void) +{ + if(s_pmu_sleep_regdma_backup_enabled){ + assert(PMU_instance()->hal); + pmu_hal_hp_set_sleep_active_backup_disable(PMU_instance()->hal); + pmu_hal_hp_set_sleep_modem_backup_disable(PMU_instance()->hal); + pmu_hal_hp_set_modem_active_backup_disable(PMU_instance()->hal); + s_pmu_sleep_regdma_backup_enabled = false; + } +} + +uint32_t pmu_sleep_calculate_hw_wait_time(uint32_t pd_flags, uint32_t slowclk_period, uint32_t fastclk_period) +{ + const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + + /* LP core hardware wait time, microsecond */ + const int lp_wakeup_wait_time_us = rtc_time_slowclk_to_us(mc->lp.wakeup_wait_cycle, slowclk_period); + const int lp_clk_switch_time_us = rtc_time_slowclk_to_us(mc->lp.clk_switch_cycle, slowclk_period); + const int lp_clk_power_on_wait_time_us = (pd_flags & PMU_SLEEP_PD_XTAL) ? mc->lp.xtal_wait_stable_time_us \ + : rtc_time_slowclk_to_us(mc->lp.clk_power_on_wait_cycle, slowclk_period); + const int lp_control_wait_time_us = mc->lp.isolate_wait_time_us + mc->lp.reset_wait_time_us; + + const int lp_hw_wait_time_us = mc->lp.min_slp_time_us + mc->lp.analog_wait_time_us + lp_clk_power_on_wait_time_us \ + + lp_wakeup_wait_time_us + lp_clk_switch_time_us + mc->lp.power_supply_wait_time_us \ + + mc->lp.power_up_wait_time_us + lp_control_wait_time_us; + + /* HP core hardware wait time, microsecond */ + const int hp_digital_power_up_wait_time_us = mc->hp.power_supply_wait_time_us + mc->hp.power_up_wait_time_us; + const int hp_control_wait_time_us = mc->hp.isolate_wait_time_us + mc->hp.reset_wait_time_us; + const int hp_regdma_wait_time_us = MAX(mc->hp.regdma_s2m_work_time_us + mc->hp.regdma_m2a_work_time_us, mc->hp.regdma_s2a_work_time_us); + const int hp_clock_wait_time_us = mc->hp.xtal_wait_stable_time_us + mc->hp.pll_wait_stable_time_us; + + const int hp_hw_wait_time_us = mc->hp.analog_wait_time_us + MAX(hp_clock_wait_time_us, \ + hp_digital_power_up_wait_time_us + hp_control_wait_time_us + hp_regdma_wait_time_us); + + /* When the SOC wakeup (lp timer or GPIO wakeup) and Modem wakeup (Beacon wakeup) complete, the soc + * wakeup will be delayed until the RF is turned on in Modem state. + * + * modem wakeup TBTT, RF on by HW + * | | + * \|/ \|/ + * PMU_HP_ACTIVE /------ + * PMU_HP_MODEM /------------////////////////// + * PMU_HP_SLEEP ----------------------////////////////// + * /|\ /|\ /|\ /|\ /|\ /|\ + * |<- some hw wait ->| | | |<- M2A switch ->| + * | slow cycles & | soc wakeup | | + * | FOSC cycles |<- S2M switch ->| | + * | | + * |<-- PMU guard time, also the maximum time for the SOC -->| + * | wake-up delay | + */ +#if SOC_PM_SUPPORT_PMU_MODEM_STATE && CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + const int rf_on_protect_time_us = mc->hp.regdma_rf_on_work_time_us; + const int total_hw_wait_time_us = lp_hw_wait_time_us + hp_hw_wait_time_us + mc->hp.clock_domain_sync_time_us; +#else + const int rf_on_protect_time_us = 0; + const int total_hw_wait_time_us = lp_hw_wait_time_us + hp_hw_wait_time_us; +#endif + return total_hw_wait_time_us + rf_on_protect_time_us; +} + +#define rtc_time_us_to_fastclk(time_us, period) rtc_time_us_to_slowclk((time_us), (period)) + +static inline pmu_sleep_param_config_t * pmu_sleep_param_config_default( + pmu_sleep_param_config_t *param, + pmu_sleep_power_config_t *power, /* We'll use the runtime power parameter to determine some hardware parameters */ + const uint32_t pd_flags, + const uint32_t adjustment, + const uint32_t slowclk_period, + const uint32_t fastclk_period + ) +{ + const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + + param->hp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->hp.min_slp_time_us, slowclk_period); + param->hp_sys.analog_wait_target_cycle = rtc_time_us_to_fastclk(mc->hp.analog_wait_time_us, fastclk_period); + param->hp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_supply_wait_time_us, fastclk_period); + param->hp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->hp.power_up_wait_time_us, fastclk_period); + param->hp_sys.pll_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.pll_wait_stable_time_us, fastclk_period); + param->hp_sys.isolate_wait_cycle = rtc_time_us_to_fastclk(mc->hp.isolate_wait_time_us, fastclk_period); + param->hp_sys.reset_wait_cycle = rtc_time_us_to_fastclk(mc->hp.reset_wait_time_us, fastclk_period); + + const int hw_wait_time_us = pmu_sleep_calculate_hw_wait_time(pd_flags, slowclk_period, fastclk_period); + const int modem_state_skip_time_us = mc->hp.regdma_m2a_work_time_us + mc->hp.system_dfs_up_work_time_us + mc->lp.min_slp_time_us; + const int modem_wakeup_wait_time_us = adjustment - hw_wait_time_us + modem_state_skip_time_us + mc->hp.regdma_rf_on_work_time_us; + param->hp_sys.modem_wakeup_wait_cycle = rtc_time_us_to_fastclk(modem_wakeup_wait_time_us, fastclk_period); + + param->lp_sys.min_slp_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.min_slp_time_us, slowclk_period); + param->lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(mc->lp.analog_wait_time_us, slowclk_period); + param->lp_sys.digital_power_supply_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_supply_wait_time_us, fastclk_period); + param->lp_sys.digital_power_up_wait_cycle = rtc_time_us_to_fastclk(mc->lp.power_up_wait_time_us, fastclk_period); + param->lp_sys.isolate_wait_cycle = rtc_time_us_to_fastclk(mc->lp.isolate_wait_time_us, fastclk_period); + param->lp_sys.reset_wait_cycle = rtc_time_us_to_fastclk(mc->lp.reset_wait_time_us, fastclk_period); + + if (power->hp_sys.xtal.xpd_xtal) { + param->hp_lp.xtal_stable_wait_slow_clk_cycle = rtc_time_us_to_slowclk(mc->lp.xtal_wait_stable_time_us, slowclk_period); + } else { + param->hp_lp.xtal_stable_wait_cycle = rtc_time_us_to_fastclk(mc->hp.xtal_wait_stable_time_us, fastclk_period); + } + return param; +} + +const pmu_sleep_config_t* pmu_sleep_config_default( + pmu_sleep_config_t *config, + uint32_t pd_flags, + uint32_t adjustment, + uint32_t slowclk_period, + uint32_t fastclk_period, + bool dslp + ) +{ + pmu_sleep_power_config_t power_default = PMU_SLEEP_POWER_CONFIG_DEFAULT(pd_flags); + + uint32_t iram_pd_flags = 0; + iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G0) ? BIT(0) : 0; + iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G1) ? BIT(1) : 0; + iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G2) ? BIT(2) : 0; + iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G3) ? BIT(3) : 0; + config->power = power_default; + + pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags); + config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period); + + if (dslp) { + config->param.lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US, slowclk_period); + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags); + config->analog = analog_default; + } else { + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags); + config->digital = digital_default; + + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags); + + if (!(pd_flags & PMU_SLEEP_PD_XTAL) || !(pd_flags & PMU_SLEEP_PD_RC_FAST)){ + analog_default.hp_sys.analog.pd_cur = PMU_PD_CUR_SLEEP_ON; + analog_default.hp_sys.analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; + analog_default.hp_sys.analog.dbias = HP_CALI_DBIAS_SLP_1V1; + analog_default.hp_sys.analog.dbg_atten = 0; + + analog_default.lp_sys[LP(SLEEP)].analog.pd_cur = PMU_PD_CUR_SLEEP_ON; + analog_default.lp_sys[LP(SLEEP)].analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; + analog_default.lp_sys[LP(SLEEP)].analog.dbias = LP_CALI_DBIAS_SLP_1V1; + analog_default.lp_sys[LP(SLEEP)].analog.dbg_atten = 0; + } + + config->analog = analog_default; + } + return config; +} + +static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_config_t *power, bool dslp) +{ + pmu_ll_hp_set_dig_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.dig_power.val); + pmu_ll_hp_set_clk_power(ctx->hal->dev, HP(SLEEP), power->hp_sys.clk_power.val); + pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, HP(SLEEP), power->hp_sys.xtal.xpd_xtal); + + pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].dig_power.val); + pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(ACTIVE), power->lp_sys[LP(ACTIVE)].clk_power.val); + + pmu_ll_lp_set_dig_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].dig_power.val); + pmu_ll_lp_set_clk_power(ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].clk_power.val); + pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, LP(SLEEP), power->lp_sys[LP(SLEEP)].xtal.xpd_xtal); +} + +static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig) +{ + pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); +} + +static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) +{ + assert(ctx->hal); + pmu_ll_hp_set_dbg_atten (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbg_atten); + pmu_ll_hp_set_current_power_off (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.pd_cur); + pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.bias_sleep); + pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd); + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias); + pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b); + + pmu_ll_lp_set_dbg_atten (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbg_atten); + pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur); + pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.bias_sleep); + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.slp_xpd); + pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.xpd); + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.slp_dbias); + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbias); + pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.drv_b); +} + +static void pmu_sleep_param_init(pmu_context_t *ctx, const pmu_sleep_param_config_t *param, bool dslp) +{ + assert(ctx->hal); + pmu_ll_hp_set_min_sleep_cycle(ctx->hal->dev, param->hp_sys.min_slp_slow_clk_cycle); + pmu_ll_lp_set_min_sleep_cycle(ctx->hal->dev, param->lp_sys.min_slp_slow_clk_cycle); + + pmu_ll_hp_set_analog_wait_target_cycle(ctx->hal->dev, param->hp_sys.analog_wait_target_cycle); + pmu_ll_lp_set_analog_wait_target_cycle(ctx->hal->dev, param->lp_sys.analog_wait_target_cycle); + + pmu_hal_hp_set_digital_power_up_wait_cycle(ctx->hal, param->hp_sys.digital_power_supply_wait_cycle, param->hp_sys.digital_power_up_wait_cycle); + pmu_hal_lp_set_digital_power_up_wait_cycle(ctx->hal, param->lp_sys.digital_power_supply_wait_cycle, param->lp_sys.digital_power_up_wait_cycle); + + pmu_hal_hp_set_control_ready_wait_cycle(ctx->hal, param->hp_sys.isolate_wait_cycle, param->hp_sys.reset_wait_cycle); + pmu_hal_lp_set_control_ready_wait_cycle(ctx->hal, param->lp_sys.isolate_wait_cycle, param->lp_sys.reset_wait_cycle); + + pmu_ll_set_modem_wait_target_cycle(ctx->hal->dev, param->hp_sys.modem_wakeup_wait_cycle); + pmu_ll_set_xtal_stable_wait_cycle(ctx->hal->dev, param->hp_lp.xtal_stable_wait_slow_clk_cycle); + pmu_ll_set_pll_stable_wait_cycle(ctx->hal->dev, param->hp_sys.pll_stable_wait_cycle); +} + +bool pmu_sleep_pll_already_enabled(void) +{ + return (pmu_ll_get_sysclk_sleep_select_state(PMU_instance()->hal->dev) != 0); +} + +void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) +{ + assert(PMU_instance()); + pmu_sleep_power_init(PMU_instance(), &config->power, dslp); + if(!dslp){ + pmu_sleep_digital_init(PMU_instance(), &config->digital); + } + pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); + pmu_sleep_param_init(PMU_instance(), &config->param, dslp); +} + +uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) +{ + assert(PMU_instance()->hal); + + lp_aon_hal_inform_wakeup_type(dslp); + + pmu_ll_hp_set_wakeup_enable(PMU_instance()->hal->dev, wakeup_opt); + pmu_ll_hp_set_reject_enable(PMU_instance()->hal->dev, reject_opt); + + pmu_ll_hp_clear_wakeup_intr_status(PMU_instance()->hal->dev); + pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev); + pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev); + + /* Start entry into sleep mode */ + pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev); + + /* In pd_cpu lightsleep and deepsleep mode, we never get here */ + while (!pmu_ll_hp_is_sleep_wakeup(PMU_instance()->hal->dev) && + !pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { + ; + } + + return pmu_sleep_finish(dslp); +} + +bool pmu_sleep_finish(bool dslp) +{ + (void)dslp; + + // Wait eFuse memory update done. + while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); + + return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); +} + +void pmu_sleep_enable_hp_sleep_sysclk(bool enable) +{ + pmu_ll_hp_set_icg_sysclk_enable(PMU_instance()->hal->dev, HP(SLEEP), enable); +} + +uint32_t pmu_sleep_get_wakup_retention_cost(void) +{ + const pmu_sleep_machine_constant_t *mc = (pmu_sleep_machine_constant_t *)PMU_instance()->mc; + return mc->hp.regdma_s2a_work_time_us; +} diff --git a/components/esp_hw_support/port/esp32c61/rtc_time.c b/components/esp_hw_support/port/esp32c61/rtc_time.c index 37c3637fb6..900e5fe3b5 100644 --- a/components/esp_hw_support/port/esp32c61/rtc_time.c +++ b/components/esp_hw_support/port/esp32c61/rtc_time.c @@ -185,9 +185,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - // return lp_timer_hal_get_cycle_count(); - ESP_EARLY_LOGW(TAG, "rtc_timer has not been implemented yet"); // TODO: IDF-9244 - return 0; + return lp_timer_hal_get_cycle_count(); } uint32_t rtc_clk_freq_cal(uint32_t cal_val) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index d49c1920c8..45d0cf68ec 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -96,6 +96,9 @@ #elif CONFIG_IDF_TARGET_ESP32C5 #include "esp32c5/rom/rtc.h" #include "hal/gpio_ll.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rom/rtc.h" +#include "hal/gpio_ll.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" #include "esp32h2/rom/cache.h" @@ -152,6 +155,9 @@ #elif CONFIG_IDF_TARGET_ESP32C5 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) +#elif CONFIG_IDF_TARGET_ESP32C61 +#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) +#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) #elif CONFIG_IDF_TARGET_ESP32H2 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) @@ -196,7 +202,7 @@ #define MAX_DSLP_HOOKS 3 static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS] = {0}; -#if CONFIG_ESP_PHY_ENABLED +#if CONFIG_ESP_PHY_ENABLED && SOC_DEEP_SLEEP_SUPPORTED static esp_deep_sleep_cb_t s_dslp_phy_cb[MAX_DSLP_HOOKS] = {0}; #endif @@ -247,7 +253,9 @@ void esp_sleep_set_sleep_context(esp_sleep_context_t *sleep_ctx) static uint32_t s_lightsleep_cnt = 0; +#if SOC_RTCIO_PIN_COUNT > 0 _Static_assert(22 >= SOC_RTCIO_PIN_COUNT, "Chip has more RTCIOs than 22, should increase ext1_rtc_gpio_mask field size"); +#endif static sleep_config_t s_config = { .domain = { @@ -676,7 +684,7 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(uint32_t pd_flags, bool deep_s #endif } -#if !CONFIG_IDF_TARGET_ESP32P4 +#if !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C61 // TODO: IDF-7370 if (!(deep_sleep && s_adc_tsen_enabled)){ sar_periph_ctrl_power_disable(); @@ -703,7 +711,9 @@ FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t pd_flags) #if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP sleep_console_usj_pad_restore(); #endif +#if !CONFIG_IDF_TARGET_ESP32C61 sar_periph_ctrl_power_enable(); +#endif #if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_RTCCNTL sleep_disable_cpu_retention(); #endif @@ -789,7 +799,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m should_skip_sleep = light_sleep_uart_prepare(pd_flags, sleep_duration); } -#if CONFIG_ESP_PHY_ENABLED +#if CONFIG_ESP_PHY_ENABLED && SOC_DEEP_SLEEP_SUPPORTED // Do deep-sleep PHY related callback, which need to be executed when the PLL clock is exists. // For light-sleep, PHY state is managed by the upper layer of the wifi/bt protocol stack. if (deep_sleep) { @@ -1765,7 +1775,7 @@ static void ext0_wakeup_prepare(void) #endif // SOC_PM_SUPPORT_EXT0_WAKEUP -#if SOC_PM_SUPPORT_EXT1_WAKEUP +#if SOC_PM_SUPPORT_EXT1_WAKEUP && SOC_RTCIO_PIN_COUNT > 0 esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode) { if (io_mask == 0 && level_mode > ESP_EXT1_WAKEUP_ANY_HIGH) { @@ -1945,7 +1955,7 @@ uint64_t esp_sleep_get_ext1_wakeup_status(void) return gpio_mask; } -#endif // SOC_PM_SUPPORT_EXT1_WAKEUP +#endif // SOC_PM_SUPPORT_EXT1_WAKEUP && SOC_RTCIO_PIN_COUNT > 0 #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && SOC_DEEP_SLEEP_SUPPORTED uint64_t esp_sleep_get_gpio_wakeup_status(void) diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index e56c1d1e50..bb690e7c15 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -63,14 +63,12 @@ static const char* TAG = "phy_init"; static _lock_t s_phy_access_lock; #if SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD -#if !SOC_PMU_SUPPORTED -#if !(CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61) // TODO: [ESP32C5] IDF-8667 +#if SOC_PM_MODEM_PD_BY_SW static DRAM_ATTR struct { int count; /* power on count of wifi and bt power domain */ _lock_t lock; } s_wifi_bt_pd_controller = { .count = 0 }; -#endif -#endif // !SOC_PMU_SUPPORTED +#endif // SOC_PM_MODEM_PD_BY_SW #endif // SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD #if CONFIG_IDF_TARGET_ESP32 @@ -339,8 +337,7 @@ void esp_phy_disable(esp_phy_modem_t modem) void IRAM_ATTR esp_wifi_bt_power_domain_on(void) { #if SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD -#if !SOC_PMU_SUPPORTED -#if !(CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61) // TODO: [ESP32C5] IDF-8667 +#if SOC_PM_MODEM_PD_BY_SW _lock_acquire(&s_wifi_bt_pd_controller.lock); if (s_wifi_bt_pd_controller.count++ == 0) { CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_WIFI_FORCE_PD); @@ -358,24 +355,21 @@ void IRAM_ATTR esp_wifi_bt_power_domain_on(void) wifi_bt_common_module_disable(); } _lock_release(&s_wifi_bt_pd_controller.lock); -#endif -#endif // !SOC_PMU_SUPPORTED +#endif // SOC_PM_MODEM_PD_BY_SW #endif // SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD } void esp_wifi_bt_power_domain_off(void) { #if SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD -#if !SOC_PMU_SUPPORTED -#if !(CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61) // TODO: [ESP32C5] IDF-8667 +#if SOC_PM_MODEM_PD_BY_SW _lock_acquire(&s_wifi_bt_pd_controller.lock); if (--s_wifi_bt_pd_controller.count == 0) { SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_WIFI_FORCE_ISO); SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_WIFI_FORCE_PD); } _lock_release(&s_wifi_bt_pd_controller.lock); -#endif -#endif // !SOC_PMU_SUPPORTED +#endif // SOC_PM_MODEM_PD_BY_SW #endif // SOC_PM_SUPPORT_MODEM_PD || SOC_PM_SUPPORT_WIFI_PD } diff --git a/components/esp_rom/esp32c61/include/esp32c61/rom/rtc.h b/components/esp_rom/esp32c61/include/esp32c61/rom/rtc.h index c9c6663ba2..2f88538f45 100644 --- a/components/esp_rom/esp32c61/include/esp32c61/rom/rtc.h +++ b/components/esp_rom/esp32c61/include/esp32c61/rom/rtc.h @@ -64,8 +64,8 @@ extern "C" { #define RTC_ENTRY_ADDR_REG LP_AON_STORE6_REG #define RTC_RESET_CAUSE_REG LP_AON_STORE6_REG #define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG -#define LIGHT_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG -#define SLEEP_MODE_REG LP_AON_STORE9_REG +#define RTC_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG +#define RTC_SLEEP_MODE_REG LP_AON_STORE8_REG #define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code. diff --git a/components/hal/esp32c61/include/hal/efuse_ll.h b/components/hal/esp32c61/include/hal/efuse_ll.h index c219dc2999..a210647861 100644 --- a/components/hal/esp32c61/include/hal/efuse_ll.h +++ b/components/hal/esp32c61/include/hal/efuse_ll.h @@ -18,6 +18,15 @@ extern "C" { #endif +typedef enum { + EFUSE_CONTROLLER_STATE_RESET = 0, ///< efuse_controllerid is on reset state. + EFUSE_CONTROLLER_STATE_IDLE = 1, ///< efuse_controllerid is on idle state. + EFUSE_CONTROLLER_STATE_READ_INIT = 2, ///< efuse_controllerid is on read init state. + EFUSE_CONTROLLER_STATE_READ_BLK0 = 3, ///< efuse_controllerid is on reading block0 state. + EFUSE_CONTROLLER_STATE_BLK0_CRC_CHECK = 4, ///< efuse_controllerid is on checking block0 crc state. + EFUSE_CONTROLLER_STATE_READ_RS_BLK = 5, ///< efuse_controllerid is on reading RS block state. +} efuse_controller_state_t; + // Always inline these functions even no gcc optimization is applied. /******************* eFuse fields *************************/ @@ -153,6 +162,10 @@ __attribute__((always_inline)) static inline void efuse_ll_rs_bypass_update(void } /******************* eFuse control functions *************************/ +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_controller_state(void) +{ + return EFUSE0.status.state; +} #ifdef __cplusplus } diff --git a/components/hal/esp32c61/include/hal/lp_aon_hal.h b/components/hal/esp32c61/include/hal/lp_aon_hal.h new file mode 100644 index 0000000000..2090a64928 --- /dev/null +++ b/components/hal/esp32c61/include/hal/lp_aon_hal.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "hal/lp_aon_ll.h" + +#define rtc_hal_ext1_get_wakeup_status() lp_aon_ll_ext1_get_wakeup_status() +#define rtc_hal_ext1_clear_wakeup_status() lp_aon_ll_ext1_clear_wakeup_status() +#define rtc_hal_ext1_set_wakeup_pins(io_mask, mode_mask) lp_aon_ll_ext1_set_wakeup_pins(io_mask, mode_mask) +#define rtc_hal_ext1_clear_wakeup_pins() lp_aon_ll_ext1_clear_wakeup_pins() +#define rtc_hal_ext1_get_wakeup_pins() lp_aon_ll_ext1_get_wakeup_pins() + +#define lp_aon_hal_inform_wakeup_type(dslp) lp_aon_ll_inform_wakeup_type(dslp) diff --git a/components/hal/esp32c61/include/hal/lp_aon_ll.h b/components/hal/esp32c61/include/hal/lp_aon_ll.h new file mode 100644 index 0000000000..fea02e9da2 --- /dev/null +++ b/components/hal/esp32c61/include/hal/lp_aon_ll.h @@ -0,0 +1,114 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for ESP32-C61 LP_AON register operations + +#pragma once + +#include +#include "soc/soc.h" +#include "soc/lp_aon_struct.h" +#include "hal/misc.h" +#include "esp32c61/rom/rtc.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get ext1 wakeup source status + * @return The lower 8 bits of the returned value are the bitmap of + * the wakeup source status, bit 0~7 corresponds to LP_IO 0~7 + */ +static inline uint32_t lp_aon_ll_ext1_get_wakeup_status(void) +{ + return HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_status); +} + +/** + * @brief Clear the ext1 wakeup source status + */ +static inline void lp_aon_ll_ext1_clear_wakeup_status(void) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_status_clr, 1); +} + +/** + * @brief Set the wake-up LP_IO of the ext1 wake-up source + * @param io_mask wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7 + * @param level_mask LP_IO wakeup level bitmap, bit 0~7 corresponds to LP_IO 0~7 wakeup level + * each bit's corresponding position is set to 0, the wakeup level will be low + * on the contrary, each bit's corresponding position is set to 1, the wakeup + * level will be high + */ +static inline void lp_aon_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t level_mask) +{ + uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel); + wakeup_sel_mask |= io_mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel, wakeup_sel_mask); + + uint32_t wakeup_level_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv); + wakeup_level_mask |= io_mask & level_mask; + wakeup_level_mask &= ~(io_mask & ~level_mask); + + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv, wakeup_level_mask); +} + +/** + * @brief Clear all ext1 wakup-source setting + */ +static inline void lp_aon_ll_ext1_clear_wakeup_pins(void) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel, 0); +} + +/** + * @brief Get ext1 wakeup source setting + * @return The lower 8 bits of the returned value are the bitmap of + * the wakeup source status, bit 0~7 corresponds to LP_IO 0~7 + */ +static inline uint32_t lp_aon_ll_ext1_get_wakeup_pins(void) +{ + return HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel); +} + + +/** + * @brief ROM obtains the wake-up type through LP_AON_STORE9_REG[0]. + * Set the flag to inform + * @param true: deepsleep false: lightsleep + */ +static inline void lp_aon_ll_inform_wakeup_type(bool dslp) +{ + if (dslp) { + REG_SET_BIT(RTC_SLEEP_MODE_REG, BIT(0)); /* Tell rom to run deep sleep wake stub */ + + } else { + REG_CLR_BIT(RTC_SLEEP_MODE_REG, BIT(0)); /* Tell rom to run light sleep wake stub */ + } +} + +/** + * @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/esp32c61/include/hal/lp_timer_ll.h b/components/hal/esp32c61/include/hal/lp_timer_ll.h new file mode 100644 index 0000000000..1817542336 --- /dev/null +++ b/components/hal/esp32c61/include/hal/lp_timer_ll.h @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for ESP32-C61 LP_Timer register operations + +#pragma once + +#include +#include +#include "soc/soc.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 "hal/misc.h" +#include "esp_attr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, main_timer_tar_high0, (value >> 32) & 0xFFFF); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].lo, main_timer_tar_low0, value & 0xFFFFFFFF); +} + +FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en) +{ + dev->target[timer_id].hi.main_timer_tar_en0 = en; +} + +FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t buffer_id) +{ + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].lo, main_timer_buf0_low); +} + +FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t buffer_id) +{ + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].hi, main_timer_buf0_high); +} + +FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev) +{ + dev->update.main_timer_update = 1; +} + +FORCE_INLINE_ATTR void lp_timer_ll_clear_alarm_intr_status(lp_timer_dev_t *dev) +{ + dev->int_clr.soc_wakeup_int_clr = 1; +} + +FORCE_INLINE_ATTR void lp_timer_ll_clear_overflow_intr_status(lp_timer_dev_t *dev) +{ + dev->int_clr.overflow_clr = 1; +} + +FORCE_INLINE_ATTR void lp_timer_ll_clear_lp_alarm_intr_status(lp_timer_dev_t *dev) +{ + 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; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32c61/include/hal/pmu_hal.h b/components/hal/esp32c61/include/hal/pmu_hal.h index 924695a681..89237b8ffb 100644 --- a/components/hal/esp32c61/include/hal/pmu_hal.h +++ b/components/hal/esp32c61/include/hal/pmu_hal.h @@ -16,8 +16,6 @@ extern "C" { #include "hal/pmu_ll.h" #include "hal/pmu_types.h" -// TODO: [ESP32C61] IDF-9250, inherit from c6 - typedef struct { pmu_dev_t *dev; } pmu_hal_context_t; @@ -30,6 +28,10 @@ void pmu_hal_lp_set_digital_power_up_wait_cycle(pmu_hal_context_t *hal, uint32_t uint32_t pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal); +void pmu_hal_hp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle); + +void pmu_hal_lp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle); + void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal); void pmu_hal_hp_set_sleep_active_backup_disable(pmu_hal_context_t *hal); diff --git a/components/hal/esp32c61/include/hal/pmu_ll.h b/components/hal/esp32c61/include/hal/pmu_ll.h index b346121407..70864dcb0f 100644 --- a/components/hal/esp32c61/include/hal/pmu_ll.h +++ b/components/hal/esp32c61/include/hal/pmu_ll.h @@ -17,8 +17,6 @@ #include "hal/pmu_types.h" #include "hal/misc.h" -// TODO: [ESP32C61] IDF-9250 -#pragma message "pmu_ll.h has not been fully updated on ESP32C61 (IDF-9250). Use with care!" #ifdef __cplusplus extern "C" { diff --git a/components/hal/esp32c61/pmu_hal.c b/components/hal/esp32c61/pmu_hal.c index 2b86d72e58..508d66faaa 100644 --- a/components/hal/esp32c61/pmu_hal.c +++ b/components/hal/esp32c61/pmu_hal.c @@ -37,6 +37,18 @@ uint32_t pmu_hal_lp_get_digital_power_up_wait_cycle(pmu_hal_context_t *hal) return power_supply_wait_cycle + power_up_wait_cycle; } +void pmu_hal_hp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle) +{ + pmu_ll_hp_set_isolate_wait_cycle(hal->dev, isolate_wait_cycle); + pmu_ll_hp_set_reset_wait_cycle(hal->dev, reset_wait_cycle); +} + +void pmu_hal_lp_set_control_ready_wait_cycle(pmu_hal_context_t *hal, uint32_t isolate_wait_cycle, uint32_t reset_wait_cycle) +{ + pmu_ll_lp_set_isolate_wait_cycle(hal->dev, isolate_wait_cycle); + pmu_ll_lp_set_reset_wait_cycle(hal->dev, reset_wait_cycle); +} + void pmu_hal_hp_set_sleep_active_backup_enable(pmu_hal_context_t *hal) { pmu_ll_hp_set_active_to_sleep_backup_enable(hal->dev); diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 54613e95c7..f6f4b25e22 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -871,6 +871,10 @@ config SOC_CONFIGURABLE_VDDSDIO_SUPPORTED bool default y +config SOC_PM_MODEM_PD_BY_SW + bool + default y + config SOC_CLK_APLL_SUPPORTED bool default y diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 7a4c7e0211..bb35d3718a 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -415,7 +415,7 @@ #define SOC_PM_SUPPORT_MODEM_PD (1) /*!