Skip to content

Commit eedbd9f

Browse files
committed
feat(dsi): split the dphy config clock and pll reference clock
this is a breaking change in the esp32p4 ver3.0 silicon.
1 parent b7fc7ac commit eedbd9f

File tree

24 files changed

+449
-215
lines changed

24 files changed

+449
-215
lines changed

components/esp_lcd/Kconfig

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
menu "ESP-Driver:LCD Controller Configurations"
2-
config LCD_ENABLE_DEBUG_LOG
3-
bool "Enable debug log"
4-
default n
5-
help
6-
whether to enable the debug log message for LCD driver.
7-
Note that, this option only controls the LCD driver log, won't affect other drivers.
82

93
if SOC_LCD_RGB_SUPPORTED
104
config LCD_RGB_ISR_IRAM_SAFE
@@ -28,14 +22,37 @@ menu "ESP-Driver:LCD Controller Configurations"
2822
endif # SOC_LCD_RGB_SUPPORTED
2923

3024
if SOC_MIPI_DSI_SUPPORTED
31-
config LCD_DSI_ISR_IRAM_SAFE
32-
bool "DSI LCD ISR IRAM-Safe"
33-
default n
25+
config LCD_DSI_ISR_HANDLER_IN_IRAM
26+
bool "Place DSI ISR handler in IRAM to reduce latency"
27+
default y
28+
select LCD_DSI_OBJ_FORCE_INTERNAL
29+
help
30+
Place DSI ISR handler in IRAM to reduce latency caused by cache miss.
31+
32+
config LCD_DSI_ISR_CACHE_SAFE
33+
bool "Allow DSI ISR to execute when cache is disabled" if !SPI_FLASH_AUTO_SUSPEND
34+
select LCD_DSI_ISR_HANDLER_IN_IRAM
3435
select DW_GDMA_ISR_IRAM_SAFE # relies on DW_GDMA Full trans done interrupt
36+
default n
3537
help
36-
Ensure the LCD interrupt is IRAM-Safe by allowing the interrupt handler to be
37-
executable when the cache is disabled (e.g. SPI Flash write).
38-
If you want the LCD driver to keep flushing the screen even when cache ops disabled,
39-
you can enable this option. Note, this will also increase the IRAM usage.
38+
Enable this option to allow the DSI Interrupt Service Routine (ISR)
39+
to execute even when the cache is disabled. This can be useful in scenarios where the cache
40+
might be turned off, but the DSI functionality is still required to operate correctly.
41+
42+
config LCD_DSI_OBJ_FORCE_INTERNAL
43+
bool
44+
default n
45+
help
46+
This will ensure the DSI driver object will always be allocated in internal RAM.
4047
endif # SOC_MIPI_DSI_SUPPORTED
48+
49+
config LCD_ENABLE_DEBUG_LOG
50+
bool "Force enable debug log"
51+
default n
52+
help
53+
If enabled, LCD driver component will:
54+
1. ignore the global logging settings
55+
2. compile all log messages into the binary
56+
3. set the runtime log level to VERBOSE
57+
Please enable this option by caution, as it will increase the binary size.
4158
endmenu

components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6-
#include "freertos/FreeRTOS.h"
7-
#include "freertos/task.h"
8-
#include "soc/soc_caps.h"
9-
#include "esp_check.h"
106
#include "esp_lcd_mipi_dsi.h"
117
#include "esp_clk_tree.h"
12-
#include "esp_private/esp_clk_tree_common.h"
138
#include "mipi_dsi_priv.h"
149

15-
static const char *TAG = "lcd.dsi.bus";
16-
1710
#define MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ 10
1811
// TxClkEsc frequency must be configured between 2 and 20 MHz
1912
#define MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ 18
@@ -38,25 +31,31 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc
3831
dsi_bus->bus_id = bus_id;
3932

4033
// Enable the APB clock for accessing the DSI host and bridge registers
41-
DSI_RCC_ATOMIC() {
34+
PERIPH_RCC_ATOMIC() {
4235
mipi_dsi_ll_enable_bus_clock(bus_id, true);
4336
mipi_dsi_ll_reset_register(bus_id);
4437
}
4538

4639
// if the clock source is not assigned, fallback to the default clock source
47-
mipi_dsi_phy_clock_source_t phy_clk_src = bus_config->phy_clk_src;
40+
mipi_dsi_phy_pllref_clock_source_t phy_clk_src = bus_config->phy_clk_src;
4841
if (phy_clk_src == 0) {
49-
phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT;
42+
#if SOC_IS(ESP32P4) && HAL_CONFIG(CHIP_SUPPORT_MIN_REV) < 300
43+
phy_clk_src = MIPI_DSI_PHY_PLLREF_CLK_SRC_DEFAULT_LEGACY;
44+
#else
45+
phy_clk_src = MIPI_DSI_PHY_PLLREF_CLK_SRC_DEFAULT;
46+
#endif
5047
}
5148
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)phy_clk_src, true), err, TAG, "clock source enable failed");
5249
// enable the clock source for DSI PHY
53-
DSI_CLOCK_SRC_ATOMIC() {
54-
// set clock source for DSI PHY
55-
mipi_dsi_ll_set_phy_clock_source(bus_id, phy_clk_src);
50+
PERIPH_RCC_ATOMIC() {
51+
// set the DSI PHY configuration clock
5652
// the configuration clock is used for all modes except the shutdown mode
53+
mipi_dsi_ll_set_phy_config_clock_source(bus_id, MIPI_DSI_PHY_CFG_CLK_SRC_DEFAULT);
5754
mipi_dsi_ll_enable_phy_config_clock(bus_id, true);
58-
// enable the clock for generating the serial clock
59-
mipi_dsi_ll_enable_phy_reference_clock(bus_id, true);
55+
// set the DSI PHY PLL reference clock
56+
mipi_dsi_ll_set_phy_pllref_clock_source(bus_id, phy_clk_src);
57+
mipi_dsi_ll_set_phy_pll_ref_clock_div(bus_id, 1); // no division
58+
mipi_dsi_ll_enable_phy_pllref_clock(bus_id, true);
6059
}
6160

6261
#if CONFIG_PM_ENABLE
@@ -135,12 +134,12 @@ esp_err_t esp_lcd_del_dsi_bus(esp_lcd_dsi_bus_handle_t bus)
135134
ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
136135
int bus_id = bus->bus_id;
137136
// disable the clock source for DSI PHY
138-
DSI_CLOCK_SRC_ATOMIC() {
139-
mipi_dsi_ll_enable_phy_reference_clock(bus_id, false);
137+
PERIPH_RCC_ATOMIC() {
138+
mipi_dsi_ll_enable_phy_pllref_clock(bus_id, false);
140139
mipi_dsi_ll_enable_phy_config_clock(bus_id, false);
141140
}
142141
// disable the APB clock for accessing the DSI peripheral registers
143-
DSI_RCC_ATOMIC() {
142+
PERIPH_RCC_ATOMIC() {
144143
mipi_dsi_ll_enable_bus_clock(bus_id, false);
145144
}
146145
#if CONFIG_PM_ENABLE
@@ -152,3 +151,11 @@ esp_err_t esp_lcd_del_dsi_bus(esp_lcd_dsi_bus_handle_t bus)
152151
free(bus);
153152
return ESP_OK;
154153
}
154+
155+
#if CONFIG_LCD_ENABLE_DEBUG_LOG
156+
__attribute__((constructor))
157+
static void mipi_dsi_override_default_log_level(void)
158+
{
159+
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
160+
}
161+
#endif

components/esp_lcd/dsi/esp_lcd_panel_dpi.c

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66
#include <sys/param.h>
7-
#include "freertos/FreeRTOS.h"
8-
#include "freertos/task.h"
9-
#include "freertos/semphr.h"
10-
#include "soc/soc_caps.h"
11-
#include "esp_check.h"
127
#include "esp_lcd_panel_interface.h"
138
#include "esp_lcd_mipi_dsi.h"
149
#include "esp_clk_tree.h"
@@ -17,13 +12,8 @@
1712
#include "esp_async_fbcpy.h"
1813
#include "esp_memory_utils.h"
1914
#include "esp_private/dw_gdma.h"
20-
#include "esp_private/esp_clk_tree_common.h"
21-
#include "hal/cache_hal.h"
22-
#include "hal/cache_ll.h"
2315
#include "hal/color_hal.h"
2416

25-
static const char *TAG = "lcd.dsi.dpi";
26-
2717
typedef struct esp_lcd_dpi_panel_t esp_lcd_dpi_panel_t;
2818

2919
static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel);
@@ -77,8 +67,7 @@ static bool async_fbcpy_done_cb(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_ev
7767
return need_yield;
7868
}
7969

80-
IRAM_ATTR
81-
static bool dma_trans_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data)
70+
bool mipi_dsi_dma_trans_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data)
8271
{
8372
bool yield_needed = false;
8473
esp_lcd_dpi_panel_t *dpi_panel = (esp_lcd_dpi_panel_t *)user_data;
@@ -152,7 +141,7 @@ static esp_err_t dpi_panel_create_dma_link(esp_lcd_dpi_panel_t *dpi_panel)
152141

153142
// register DMA ISR callbacks
154143
dw_gdma_event_callbacks_t dsi_dma_cbs = {
155-
.on_full_trans_done = dma_trans_done_cb,
144+
.on_full_trans_done = mipi_dsi_dma_trans_done_cb,
156145
};
157146
ESP_RETURN_ON_ERROR(dw_gdma_channel_register_event_callbacks(dma_chan, &dsi_dma_cbs, dpi_panel), TAG, "register DMA callbacks failed");
158147

@@ -232,20 +221,16 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
232221
dpi_panel->num_fbs = num_fbs;
233222

234223
// allocate frame buffer from PSRAM
235-
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
236-
// DMA doesn't have requirement on the buffer alignment, but the cache does
237-
uint32_t alignment = cache_line_size;
238224
size_t fb_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8;
239-
uint8_t *frame_buffer = NULL;
240225
for (int i = 0; i < num_fbs; i++) {
241-
frame_buffer = heap_caps_aligned_calloc(alignment, 1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
226+
uint8_t *frame_buffer = heap_caps_calloc(1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
242227
ESP_GOTO_ON_FALSE(frame_buffer, ESP_ERR_NO_MEM, err, TAG, "no memory for frame buffer");
243228
dpi_panel->fbs[i] = frame_buffer;
244229
ESP_LOGD(TAG, "fb[%d] @%p", i, frame_buffer);
245230
// preset the frame buffer with black color
246-
// the frame buffer address alignment is ensured by `heap_caps_aligned_calloc`
231+
// the frame buffer address alignment is ensured by `heap_caps_calloc`
247232
// while the value of the fb_size may not be aligned to the cache line size
248-
// but that's not a problem because the `heap_caps_aligned_calloc` internally allocated a buffer whose size is aligned up to the cache line size
233+
// but that's not a problem because the `heap_caps_calloc` internally allocated a buffer whose size is aligned up to the cache line size
249234
ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED),
250235
err, TAG, "cache write back failed");
251236
}
@@ -278,7 +263,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
278263
uint32_t dpi_div = mipi_dsi_hal_host_dpi_calculate_divider(hal, dpi_clk_src_freq_hz / 1000 / 1000, panel_config->dpi_clock_freq_mhz);
279264
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)dpi_clk_src, true), err, TAG, "clock source enable failed");
280265
// set the clock source, set the divider, and enable the dpi clock
281-
DSI_CLOCK_SRC_ATOMIC() {
266+
PERIPH_RCC_ATOMIC() {
282267
mipi_dsi_ll_set_dpi_clock_source(bus_id, dpi_clk_src);
283268
mipi_dsi_ll_set_dpi_clock_div(bus_id, dpi_div);
284269
mipi_dsi_ll_enable_dpi_clock(bus_id, true);
@@ -297,7 +282,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
297282
ESP_GOTO_ON_ERROR(dpi_panel_create_dma_link(dpi_panel), err, TAG, "initialize DMA link failed");
298283

299284
mipi_dsi_host_ll_dpi_set_vcid(hal->host, panel_config->virtual_channel);
300-
mipi_dsi_hal_host_dpi_set_color_coding(hal, out_color_format, 0);
285+
mipi_dsi_host_ll_dpi_set_color_coding(hal->host, out_color_format, 0);
301286
// these signals define how the DPI interface interacts with the controller
302287
mipi_dsi_host_ll_dpi_set_timing_polarity(hal->host, false, false, false, false, false);
303288

@@ -335,8 +320,9 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_
335320
panel_config->video_timing.vsync_front_porch);
336321
mipi_dsi_brg_ll_set_num_pixel_bits(hal->bridge, panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel);
337322
mipi_dsi_brg_ll_set_underrun_discard_count(hal->bridge, panel_config->video_timing.h_size);
338-
// set input color space
339-
mipi_dsi_brg_ll_set_input_color_space(hal->bridge, COLOR_SPACE_TYPE(in_color_format));
323+
// set the in/out color formats in the DSI bridge
324+
mipi_dsi_brg_ll_set_input_color_format(hal->bridge, in_color_format);
325+
mipi_dsi_brg_ll_set_output_color_format(hal->bridge, out_color_format, 0);
340326
// use the DW_GDMA as the flow controller
341327
mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_DMA);
342328
mipi_dsi_brg_ll_set_multi_block_number(hal->bridge, DPI_PANEL_MIN_DMA_NODES_PER_LINK);
@@ -366,7 +352,7 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel)
366352
int bus_id = bus->bus_id;
367353
mipi_dsi_hal_context_t *hal = &bus->hal;
368354
// disable the DPI clock
369-
DSI_CLOCK_SRC_ATOMIC() {
355+
PERIPH_RCC_ATOMIC() {
370356
mipi_dsi_ll_enable_dpi_clock(bus_id, false);
371357
}
372358
// disable the DSI bridge
@@ -588,6 +574,7 @@ esp_err_t esp_lcd_dpi_panel_set_color_conversion(esp_lcd_panel_handle_t panel, c
588574
if (dpi_panel->in_color_format == COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422)
589575
&& COLOR_SPACE_TYPE(dpi_panel->out_color_format) == LCD_COLOR_SPACE_RGB) {
590576
// YUV422->RGB
577+
mipi_dsi_brg_ll_set_input_color_range(hal->bridge, config->in_color_range);
591578
mipi_dsi_brg_ll_set_yuv_convert_std(hal->bridge, config->spec.yuv.conv_std);
592579
mipi_dsi_brg_ll_set_yuv422_pack_order(hal->bridge, config->spec.yuv.yuv422.in_pack_order);
593580
} else {
@@ -625,7 +612,7 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
625612
{
626613
ESP_RETURN_ON_FALSE(panel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
627614
esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base);
628-
#if CONFIG_LCD_DSI_ISR_IRAM_SAFE
615+
#if CONFIG_LCD_DSI_ISR_HANDLER_IN_IRAM
629616
if (cbs->on_color_trans_done) {
630617
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_color_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_color_trans_done callback not in IRAM");
631618
}
@@ -635,7 +622,7 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane
635622
if (user_ctx) {
636623
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
637624
}
638-
#endif // CONFIG_LCD_RGB_ISR_IRAM_SAFE
625+
#endif // CONFIG_LCD_DSI_ISR_HANDLER_IN_IRAM
639626
dpi_panel->on_color_trans_done = cbs->on_color_trans_done;
640627
dpi_panel->on_refresh_done = cbs->on_refresh_done;
641628
dpi_panel->user_ctx = user_ctx;

components/esp_lcd/dsi/esp_lcd_panel_io_dbi.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6-
#include "freertos/FreeRTOS.h"
7-
#include "freertos/task.h"
8-
#include "soc/soc_caps.h"
9-
#include "esp_check.h"
106
#include "esp_lcd_panel_io_interface.h"
117
#include "esp_lcd_mipi_dsi.h"
128
#include "mipi_dsi_priv.h"
139

14-
static const char *TAG = "lcd.dsi.dbi";
15-
1610
typedef struct esp_lcd_dbi_io_t esp_lcd_dbi_io_t;
1711

1812
struct esp_lcd_dbi_io_t {

components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extern "C" {
2323
typedef struct {
2424
int bus_id; /*!< Select which DSI controller, index from 0 */
2525
uint8_t num_data_lanes; /*!< Number of data lanes, if set to 0, the driver will fallback to use maximum number of lanes */
26-
mipi_dsi_phy_clock_source_t phy_clk_src; /*!< MIPI DSI PHY clock source */
26+
mipi_dsi_phy_pllref_clock_source_t phy_clk_src; /*!< The clock source for the PHY PLL */
2727
uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */
2828
} esp_lcd_dsi_bus_config_t;
2929

components/esp_lcd/dsi/mipi_dsi_priv.h

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66
#pragma once
77

8-
#include "hal/mipi_dsi_hal.h"
9-
#include "hal/mipi_dsi_ll.h"
8+
#include <stdint.h>
9+
#include "sdkconfig.h"
10+
#if CONFIG_LCD_ENABLE_DEBUG_LOG
11+
// The local log level must be defined before including esp_log.h
12+
// Set the maximum log level for gptimer driver
13+
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
14+
#endif
15+
#include "soc/soc_caps_full.h"
16+
#include "freertos/FreeRTOS.h"
17+
#include "freertos/task.h"
18+
#include "freertos/semphr.h"
19+
#include "esp_err.h"
20+
#include "esp_log.h"
21+
#include "esp_check.h"
22+
#include "esp_attr.h"
1023
#include "esp_heap_caps.h"
1124
#include "esp_private/periph_ctrl.h"
25+
#include "esp_private/esp_clk_tree_common.h"
1226
#include "esp_pm.h"
27+
#include "hal/mipi_dsi_hal.h"
28+
#include "hal/mipi_dsi_ll.h"
1329

14-
#if SOC_PERIPH_CLK_CTRL_SHARED
15-
#define DSI_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
16-
#else
17-
#define DSI_CLOCK_SRC_ATOMIC()
18-
#endif
19-
20-
#if !SOC_RCC_IS_INDEPENDENT
21-
#define DSI_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
22-
#else
23-
#define DSI_RCC_ATOMIC()
24-
#endif
25-
26-
#if CONFIG_LCD_DSI_ISR_IRAM_SAFE
30+
#if CONFIG_LCD_DSI_OBJ_FORCE_INTERNAL
2731
#define DSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
2832
#else
2933
#define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
@@ -32,6 +36,9 @@
3236
#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of frame buffers that can be maintained by the driver
3337
#define DPI_PANEL_MIN_DMA_NODES_PER_LINK 1 // NOTE: we assume 1 DMA link item can carry the WHOLE image
3438

39+
///!< Logging settings
40+
#define TAG "lcd.dsi"
41+
3542
#ifdef __cplusplus
3643
extern "C" {
3744
#endif

0 commit comments

Comments
 (0)