[PATCH] video: panel-startek-kd070fhfid078: new driver

David Lechner <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <20260814-mtk-video-panel-startek-078-v1-1-5f84a57244bc@baylibre.com>
Add a driver for the Startek KD070FHFID078 7" DSI panel. This panel is
used on the MediaTek Genio 360 EVK board.

Signed-off-by: David Lechner <[email protected]>
---
 MAINTAINERS                                 |   6 +
 drivers/video/Kconfig                       |  10 +
 drivers/video/Makefile                      |   1 +
 drivers/video/panel-startek-kd070fhfid078.c | 288 ++++++++++++++++++++++++++++
 4 files changed, 305 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index acaba95ed03..faef7b0aa2c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1750,6 +1750,12 @@ F:	common/stackprot.c
 F:	cmd/stackprot_test.c
 F:	test/py/tests/test_stackprotector.py
 
+STARTEK KD070FHFID078 PANEL
+M:	David Lechner <[email protected]>
+R:	GSS_MTK_Uboot_upstream <[email protected]>
+S:	Maintained
+F:	drivers/video/panel-startek-kd070fhfid078.c
+
 TARGET_BCMNS3
 M:	Rayagonda Kokatanur <[email protected]>
 S:	Maintained
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 15000e21840..64921155a54 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -320,6 +320,16 @@ config PANEL_HX8238D
 	  It can drive a maximum 960x240 dot graphics on a-TFT panel
 	  displays in 16M colors with dithering.
 
+config PANEL_STARTEK_KD070FHFID078
+	bool "STARTEK KD070FHFID078 panel"
+	depends on PANEL && DM_GPIO
+	select VIDEO_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for STARTEK KD070FHFID078 DSI panel.
+	  The panel is a 7-inch TFT LCD display with a resolution of 1200 x 1920
+	  pixels. It provides a MIPI DSI interface to the host, a built-in LED
+	  backlight and touch controller.
+
 config VIDEO_BOCHS
 	bool "Enable Bochs video emulation for QEMU"
 	help
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 082b8967982..bbde29a1cb0 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_$(PHASE_)VIDEO) += video-uclass.o vidconsole-uclass.o
 obj-$(CONFIG_$(PHASE_)VIDEO) += video_bmp.o
 obj-$(CONFIG_$(PHASE_)PANEL) += panel-uclass.o
 obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o
+obj-$(CONFIG_PANEL_STARTEK_KD070FHFID078) += panel-startek-kd070fhfid078.o
 obj-$(CONFIG_$(PHASE_)SIMPLE_PANEL) += simple_panel.o
 
 obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.bmp.o
diff --git a/drivers/video/panel-startek-kd070fhfid078.c b/drivers/video/panel-startek-kd070fhfid078.c
new file mode 100644
index 00000000000..8b96fe727bd
--- /dev/null
+++ b/drivers/video/panel-startek-kd070fhfid078.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2016 InforceComputing
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2025 MediaTek Inc.
+ * Copyright (C) 2026 BayLibre, SAS
+ *
+ * Authors:
+ * - Vinay Simha BN <[email protected]>
+ * - Sumit Semwal <[email protected]>
+ * - Guillaume La Roque <[email protected]>
+ * - Jitao Shi <[email protected]>
+ * - David Lechner <[email protected]>
+ */
+
+#include <asm-generic/gpio.h>
+#include <backlight.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <linux/delay.h>
+#include <mipi_dsi.h>
+#include <panel.h>
+#include <power/regulator.h>
+
+struct stk078_panel {
+	const struct drm_display_mode *mode;
+	struct udevice *dev;
+	struct gpio_desc *enable_gpio;
+	struct gpio_desc *reset_gpio;
+	struct mipi_dsi_device *dsi;
+	struct udevice *iovcc;
+	struct udevice *vdd;
+	struct udevice *backlight;
+};
+
+static const struct drm_display_mode default_mode = {
+	.clock = 157126,
+	.hdisplay = 1200,
+	.hsync_start = 1200 + 50,
+	.hsync_end = 1200 + 50 + 10,
+	.htotal = 1200 + 50 + 10 + 70,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 25,
+	.vsync_end = 1920 + 25 + 4,
+	.vtotal = 1920 + 25 + 4 + 20,
+};
+
+static int stk078_panel_init(struct stk078_panel *stk)
+{
+	struct mipi_dsi_device *dsi = stk->dsi;
+
+	mipi_dsi_generic_write_seq(dsi, 0xB0, 0x05);
+	mipi_dsi_generic_write_seq(dsi, 0xB3, 0x52);
+	mipi_dsi_generic_write_seq(dsi, 0xB8, 0x7F);
+	mipi_dsi_generic_write_seq(dsi, 0xBC, 0x20);
+	mipi_dsi_generic_write_seq(dsi, 0xD6, 0x7F);
+	mipi_dsi_generic_write_seq(dsi, 0xB0, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xC0, 0x0D);
+	mipi_dsi_generic_write_seq(dsi, 0xC1, 0x0D);
+	mipi_dsi_generic_write_seq(dsi, 0xC2, 0x06);
+	mipi_dsi_generic_write_seq(dsi, 0xC3, 0x06);
+	mipi_dsi_generic_write_seq(dsi, 0xC4, 0x08);
+	mipi_dsi_generic_write_seq(dsi, 0xC5, 0x08);
+	mipi_dsi_generic_write_seq(dsi, 0xC6, 0x0A);
+	mipi_dsi_generic_write_seq(dsi, 0xC7, 0x0A);
+	mipi_dsi_generic_write_seq(dsi, 0xC8, 0x0C);
+	mipi_dsi_generic_write_seq(dsi, 0xC9, 0x0C);
+	mipi_dsi_generic_write_seq(dsi, 0xCA, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xCB, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xCC, 0x0E);
+	mipi_dsi_generic_write_seq(dsi, 0xCD, 0x0E);
+	mipi_dsi_generic_write_seq(dsi, 0xCE, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xCF, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xD0, 0x04);
+	mipi_dsi_generic_write_seq(dsi, 0xD1, 0x04);
+	mipi_dsi_generic_write_seq(dsi, 0xD2, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xD3, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xD4, 0x0D);
+	mipi_dsi_generic_write_seq(dsi, 0xD5, 0x0D);
+	mipi_dsi_generic_write_seq(dsi, 0xD6, 0x05);
+	mipi_dsi_generic_write_seq(dsi, 0xD7, 0x05);
+	mipi_dsi_generic_write_seq(dsi, 0xD8, 0x07);
+	mipi_dsi_generic_write_seq(dsi, 0xD9, 0x07);
+	mipi_dsi_generic_write_seq(dsi, 0xDA, 0x09);
+	mipi_dsi_generic_write_seq(dsi, 0xDB, 0x09);
+	mipi_dsi_generic_write_seq(dsi, 0xDC, 0x0B);
+	mipi_dsi_generic_write_seq(dsi, 0xDD, 0x0B);
+	mipi_dsi_generic_write_seq(dsi, 0xDE, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xDF, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xE0, 0x0E);
+	mipi_dsi_generic_write_seq(dsi, 0xE1, 0x0E);
+	mipi_dsi_generic_write_seq(dsi, 0xE2, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xE3, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xE4, 0x03);
+	mipi_dsi_generic_write_seq(dsi, 0xE5, 0x03);
+	mipi_dsi_generic_write_seq(dsi, 0xE6, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xE7, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xB0, 0x03);
+	mipi_dsi_generic_write_seq(dsi, 0xBA, 0xF0);
+	mipi_dsi_generic_write_seq(dsi, 0xC8, 0x07);
+	mipi_dsi_generic_write_seq(dsi, 0xC9, 0x03);
+	mipi_dsi_generic_write_seq(dsi, 0xCA, 0x41);
+	mipi_dsi_generic_write_seq(dsi, 0xD2, 0x01);
+	mipi_dsi_generic_write_seq(dsi, 0xD3, 0x05);
+	mipi_dsi_generic_write_seq(dsi, 0xD4, 0x05);
+	mipi_dsi_generic_write_seq(dsi, 0xD5, 0x8A);
+	mipi_dsi_generic_write_seq(dsi, 0xE4, 0xC0);
+	mipi_dsi_generic_write_seq(dsi, 0xE5, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xB0, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xBF, 0x1F);
+	mipi_dsi_generic_write_seq(dsi, 0xC0, 0x12);
+	mipi_dsi_generic_write_seq(dsi, 0xC2, 0x1E);
+	mipi_dsi_generic_write_seq(dsi, 0xC4, 0x1E);
+	mipi_dsi_generic_write_seq(dsi, 0xB0, 0x06);
+	mipi_dsi_generic_write_seq(dsi, 0xB8, 0xA5);
+	mipi_dsi_generic_write_seq(dsi, 0xC0, 0xA5);
+	mipi_dsi_generic_write_seq(dsi, 0xBC, 0x11);
+	mipi_dsi_generic_write_seq(dsi, 0xD5, 0x48);
+	mipi_dsi_generic_write_seq(dsi, 0xB8, 0x00);
+	mipi_dsi_generic_write_seq(dsi, 0xC0, 0x00);
+	mipi_dsi_dcs_write_seq(dsi, 0x11);
+	mdelay(120);
+	mipi_dsi_dcs_write_seq(dsi, 0x29);
+	mdelay(20);
+
+	return 0;
+}
+
+static int stk078_panel_enable_backlight(struct udevice *dev)
+{
+	struct stk078_panel *stk = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *dsi = plat->device;
+	int ret;
+
+	stk->dsi = dsi;
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
+		return ret;
+	}
+
+	dm_gpio_set_value(stk->reset_gpio, 0);
+	dm_gpio_set_value(stk->enable_gpio, 0);
+	mdelay(10);
+
+	ret = regulator_enable(stk->vdd);
+	if (ret < 0) {
+		dev_err(dev, "enable vdd failed: %d\n", ret);
+		goto out_gpio;
+	}
+
+	ret = regulator_enable(stk->iovcc);
+	if (ret < 0) {
+		dev_err(dev, "enable iovcc failed: %d\n", ret);
+		goto out_vdd;
+	}
+
+	mdelay(15);
+	dm_gpio_set_value(stk->enable_gpio, 1);
+	mdelay(10);
+	dm_gpio_set_value(stk->reset_gpio, 1);
+	mdelay(140);
+
+	ret = stk078_panel_init(stk);
+	if (ret < 0) {
+		dev_err(dev, "panel init sequence failed: %d\n", ret);
+		goto out_power;
+	}
+
+	if (stk->backlight) {
+		ret = backlight_enable(stk->backlight);
+		if (ret < 0) {
+			dev_err(dev, "enable backlight failed: %d\n", ret);
+			goto out_power;
+		}
+	}
+
+	return 0;
+
+out_power:
+	regulator_disable(stk->iovcc);
+out_vdd:
+	regulator_disable(stk->vdd);
+out_gpio:
+	dm_gpio_set_value(stk->reset_gpio, 0);
+	dm_gpio_set_value(stk->enable_gpio, 0);
+
+	return ret;
+}
+
+static int stk078_panel_add(struct stk078_panel *stk)
+{
+	struct udevice *dev = stk->dev;
+	int ret;
+
+	stk->mode = &default_mode;
+
+	ret = device_get_supply_regulator(dev, "iovcc-supply", &stk->iovcc);
+	if (ret) {
+		dev_err(dev, "Failed to get iovcc regulator: %d\n", ret);
+		return ret;
+	}
+
+	ret = device_get_supply_regulator(dev, "vdd-supply", &stk->vdd);
+	if (ret) {
+		dev_err(dev, "Failed to get vdd regulator: %d\n", ret);
+		return ret;
+	}
+
+	stk->reset_gpio = devm_gpiod_get(dev, "reset",
+					 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (IS_ERR(stk->reset_gpio)) {
+		ret = PTR_ERR(stk->reset_gpio);
+		dev_err(dev, "cannot get reset-gpios %d\n", ret);
+		return ret;
+	}
+
+	stk->enable_gpio = devm_gpiod_get(dev, "enable",
+					  GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (IS_ERR(stk->enable_gpio)) {
+		ret = PTR_ERR(stk->enable_gpio);
+		dev_err(dev, "cannot get enable-gpio %d\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &stk->backlight);
+	if (ret)
+		dev_warn(dev, "failed to get backlight: %d\n", ret);
+
+	return 0;
+}
+
+static int stk078_panel_probe(struct udevice *dev)
+{
+	struct stk078_panel *stk = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	stk->dev = dev;
+
+	plat->lanes = 4;
+	plat->format = MIPI_DSI_FMT_RGB888;
+	plat->mode_flags = MIPI_DSI_MODE_VIDEO |
+			   MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			   MIPI_DSI_MODE_LPM;
+
+	ret = stk078_panel_add(stk);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int stk078_panel_get_modes(struct udevice *dev,
+				  const struct drm_display_mode **modes)
+{
+	struct stk078_panel *stk = dev_get_priv(dev);
+
+	if (!stk->mode)
+		return -ENODEV;
+
+	*modes = stk->mode;
+
+	return 1;
+}
+
+static const struct panel_ops stk078_panel_ops = {
+	.enable_backlight = stk078_panel_enable_backlight,
+	.get_modes = stk078_panel_get_modes,
+};
+
+static const struct udevice_id stk078_of_match[] = {
+	{ .compatible = "startek,kd070fhfid078" },
+	{ }
+};
+
+U_BOOT_DRIVER(stk078_panel_driver) = {
+	.name		= "panel-startek-kd070fhfid078",
+	.id		= UCLASS_PANEL,
+	.of_match	= stk078_of_match,
+	.ops		= &stk078_panel_ops,
+	.probe		= stk078_panel_probe,
+	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
+	.priv_auto	= sizeof(struct stk078_panel),
+};

---
base-commit: d3e8597e46b635ec556a057bc42f0b0859654bdf
change-id: 20260814-mtk-video-panel-startek-078-1a9ab38e89f7
prerequisite-message-id: <20260806-add_mipi_dsi_write_seq_helper_macros-v1-0-6b533788d0ac@baylibre.com>
prerequisite-patch-id: cf35ac4802976971af68bd0ce1dc0ab872fdb661
prerequisite-patch-id: 9f6aca2bfde84a5d84329b77b3b9af8898b18e4a
prerequisite-patch-id: e7bb7ee54b88b6d6e00f74fe84b1c81d00957051
prerequisite-patch-id: d4a530120b1a93d68e4b17c6e1fcf2878e784454
prerequisite-patch-id: 18b1bbeab6808decceaf5117b3e999baf4495e1d
prerequisite-patch-id: d50e7e28a399c303226ff08c78e60749930a7243

Best regards,
--  
David Lechner <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.