[PATCH v2] video: panel-startek-kd070fhfid078: new driver
David Lechner <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <20260826-mtk-video-panel-startek-078-v2-1-c56342b77835@baylibre.com> |
Add a driver for the Startek KD070FHFID078 7" DSI panel. This panel is used on the MediaTek Genio 360 EVK board. The display mode and DSI mode flags follow the upstream Linux driver panel-himax-hx8279.c, which is what the "himax,hx8279" fallback compatible in the device tree binds to. Signed-off-by: David Lechner <[email protected]> --- Add a driver for the Startek KD070FHFID078 7" DSI panel. This depends on the mipi_dsi {generic,dcs}_write_seq helper macros series for mipi_dsi_generic_write_seq(). Note: no defconfig enables this driver yet, since there is no MediaTek DSI host driver in U-Boot at this point. It will be enabled together with the display pipeline support. --- Changes in v2: - Added missing BACKLIGHT and DM_REGULATOR Kconfig dependencies. - Use the display mode and MIPI_DSI_CLOCK_NON_CONTINUOUS flag from the upstream Linux panel-himax-hx8279.c driver instead of the MediaTek downstream driver. - enable-gpios is now optional, matching the binding. - A missing backlight is now an error instead of a warning. - Do not request reset/enable GPIOs as active, so they are not asserted before the regulators are enabled. - Use mipi_dsi_dcs_exit_sleep_mode()/mipi_dsi_dcs_set_display_on() instead of raw DCS opcodes and check their return values. - Dropped stale InforceComputing/Linaro copyright and author lines. - Dropped the unused dev field and the unreachable mode check. - Link to v1: https://patch.msgid.link/20260814-mtk-video-panel-startek-078-v1-1-5f84a57244bc@baylibre.com --- MAINTAINERS | 6 + drivers/video/Kconfig | 10 + drivers/video/Makefile | 1 + drivers/video/panel-startek-kd070fhfid078.c | 283 ++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fabcb8b2968..b3bf5b1f8c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1723,6 +1723,12 @@ R: GSS_MTK_Uboot_upstream <[email protected]> S: Maintained F: drivers/video/panel-startek-kd070fhfid015.c +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 37ab17f0ab2..495e4382a22 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -330,6 +330,16 @@ config PANEL_STARTEK_KD070FHFID015 1200 x 1920 pixels. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config PANEL_STARTEK_KD070FHFID078 + bool "STARTEK KD070FHFID078 panel" + depends on PANEL && BACKLIGHT && DM_GPIO && DM_REGULATOR + 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 7a54f1f290d..7a7b54e6b53 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -23,6 +23,7 @@ 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_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..dd5cac46267 --- /dev/null +++ b/drivers/video/panel-startek-kd070fhfid078.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 MediaTek Inc. + * Copyright (C) 2026 BayLibre, SAS + * + * Authors: + * - 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 { + 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 = 156458, + .hdisplay = 1200, + .hsync_start = 1200 + 50, + .hsync_end = 1200 + 50 + 24, + .htotal = 1200 + 50 + 24 + 66, + .vdisplay = 1920, + .vsync_start = 1920 + 14, + .vsync_end = 1920 + 14 + 2, + .vtotal = 1920 + 14 + 2 + 10, +}; + +static int stk078_panel_init(struct stk078_panel *stk) +{ + struct mipi_dsi_device *dsi = stk->dsi; + int ret; + + 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); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) + return ret; + + mdelay(120); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) + return ret; + + 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); + if (stk->enable_gpio) + 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); + if (stk->enable_gpio) + 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; + } + + 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); + if (stk->enable_gpio) + dm_gpio_set_value(stk->enable_gpio, 0); + + return ret; +} + +static int stk078_panel_add(struct udevice *dev) +{ + struct stk078_panel *stk = dev_get_priv(dev); + int ret; + + 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); + 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_optional(dev, "enable", GPIOD_IS_OUT); + if (IS_ERR(stk->enable_gpio)) { + ret = PTR_ERR(stk->enable_gpio); + dev_err(dev, "cannot get enable-gpios %d\n", ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &stk->backlight); + if (ret) { + dev_err(dev, "failed to get backlight: %d\n", ret); + return ret; + } + + return 0; +} + +static int stk078_panel_probe(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); + int ret; + + 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 | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ret = stk078_panel_add(dev); + if (ret < 0) + return ret; + + return 0; +} + +static int stk078_panel_get_modes(struct udevice *dev, + const struct drm_display_mode **modes) +{ + *modes = &default_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: f252d228be2b2d180737ad0a851f91749273cbd9 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]>