[PATCH] video: panel: Support for startek-kd070fhfid015 MIPI-DSI panel
Julien Stephan <[email protected]> Thu, 06 Aug 2026 13:53:14 +0200
| Newsgroups | gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <20260806-add-panel-startek-kd070fhfid015-v1-1-7899337feb34__46014.7212537535$1786017225$gmane$org@baylibre.com> |
This driver support the Startek KD070FHFID015, which is a 7-inch TFT LCD
display using MIPI DSI interface. It is based on kernel commit
b080a60731ad ("drm/panel: startek-kd070fhfid015: transition to mipi_dsi
wrapped functions").
Signed-off-by: Julien Stephan <[email protected]>
---
This driver support the Startek KD070FHFID015, which is a 7-inch TFT LCD
display using MIPI DSI interface. It is based on kernel commit
b080a60731ad ("drm/panel: startek-kd070fhfid015: transition to mipi_dsi
wrapped functions").
This panel is used on some Mediatek Genio EVKS, such as Genio-350.
The full video pipeline series enabling full support will be sent later.
This series depends on [1], for mipi_dsi_write_seq helpers.
[1]: https://lore.kernel.org/all/20260806-add_mipi_dsi_write_seq_helper_macros-v1-0-6b533788d0ac@baylibre.com/
---
drivers/video/Kconfig | 10 ++
drivers/video/Makefile | 1 +
drivers/video/panel-startek-kd070fhfid015.c | 267 ++++++++++++++++++++++++++++
3 files changed, 278 insertions(+)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cb3ba6a6f63..6de28d78705 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_KD070FHFID015
+ bool "STARTEK KD070FHFID015 panel"
+ depends on PANEL && DM_GPIO
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for STARTEK KD070FHFID015 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 a20011b9b17..7a54f1f290d 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_KD070FHFID015) += panel-startek-kd070fhfid015.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-kd070fhfid015.c b/drivers/video/panel-startek-kd070fhfid015.c
new file mode 100644
index 00000000000..c0b3cf1a5ff
--- /dev/null
+++ b/drivers/video/panel-startek-kd070fhfid015.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2016 InforceComputing
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2026 BayLibre, SAS
+ *
+ * Authors:
+ * - Vinay Simha BN <[email protected]>
+ * - Sumit Semwal <[email protected]>
+ * - Guillaume La Roque <[email protected]>
+ *
+ * U-Boot port:
+ * Authors:
+ * - Julien Stephan <[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 <malloc.h>
+#include <mipi_dsi.h>
+#include <panel.h>
+#include <power/regulator.h>
+
+#define DSI_REG_MCAP 0xb0
+#define DSI_REG_IS 0xb3 /* Interface Setting */
+#define DSI_REG_IIS 0xb4 /* Interface ID Setting */
+#define DSI_REG_CTRL 0xb6
+
+struct stk_panel {
+ const struct drm_display_mode *mode;
+ struct udevice *dev;
+ struct gpio_desc *enable_gpio; /* Power IC supply enable */
+ struct gpio_desc *reset_gpio; /* External reset */
+ struct mipi_dsi_device *dsi;
+ struct udevice *iovcc;
+ struct udevice *power;
+};
+
+static const struct drm_display_mode default_mode = {
+ .clock = 163204,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 144,
+ .hsync_end = 1200 + 144 + 16,
+ .htotal = 1200 + 144 + 16 + 45,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 8,
+ .vsync_end = 1920 + 8 + 4,
+ .vtotal = 1920 + 8 + 4 + 4,
+};
+
+static int stk_panel_init(struct stk_panel *stk)
+{
+ struct mipi_dsi_device *dsi = stk->dsi;
+ struct udevice *dev = stk->dsi->dev;
+ int ret;
+
+ ret = mipi_dsi_dcs_soft_reset(dsi);
+ if (ret < 0) {
+ dev_err(dev, "failed to mipi_dsi_dcs_soft_reset: %d\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
+ return ret;
+ }
+ mdelay(120);
+
+ mipi_dsi_generic_write_seq(dsi, DSI_REG_MCAP, 0x04);
+
+ /* Interface setting, video mode */
+ mipi_dsi_generic_write_seq(dsi, DSI_REG_IS, 0x14, 0x08, 0x00, 0x22, 0x00);
+ mipi_dsi_generic_write_seq(dsi, DSI_REG_IIS, 0x0c, 0x00);
+ mipi_dsi_generic_write_seq(dsi, DSI_REG_CTRL, 0x3a, 0xd3);
+
+ ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x77);
+ if (ret < 0) {
+ dev_err(dev, "failed to write display brightness: %d\n", ret);
+ return ret;
+ }
+
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+ MIPI_DCS_WRITE_MEMORY_START);
+
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
+ if (ret < 0) {
+ dev_err(dev, "failed to set pixel format: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_dcs_set_column_address(dsi, 0, stk->mode->hdisplay - 1);
+ if (ret < 0) {
+ dev_err(dev, "failed to set column address: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_dcs_set_page_address(dsi, 0, stk->mode->vdisplay - 1);
+ if (ret < 0) {
+ dev_err(dev, "failed to set page address: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stk_panel_on(struct stk_panel *stk)
+{
+ struct mipi_dsi_device *dsi = stk->dsi;
+ struct udevice *dev = stk->dsi->dev;
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0)
+ dev_err(dev, "failed to set display on: %d\n", ret);
+
+ mdelay(20);
+
+ return ret;
+}
+
+static int stk_panel_enable_backlight(struct udevice *dev)
+{
+ struct stk_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)
+ return ret;
+
+ dm_gpio_set_value(stk->reset_gpio, 0);
+ dm_gpio_set_value(stk->enable_gpio, 0);
+ ret = regulator_enable(stk->iovcc);
+ if (ret < 0)
+ return ret;
+
+ mdelay(8);
+ ret = regulator_enable(stk->power);
+ if (ret < 0)
+ goto iovccoff;
+
+ mdelay(20);
+ dm_gpio_set_value(stk->enable_gpio, 1);
+ mdelay(20);
+ dm_gpio_set_value(stk->reset_gpio, 1);
+ mdelay(10);
+
+ ret = stk_panel_init(stk);
+ if (ret < 0) {
+ dev_err(dev, "failed to init panel: %d\n", ret);
+ goto poweroff;
+ }
+
+ ret = stk_panel_on(stk);
+ if (ret < 0) {
+ dev_err(dev, "failed to set panel on: %d\n", ret);
+ goto poweroff;
+ }
+
+ return 0;
+
+poweroff:
+ regulator_disable(stk->power);
+iovccoff:
+ regulator_disable(stk->iovcc);
+ dm_gpio_set_value(stk->reset_gpio, 0);
+ dm_gpio_set_value(stk->enable_gpio, 0);
+
+ return ret;
+}
+
+static int stk_panel_add(struct stk_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, "power-supply", &stk->power);
+ if (ret) {
+ dev_err(dev, "Failed to get power 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;
+ }
+
+ return 0;
+}
+
+static int stk_panel_probe(struct udevice *dev)
+{
+ struct stk_panel *stk = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ int ret;
+
+ stk->dev = dev;
+
+ /* fill characteristics of DSI data link */
+ plat->lanes = 4;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
+
+ ret = stk_panel_add(stk);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int stk_panel_get_modes(struct udevice *dev, const struct drm_display_mode **modes)
+{
+ struct stk_panel *stk = dev_get_priv(dev);
+
+ if (!stk->mode)
+ return -ENODEV;
+
+ *modes = stk->mode;
+ return 1;
+}
+
+static const struct panel_ops stk_panel_ops = {
+ .enable_backlight = stk_panel_enable_backlight,
+ .get_modes = stk_panel_get_modes,
+};
+
+static const struct udevice_id stk_of_match[] = {
+ { .compatible = "startek,kd070fhfid015", },
+ { }
+};
+
+U_BOOT_DRIVER(stk_panel_driver) = {
+ .name = "panel-startek-kd070fhfid015",
+ .id = UCLASS_PANEL,
+ .of_match = stk_of_match,
+ .ops = &stk_panel_ops,
+ .probe = stk_panel_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct stk_panel),
+};
---
base-commit: f562ed02aa7ae4dc2775d90d2e6c40bab82e2715
change-id: 20260806-add-panel-startek-kd070fhfid015-a8ddf39cfa58
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,
--
Julien Stephan <[email protected]>