diff --git a/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h index 8acb981c5b1..d1e7a791b4c 100644 --- a/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32s31/include/hal/clk_gate_ll.h @@ -325,6 +325,16 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_160m_clk_en(bool enable) { HP_SYS_CLKRST.ref_160m_ctrl0.reg_ref_160m_clk_en = enable; } + +/** + * Check if the clock gate for ref_160m is enabled + * @return true if enabled, false otherwise + */ +FORCE_INLINE_ATTR bool clk_gate_ll_ref_160m_clk_is_enabled(void) +{ + return HP_SYS_CLKRST.ref_160m_ctrl0.reg_ref_160m_clk_en; +} + /// 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_160m_clk_en(...) do { \ @@ -332,6 +342,39 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_160m_clk_en(bool enable) _clk_gate_ll_ref_160m_clk_en(__VA_ARGS__); \ } while(0) +/** + * Check if the clock gate for modem PLL is enabled + * @return true if enabled, false otherwise + */ +FORCE_INLINE_ATTR bool clk_gate_ll_modem_pll_clk_is_enabled(void) +{ + return HP_SYS_CLKRST.modem_conf.modem_pll_clk_en; +} + +/** + * Check if the clock gate for modem clock source is PLL + * @return true if PLL, false otherwise + */ +FORCE_INLINE_ATTR bool clk_gate_ll_modem_clk_source_is_pll(void) +{ + return HP_SYS_CLKRST.modem_conf.modem_clk_source_sel; +} + +/** + * Enable or disable the clock gate for modem PLL source + * @param enable Enable / disable + */ +FORCE_INLINE_ATTR void _clk_gate_ll_modem_pll_source_cg_en(bool enable) +{ + if (enable) { + HP_SYS_CLKRST.modem_conf.val = 0x15; + HP_SYS_CLKRST.modem_conf.val = 0x1d; + } else { + HP_SYS_CLKRST.modem_conf.val = 0x2d; + HP_SYS_CLKRST.modem_conf.val = 0x25; + } +} + /** * Enable or disable the clock gate for ref_240m (derived from BBPLL). * @param enable Enable / disable diff --git a/components/esp_hw_support/lowpower/port/esp32s31/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32s31/sleep_clock.c index 324fec15684..13c8c753411 100644 --- a/components/esp_hw_support/lowpower/port/esp32s31/sleep_clock.c +++ b/components/esp_hw_support/lowpower/port/esp32s31/sleep_clock.c @@ -74,7 +74,7 @@ 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_MODEM_INTR_STATUS_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) const static sleep_retention_entries_config_t modem_regs_retention[] = { - /* !!! pll_source_regs_retention link above does not above guarantee that the PMU has released the clock gate for the PLL. + /* !!! pll_source_regs_retention link above does not guarantee that the PMU has released the clock gate for the PLL. * And due to hardware limitations, REGDMA is also unable to obtain the PMU's PLL gate status when the chip is in PD_TOP mode. * So WORKAROUND with issue a dummy write to MODEM_SYSCON_DATE_REG as the first REGDMA node to avoid an APB access timeout * during the subsequent REGDMA operations. */ @@ -82,7 +82,8 @@ esp_err_t sleep_clock_modem_retention_init(void *arg) [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(1), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ [2] = { .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 SYSCON */ [3] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_CLOCK_ICG_LINK(0), HP_SYS_CLKRST_REF_160M_CTRL0_REG, HP_SYS_CLKRST_REG_REF_160M_CLK_EN, HP_SYS_CLKRST_REG_REF_160M_CLK_EN_M, 1, 0), .owner = ENTRY(1)}, - [4] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_CLOCK_ICG_LINK(1), HP_SYS_CLKRST_MODEM_CONF_REG, 0x3d, 0x3d, 1, 0), .owner = ENTRY(1)}, + [4] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_CLOCK_ICG_LINK(1), HP_SYS_CLKRST_MODEM_CONF_REG, 0x15, 0xff, 1, 0), .owner = ENTRY(1)}, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_CLOCK_ICG_LINK(2), HP_SYS_CLKRST_MODEM_CONF_REG, 0x1d, 0xff, 1, 0), .owner = ENTRY(1)}, }; 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); diff --git a/components/esp_hw_support/port/esp32s31/pmu_sleep.c b/components/esp_hw_support/port/esp32s31/pmu_sleep.c index ce3a73e0379..31481ba649c 100644 --- a/components/esp_hw_support/port/esp32s31/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32s31/pmu_sleep.c @@ -14,11 +14,11 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/pmu_struct.h" -#include "soc/hp_sys_clkrst_struct.h" #include "esp_private/esp_pmu.h" #include "esp_private/esp_clk_tree_common.h" #include "esp_private/sleep_clock_icg.h" #include "pmu_param.h" +#include "hal/clk_gate_ll.h" #include "hal/clk_tree_hal.h" #include "hal/clk_tree_ll.h" #include "hal/lp_aon_hal.h" @@ -402,9 +402,25 @@ bool pmu_sleep_finish(bool dslp) esp_psram_impl_exit_halfsleep_mode(); #endif #endif - /* PLL_SOURCE retention may leave BBPLL powered on; align HW to clk_tree ref. */ - if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL) && !HP_SYS_CLKRST.modem_conf.modem_pll_clk_en) { - clk_ll_bbpll_disable(); + const bool modem_pll_clk_enabled = clk_gate_ll_modem_pll_clk_is_enabled(); + assert(modem_pll_clk_enabled == clk_gate_ll_modem_clk_source_is_pll()); + if (!modem_pll_clk_enabled) { // wake up from non-modem clock retention + /* Workaround for issue WIFI-7620 + * The BA bitmap and start sequence number are updated in the read-only + * registers only after the PLL clock is available. */ + bool ref_160_enabled = clk_gate_ll_ref_160m_clk_is_enabled(); + if (!ref_160_enabled) { + _clk_gate_ll_ref_160m_clk_en(true); + } + _clk_gate_ll_modem_pll_source_cg_en(true); + _clk_gate_ll_modem_pll_source_cg_en(false); + if (!ref_160_enabled) { + _clk_gate_ll_ref_160m_clk_en(false); + } + + if (!esp_clk_tree_is_power_on(SOC_ROOT_CIRCUIT_CLK_BBPLL)) { // clear align HW to clk_tree ref + clk_ll_bbpll_disable(); + } } } diff --git a/components/hal/esp32s31/modem_clock_hal.c b/components/hal/esp32s31/modem_clock_hal.c index 6a69cadd4b5..55db550ac80 100644 --- a/components/hal/esp32s31/modem_clock_hal.c +++ b/components/hal/esp32s31/modem_clock_hal.c @@ -120,13 +120,19 @@ uint32_t IRAM_ATTR modem_clock_hal_get_clock_domain_icg_bitmap(modem_clock_hal_c void IRAM_ATTR modem_clock_hal_enable_soc_pll_source_cg(modem_clock_hal_context_t *hal, bool enable) { (void)hal; - HP_SYS_CLKRST.modem_conf.val = enable ? 0x3d : 0x25; + if (enable) { + HP_SYS_CLKRST.modem_conf.val = 0x15; + HP_SYS_CLKRST.modem_conf.val = 0x1d; + } else { + HP_SYS_CLKRST.modem_conf.val = 0x2d; + HP_SYS_CLKRST.modem_conf.val = 0x25; + } } bool IRAM_ATTR modem_clock_hal_soc_pll_source_cg_is_enabled(modem_clock_hal_context_t *hal) { (void)hal; - return (HP_SYS_CLKRST.modem_conf.val == 0x3d); + return (HP_SYS_CLKRST.modem_conf.val == 0x1d); } void IRAM_ATTR modem_clock_hal_enable_modem_common_fe_clock(modem_clock_hal_context_t *hal, bool enable)