diff --git a/LCD.md b/LCD.md
index 60db4549..dea816b4 100644
--- a/LCD.md
+++ b/LCD.md
@@ -20,3 +20,4 @@ The list of available LCD displays and links to LCD driver component and touch d
| | Parallel/SPI | ST7796 | [Component Manager](https://components.espressif.com/component/espressif/esp_lcd_st7796) | - | - | |
| | [ESP32-S3-LCD-EV-Board](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html) | GC9503 | [Component Manager](https://components.espressif.com/component/espressif/esp_lcd_gc9503) | FT5X06 | [Component Manager](https://components.espressif.com/component/espressif/esp_lcd_touch_ft5x06) | |
| | [ESP32-S3-LCD-EV-Board-2](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html) | ST7262E43 | **N/A** | GT1151 | [Component Manager](https://components.espressif.com/component/espressif/esp_lcd_touch_gt1151) | |
+| | HDMI | LT8912B | [Component Manager](https://components.espressif.com/component/espressif/esp_lcd_lt8912b) | - | - | |
diff --git a/bsp/esp32_p4_function_ev_board/Kconfig b/bsp/esp32_p4_function_ev_board/Kconfig
index c69edaf0..b21e39ce 100644
--- a/bsp/esp32_p4_function_ev_board/Kconfig
+++ b/bsp/esp32_p4_function_ev_board/Kconfig
@@ -1,4 +1,4 @@
-menu "Board Support Package(ESP32-P4)"
+menu "Board Support Package (ESP32-P4)"
config BSP_ERROR_CHECK
bool "Enable error check in BSP"
@@ -131,7 +131,26 @@ menu "Board Support Package(ESP32-P4)"
bool "LCD 7-inch 1024x600 - ek79007"
config BSP_LCD_TYPE_1280_800
bool "LCD 1280x800 - ili9881c"
- endchoice
+ config BSP_LCD_TYPE_HDMI
+ bool "HDMI - lt8912b"
+ endchoice
+
+ choice BSP_LCD_HDMI_RESOLUTION
+ depends on BSP_LCD_TYPE_HDMI
+ prompt "Select HDMI resolution"
+ default BSP_LCD_HDMI_1280x720_60HZ
+ help
+ Select the HDMI resolution.
+
+ config BSP_LCD_HDMI_800x600_60HZ
+ bool "800x600@60HZ"
+ config BSP_LCD_HDMI_1280x720_60HZ
+ bool "1280x720@60HZ"
+ config BSP_LCD_HDMI_1280x800_60HZ
+ bool "1280x800@60HZ"
+ config BSP_LCD_HDMI_1920x1080_30HZ
+ bool "1920x1080@30HZ"
+ endchoice
endmenu
diff --git a/bsp/esp32_p4_function_ev_board/README.md b/bsp/esp32_p4_function_ev_board/README.md
index 45e904d8..6cf9379b 100644
--- a/bsp/esp32_p4_function_ev_board/README.md
+++ b/bsp/esp32_p4_function_ev_board/README.md
@@ -15,13 +15,24 @@ ESP32-P4 Function EV Board is internal Espressif board for testing features on E
Configuration in `menuconfig`.
Selection LCD display `Board Support Package(ESP32-P4) --> Display --> Select LCD type`
-- LCD 7-inch 1280x800 - ili9881c (default)
+- LCD 1280x800 - ili9881c (default)
- LCD 1024x600 - ek79007
+- HDMI - lt8912b
+ - 800x600@60HZ
+ - 1280x720@60HZ
+ - 1280x800@60HZ
+ - 1920x1080@30HZ
Selection color format `Board Support Package(ESP32-P4) --> Display --> Select LCD color format`
- RGB565 (default)
- RGB888
+## HDMI Support
+
+This BSP supports HDMI converter Lontium LT8912B. Follow these rules for using it with HDMI:
+- Use ESP-IDF 5.4 or older (from commit [93fdbf2](https://github.com/espressif/esp-idf/commit/93fdbf25b3ea7e44d1f519ed61050847dcc8a076))
+- Only RGB888 is supported with HDMI
+- Use MIPI-DSI to HDMI converter Lontium LT8912B
### Capabilities and dependencies
diff --git a/bsp/esp32_p4_function_ev_board/esp32_p4_function_ev_board.c b/bsp/esp32_p4_function_ev_board/esp32_p4_function_ev_board.c
index 16bbbeec..e8584812 100644
--- a/bsp/esp32_p4_function_ev_board/esp32_p4_function_ev_board.c
+++ b/bsp/esp32_p4_function_ev_board/esp32_p4_function_ev_board.c
@@ -21,6 +21,8 @@
#if CONFIG_BSP_LCD_TYPE_1024_600
#include "esp_lcd_ek79007.h"
+#elif CONFIG_BSP_LCD_TYPE_HDMI
+#include "esp_lcd_lt8912b.h"
#else
#include "esp_lcd_ili9881c.h"
#endif
@@ -402,12 +404,14 @@ esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_hand
esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_lcd_handles_t *ret_handles)
{
esp_err_t ret = ESP_OK;
+ esp_lcd_panel_io_handle_t io = NULL;
+ esp_lcd_panel_handle_t disp_panel = NULL;
ESP_RETURN_ON_ERROR(bsp_display_brightness_init(), TAG, "Brightness init failed");
ESP_RETURN_ON_ERROR(bsp_enable_dsi_phy_power(), TAG, "DSI PHY power failed");
/* create MIPI DSI bus first, it will initialize the DSI PHY as well */
- esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
+ esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = BSP_LCD_MIPI_DSI_LANE_NUM,
@@ -416,17 +420,17 @@ esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_l
};
ESP_RETURN_ON_ERROR(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus), TAG, "New DSI bus init failed");
+#if !CONFIG_BSP_LCD_TYPE_HDMI
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
// we use DBI interface to send LCD commands and parameters
- esp_lcd_panel_io_handle_t io;
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
- .lcd_cmd_bits = 8, // according to the LCD ILI9881C spec
- .lcd_param_bits = 8, // according to the LCD ILI9881C spec
+ .lcd_cmd_bits = 8, // according to the LCD spec
+ .lcd_param_bits = 8, // according to the LCD spec
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io), err, TAG, "New panel IO failed");
+#endif
- esp_lcd_panel_handle_t disp_panel = NULL;
#if CONFIG_BSP_LCD_TYPE_1024_600
// create EK79007 control panel
ESP_LOGI(TAG, "Install EK79007 LCD control panel");
@@ -453,7 +457,7 @@ esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_l
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_ek79007(io, &lcd_dev_config, &disp_panel), err, TAG, "New LCD panel EK79007 failed");
ESP_GOTO_ON_ERROR(esp_lcd_panel_reset(disp_panel), err, TAG, "LCD panel reset failed");
ESP_GOTO_ON_ERROR(esp_lcd_panel_init(disp_panel), err, TAG, "LCD panel init failed");
-#else
+#elif CONFIG_BSP_LCD_TYPE_1280_800
// create ILI9881C control panel
ESP_LOGI(TAG, "Install ILI9881C LCD control panel");
#if CONFIG_BSP_LCD_COLOR_FORMAT_RGB888
@@ -480,7 +484,92 @@ esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_l
ESP_GOTO_ON_ERROR(esp_lcd_panel_reset(disp_panel), err, TAG, "LCD panel reset failed");
ESP_GOTO_ON_ERROR(esp_lcd_panel_init(disp_panel), err, TAG, "LCD panel init failed");
ESP_GOTO_ON_ERROR(esp_lcd_panel_disp_on_off(disp_panel, true), err, TAG, "LCD panel ON failed");
+
+#elif CONFIG_BSP_LCD_TYPE_HDMI
+
+#if !CONFIG_BSP_LCD_COLOR_FORMAT_RGB888
+#error The color format must be RGB888 in HDMI display type!
+#endif
+ ESP_LOGI(TAG, "Install MIPI DSI HDMI control panel");
+ ESP_RETURN_ON_ERROR(bsp_i2c_init(), TAG, "I2C init failed");
+
+ /* Main IO */
+ esp_lcd_panel_io_i2c_config_t io_config = LT8912B_IO_CFG(CONFIG_BSP_I2C_CLK_SPEED_HZ, LT8912B_IO_I2C_MAIN_ADDRESS);
+ ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_handle, &io_config, &io));
+
+ /* CEC DSI IO */
+ esp_lcd_panel_io_handle_t io_cec_dsi = NULL;
+ esp_lcd_panel_io_i2c_config_t io_config_cec = LT8912B_IO_CFG(CONFIG_BSP_I2C_CLK_SPEED_HZ, LT8912B_IO_I2C_CEC_ADDRESS);
+ ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_handle, &io_config_cec, &io_cec_dsi));
+
+ /* AVI IO */
+ esp_lcd_panel_io_handle_t io_avi = NULL;
+ esp_lcd_panel_io_i2c_config_t io_config_avi = LT8912B_IO_CFG(CONFIG_BSP_I2C_CLK_SPEED_HZ, LT8912B_IO_I2C_AVI_ADDRESS);
+ ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_handle, &io_config_avi, &io_avi));
+
+ /* DPI config */
+#if CONFIG_BSP_LCD_HDMI_800x600_60HZ
+ ESP_LOGI(TAG, "HDMI configuration for 800x600@60HZ");
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_800x600_PANEL_60HZ_DPI_CONFIG();
+#elif CONFIG_BSP_LCD_HDMI_1024x768_60HZ
+ ESP_LOGI(TAG, "HDMI configuration for 1024x768@60HZ");
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_1024x768_PANEL_60HZ_DPI_CONFIG();
+#elif CONFIG_BSP_LCD_HDMI_1280x720_60HZ
+ ESP_LOGI(TAG, "HDMI configuration for 1280x720@60HZ");
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_1280x720_PANEL_60HZ_DPI_CONFIG();
+#elif CONFIG_BSP_LCD_HDMI_1280x800_60HZ
+ ESP_LOGI(TAG, "HDMI configuration for 1280x800@60HZ");
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_1280x800_PANEL_60HZ_DPI_CONFIG();
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_30HZ
+ ESP_LOGI(TAG, "HDMI configuration for 1920x1080@30HZ");
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_1920x1080_PANEL_30HZ_DPI_CONFIG();
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_60HZ
+ ESP_LOGI(TAG, "HDMI configuration for 1920x1080@60HZ");
+ /* This setting is not working yet, it is only for developing and testing */
+ esp_lcd_dpi_panel_config_t dpi_config = LT8912B_1920x1080_PANEL_60HZ_DPI_CONFIG();
+#else
+#error Unsupported display type
#endif
+ dpi_config.num_fbs = CONFIG_BSP_LCD_DPI_BUFFER_NUMS;
+ lt8912b_vendor_config_t vendor_config = {
+#if CONFIG_BSP_LCD_HDMI_800x600_60HZ
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_800x600_60Hz(),
+#elif CONFIG_BSP_LCD_HDMI_1024x768_60HZ
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_1024x768_60Hz(),
+#elif CONFIG_BSP_LCD_HDMI_1280x720_60HZ
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_1280x720_60Hz(),
+#elif CONFIG_BSP_LCD_HDMI_1280x800_60HZ
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_1280x800_60Hz(),
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_30HZ
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_1920x1080_30Hz(),
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_60HZ
+ /* This setting is not working yet, it is only for developing and testing */
+ .video_timing = ESP_LCD_LT8912B_VIDEO_TIMING_1920x1080_60Hz(),
+#else
+#error Unsupported display type
+#endif
+ .mipi_config = {
+ .dsi_bus = mipi_dsi_bus,
+ .dpi_config = &dpi_config,
+ .lane_num = BSP_LCD_MIPI_DSI_LANE_NUM,
+ },
+ };
+ const esp_lcd_panel_dev_config_t panel_config = {
+ .bits_per_pixel = 24,
+ .rgb_ele_order = BSP_LCD_COLOR_SPACE,
+ .reset_gpio_num = BSP_LCD_RST,
+ .vendor_config = &vendor_config,
+ };
+ const esp_lcd_panel_lt8912b_io_t io_all = {
+ .main = io,
+ .cec_dsi = io_cec_dsi,
+ .avi = io_avi,
+ };
+ ESP_ERROR_CHECK(esp_lcd_new_panel_lt8912b(&io_all, &panel_config, &disp_panel));
+ ESP_GOTO_ON_ERROR(esp_lcd_panel_reset(disp_panel), err, TAG, "LCD panel reset failed");
+ ESP_GOTO_ON_ERROR(esp_lcd_panel_init(disp_panel), err, TAG, "LCD panel init failed");
+
+#endif //CONFIG_BSP_LCD_TYPE_
/* Return all handles */
ret_handles->io = io;
@@ -488,7 +577,7 @@ esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_l
ret_handles->panel = disp_panel;
ret_handles->control = NULL;
- ESP_LOGI(TAG, "Display initialized");
+ ESP_LOGI(TAG, "Display initialized with resolution %dx%d", BSP_LCD_H_RES, BSP_LCD_V_RES);
return ret;
@@ -499,12 +588,21 @@ esp_err_t bsp_display_new_with_handles(const bsp_display_config_t *config, bsp_l
if (io) {
esp_lcd_panel_io_del(io);
}
+#if CONFIG_BSP_LCD_TYPE_HDMI
+ if (io_cec_dsi) {
+ esp_lcd_panel_io_del(io_cec_dsi);
+ }
+ if (io_avi) {
+ esp_lcd_panel_io_del(io_avi);
+ }
+#endif
if (mipi_dsi_bus) {
esp_lcd_del_dsi_bus(mipi_dsi_bus);
}
return ret;
}
+#if !CONFIG_BSP_LCD_TYPE_HDMI
esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t *ret_touch)
{
/* Initilize I2C */
@@ -537,6 +635,7 @@ esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c(i2c_handle, &tp_io_config, &tp_io_handle), TAG, "");
return esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, ret_touch);
}
+#endif //!CONFIG_BSP_LCD_TYPE_HDMI
#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0)
static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)
@@ -601,6 +700,7 @@ static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)
return lvgl_port_add_disp_dsi(&disp_cfg, &dpi_cfg);
}
+#if !CONFIG_BSP_LCD_TYPE_HDMI
static lv_indev_t *bsp_display_indev_init(lv_display_t *disp)
{
esp_lcd_touch_handle_t tp;
@@ -615,6 +715,7 @@ static lv_indev_t *bsp_display_indev_init(lv_display_t *disp)
return lvgl_port_add_touch(&touch_cfg);
}
+#endif //!CONFIG_BSP_LCD_TYPE_HDMI
lv_display_t *bsp_display_start(void)
{
@@ -645,9 +746,9 @@ lv_display_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg)
BSP_ERROR_CHECK_RETURN_NULL(bsp_display_brightness_init());
BSP_NULL_CHECK(disp = bsp_display_lcd_init(cfg), NULL);
-
+#if !CONFIG_BSP_LCD_TYPE_HDMI
BSP_NULL_CHECK(disp_indev = bsp_display_indev_init(disp), NULL);
-
+#endif
return disp;
}
diff --git a/bsp/esp32_p4_function_ev_board/idf_component.yml b/bsp/esp32_p4_function_ev_board/idf_component.yml
index 3536bae7..c2cf40e2 100644
--- a/bsp/esp32_p4_function_ev_board/idf_component.yml
+++ b/bsp/esp32_p4_function_ev_board/idf_component.yml
@@ -1,4 +1,4 @@
-version: "4.1.1"
+version: "4.2.0"
description: Board Support Package (BSP) for ESP32-P4 Function EV Board (preview)
url: https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_p4_function_ev_board
@@ -23,3 +23,7 @@ dependencies:
esp_codec_dev:
version: "1.2.*"
public: true
+
+ espressif/esp_lcd_lt8912b:
+ version: ">=0.1.0,<1.0.0"
+ override_path: "../../components/lcd/esp_lcd_lt8912b"
diff --git a/bsp/esp32_p4_function_ev_board/include/bsp/display.h b/bsp/esp32_p4_function_ev_board/include/bsp/display.h
index 68b9d0c2..97593857 100644
--- a/bsp/esp32_p4_function_ev_board/include/bsp/display.h
+++ b/bsp/esp32_p4_function_ev_board/include/bsp/display.h
@@ -47,6 +47,37 @@
#define BSP_LCD_MIPI_DSI_LCD_VSYNC (635)
#define BSP_LCD_MIPI_DSI_LCD_VBP (23)
#define BSP_LCD_MIPI_DSI_LCD_VFP (12)
+
+#elif CONFIG_BSP_LCD_TYPE_HDMI
+#if CONFIG_BSP_LCD_HDMI_800x600_60HZ
+/* LCD display definition 800x600 60Hz */
+#define BSP_LCD_H_RES (800)
+#define BSP_LCD_V_RES (600)
+#elif CONFIG_BSP_LCD_HDMI_1024x768_60HZ
+/* LCD display definition 1024x768 60Hz */
+#define BSP_LCD_H_RES (1024)
+#define BSP_LCD_V_RES (768)
+#elif CONFIG_BSP_LCD_HDMI_1280x720_60HZ
+/* LCD display definition 1280x720 60Hz */
+#define BSP_LCD_H_RES (1280)
+#define BSP_LCD_V_RES (720)
+#elif CONFIG_BSP_LCD_HDMI_1280x800_60HZ
+/* LCD display definition 1280x800 60Hz */
+#define BSP_LCD_H_RES (1280)
+#define BSP_LCD_V_RES (800)
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_30HZ
+/* LCD display definition 1920x1080 30Hz */
+#define BSP_LCD_H_RES (1920)
+#define BSP_LCD_V_RES (1080)
+#elif CONFIG_BSP_LCD_HDMI_1920x1080_60HZ
+/* LCD display definition 1920x1080 60Hz */
+/* This setting is not working yet, it is only for developing and testing */
+#define BSP_LCD_H_RES (1920)
+#define BSP_LCD_V_RES (1080)
+#else
+#error Unsupported display type
+#endif
+
#else
/* LCD display definition 1280x800 */
#define BSP_LCD_H_RES (800)
diff --git a/components/lcd/esp_lcd_lt8912b/CMakeLists.txt b/components/lcd/esp_lcd_lt8912b/CMakeLists.txt
new file mode 100644
index 00000000..abd1b9ee
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/CMakeLists.txt
@@ -0,0 +1,4 @@
+idf_component_register(SRCS "esp_lcd_lt8912b.c"
+ INCLUDE_DIRS "include"
+ REQUIRES "esp_lcd"
+ PRIV_REQUIRES "esp_driver_gpio")
diff --git a/components/lcd/esp_lcd_lt8912b/README.md b/components/lcd/esp_lcd_lt8912b/README.md
new file mode 100644
index 00000000..8a18e8bc
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/README.md
@@ -0,0 +1,24 @@
+# ESP LCD LT8912B
+
+[![Component Registry](https://components.espressif.com/components/espressif/esp_lcd_lt8912b/badge.svg)](https://components.espressif.com/components/espressif/esp_lcd_lt8912b)
+
+Implementation of the LT8912B MIPI-DSI to HDMI bridge with esp_lcd component.
+
+| LCD controller | Communication interface | Component name | Link to datasheet |
+| :------------: | :---------------------: | :------------: | :---------------: |
+| LT8912B | I2C | esp_lcd_lt8912b | [Specification](http://www.lontiumsemi.com/UploadFiles/2022-03/LT8912B_Brief_R1.3.pdf) |
+
+> [!WARNING]
+> This controller suports only RGB888 color mode.
+
+## Add to project
+
+Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/).
+You can add them to your project via `idf.py add-dependency`, e.g.
+
+```text
+idf.py add-dependency esp_lcd_lt8912b
+```
+
+Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
+
diff --git a/components/lcd/esp_lcd_lt8912b/esp_lcd_lt8912b.c b/components/lcd/esp_lcd_lt8912b/esp_lcd_lt8912b.c
new file mode 100644
index 00000000..1626e394
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/esp_lcd_lt8912b.c
@@ -0,0 +1,711 @@
+/*
+ * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+#include
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_lcd_panel_interface.h"
+#include "esp_lcd_panel_io.h"
+#include "esp_lcd_panel_vendor.h"
+#include "esp_lcd_panel_ops.h"
+#include "esp_lcd_panel_commands.h"
+#include "driver/gpio.h"
+#include "esp_log.h"
+#include "esp_check.h"
+#include "esp_lcd_lt8912b.h"
+
+#define ENABLE_TEST_PATTERN 0
+
+static const char *TAG = "lt8912b";
+
+static esp_err_t panel_lt8912b_del(esp_lcd_panel_t *panel);
+static esp_err_t panel_lt8912b_reset(esp_lcd_panel_t *panel);
+static esp_err_t panel_lt8912b_init(esp_lcd_panel_t *panel);
+static esp_err_t panel_lt8912b_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
+static esp_err_t panel_lt8912b_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
+static esp_err_t panel_lt8912b_disp_on_off(esp_lcd_panel_t *panel, bool off);
+static esp_err_t panel_lt8912b_sleep(esp_lcd_panel_t *panel, bool sleep);
+
+static esp_err_t _panel_lt8912b_detect_input_mipi(esp_lcd_panel_t *panel);
+static bool _panel_lt8912b_get_hpd(esp_lcd_panel_t *panel);
+
+typedef struct {
+ esp_lcd_panel_lt8912b_io_t io;
+ esp_lcd_panel_lt8912b_video_timing_t video_timing;
+ int reset_gpio_num;
+ bool reset_level;
+ uint8_t lane_num;
+ // To save the original functions of MIPI DPI panel
+ esp_err_t (*del)(esp_lcd_panel_t *panel);
+ esp_err_t (*init)(esp_lcd_panel_t *panel);
+} lt8912b_panel_t;
+
+typedef struct {
+ uint8_t cmd;
+ uint8_t data;
+} lt8912b_lcd_init_cmd_t;
+
+static const lt8912b_lcd_init_cmd_t cmd_digital_clock_en[] = {
+ // {cmd, data}
+
+ /* Digital clock en*/
+ {0x02, 0xf7},
+ {0x08, 0xff},
+ {0x09, 0xff},
+ {0x0a, 0xff},
+ {0x0b, 0x7c},
+ {0x0c, 0xff},
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_tx_analog[] = {
+ // {cmd, data}
+
+ /*Tx Analog*/
+ {0x31, 0xe1},
+ {0x32, 0xe1},
+ {0x33, 0x0c},
+ {0x37, 0x00},
+ {0x38, 0x22},
+ {0x60, 0x82},
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_cbus_analog[] = {
+ // {cmd, data}
+
+ /*Cbus Analog*/
+ {0x39, 0x45},
+ {0x3a, 0x00},
+ {0x3b, 0x00},
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_hdmi_pll_analog[] = {
+ // {cmd, data}
+
+ /*HDMI Pll Analog*/
+ {0x44, 0x31},
+ {0x55, 0x44},
+ {0x57, 0x01},
+ {0x5a, 0x02},
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_audio_iis_mode[] = {
+ // {cmd, data}
+
+ /*Audio IIs Mode */
+ {0xB2, 0x01}, //DVI mode:0x00; HDMI mode:0x01;
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_audio_iis_en[] = {
+ // {cmd, data}
+
+ /*Audio IIs En*/
+ {0x06, 0x08},
+ {0x07, 0xF0},
+ {0x34, 0xD2},
+ {0x0F, 0x2B},
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_lvds[] = {
+ // {cmd, data}
+
+ /* Lvds Power Up */
+ {0x44, 0x30},
+ {0x51, 0x05},
+
+ /*Lvds Bypass*/
+ {0x50, 0x24}, //cp=50uA
+ {0x51, 0x2d}, //Pix_clk as reference,second order passive LPF PLL
+ {0x52, 0x04}, //loopdiv=0;use second-order PLL
+ {0x69, 0x0e}, //CP_PRESET_DIV_RATIO
+ {0x69, 0x8e},
+ {0x6a, 0x00},
+ {0x6c, 0xb8}, //RGD_CP_SOFT_K_EN,RGD_CP_SOFT_K[13:8]
+ {0x6b, 0x51},
+
+ {0x04, 0xfb}, //core pll reset
+ {0x04, 0xff},
+
+ {0x7f, 0x00}, //disable scaler
+ {0xa8, 0x13}, //0x13:VSEA ; 0x33:JEIDA;
+};
+
+static const lt8912b_lcd_init_cmd_t cmd_dds_config[] = {
+ // {cmd, data}
+
+ /*DDS Config*/
+ {0x4e, 0x93}, //strm_sw_freq_word[ 7: 0]
+ {0x4f, 0x3E}, //strm_sw_freq_word[15: 8]
+ {0x50, 0x29}, //strm_sw_freq_word[23:16]
+ {0x51, 0x80}, //[0]=strm_sw_freq_word[24]
+ {0x1e, 0x4f},
+ {0x1f, 0x5e}, //full_value 464
+ {0x20, 0x01},
+ {0x21, 0x2c}, //full_value1 416
+ {0x22, 0x01},
+ {0x23, 0xfa}, //full_value2 400
+ {0x24, 0x00},
+ {0x25, 0xc8}, //full_value3 384
+ {0x26, 0x00},
+ {0x27, 0x5e}, //empty_value 464
+ {0x28, 0x01},
+ {0x29, 0x2c}, //empty_value1 416
+ {0x2a, 0x01},
+ {0x2b, 0xfa}, //empty_value2 400
+ {0x2c, 0x00},
+ {0x2d, 0xc8}, //empty_value3 384
+ {0x2e, 0x00},
+ {0x42, 0x64}, //tmr_set[ 7:0]:100us
+ {0x43, 0x00}, //tmr_set[15:8]:100us
+ {0x44, 0x04}, //timer step
+ {0x45, 0x00},
+ {0x46, 0x59},
+ {0x47, 0x00},
+ {0x48, 0xf2},
+ {0x49, 0x06},
+ {0x4a, 0x00},
+ {0x4b, 0x72},
+ {0x4c, 0x45},
+ {0x4d, 0x00},
+ {0x52, 0x08}, // trend step
+ {0x53, 0x00},
+ {0x54, 0xb2},
+ {0x55, 0x00},
+ {0x56, 0xe4},
+ {0x57, 0x0d},
+ {0x58, 0x00},
+ {0x59, 0xe4},
+ {0x5a, 0x8a},
+ {0x5b, 0x00},
+ {0x5c, 0x34},
+ {0x51, 0x00},
+};
+
+esp_err_t esp_lcd_new_panel_lt8912b(const esp_lcd_panel_lt8912b_io_t *io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
+{
+ ESP_RETURN_ON_FALSE(io && io->main && io->cec_dsi && io->avi && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+ lt8912b_vendor_config_t *vendor_config = (lt8912b_vendor_config_t *)panel_dev_config->vendor_config;
+ ESP_RETURN_ON_FALSE(vendor_config && vendor_config->mipi_config.dpi_config && vendor_config->mipi_config.dsi_bus, ESP_ERR_INVALID_ARG, TAG, "invalid vendor config");
+
+
+ esp_err_t ret = ESP_OK;
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)calloc(1, sizeof(lt8912b_panel_t));
+ ESP_RETURN_ON_FALSE(lt8912b, ESP_ERR_NO_MEM, TAG, "no mem for lt8912b panel");
+
+ if (panel_dev_config->reset_gpio_num >= 0) {
+ gpio_config_t io_conf = {
+ .mode = GPIO_MODE_OUTPUT,
+ .pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
+ };
+ ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
+ }
+
+ memcpy(<8912b->io, io, sizeof(esp_lcd_panel_lt8912b_io_t));
+ memcpy(<8912b->video_timing, &vendor_config->video_timing, sizeof(esp_lcd_panel_lt8912b_video_timing_t));
+ lt8912b->lane_num = vendor_config->mipi_config.lane_num;
+ lt8912b->reset_gpio_num = panel_dev_config->reset_gpio_num;
+ lt8912b->reset_level = panel_dev_config->flags.reset_active_high;
+
+ // Create MIPI DPI panel
+ ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, ret_panel), err, TAG,
+ "create MIPI DPI panel failed");
+ ESP_LOGD(TAG, "new MIPI DPI panel @%p", *ret_panel);
+
+ // Save the original functions of MIPI DPI panel
+ lt8912b->del = (*ret_panel)->del;
+ lt8912b->init = (*ret_panel)->init;
+ // Overwrite the functions of MIPI DPI panel
+ (*ret_panel)->del = panel_lt8912b_del;
+ (*ret_panel)->init = panel_lt8912b_init;
+ (*ret_panel)->reset = panel_lt8912b_reset;
+ (*ret_panel)->mirror = panel_lt8912b_mirror;
+ (*ret_panel)->invert_color = panel_lt8912b_invert_color;
+ (*ret_panel)->disp_on_off = panel_lt8912b_disp_on_off;
+ (*ret_panel)->disp_sleep = panel_lt8912b_sleep;
+ (*ret_panel)->user_data = lt8912b;
+ ESP_LOGD(TAG, "new lt8912b panel @%p", lt8912b);
+
+ return ESP_OK;
+
+err:
+ if (lt8912b) {
+ if (panel_dev_config->reset_gpio_num >= 0) {
+ gpio_reset_pin(panel_dev_config->reset_gpio_num);
+ }
+ free(lt8912b);
+ }
+ return ret;
+}
+
+bool esp_lcd_panel_lt8912b_is_ready(esp_lcd_panel_t *panel)
+{
+ _panel_lt8912b_detect_input_mipi(panel);
+ return _panel_lt8912b_get_hpd(panel);
+}
+
+static esp_err_t panel_lt8912b_del(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+
+ if (lt8912b->reset_gpio_num >= 0) {
+ gpio_reset_pin(lt8912b->reset_gpio_num);
+ }
+ // Delete MIPI DPI panel
+ lt8912b->del(panel);
+ free(lt8912b);
+ return ESP_OK;
+}
+
+static esp_err_t panel_lt8912b_reset(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+
+ // perform hardware reset
+ if (lt8912b->reset_gpio_num >= 0) {
+ gpio_set_level(lt8912b->reset_gpio_num, lt8912b->reset_level);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ gpio_set_level(lt8912b->reset_gpio_num, !lt8912b->reset_level);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ } else { // perform software reset
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io_main, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
+ vTaskDelay(pdMS_TO_TICKS(20)); // spec, wait at least 5ms before sending new command
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_data(esp_lcd_panel_io_handle_t io, uint8_t reg, uint8_t data)
+{
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, reg, (uint8_t []) {
+ data
+ }, 1), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_data_array(esp_lcd_panel_io_handle_t io, const lt8912b_lcd_init_cmd_t *cmds, uint16_t cmds_size)
+{
+ for (int i = 0; i < cmds_size; i++) {
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io, cmds[i].cmd, cmds[i].data), TAG, "send command failed");
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_mipi_analog(esp_lcd_panel_io_handle_t io_main, bool pn_swap)
+{
+ /* P/N swap or not */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x3e, (pn_swap ? 0xf6 : 0xd6)), TAG, "send command failed");
+
+ /* EQ */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x3f, 0xd4), TAG, "send command failed");
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x41, 0x3c), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_mipi_basic_set(esp_lcd_panel_io_handle_t io_cec, uint8_t lane_count, bool lane_swap)
+{
+ /* term en */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x10, 0x01), TAG, "send command failed");
+ /* settle */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x11, 0x10), TAG, "send command failed");
+ /* trail */
+ //ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x12, 0x08), TAG, "send command failed");
+ /* 00: 4 lane, 01: 1 lane, 02: 2 lane, 03: 3lane */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x13, lane_count), TAG, "send command failed");
+ /* debug mux */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x14, 0x00), TAG, "send command failed");
+ /* Lane swap */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x15, (lane_swap ? 0xa8 : 0x00)), TAG, "send command failed");
+
+ /* hshift 3 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x1a, 0x03), TAG, "send command failed");
+ /* vshift 3 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec, 0x1b, 0x03), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_video_setup(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_cec_dsi = lt8912b->io.cec_dsi;
+ esp_lcd_panel_lt8912b_video_timing_t *video_format = <8912b->video_timing;
+
+ /* hwidth */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x18, (uint8_t)(video_format->hs % 256)), TAG, "send command failed");
+ /* vwidth */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x19, (uint8_t)(video_format->vs % 256)), TAG, "send command failed");
+ /* H_active[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x1c, (uint8_t)(video_format->hact % 256)), TAG, "send command failed");
+ /* H_active[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x1d, (uint8_t)(video_format->hact / 256)), TAG, "send command failed");
+ /* fifo_buff_length 12 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x2f, 0x0c), TAG, "send command failed");
+ /* H_total[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x34, (uint8_t)(video_format->htotal % 256)), TAG, "send command failed");
+ /* H_total[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x35, (uint8_t)(video_format->htotal / 256)), TAG, "send command failed");
+ /* V_total[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x36, (uint8_t)(video_format->vtotal % 256)), TAG, "send command failed");
+ /* V_total[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x37, (uint8_t)(video_format->vtotal / 256)), TAG, "send command failed");
+ /* VBP[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x38, (uint8_t)(video_format->vbp % 256)), TAG, "send command failed");
+ /* VBP[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x39, (uint8_t)(video_format->vbp / 256)), TAG, "send command failed");
+ /* VFP[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3a, (uint8_t)(video_format->vfp % 256)), TAG, "send command failed");
+ /* VFP[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3b, (uint8_t)(video_format->vfp / 256)), TAG, "send command failed");
+ /* HBP[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3c, (uint8_t)(video_format->hbp % 256)), TAG, "send command failed");
+ /* HBP[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3d, (uint8_t)(video_format->hbp / 256)), TAG, "send command failed");
+ /* HFP[7:0] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3e, (uint8_t)(video_format->hfp % 256)), TAG, "send command failed");
+ /* HFP[15:8] */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x3f, (uint8_t)(video_format->hfp / 256)), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_send_avi_infoframe(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+ esp_lcd_panel_io_handle_t io_avi = lt8912b->io.avi;
+ esp_lcd_panel_lt8912b_video_timing_t *video_timing = <8912b->video_timing;
+
+ uint8_t vic = video_timing->vic;
+ uint8_t aspect_ratio = video_timing->aspect_ratio;
+ uint8_t pb0, pb2, pb4, sync_polarity;
+
+ /* enable null package */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x3c, 0x41), TAG, "send command failed");
+
+ sync_polarity = (video_timing->h_polarity * 0x02) + (video_timing->v_polarity * 0x01);
+ pb2 = (aspect_ratio << 4) + 0x08;
+ pb4 = vic;
+ pb0 = (((pb2 + pb4) <= 0x5f) ? (0x5f - pb2 - pb4) : (0x15f - pb2 - pb4));
+
+ /* sync polarity */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0xab, sync_polarity), TAG, "send command failed");
+
+ /* PB0:check sum */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x43, pb0), TAG, "send command failed");
+ /* PB1:RGB888 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x44, 0x10), TAG, "send command failed");
+ /* PB2 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x45, pb2), TAG, "send command failed");
+ /* PB3 */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x46, 0x00), TAG, "send command failed");
+ /* PB4:vic */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_avi, 0x47, pb4), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_mipi_rx_logic_reset(esp_lcd_panel_io_handle_t io_main)
+{
+ /* mipi rx reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x03, 0x7f), TAG, "send command failed");
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x03, 0xff), TAG, "send command failed");
+
+ /* DDS Reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x05, 0xfb), TAG, "send command failed");
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x05, 0xff), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_detect_input_mipi(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+
+ uint8_t hsync_l = 0, hsync_h = 0, vsync_l = 0, vsync_h = 0;
+
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_main, 0x9c, &hsync_l, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_main, 0x9d, &hsync_h, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_main, 0x9e, &vsync_l, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_main, 0x9f, &vsync_h, 1), TAG, "read data failed");
+
+ ESP_LOGI(TAG, "Detected MIPI input. H sync: 0x%02x 0x%02x, V sync: 0x%02x 0x%02x", hsync_h, hsync_l, vsync_h, vsync_l);
+
+
+ /* MIPI Video Setup */
+ //ESP_RETURN_ON_ERROR(_panel_lt8912b_send_video_setup(panel), TAG, "send command failed");
+
+ /* AVI Infoframe */
+ //ESP_RETURN_ON_ERROR(_panel_lt8912b_send_avi_infoframe(panel), TAG, "send command failed");
+
+ /* MIPI RX Logic Reset */
+ //ESP_RETURN_ON_ERROR(_panel_lt8912b_mipi_rx_logic_reset(io_main), TAG, "send command failed");
+
+ return ESP_OK;
+}
+
+static bool _panel_lt8912b_get_hpd(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+
+ uint8_t data = 0;
+ esp_lcd_panel_io_rx_param(io_main, 0xc1, &data, 1);
+
+ if ((data & 0x80) == 0x80) {
+ return true;
+ }
+ return false;
+}
+
+static esp_err_t _panel_lt8912b_lvds_output(esp_lcd_panel_io_handle_t io_main, bool on)
+{
+ if (on) {
+ /* lvds pll reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x02, 0xf7), TAG, "read data failed");
+ /* scaler module reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x02, 0xff), TAG, "read data failed");
+ /* lvds tx module reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x03, 0xcb), TAG, "read data failed");
+
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x03, 0xfb), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x03, 0xff), TAG, "read data failed");
+
+ /* enbale lvds output */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x44, 0x30), TAG, "read data failed");
+
+ ESP_LOGI(TAG, "LT8912 LVDS output enabled!");
+ } else {
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x44, 0x31), TAG, "read data failed");
+ ESP_LOGI(TAG, "LT8912 LVDS output disabled!");
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t _panel_lt8912b_hdmi_output(esp_lcd_panel_io_handle_t io_main, bool on)
+{
+ if (on) {
+ /* enable hdmi output */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x33, 0x0e), TAG, "read data failed");
+ ESP_LOGI(TAG, "LT8912 HDMI output enabled!");
+ } else {
+ /* disable hdmi output */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_main, 0x33, 0x0c), TAG, "read data failed");
+ ESP_LOGI(TAG, "LT8912 HDMI output disabled!");
+ }
+
+ return ESP_OK;
+}
+
+#if ENABLE_TEST_PATTERN
+static esp_err_t _panel_lt8912b_send_test(esp_lcd_panel_t *panel)
+{
+ uint32_t DDS_initial_value;
+ uint8_t pclk_Mhz;
+
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_cec_dsi = lt8912b->io.cec_dsi;
+ esp_lcd_panel_lt8912b_video_timing_t *video_format = <8912b->video_timing;
+
+ /************* Pattern resolution set *************/
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x72, 0x12), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x73, (uint8_t)((video_format->hs + video_format->hbp) % 256)), TAG, "send command failed"); //RGD_PTN_DE_DLY[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x74, (uint8_t)((video_format->hs + video_format->hbp) / 256)), TAG, "send command failed"); //RGD_PTN_DE_DLY[11:8]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x75, (uint8_t)((video_format->vs + video_format->vbp) % 256)), TAG, "send command failed"); //RGD_PTN_DE_TOP[6:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x76, (uint8_t)(video_format->hact % 256)), TAG, "send command failed"); //RGD_PTN_DE_CNT[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x77, (uint8_t)(video_format->vact % 256)), TAG, "send command failed"); //RGD_PTN_DE_LIN[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x78, ((((uint8_t)(video_format->vact / 256)) << 4) + ((uint8_t)(video_format->hact / 256)))), TAG, "send command failed"); //RGD_PTN_DE_LIN[10:8],RGD_PTN_DE_CNT[11:8]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x79, (uint8_t)(video_format->htotal % 256)), TAG, "send command failed"); //RGD_PTN_H_TOTAL[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x7a, (uint8_t)(video_format->vtotal % 256)), TAG, "send command failed"); //RGD_PTN_V_TOTAL[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x7b, ((((uint8_t)(video_format->vtotal / 256)) << 4) + ((uint8_t)(video_format->htotal / 256)))), TAG, "send command failed"); //RGD_PTN_V_TOTAL[10:8],RGD_PTN_H_TOTAL[11:8]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x7c, (uint8_t)(video_format->hs % 256)), TAG, "send command failed"); //RGD_PTN_HWIDTH[7:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x7d, ((((uint8_t)(video_format->hs / 256)) << 6) + ((uint8_t)(video_format->vs % 256)))), TAG, "send command failed"); //RGD_PTN_HWIDTH[9:8],RGD_PTN_VWIDTH[5:0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x70, 0x80), TAG, "send command failed"); //pattern enable
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x71, 0x51), TAG, "send command failed");
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x42, 0x12), TAG, "send command failed");
+ /**************************************************/
+
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x1e, 0x67), TAG, "send command failed"); //h v d pol hdmi sel pll sel
+
+
+ /************* Pattern pixl clock set *************/
+ uint32_t DDS_initial_value = (uint32_t)(video_format->pclk_mhz * 0x16C16);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x4e, (uint8_t)(DDS_initial_value & 0x000000ff)), TAG, "send command failed"); //strm_sw_freq_word[ 7: 0]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x4f, (uint8_t)((DDS_initial_value & 0x0000ff00) >> 8)), TAG, "send command failed"); //strm_sw_freq_word[15: 8]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x50, (uint8_t)((DDS_initial_value & 0x00ff0000) >> 16)), TAG, "send command failed"); //strm_sw_freq_word[23:16]
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x51, 0x80), TAG, "send command failed");
+
+// ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x4e, 0x3E), TAG, "send command failed"); //strm_sw_freq_word[ 7: 0]
+// ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x4f, 0xE9), TAG, "send command failed"); //strm_sw_freq_word[15: 8]
+// ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x50, 0xD3), TAG, "send command failed"); //strm_sw_freq_word[23:16]
+// ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data(io_cec_dsi, 0x51, 0x80), TAG, "send command failed"); //pattern en
+ /**************************************************/
+
+ ESP_LOGW(TAG, "Test pattern enabled!");
+
+ return ESP_OK;
+}
+#endif //ENABLE_TEST_PATTERN
+
+#if 0 //For testing purposes
+static esp_err_t _panel_lt8912b_read_dds(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_cec_dsi = lt8912b->io.cec_dsi;
+
+ uint8_t reg_920c = 0, reg_920d = 0, reg_920e = 0, reg_920f = 0;
+
+ for (int i = 0; i < 10; i++) {
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_cec_dsi, 0x0c, ®_920c, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_cec_dsi, 0x0d, ®_920d, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_cec_dsi, 0x0e, ®_920e, 1), TAG, "read data failed");
+ ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io_cec_dsi, 0x0f, ®_920f, 1), TAG, "read data failed");
+
+ ESP_LOGI(TAG, "DDS: 0x%02x 0x%02x 0x%02x 0x%02x", reg_920c, reg_920d, reg_920e, reg_920f);
+ if ((reg_920e == 0xd2) && (reg_920d < 0xff) && (reg_920d > 0xd0)) { //shall update threshold here base on actual dds result.
+ ESP_LOGI(TAG, "lvds_check_dds: stable!");
+ }
+ }
+
+ return ESP_OK;
+}
+#endif
+
+static esp_err_t panel_lt8912b_init(esp_lcd_panel_t *panel)
+{
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+ esp_lcd_panel_io_handle_t io_cec_dsi = lt8912b->io.cec_dsi;
+ esp_lcd_panel_io_handle_t io_avi = lt8912b->io.avi;
+
+ /* Digital Clock En */
+ uint16_t cmds_size = sizeof(cmd_digital_clock_en) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_digital_clock_en, cmds_size), TAG, "send command failed");
+
+ /* Tx Analog */
+ cmds_size = sizeof(cmd_tx_analog) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_tx_analog, cmds_size), TAG, "send command failed");
+
+ /* Cbus Analog */
+ cmds_size = sizeof(cmd_cbus_analog) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_cbus_analog, cmds_size), TAG, "send command failed");
+
+ /* HDMI Pll Analog */
+ cmds_size = sizeof(cmd_hdmi_pll_analog) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_hdmi_pll_analog, cmds_size), TAG, "send command failed");
+
+ /* Mipi Analog - Set P/N swap */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_mipi_analog(io_main, false), TAG, "send command failed");
+
+ /* Mipi Basic Set - lines count, lines swapped */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_mipi_basic_set(io_cec_dsi, 2, false), TAG, "send command failed");
+
+ /* DDS Config */
+ cmds_size = sizeof(cmd_dds_config) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_cec_dsi, cmd_dds_config, cmds_size), TAG, "send command failed");
+
+ /* MIPI Video Setup */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_video_setup(panel), TAG, "send command failed");
+
+ /* MIPI Input detection */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_detect_input_mipi(panel), TAG, "send command failed");
+
+ /* MIPI Video Setup */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_video_setup(panel), TAG, "send command failed");
+
+ /* AVI Infoframe */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_avi_infoframe(panel), TAG, "send command failed");
+
+ /* MIPI RX Logic Reset */
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_mipi_rx_logic_reset(io_main), TAG, "send command failed");
+
+ /* Audio IIs Mode */
+ cmds_size = sizeof(cmd_audio_iis_mode) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_audio_iis_mode, cmds_size), TAG, "send command failed");
+
+ /* Audio IIs En */
+ cmds_size = sizeof(cmd_audio_iis_en) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_avi, cmd_audio_iis_en, cmds_size), TAG, "send command failed");
+
+ /* Lvds Bypass */
+ cmds_size = sizeof(cmd_lvds) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_send_data_array(io_main, cmd_lvds, cmds_size), TAG, "send command failed");
+
+ /* LVDS Enable */
+ cmds_size = sizeof(cmd_lvds) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_lvds_output(io_main, false), TAG, "send command failed");
+
+ /* HDMI Enable */
+ cmds_size = sizeof(cmd_lvds) / sizeof(lt8912b_lcd_init_cmd_t);
+ ESP_RETURN_ON_ERROR(_panel_lt8912b_hdmi_output(io_main, true), TAG, "send command failed");
+
+#if ENABLE_TEST_PATTERN
+ /* Show test pattern - debug */
+ _panel_lt8912b_send_test(panel);
+#endif //ENABLE_TEST_PATTERN
+
+ ESP_RETURN_ON_ERROR(lt8912b->init(panel), TAG, "init MIPI DPI panel failed");
+
+ return ESP_OK;
+}
+
+static esp_err_t panel_lt8912b_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
+{
+ return ESP_ERR_NOT_SUPPORTED;
+}
+
+static esp_err_t panel_lt8912b_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
+{
+ ESP_LOGW(TAG, "Mirror is not supported in LT8912B driver. Please use SW rotation.");
+ return ESP_ERR_NOT_SUPPORTED;
+}
+
+static esp_err_t panel_lt8912b_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
+{
+ return ESP_ERR_NOT_SUPPORTED;
+}
+
+static esp_err_t panel_lt8912b_sleep(esp_lcd_panel_t *panel, bool sleep)
+{
+ esp_err_t ret = ESP_OK;
+ lt8912b_panel_t *lt8912b = (lt8912b_panel_t *)panel->user_data;
+ esp_lcd_panel_io_handle_t io_main = lt8912b->io.main;
+
+ if (sleep) {
+ ret |= _panel_lt8912b_send_data(io_main, 0x54, 0x1d);
+ ret |= _panel_lt8912b_send_data(io_main, 0x51, 0x15);
+ ret |= _panel_lt8912b_send_data(io_main, 0x44, 0x31);
+ ret |= _panel_lt8912b_send_data(io_main, 0x41, 0xbd);
+ ret |= _panel_lt8912b_send_data(io_main, 0x5c, 0x11);
+ } else {
+ ret |= _panel_lt8912b_send_data(io_main, 0x5c, 0x10);
+ ret |= _panel_lt8912b_send_data(io_main, 0x54, 0x1c);
+ ret |= _panel_lt8912b_send_data(io_main, 0x51, 0x2d);
+ ret |= _panel_lt8912b_send_data(io_main, 0x44, 0x30);
+ ret |= _panel_lt8912b_send_data(io_main, 0x41, 0xbc);
+
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ret |= _panel_lt8912b_send_data(io_main, 0x03, 0x7f);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ret |= _panel_lt8912b_send_data(io_main, 0x03, 0xff);
+
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ret |= _panel_lt8912b_send_data(io_main, 0x05, 0xfb);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ ret |= _panel_lt8912b_send_data(io_main, 0x05, 0xff);
+ }
+ vTaskDelay(pdMS_TO_TICKS(100));
+
+ return ret;
+}
diff --git a/components/lcd/esp_lcd_lt8912b/idf_component.yml b/components/lcd/esp_lcd_lt8912b/idf_component.yml
new file mode 100644
index 00000000..964a358b
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/idf_component.yml
@@ -0,0 +1,7 @@
+version: "0.1.0"
+description: ESP LCD LT8912B (MIPI DSI - HDMI)
+url: https://github.com/espressif/esp-bsp/tree/master/components/lcd/esp_lcd_lt8912b
+repository: "https://github.com/espressif/esp-bsp.git"
+issues: "https://github.com/espressif/esp-bsp/issues" # URL of the issue tracker
+dependencies:
+ idf: ">=5.3"
diff --git a/components/lcd/esp_lcd_lt8912b/include/esp_lcd_lt8912b.h b/components/lcd/esp_lcd_lt8912b/include/esp_lcd_lt8912b.h
new file mode 100644
index 00000000..0b669ce3
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/include/esp_lcd_lt8912b.h
@@ -0,0 +1,402 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/**
+ * @file
+ * @brief ESP LCD: LT8912B
+ */
+
+#pragma once
+
+#include "esp_lcd_panel_vendor.h"
+#include "esp_lcd_mipi_dsi.h"
+#include "esp_lcd_panel_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief LCD IO handles.
+ */
+typedef struct {
+ esp_lcd_panel_io_handle_t main;
+ esp_lcd_panel_io_handle_t cec_dsi;
+ esp_lcd_panel_io_handle_t avi;
+} esp_lcd_panel_lt8912b_io_t;
+
+/**
+ * @brief LCD panel video timing configuration.
+ */
+typedef struct {
+ uint16_t hfp;
+ uint16_t hs;
+ uint16_t hbp;
+ uint16_t hact;
+ uint16_t htotal;
+ uint16_t vfp;
+ uint16_t vs;
+ uint16_t vbp;
+ uint16_t vact;
+ uint16_t vtotal;
+ bool h_polarity;
+ bool v_polarity;
+ uint16_t vic;
+ uint8_t aspect_ratio; // 0=no data, 1=4:3, 2=16:9, 3=no data.
+ uint32_t pclk_mhz;
+} esp_lcd_panel_lt8912b_video_timing_t;
+
+/**
+ * @brief LCD panel vendor configuration.
+ *
+ * @note This structure needs to be passed to the `esp_lcd_panel_dev_config_t::vendor_config`.
+ *
+ */
+typedef struct {
+ esp_lcd_panel_lt8912b_video_timing_t video_timing; /*!< Video timing settings for HDMI */
+ struct {
+ esp_lcd_dsi_bus_handle_t dsi_bus; /*!< MIPI-DSI bus configuration */
+ const esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */
+ uint8_t lane_num; /*!< Number of MIPI-DSI lanes */
+ } mipi_config;
+} lt8912b_vendor_config_t;
+
+/**
+ * @brief Create LCD control panel for LT8912B
+ *
+ * @param[in] io LCD panel IO handles
+ * @param[in] panel_dev_config general panel device configuration
+ * @param[out] ret_panel Returned LCD panel handle
+ * @return
+ * - ESP_OK: Create LCD panel successfully
+ * - ESP_ERR_INVALID_ARG: Create LCD panel failed because of invalid arguments
+ * - ESP_ERR_NO_MEM: Create LCD panel failed because of memory allocation failure
+ * - ESP_FAIL: Create LCD panel failed because of other errors
+ */
+esp_err_t esp_lcd_new_panel_lt8912b(const esp_lcd_panel_lt8912b_io_t *io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
+
+/**
+ * @brief Return true if HDMI is ready
+ *
+ * @param[in] panel LCD panel handle
+ * @return
+ * - true when ready
+ */
+bool esp_lcd_panel_lt8912b_is_ready(esp_lcd_panel_t *panel);
+
+/**
+ * @brief I2C address of the LT8912B controller
+ *
+ */
+#define LT8912B_IO_I2C_MAIN_ADDRESS (0x48)
+#define LT8912B_IO_I2C_CEC_ADDRESS (0x49)
+#define LT8912B_IO_I2C_AVI_ADDRESS (0x4A)
+
+
+#define LT8912B_ASPECT_RATION_NO 0x00
+#define LT8912B_ASPECT_RATION_4_3 0x01
+#define LT8912B_ASPECT_RATION_16_9 0x02
+
+/**
+ * @brief MIPI-DSI bus configuration structure
+ *
+ */
+#define LT8912B_PANEL_BUS_DSI_2CH_CONFIG() \
+ { \
+ .bus_id = 0, \
+ .num_data_lanes = 2, \
+ .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, \
+ .lane_bit_rate_mbps = 1000, \
+ }
+
+/**
+ * @brief MIPI-I2C panel IO configuration structure
+ *
+ */
+#define LT8912B_IO_CFG(clk_speed_hz, address) \
+ { \
+ .scl_speed_hz = clk_speed_hz, \
+ .dev_addr = address, \
+ .control_phase_bytes = 1, \
+ .lcd_cmd_bits = 8, \
+ .lcd_param_bits = 8, \
+ .dc_bit_offset = 0, \
+ .flags = \
+ { \
+ .disable_control_phase = 1, \
+ } \
+ }
+
+/**
+ * @brief Video timing configuration structure (800x600 60Hz)
+ *
+ */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_800x600_60Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 128, \
+ .hbp = 88, \
+ .hact = 800, \
+ .htotal = 1056, \
+ .vfp = 1, \
+ .vs = 4, \
+ .vbp = 23, \
+ .vact = 600, \
+ .vtotal = 628, \
+ .h_polarity = 1, \
+ .v_polarity = 1, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 40, \
+ }
+
+#define LT8912B_800x600_PANEL_60HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 40, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 88, \
+ .hsync_pulse_width = 128, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 23, \
+ .vsync_pulse_width = 4, \
+ .vsync_front_porch = 1, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+/**
+ * @brief Video timing configuration structure (1024x768 60Hz)
+ *
+ */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_1024x768_60Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 32, \
+ .hbp = 80, \
+ .hact = 1024, \
+ .htotal = 1184, \
+ .vfp = 3, \
+ .vs = 4, \
+ .vbp = 15, \
+ .vact = 768, \
+ .vtotal = 790, \
+ .h_polarity = 1, \
+ .v_polarity = 0, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 56, \
+ }
+
+#define LT8912B_1024x768_PANEL_60HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 56, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 80, \
+ .hsync_pulse_width = 32, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 15, \
+ .vsync_pulse_width = 4, \
+ .vsync_front_porch = 3, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+/**
+ * @brief Video timing configuration structure (1280x720 60Hz)
+ *
+ */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_1280x720_60Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 32, \
+ .hbp = 80, \
+ .hact = 1280, \
+ .htotal = 1440, \
+ .vfp = 3, \
+ .vs = 5, \
+ .vbp = 13, \
+ .vact = 720, \
+ .vtotal = 741, \
+ .h_polarity = 1, \
+ .v_polarity = 0, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 64, \
+ }
+
+#define LT8912B_1280x720_PANEL_60HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 64, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 80, \
+ .hsync_pulse_width = 32, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 13, \
+ .vsync_pulse_width = 5, \
+ .vsync_front_porch = 3, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+/**
+ * @brief Video timing configuration structure (1280x800 60Hz)
+ *
+ */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_1280x800_60Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 32, \
+ .hbp = 80, \
+ .hact = 1280, \
+ .htotal = 1440, \
+ .vfp = 3, \
+ .vs = 6, \
+ .vbp = 14, \
+ .vact = 800, \
+ .vtotal = 823, \
+ .h_polarity = 1, \
+ .v_polarity = 0, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 70, \
+ }
+
+#define LT8912B_1280x800_PANEL_60HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 70, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 80, \
+ .hsync_pulse_width = 32, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 14, \
+ .vsync_pulse_width = 6, \
+ .vsync_front_porch = 3, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+/**
+ * @brief Video timing configuration structure (1920x1080 30Hz)
+ *
+ */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_1920x1080_30Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 32, \
+ .hbp = 80, \
+ .hact = 1920, \
+ .htotal = 2080, \
+ .vfp = 3, \
+ .vs = 5, \
+ .vbp = 8, \
+ .vact = 1080, \
+ .vtotal = 1096, \
+ .h_polarity = 1, \
+ .v_polarity = 0, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 70, \
+ }
+
+#define LT8912B_1920x1080_PANEL_30HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 70, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 80, \
+ .hsync_pulse_width = 32, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 8, \
+ .vsync_pulse_width = 5, \
+ .vsync_front_porch = 3, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+/**
+ * @brief Video timing configuration structure (1920x1080 60Hz)
+ *
+ */
+
+/* This setting is not working yet, it is only for developing and testing */
+#define ESP_LCD_LT8912B_VIDEO_TIMING_1920x1080_60Hz() \
+ { \
+ .hfp = 48, \
+ .hs = 32, \
+ .hbp = 80, \
+ .hact = 1920, \
+ .htotal = 2080, \
+ .vfp = 3, \
+ .vs = 5, \
+ .vbp = 19, \
+ .vact = 1080, \
+ .vtotal = 1107, \
+ .h_polarity = 1, \
+ .v_polarity = 0, \
+ .vic = 0, \
+ .aspect_ratio = LT8912B_ASPECT_RATION_16_9, \
+ .pclk_mhz = 120, \
+ }
+
+/* This setting is not working yet, it is only for developing and testing */
+#define LT8912B_1920x1080_PANEL_60HZ_DPI_CONFIG() \
+ { \
+ .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
+ .dpi_clock_freq_mhz = 120, \
+ .virtual_channel = 0, \
+ .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, \
+ .num_fbs = 1, \
+ .video_timing = { \
+ .h_size = BSP_LCD_H_RES, \
+ .v_size = BSP_LCD_V_RES, \
+ .hsync_back_porch = 80, \
+ .hsync_pulse_width = 32, \
+ .hsync_front_porch = 48, \
+ .vsync_back_porch = 19, \
+ .vsync_pulse_width = 5, \
+ .vsync_front_porch = 3, \
+ }, \
+ .flags.use_dma2d = true, \
+ .flags.disable_lp = true, \
+ }
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/components/lcd/esp_lcd_lt8912b/license.txt b/components/lcd/esp_lcd_lt8912b/license.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/components/lcd/esp_lcd_lt8912b/license.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/docu/pics/Lontium.webp b/docu/pics/Lontium.webp
new file mode 100644
index 00000000..4b3281d4
Binary files /dev/null and b/docu/pics/Lontium.webp differ