From 0b7f047e9e927357efe1936c5b467ddafd92b48a Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 27 May 2026 14:18:21 +0800 Subject: [PATCH] fix(driver): fix drivers clock management --- .../dvp/src/esp_cam_ctlr_dvp_cam.c | 16 ++++++++++++++++ .../gptimer/main/test_gptimer_sleep.c | 10 ++++++++-- components/esp_hw_support/etm/esp_etm.c | 18 +++++++++++++++++- .../modem/port/esp32s31/modem_clock_impl.c | 8 ++++++++ .../esp_hw_support/port/esp32s31/rtc_time.c | 3 +++ components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 16 ++++++++++++++++ components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 14 ++++++++++++++ 7 files changed, 82 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index a64df57d63e..2b2bcd5735e 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -66,6 +66,7 @@ typedef struct dvp_platform { static dvp_platform_t s_platform; static const char *TAG = "dvp_cam"; +static soc_module_clk_t s_dvp_clk_src[CAP_DVP_PERIPH_NUM]; /** * @brief Claim DVP controller @@ -346,6 +347,11 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e esp_rom_gpio_connect_out_signal(pin->xclk_io, cam_periph_signals.buses[ctlr_id].clk_sig, false, false); } +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true)); +#endif + PERIPH_RCC_ACQUIRE_ATOMIC(cam_periph_signals.buses[ctlr_id].module, ref_count) { if (ref_count == 0) { cam_ll_enable_bus_clock(ctlr_id, true); @@ -354,6 +360,7 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e } ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true)); + s_dvp_clk_src[ctlr_id] = (soc_module_clk_t)clk_src; PERIPH_RCC_ATOMIC() { cam_ll_enable_clk(ctlr_id, true); cam_ll_select_clk_src(ctlr_id, clk_src); @@ -458,6 +465,15 @@ esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id) } } + if (s_dvp_clk_src[ctlr_id]) { + esp_clk_tree_enable_src(s_dvp_clk_src[ctlr_id], false); + s_dvp_clk_src[ctlr_id] = 0; + } + +#if CONFIG_IDF_TARGET_ESP32S31 + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); +#endif + return ESP_OK; } diff --git a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c index 49f7637cb1c..788ef809946 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c +++ b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,7 +18,13 @@ #include "esp_private/esp_sleep_internal.h" #include "esp_private/esp_pmu.h" -static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +#if CONFIG_GPTIMER_ISR_CACHE_SAFE +#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR +#else +#define TEST_ALARM_CALLBACK_ATTR +#endif // CONFIG_GPTIMER_ISR_CACHE_SAFE + +TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { TaskHandle_t task_handle = (TaskHandle_t)user_data; BaseType_t high_task_wakeup; diff --git a/components/esp_hw_support/etm/esp_etm.c b/components/esp_hw_support/etm/esp_etm.c index 8bb34071ae2..0b3d65952c2 100644 --- a/components/esp_hw_support/etm/esp_etm.c +++ b/components/esp_hw_support/etm/esp_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,7 @@ #include "esp_private/etm_interface.h" #include "esp_private/sleep_retention.h" #include "esp_private/critical_section.h" +#include "esp_private/esp_clk_tree_common.h" #define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT @@ -63,6 +64,9 @@ struct esp_etm_channel_t { _Atomic etm_chan_fsm_t fsm; // record ETM channel's driver state esp_etm_event_handle_t event; // which event is connect to the channel esp_etm_task_handle_t task; // which task is connect to the channel +#if ETM_LL_SUPPORT(CLOCK_SRC) + etm_clock_source_t clk_src; // function clock source enabled for this channel +#endif }; // ETM driver platform, it's always a singleton @@ -272,6 +276,8 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch if (clk_src == 0) { clk_src = ETM_CLK_SRC_DEFAULT; } + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), err, TAG, "clock source enable failed"); + chan->clk_src = clk_src; etm_ll_set_clock_source(group_id, clk_src); #endif @@ -290,6 +296,11 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch err: if (chan) { +#if ETM_LL_SUPPORT(CLOCK_SRC) + if (chan->clk_src != 0) { + esp_clk_tree_enable_src((soc_module_clk_t)chan->clk_src, false); + } +#endif etm_chan_destroy(chan); } return ret; @@ -310,6 +321,11 @@ esp_err_t esp_etm_del_channel(esp_etm_channel_handle_t chan) etm_ll_channel_set_task(group->hal.regs, chan_id, 0); ESP_LOGD(TAG, "del etm channel (%d,%d)", group_id, chan_id); +#if ETM_LL_SUPPORT(CLOCK_SRC) + // Back to hardware default clock selection, otherwise it might get stuck when stopping the bus during sleep process. + etm_ll_set_clock_source(group_id, ETM_CLK_SRC_XTAL); + ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)chan->clk_src, false), TAG, "clock source disable failed"); +#endif // recycle memory resource ESP_RETURN_ON_ERROR(etm_chan_destroy(chan), TAG, "destroy etm channel failed"); return ESP_OK; diff --git a/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c b/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c index f927d61b208..1cfe9aa83ea 100644 --- a/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c +++ b/components/esp_hw_support/modem/port/esp32s31/modem_clock_impl.c @@ -6,6 +6,8 @@ #include "sdkconfig.h" #include "esp_attr.h" +#include "esp_check.h" +#include "esp_clk_tree.h" #include "soc/soc_caps.h" #include "modem/modem_clock_impl.h" #include "esp_private/regi2c_ctrl.h" @@ -212,7 +214,13 @@ static void IRAM_ATTR modem_clock_coex_configure(modem_clock_context_t *ctx, boo #if SOC_MODEM_CLOCK_SOC_PLL_SOURCE_CG_SUPPORTED static void IRAM_ATTR modem_clock_soc_pll_source_cg_configure(modem_clock_context_t *ctx, bool enable) { + if (enable) { + ESP_ERROR_CHECK(esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F160M, true)); + } modem_clock_hal_enable_soc_pll_source_cg(ctx->hal, enable); + if (!enable) { + ESP_ERROR_CHECK(esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F160M, false)); + } } #endif diff --git a/components/esp_hw_support/port/esp32s31/rtc_time.c b/components/esp_hw_support/port/esp32s31/rtc_time.c index 6c60a93f95a..004a143e62d 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_time.c +++ b/components/esp_hw_support/port/esp32s31/rtc_time.c @@ -144,6 +144,9 @@ uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32 } CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); clk_ll_freq_calculation_set_divider(1); + // Back to always on clock source, Otherwise, if the source for this calibration is subsequently turned off, + // the next calibration will not be able to switch to the new calibration source. + clk_ll_freq_calulation_set_target(CLK_CAL_RC_SLOW); /* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */ if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) { diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index d4ccb44585a..ca17ae55e3d 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -123,6 +123,9 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc { esp_err_t ret = ESP_OK; esp_lcd_i80_bus_t *bus = NULL; +#if CONFIG_IDF_TARGET_ESP32S31 + bool pll_f120m_enabled = false; +#endif ESP_RETURN_ON_FALSE(bus_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); // although LCD_CAM can support up to 24 data lines, we restrict users to only use 8 or 16 bit width ESP_RETURN_ON_FALSE(bus_config->bus_width == 8 || bus_config->bus_width == 16, ESP_ERR_INVALID_ARG, @@ -181,6 +184,11 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc #endif // I80_USE_RETENTION_LINK // initialize HAL layer, so we can call LL APIs later lcd_hal_init(&bus->hal, bus_id); +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true), err, TAG, "clock source enable failed"); + pll_f120m_enabled = true; +#endif PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(bus->hal.dev, true); } @@ -264,6 +272,11 @@ err: esp_clk_tree_enable_src(bus->clk_src, false); bus->clk_src = SOC_MOD_CLK_INVALID; } +#if CONFIG_IDF_TARGET_ESP32S31 + if (pll_f120m_enabled) { + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); + } +#endif #if CONFIG_PM_ENABLE if (bus->pm_lock) { esp_pm_lock_delete(bus->pm_lock); @@ -287,6 +300,9 @@ esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus) esp_clk_tree_enable_src(bus->clk_src, false); bus->clk_src = SOC_MOD_CLK_INVALID; } +#if CONFIG_IDF_TARGET_ESP32S31 + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false), err, TAG, "clock source disable failed"); +#endif #if I80_USE_RETENTION_LINK const periph_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module; sleep_retention_module_detach(module_id); diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 8a5a73d5e6a..ec9bc5725e5 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -173,6 +173,9 @@ struct esp_rgb_panel_t { uint32_t fb_behind_cache: 1; // Whether the frame buffer is behind the cache uint32_t bb_behind_cache: 1; // Whether the bounce buffer is behind the cache uint32_t user_fb: 1; // Whether the frame buffer is provided by user +#if CONFIG_IDF_TARGET_ESP32S31 + uint32_t pll_f120m_enabled: 1; // Whether PLL_F120M was enabled for this panel instance +#endif } flags; // hook fields esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function @@ -265,6 +268,12 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel) PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(rgb_panel->hal.dev, false); } +#if CONFIG_IDF_TARGET_ESP32S31 + if (rgb_panel->flags.pll_f120m_enabled) { + esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, false); + rgb_panel->flags.pll_f120m_enabled = 0; + } +#endif if (rgb_panel->clk_src) { esp_clk_tree_enable_src(rgb_panel->clk_src, false); } @@ -419,6 +428,11 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf lcd_hal_init(&rgb_panel->hal, panel_id); lcd_hal_context_t *hal = &rgb_panel->hal; // enable clock +#if CONFIG_IDF_TARGET_ESP32S31 + // PLL 120M was selected in esp_perip_clk_init on esp32s31. + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)SOC_MOD_CLK_PLL_F120M, true), err, TAG, "clock source enable failed"); + rgb_panel->flags.pll_f120m_enabled = 1; +#endif PERIPH_RCC_ATOMIC() { lcd_ll_enable_clock(hal->dev, true); }