[PATCH] video: panel-startek-kd070fhfid078: new driver
David Lechner <[email protected]>
| Newsgroups | gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <20260814-mtk-video-panel-startek-078-v1-1-5f84a57244bc__10492.4712258921$1786736825$gmane$org@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]>