Files
BPI-M2C/MPI_DSI/0002-uboot-auto-select-hdmi-or-mipi.patch
2026-09-22 09:38:26 +08:00

198 lines
6.1 KiB
Diff

From: Codex <[email protected]>
Subject: [PATCH 2/2] video: sprd: select HDMI by sink EDID
The LT8912B is a DSI-to-HDMI bridge and does not answer a MIPI DCS panel
ID transaction. Its HPD status register also reads low before the bridge
has been fully configured, which caused a connected HDMI sink to be missed.
The 2h10 board routes HDMI DDC to AP I2C3. Enable HDMI power, read the
standard EDID header at address 0x50 using 100 kHz DDC, and select DSI0 only
when a real HDMI sink responds. Otherwise power the bridge down and continue
probing the ILI9881 panel on DSI1. HDMI has priority if both are connected.
---
arch/arm/dts/lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi | 9 +-
arch/arm/dts/uis7885_2h10.dts | 4 +
drivers/video/sprd/sprd_panel.c | 104 +++++++++++++++++++++-
3 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/arch/arm/dts/lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi b/arch/arm/dts/lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi
--- a/arch/arm/dts/lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi
+++ b/arch/arm/dts/lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi
@@ -17,13 +17,14 @@
/* panel interface type: 2:MIPI; 3:SPI */
sprd,panel-if-type = <2>;
+ sprd,mipi-port = <0>;
sprd,video-lp-cmd-enable = <0>;
sprd,hporch-lp-disable = <1>;
- /*----Id register ----*/
- sprd,lcd-id-register = [F4];
- sprd,lcd-id-value-len = <1>;
- sprd,lcd-id-value = [96];
+ /* LT8912B has no MIPI DCS panel ID; detect the sink by EDID. */
+ sprd,detect-lt8912b-hdmi;
+ sprd,hdmi-ddc-i2c-bus = <3>;
+ sprd,hdmi-ddc-i2c-addr = <0x50>;
sprd,lcd-id-tokernel = <0x96>;
sprd,reset-on-sequence = <1 5>, <0 5>, <1 5>, <0 5>, <1 20>;
diff --git a/arch/arm/dts/uis7885_2h10.dts b/arch/arm/dts/uis7885_2h10.dts
--- a/arch/arm/dts/uis7885_2h10.dts
+++ b/arch/arm/dts/uis7885_2h10.dts
@@ -190,6 +190,10 @@
sprd,lcd-avdd-gpio = <&ap_gpio 153 GPIO_ACTIVE_HIGH>;
sprd,lcd-avee-gpio = <&ap_gpio 178 GPIO_ACTIVE_HIGH>;
sprd,lcd-reset-gpio = <&ap_gpio 152 GPIO_ACTIVE_HIGH>;
+
+ /* LT8912B HDMI bridge power and reset */
+ sprd,hdmi-power-gpio = <&ap_gpio 99 GPIO_ACTIVE_HIGH>;
+ sprd,hdmi-reset-gpio = <&ap_gpio 11 GPIO_ACTIVE_HIGH>;
};
lcd-video {
diff --git a/drivers/video/sprd/sprd_panel.c b/drivers/video/sprd/sprd_panel.c
--- a/drivers/video/sprd/sprd_panel.c
+++ b/drivers/video/sprd/sprd_panel.c
@@ -21,7 +21,10 @@
#include <fdtdec.h>
#include <asm/global_data.h>
#include <dm.h>
+#include <i2c.h>
#include <panel.h>
+#include <linux/delay.h>
+#include <asm-generic/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -30,6 +33,93 @@
static struct panel_driver lcd_drv;
struct panel_info panel_device;
+static int lt8912b_hdmi_detect(struct udevice *dev, const void *fdt,
+ int panel_offset)
+{
+ static const u8 edid_header[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+ };
+ struct gpio_desc power_gpio;
+ struct gpio_desc reset_gpio;
+ struct udevice *chip;
+ u32 bus = 3, addr = 0x50;
+ u8 header[sizeof(edid_header)];
+ int retry;
+ int ret;
+
+ fdt_getprop_u32(fdt, panel_offset, "sprd,hdmi-ddc-i2c-bus", &bus);
+ fdt_getprop_u32(fdt, panel_offset, "sprd,hdmi-ddc-i2c-addr", &addr);
+
+ ret = gpio_request_by_name(dev, "sprd,hdmi-power-gpio", 0,
+ &power_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ pr_err("LT8912B: request power gpio failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "sprd,hdmi-reset-gpio", 0,
+ &reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ pr_err("LT8912B: request reset gpio failed: %d\n", ret);
+ dm_gpio_free(dev, &power_gpio);
+ return ret;
+ }
+
+ dm_gpio_set_value(&power_gpio, 1);
+ mdelay(5);
+ dm_gpio_set_value(&reset_gpio, 1);
+ mdelay(5);
+ dm_gpio_set_value(&reset_gpio, 0);
+ mdelay(5);
+ dm_gpio_set_value(&reset_gpio, 1);
+ mdelay(100);
+
+ ret = i2c_get_chip_for_busnum(bus, addr, 1, &chip);
+ if (ret) {
+ pr_err("LT8912B: cannot access HDMI DDC i2c%u addr 0x%x: %d\n",
+ bus, addr, ret);
+ goto not_connected;
+ }
+
+ /* EDID/DDC is standard-mode I2C. Some sinks reject a 400 kHz read. */
+ ret = dm_i2c_set_bus_speed(dev_get_parent(chip), 100000);
+ if (ret) {
+ pr_err("LT8912B: cannot set HDMI DDC speed: %d\n", ret);
+ goto not_connected;
+ }
+
+ for (retry = 0; retry < 3; retry++) {
+ memset(header, 0, sizeof(header));
+ ret = dm_i2c_read(chip, 0, header, sizeof(header));
+ /* The sprd I2C driver returns the transferred message count. */
+ if (ret >= 0 &&
+ !memcmp(header, edid_header, sizeof(edid_header)))
+ break;
+ mdelay(20);
+ }
+
+ if (retry == 3) {
+ pr_info("LT8912B: HDMI sink not detected by EDID "
+ "(ret=%d, header=%02x %02x %02x %02x %02x %02x %02x %02x)\n",
+ ret, header[0], header[1], header[2], header[3],
+ header[4], header[5], header[6], header[7]);
+ ret = -ENODEV;
+ goto not_connected;
+ }
+
+ pr_info("LT8912B: HDMI sink detected by EDID\n");
+ dm_gpio_free(dev, &reset_gpio);
+ dm_gpio_free(dev, &power_gpio);
+ return 0;
+
+not_connected:
+ dm_gpio_set_value(&reset_gpio, 0);
+ dm_gpio_set_value(&power_gpio, 0);
+ dm_gpio_free(dev, &reset_gpio);
+ dm_gpio_free(dev, &power_gpio);
+ return ret;
+}
+
#ifdef CONFIG_BACKLIGHT_I2C
void set_backlight(int brightness)
{
@@ -828,6 +914,7 @@ static int sprd_panel_probe(struct udevice *dev)
int lcd_panel_offset = 0;
int info_size;
bool panel_powered;
+ bool detect_lt8912b;
struct udevice *panel_dev = NULL;
const void *fdt = gd->fdt_blob;
@@ -884,13 +971,24 @@ static int sprd_panel_probe(struct udevice *dev)
of_parse_panel(fdt, offset, info);
of_parse_timing(fdt, offset, info);
}
+ detect_lt8912b = fdt_getprop(fdt, offset,
+ "sprd,detect-lt8912b-hdmi", NULL) != NULL;
//get ops
if(info->mipi_port == 0)
panel_if_init();
else
panel_slave_if_init();
ops = panel_drv->ops;
- if (ops && ops->power) {
+ if (detect_lt8912b) {
+ ret = lt8912b_hdmi_detect(dev, fdt, offset);
+ if (ret)
+ goto panel_probe_failed;
+
+ of_parse_initdata(fdt, offset, info);
+ printf("attach HDMI bridge 0x%x success\n",
+ info->lcd_id);
+ break;
+ } else if (ops && ops->power) {
printf("enter power panel\n");
ret = ops->power(dev, true);
if (ret) {
--
2.34.1