refactor(lcdcam): move shared core clock setup to drivers

Configure the shared LCDCAM core clock through guarded LCD and CAM LL APIs,
and unify LCD functional clock LL calls around group IDs across supported targets.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
morris
2026-09-08 14:47:41 +08:00
co-authored by Cursor
parent 1fd26d0846
commit ef6b7b742f
9 changed files with 183 additions and 52 deletions
+12 -9
View File
@@ -124,7 +124,7 @@ 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;
bool core_clk_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
@@ -159,6 +159,10 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
if (ref_count == 0) {
lcd_ll_enable_bus_clock(bus_id, true);
lcd_ll_reset_register(bus_id);
#if CONFIG_IDF_TARGET_ESP32S31
lcd_ll_select_core_clk_src(bus_id, LCD_CORE_CLK_SRC_DEFAULT);
lcd_ll_set_core_clock_divider(bus_id, 2, 0, 0);
#endif
}
}
#if I80_USE_RETENTION_LINK
@@ -185,9 +189,8 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
// 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;
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)LCD_CORE_CLK_SRC_DEFAULT, true), err, TAG, "core clock source enable failed");
core_clk_enabled = true;
#endif
PERIPH_RCC_ATOMIC() {
lcd_ll_enable_clock(bus->hal.dev, true);
@@ -273,8 +276,8 @@ err:
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);
if (core_clk_enabled) {
esp_clk_tree_enable_src((soc_module_clk_t)LCD_CORE_CLK_SRC_DEFAULT, false);
}
#endif
#if CONFIG_PM_ENABLE
@@ -301,7 +304,7 @@ esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus)
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");
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)LCD_CORE_CLK_SRC_DEFAULT, false), err, TAG, "core 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;
@@ -655,9 +658,9 @@ static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz),
TAG, "get clock source frequency failed");
PERIPH_RCC_ATOMIC() {
lcd_ll_select_clk_src(bus->hal.dev, clk_src);
lcd_ll_select_clk_src(bus->bus_id, clk_src);
// force to use integer division, as fractional division might lead to clock jitter
lcd_ll_set_group_clock_coeff(bus->hal.dev, LCD_PERIPH_CLOCK_PRE_SCALE, 0, 0);
lcd_ll_set_group_clock_coeff(bus->bus_id, LCD_PERIPH_CLOCK_PRE_SCALE, 0, 0);
}
// save the resolution of the i80 bus
+13 -12
View File
@@ -173,9 +173,7 @@ 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
uint32_t core_clk_enabled: 1; // Whether the LCD core clock source was enabled for this panel instance
} flags;
// hook fields
esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function
@@ -254,9 +252,9 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
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;
if (rgb_panel->flags.core_clk_enabled) {
esp_clk_tree_enable_src((soc_module_clk_t)LCD_CORE_CLK_SRC_DEFAULT, false);
rgb_panel->flags.core_clk_enabled = 0;
}
#endif
if (rgb_panel->clk_src) {
@@ -406,6 +404,10 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
if (ref_count == 0) {
lcd_ll_enable_bus_clock(panel_id, true);
lcd_ll_reset_register(panel_id);
#if CONFIG_IDF_TARGET_ESP32S31
lcd_ll_select_core_clk_src(panel_id, LCD_CORE_CLK_SRC_DEFAULT);
lcd_ll_set_core_clock_divider(panel_id, 2, 0, 0);
#endif
}
}
@@ -414,9 +416,8 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
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;
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)LCD_CORE_CLK_SRC_DEFAULT, true), err, TAG, "core clock source enable failed");
rgb_panel->flags.core_clk_enabled = 1;
#endif
PERIPH_RCC_ATOMIC() {
lcd_ll_enable_clock(hal->dev, true);
@@ -650,7 +651,7 @@ static esp_err_t rgb_panel_init(esp_lcd_panel_t *panel)
hal_utils_clk_div_t lcd_clk_div = {};
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, &lcd_clk_div);
PERIPH_RCC_ATOMIC() {
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
lcd_ll_set_group_clock_coeff(rgb_panel->panel_id, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
}
// pixel clock phase and polarity
lcd_ll_set_clock_idle_level(rgb_panel->hal.dev, rgb_panel->timings.flags.pclk_idle_high);
@@ -1129,7 +1130,7 @@ static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_
TAG, "get clock source frequency failed");
rgb_panel->src_clk_hz = src_clk_hz;
PERIPH_RCC_ATOMIC() {
lcd_ll_select_clk_src(rgb_panel->hal.dev, clk_src);
lcd_ll_select_clk_src(rgb_panel->panel_id, clk_src);
}
// create pm lock based on different clock source
@@ -1491,7 +1492,7 @@ IRAM_ATTR static void lcd_rgb_panel_try_update_pclk(esp_rgb_panel_t *rgb_panel)
rgb_panel->flags.need_update_pclk = false;
rgb_panel->timings.pclk_hz = lcd_hal_cal_pclk_freq(&rgb_panel->hal, rgb_panel->src_clk_hz, rgb_panel->timings.pclk_hz, &lcd_clk_div);
PERIPH_RCC_ATOMIC() {
lcd_ll_set_group_clock_coeff(rgb_panel->hal.dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
lcd_ll_set_group_clock_coeff(rgb_panel->panel_id, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
}
}
portEXIT_CRITICAL_ISR(&rgb_panel->spinlock);