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-6b533788d...@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]>

Reply via email to