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