diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:11:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:11:27 +0000 |
commit | 34996e42f82bfd60bc2c191e5cae3c6ab233ec6c (patch) | |
tree | 62db60558cbf089714b48daeabca82bf2b20b20e /drivers/gpu/drm/panel | |
parent | Adding debian version 6.8.12-1. (diff) | |
download | linux-34996e42f82bfd60bc2c191e5cae3c6ab233ec6c.tar.xz linux-34996e42f82bfd60bc2c191e5cae3c6ab233ec6c.zip |
Merging upstream version 6.9.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/panel')
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 231 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-boe-himax8279d.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c | 322 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-edp.c | 120 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-himax-hx83112a.c | 372 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c | 265 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-novatek-nt35510.c | 424 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-novatek-nt36523.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-novatek-nt36672e.c | 641 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 61 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-sitronix-st7703.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-visionox-r66451.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-visionox-vtdr6130.c | 1 |
16 files changed, 2360 insertions, 254 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 888297d0d3..5b15d02948 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -67,61 +67,25 @@ config DRM_PANEL_BOE_HIMAX8279D 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. -config DRM_PANEL_BOE_TV101WUM_NL6 - tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel" +config DRM_PANEL_BOE_TH101MB31UIG002_28A + tristate "Boe TH101MB31UIG002-28A panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 - 45NA WUXGA PANEL DSI Video Mode panel + Say Y here if you want to enable support for Boe + TH101MB31UIG002-28A TFT-LCD modules. The panel has a 800x1280 + resolution and uses 24 bit RGB per pixel. It provides a MIPI DSI + interface to the host and has a built-in LED backlight. -config DRM_PANEL_DSI_CM - tristate "Generic DSI command mode panels" +config DRM_PANEL_BOE_TV101WUM_NL6 + tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - DRM panel driver for DSI command mode panels with support for - embedded and external backlights. - -config DRM_PANEL_LVDS - tristate "Generic LVDS panel driver" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS - help - This driver supports LVDS panels that don't require device-specific - handling of power supplies or control signals. It implements automatic - backlight handling if the panel is attached to a backlight controller. - -config DRM_PANEL_SIMPLE - tristate "support for simple panels (other than eDP ones)" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - depends on PM - select VIDEOMODE_HELPERS - help - DRM panel driver for dumb non-eDP panels that need at most a regulator - and a GPIO to be powered up. Optionally a backlight can be attached so - that it can be automatically turned off when the panel goes into a - low power state. - -config DRM_PANEL_EDP - tristate "support for simple Embedded DisplayPort panels" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - depends on PM - select VIDEOMODE_HELPERS - select DRM_DISPLAY_DP_HELPER - select DRM_DISPLAY_HELPER - select DRM_DP_AUX_BUS - select DRM_KMS_HELPER - help - DRM panel driver for dumb eDP panels that need at most a regulator and - a GPIO to be powered up. Optionally a backlight can be attached so - that it can be automatically turned off when the panel goes into a - low power state. + Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 + 45NA WUXGA PANEL DSI Video Mode panel config DRM_PANEL_EBBG_FT8719 tristate "EBBG FT8719 panel driver" @@ -162,6 +126,35 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D Say Y if you want to enable support for panels based on the Feiyang FY07024DI26A30-D MIPI-DSI interface. +config DRM_PANEL_DSI_CM + tristate "Generic DSI command mode panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + DRM panel driver for DSI command mode panels with support for + embedded and external backlights. + +config DRM_PANEL_LVDS + tristate "Generic LVDS panel driver" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + help + This driver supports LVDS panels that don't require device-specific + handling of power supplies or control signals. It implements automatic + backlight handling if the panel is attached to a backlight controller. + +config DRM_PANEL_HIMAX_HX83112A + tristate "Himax HX83112A-based DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_KMS_HELPER + help + Say Y here if you want to enable support for Himax HX83112A-based + display panels, such as the one found in the Fairphone 4 smartphone. + config DRM_PANEL_HIMAX_HX8394 tristate "HIMAX HX8394 MIPI-DSI LCD panels" depends on OF @@ -251,17 +244,6 @@ config DRM_PANEL_JADARD_JD9365DA_H3 WXGA MIPI DSI panel. The panel support TFT dot matrix LCD with 800RGBx1280 dots at maximum. -config DRM_PANEL_JDI_LT070ME05000 - tristate "JDI LT070ME05000 WUXGA DSI panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for JDI DSI video mode - panel as found in Google Nexus 7 (2013) devices. - The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses - 24 bit per pixel. - config DRM_PANEL_JDI_LPM102A188A tristate "JDI LPM102A188A DSI panel" depends on OF && GPIOLIB @@ -273,6 +255,17 @@ config DRM_PANEL_JDI_LPM102A188A The panel has a 2560×1800 resolution. It provides a MIPI DSI interface to the host. +config DRM_PANEL_JDI_LT070ME05000 + tristate "JDI LT070ME05000 WUXGA DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for JDI DSI video mode + panel as found in Google Nexus 7 (2013) devices. + The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses + 24 bit per pixel. + config DRM_PANEL_JDI_R63452 tristate "JDI R63452 Full HD DSI panel" depends on OF @@ -326,12 +319,6 @@ config DRM_PANEL_LEADTEK_LTK500HD1829 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. -config DRM_PANEL_SAMSUNG_LD9040 - tristate "Samsung LD9040 RGB/SPI panel" - depends on OF && SPI - depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS - config DRM_PANEL_LG_LB035Q02 tristate "LG LB035Q024573 RGB panel" depends on GPIOLIB && OF && SPI @@ -359,6 +346,17 @@ config DRM_PANEL_MAGNACHIP_D53E6EA8966 with the Magnachip D53E6EA8966 panel IC. This panel receives video data via DSI but commands via 9-bit SPI using DBI. +config DRM_PANEL_MANTIX_MLAF057WE51 + tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Mantix + MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It + has a resolution of 720x1440 pixels, a built in backlight and touch + controller. + config DRM_PANEL_NEC_NL8048HL11 tristate "NEC NL8048HL11 RGB panel" depends on GPIOLIB && OF && SPI @@ -438,6 +436,16 @@ config DRM_PANEL_NOVATEK_NT36672A around the Novatek NT36672A display controller, such as some Tianma panels used in a few Xiaomi Poco F1 mobile phones. +config DRM_PANEL_NOVATEK_NT36672E + tristate "Novatek NT36672E DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Novatek NT36672E DSI Video Mode + LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit + RGB per pixel. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI @@ -447,17 +455,6 @@ config DRM_PANEL_NOVATEK_NT39016 Say Y here if you want to enable support for the panels built around the Novatek NT39016 display controller. -config DRM_PANEL_MANTIX_MLAF057WE51 - tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for the Mantix - MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It - has a resolution of 720x1440 pixels, a built in backlight and touch - controller. - config DRM_PANEL_OLIMEX_LCD_OLINUXINO tristate "Olimex LCD-OLinuXino panel" depends on OF @@ -554,6 +551,12 @@ config DRM_PANEL_RONBO_RB070D30 Say Y here if you want to enable support for Ronbo Electronics RB070D30 1024x600 DSI panel. +config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 + tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" + depends on OF + select DRM_MIPI_DSI + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_ATNA33XC20 tristate "Samsung ATNA33XC20 eDP panel" depends on OF @@ -577,6 +580,12 @@ config DRM_PANEL_SAMSUNG_DB7430 DB7430 DPI display controller used in such devices as the LMS397KF04 480x800 DPI panel. +config DRM_PANEL_SAMSUNG_LD9040 + tristate "Samsung LD9040 RGB/SPI panel" + depends on OF && SPI + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_S6D16D0 tristate "Samsung S6D16D0 DSI video mode panel" depends on OF @@ -642,12 +651,6 @@ config DRM_PANEL_SAMSUNG_S6E63M0_DSI Say Y here if you want to be able to access the Samsung S6E63M0 panel using DSI. -config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 - tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" - depends on OF - select DRM_MIPI_DSI - select VIDEOMODE_HELPERS - config DRM_PANEL_SAMSUNG_S6E8AA0 tristate "Samsung S6E8AA0 DSI video mode panel" depends on OF @@ -746,15 +749,6 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels -config DRM_PANEL_SYNAPTICS_R63353 - tristate "Synaptics R63353-based panels" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y if you want to enable support for panels based on the - Synaptics R63353 controller. - config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI @@ -794,6 +788,43 @@ config DRM_PANEL_STARTEK_KD070FHFID015 with a resolution of 1024 x 600 pixels. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config DRM_PANEL_EDP + tristate "support for simple Embedded DisplayPort panels" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + depends on PM + select VIDEOMODE_HELPERS + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + select DRM_DP_AUX_BUS + select DRM_KMS_HELPER + help + DRM panel driver for dumb eDP panels that need at most a regulator and + a GPIO to be powered up. Optionally a backlight can be attached so + that it can be automatically turned off when the panel goes into a + low power state. + +config DRM_PANEL_SIMPLE + tristate "support for simple panels (other than eDP ones)" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + depends on PM + select VIDEOMODE_HELPERS + help + DRM panel driver for dumb non-eDP panels that need at most a regulator + and a GPIO to be powered up. Optionally a backlight can be attached so + that it can be automatically turned off when the panel goes into a + low power state. + +config DRM_PANEL_SYNAPTICS_R63353 + tristate "Synaptics R63353-based panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Synaptics R63353 controller. + config DRM_PANEL_TDO_TL070WSH30 tristate "TDO TL070WSH30 DSI panel" depends on OF @@ -837,6 +868,17 @@ config DRM_PANEL_TRULY_NT35597_WQXGA Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel +config DRM_PANEL_VISIONOX_R66451 + tristate "Visionox R66451" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + help + Say Y here if you want to enable support for Visionox + R66451 1080x2340 AMOLED DSI panel. + config DRM_PANEL_VISIONOX_RM69299 tristate "Visionox RM69299" depends on OF @@ -854,17 +896,6 @@ config DRM_PANEL_VISIONOX_VTDR6130 Say Y here if you want to enable support for Visionox VTDR6130 1080x2400 AMOLED DSI panel. -config DRM_PANEL_VISIONOX_R66451 - tristate "Visionox R66451" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - select DRM_DISPLAY_DP_HELPER - select DRM_DISPLAY_HELPER - help - Say Y here if you want to enable support for Visionox - R66451 1080x2340 AMOLED DSI panel. - config DRM_PANEL_WIDECHIPS_WS2401 tristate "Widechips WS2401 DPI panel driver" depends on SPI && GPIOLIB diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d94a644d0a..f156d7fa0b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596. obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o +obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o @@ -14,6 +15,7 @@ obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o +obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o @@ -41,6 +43,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c index 11b64acbe8..e225840b0d 100644 --- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -854,26 +854,20 @@ static int panel_add(struct panel_info *pinfo) pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->pp18_gpio)) { - ret = PTR_ERR(pinfo->pp18_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pp18 gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->pp18_gpio), + "failed to get pp18 gpio\n"); } pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->pp33_gpio)) { - ret = PTR_ERR(pinfo->pp33_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pp33 gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->pp33_gpio), + "failed to get pp33 gpio\n"); } pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->enable_gpio)) { - ret = PTR_ERR(pinfo->enable_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get enable gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->enable_gpio), + "failed to get enable gpio\n"); } drm_panel_init(&pinfo->base, dev, &panel_funcs, diff --git a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c new file mode 100644 index 0000000000..763e9f8342 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Alexander Warnecke <awarnecke002@hotmail.com> + * Copyright (c) 2023 Manuel Traut <manut@mecka.net> + * Copyright (c) 2023 Dang Huynh <danct12@riseup.net> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_connector.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct boe_th101mb31ig002 { + struct drm_panel panel; + + struct mipi_dsi_device *dsi; + + struct regulator *power; + struct gpio_desc *enable; + struct gpio_desc *reset; + + enum drm_panel_orientation orientation; +}; + +static void boe_th101mb31ig002_reset(struct boe_th101mb31ig002 *ctx) +{ + gpiod_direction_output(ctx->reset, 0); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 1); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 0); + usleep_range(5000, 6000); +} + +static int boe_th101mb31ig002_enable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + mipi_dsi_dcs_write_seq(dsi, 0xE0, 0xAB, 0xBA); + mipi_dsi_dcs_write_seq(dsi, 0xE1, 0xBA, 0xAB); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x10, 0x01, 0x47, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C, 0x14, 0x04, 0x50, 0x50, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x56, 0x53, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33, 0x30, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0xB0, 0x00, 0x00, 0x10, 0x00, 0x10, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, + 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, + 0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7C, + 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, + 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, + 0x46, 0x39, 0x26, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0xFF, 0x87, 0x12, 0x34, 0x44, 0x44, + 0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0F, + 0x00, 0x00, 0xC1); + mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x54, 0x94, 0x02, 0x85, 0x9F, 0x00, + 0x7F, 0x00, 0x54, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, + 0x22, 0x20, 0x44, 0xFF, 0x18, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC3, 0x86, 0x46, 0x05, 0x05, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0F, 0x0F, 0x0D, 0x0D, 0x13, 0x13, 0x11, + 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC4, 0x07, 0x07, 0x04, 0x04, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0E, 0x0E, 0x0C, 0x0C, 0x12, 0x12, 0x10, + 0x10, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC6, 0x2A, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0xC8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0xCA, 0xCB, 0x43); + mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x0E, 0x4B, 0x4B, 0x20, 0x19, 0x6B, + 0x06, 0xB3); + mipi_dsi_dcs_write_seq(dsi, 0xD2, 0xE3, 0x2B, 0x38, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x00, 0x01, 0x00, 0x0E, 0x04, 0x44, + 0x08, 0x10, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xE6, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF0, 0x12, 0x03, 0x20, 0x00, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF3, 0x00); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + + msleep(120); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set panel on: %d\n", ret); + return ret; + } + + return 0; +} + +static int boe_th101mb31ig002_disable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + dev_err(dev, "Failed to set panel off: %d\n", ret); + + msleep(120); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + + return 0; +} + +static int boe_th101mb31ig002_unprepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + gpiod_set_value_cansleep(ctx->reset, 1); + gpiod_set_value_cansleep(ctx->enable, 0); + regulator_disable(ctx->power); + + return 0; +} + +static int boe_th101mb31ig002_prepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_enable(ctx->power); + if (ret) { + dev_err(dev, "Failed to enable power supply: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable, 1); + msleep(50); + boe_th101mb31ig002_reset(ctx); + boe_th101mb31ig002_enable(panel); + + return 0; +} + +static const struct drm_display_mode boe_th101mb31ig002_default_mode = { + .clock = 73500, + .hdisplay = 800, + .hsync_start = 800 + 64, + .hsync_end = 800 + 64 + 16, + .htotal = 800 + 64 + 16 + 64, + .vdisplay = 1280, + .vsync_start = 1280 + 2, + .vsync_end = 1280 + 2 + 4, + .vtotal = 1280 + 2 + 4 + 12, + .width_mm = 135, + .height_mm = 216, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static int boe_th101mb31ig002_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, + &boe_th101mb31ig002_default_mode); + if (!mode) { + dev_err(panel->dev, "Failed to add mode %ux%u@%u\n", + boe_th101mb31ig002_default_mode.hdisplay, + boe_th101mb31ig002_default_mode.vdisplay, + drm_mode_vrefresh(&boe_th101mb31ig002_default_mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + connector->display_info.bpc = 8; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + /* + * TODO: Remove once all drm drivers call + * drm_connector_set_orientation_from_panel() + */ + drm_connector_set_panel_orientation(connector, ctx->orientation); + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static enum drm_panel_orientation +boe_th101mb31ig002_get_orientation(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + return ctx->orientation; +} + +static const struct drm_panel_funcs boe_th101mb31ig002_funcs = { + .prepare = boe_th101mb31ig002_prepare, + .unprepare = boe_th101mb31ig002_unprepare, + .disable = boe_th101mb31ig002_disable, + .get_modes = boe_th101mb31ig002_get_modes, + .get_orientation = boe_th101mb31ig002_get_orientation, +}; + +static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx; + int ret; + + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + ctx->dsi = dsi; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_MODE_LPM; + + ctx->power = devm_regulator_get(&dsi->dev, "power"); + if (IS_ERR(ctx->power)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), + "Failed to get power regulator\n"); + + ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable), + "Failed to get enable GPIO\n"); + + ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), + "Failed to get reset GPIO\n"); + + ret = of_drm_get_panel_orientation(dsi->dev.of_node, + &ctx->orientation); + if (ret) + return dev_err_probe(&dsi->dev, ret, + "Failed to get orientation\n"); + + drm_panel_init(&ctx->panel, &dsi->dev, &boe_th101mb31ig002_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err_probe(&dsi->dev, ret, + "Failed to attach panel to DSI host\n"); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id boe_th101mb31ig002_of_match[] = { + { .compatible = "boe,th101mb31ig002-28a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, boe_th101mb31ig002_of_match); + +static struct mipi_dsi_driver boe_th101mb31ig002_driver = { + .driver = { + .name = "boe-th101mb31ig002-28a", + .of_match_table = boe_th101mb31ig002_of_match, + }, + .probe = boe_th101mb31ig002_dsi_probe, + .remove = boe_th101mb31ig002_dsi_remove, +}; +module_mipi_dsi_driver(boe_th101mb31ig002_driver); + +MODULE_AUTHOR("Alexander Warnecke <awarnecke002@hotmail.com>"); +MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 49b8a2484d..745f3e48f0 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -71,6 +71,21 @@ struct panel_delay { unsigned int hpd_absent; /** + * @powered_on_to_enable: Time between panel powered on and enable. + * + * The minimum time, in milliseconds, that needs to have passed + * between when panel powered on and enable may begin. + * + * This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the + * power supply enabled until we can turn the backlight on and see + * valid data. + * + * This doesn't normally need to be set if timings are already met by + * prepare_to_enable or enable. + */ + unsigned int powered_on_to_enable; + + /** * @prepare_to_enable: Time between prepare and enable. * * The minimum time, in milliseconds, that needs to have passed @@ -216,6 +231,7 @@ struct panel_edp { bool prepared; ktime_t prepared_time; + ktime_t powered_on_time; ktime_t unprepared_time; const struct panel_desc *desc; @@ -456,6 +472,8 @@ static int panel_edp_prepare_once(struct panel_edp *p) gpiod_set_value_cansleep(p->enable_gpio, 1); drm_dp_dpcd_set_powered(p->aux, true); + p->powered_on_time = ktime_get_boottime(); + delay = p->desc->delay.hpd_reliable; if (p->no_hpd) delay = max(delay, p->desc->delay.hpd_absent); @@ -581,6 +599,8 @@ static int panel_edp_enable(struct drm_panel *panel) panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable); + panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable); + p->enabled = true; return 0; @@ -985,19 +1005,6 @@ static const struct panel_desc auo_b101ean01 = { }, }; -static const struct drm_display_mode auo_b116xa3_mode = { - .clock = 70589, - .hdisplay = 1366, - .hsync_start = 1366 + 40, - .hsync_end = 1366 + 40 + 40, - .htotal = 1366 + 40 + 40 + 32, - .vdisplay = 768, - .vsync_start = 768 + 10, - .vsync_end = 768 + 10 + 12, - .vtotal = 768 + 10 + 12 + 6, - .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, -}; - static const struct drm_display_mode auo_b116xak01_mode = { .clock = 69300, .hdisplay = 1366, @@ -1839,6 +1846,13 @@ static const struct panel_delay delay_200_500_p2e80 = { .prepare_to_enable = 80, }; +static const struct panel_delay delay_200_500_e50_p2e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .prepare_to_enable = 80, +}; + static const struct panel_delay delay_200_500_p2e100 = { .hpd_absent = 200, .unprepare = 500, @@ -1851,6 +1865,13 @@ static const struct panel_delay delay_200_500_e50 = { .enable = 50, }; +static const struct panel_delay delay_200_500_e50_p2e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .prepare_to_enable = 200, +}; + static const struct panel_delay delay_200_500_e80 = { .hpd_absent = 200, .unprepare = 500, @@ -1876,6 +1897,13 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 200, +}; + static const struct panel_delay delay_200_500_e200_d10 = { .hpd_absent = 200, .unprepare = 500, @@ -1889,6 +1917,13 @@ static const struct panel_delay delay_200_150_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e50_po2e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .powered_on_to_enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1914,7 +1949,9 @@ static const struct panel_delay delay_200_150_e200 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), @@ -1923,56 +1960,91 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), - EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", - &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), - EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", - &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f8, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0813, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0843, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x096e, &delay_200_500_e50_po2e200, "NV116WHM-T07 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0993, &delay_200_500_e80, "NV116WHM-T14 V8.0"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1141, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x114a, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_p2e200, "MNC207QS1-1"), + + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), @@ -1981,11 +2053,25 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, &delay_200_500_e50, "KD116N9-30NH-F3"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0000, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x048d, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0537, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112a.c b/drivers/gpu/drm/panel/panel-himax-hx83112a.c new file mode 100644 index 0000000000..466c27012a --- /dev/null +++ b/drivers/gpu/drm/panel/panel-himax-hx83112a.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2024 Luca Weiss <luca.weiss@fairphone.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +/* Manufacturer specific DSI commands */ +#define HX83112A_SETPOWER1 0xb1 +#define HX83112A_SETDISP 0xb2 +#define HX83112A_SETDRV 0xb4 +#define HX83112A_SETEXTC 0xb9 +#define HX83112A_SETBANK 0xbd +#define HX83112A_SETPTBA 0xbf +#define HX83112A_SETDGCLUT 0xc1 +#define HX83112A_SETTCON 0xc7 +#define HX83112A_SETCLOCK 0xcb +#define HX83112A_SETPANEL 0xcc +#define HX83112A_SETPOWER2 0xd2 +#define HX83112A_SETGIP0 0xd3 +#define HX83112A_SETGIP1 0xd5 +#define HX83112A_SETGIP2 0xd6 +#define HX83112A_SETGIP3 0xd8 +#define HX83112A_SETTP1 0xe7 +#define HX83112A_UNKNOWN1 0xe9 + +struct hx83112a_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data supplies[3]; + struct gpio_desc *reset_gpio; +}; + +static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel) +{ + return container_of(panel, struct hx83112a_panel, panel); +} + +static void hx83112a_reset(struct hx83112a_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(50); +} + +static int hx83112a_on(struct hx83112a_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETEXTC, 0x83, 0x11, 0x2a); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER1, + 0x08, 0x28, 0x28, 0x83, 0x83, 0x4c, 0x4f, 0x33); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDISP, + 0x00, 0x02, 0x00, 0x90, 0x24, 0x00, 0x08, 0x19, + 0xea, 0x11, 0x11, 0x00, 0x11, 0xa3); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV, + 0x58, 0x68, 0x58, 0x68, 0x0f, 0xef, 0x0b, 0xc0, + 0x0b, 0xc0, 0x0b, 0xc0, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x14, 0x15, 0x00, 0x29, 0x11, 0x07, + 0x12, 0x00, 0x29); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV, + 0x00, 0x12, 0x12, 0x11, 0x88, 0x12, 0x12, 0x00, + 0x53); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, + 0x40); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, + 0x40); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, + 0x40); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 0x01); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTCON, + 0x70, 0x00, 0x04, 0xe0, 0x33, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPANEL, 0x08); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER2, 0x2b, 0x2b); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, + 0x08, 0x03, 0x03, 0x22, 0x18, 0x07, 0x07, 0x07, + 0x07, 0x32, 0x10, 0x06, 0x00, 0x06, 0x32, 0x10, + 0x07, 0x00, 0x07, 0x32, 0x19, 0x31, 0x09, 0x31, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x09, 0x30, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x00, + 0x0f); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0, + 0x00, 0x00, 0x19, 0x10, 0x00, 0x0a, 0x00, 0x81); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP1, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xc0, 0xc0, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f, + 0x28, 0x28, 0x24, 0x24, 0x02, 0x03, 0x02, 0x03, + 0x00, 0x01, 0x00, 0x01, 0x31, 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP2, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f, + 0x24, 0x24, 0x28, 0x28, 0x01, 0x00, 0x01, 0x00, + 0x03, 0x02, 0x03, 0x02, 0x31, 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, + 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, + 0xaa, 0x2e, 0x28, 0x00, 0x00, 0x00, 0xaa, 0x2e, + 0x28, 0x00, 0x00, 0x00, 0xaa, 0xee, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa, 0xaa, 0xaa); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, + 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xff, + 0xff, 0xff, 0xff, 0xff); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, + 0x0e, 0x0e, 0x1e, 0x65, 0x1c, 0x65, 0x00, 0x50, + 0x20, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x05, + 0x14, 0x14, 0x32, 0xb9, 0x23, 0xb9, 0x08); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, + 0x02, 0x00, 0xa8, 0x01, 0xa8, 0x0d, 0xa4, 0x0e); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc3); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETCLOCK, 0xd1, 0xd6); + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f); + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc6); + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPTBA, 0x37); + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(150); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + msleep(50); + + return 0; +} + +static int hx83112a_disable(struct drm_panel *panel) +{ + struct hx83112a_panel *ctx = to_hx83112a_panel(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(20); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(120); + + return 0; +} + +static int hx83112a_prepare(struct drm_panel *panel) +{ + struct hx83112a_panel *ctx = to_hx83112a_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + hx83112a_reset(ctx); + + ret = hx83112a_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int hx83112a_unprepare(struct drm_panel *panel) +{ + struct hx83112a_panel *ctx = to_hx83112a_panel(panel); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode hx83112a_mode = { + .clock = (1080 + 28 + 8 + 8) * (2340 + 27 + 5 + 5) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 28, + .hsync_end = 1080 + 28 + 8, + .htotal = 1080 + 28 + 8 + 8, + .vdisplay = 2340, + .vsync_start = 2340 + 27, + .vsync_end = 2340 + 27 + 5, + .vtotal = 2340 + 27 + 5 + 5, + .width_mm = 67, + .height_mm = 145, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int hx83112a_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &hx83112a_mode); +} + +static const struct drm_panel_funcs hx83112a_panel_funcs = { + .prepare = hx83112a_prepare, + .unprepare = hx83112a_unprepare, + .disable = hx83112a_disable, + .get_modes = hx83112a_get_modes, +}; + +static int hx83112a_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct hx83112a_panel *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->supplies[0].supply = "vdd1"; + ctx->supplies[1].supply = "vsn"; + ctx->supplies[2].supply = "vsp"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_HSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + drm_panel_init(&ctx->panel, dev, &hx83112a_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void hx83112a_remove(struct mipi_dsi_device *dsi) +{ + struct hx83112a_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id hx83112a_of_match[] = { + { .compatible = "djn,9a-3r063-1102b" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hx83112a_of_match); + +static struct mipi_dsi_driver hx83112a_driver = { + .probe = hx83112a_probe, + .remove = hx83112a_remove, + .driver = { + .name = "panel-himax-hx83112a", + .of_match_table = hx83112a_of_match, + }, +}; +module_mipi_dsi_driver(hx83112a_driver); + +MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 8e0f5c3e3b..1a26205701 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -645,26 +645,17 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return -EINVAL; ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ctx->reset_gpio); - } + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); - if (IS_ERR(ctx->vci)) { - ret = PTR_ERR(ctx->vci); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request vci regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->vci)) + return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n"); ctx->iovcc = devm_regulator_get(dev, "iovcc"); - if (IS_ERR(ctx->iovcc)) { - ret = PTR_ERR(ctx->iovcc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(dev, PTR_ERR(ctx->iovcc), + "Failed to request iovcc regulator\n"); mipi_dsi_set_drvdata(dsi, ctx); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c index 39e408c9f7..a4c9a5cb98 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -11,6 +11,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/regulator/consumer.h> #include <video/mipi_display.h> @@ -21,25 +22,224 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> +struct ltk500hd1829_cmd { + char cmd; + char data; +}; + +struct ltk500hd1829_desc { + const struct drm_display_mode *mode; + const struct ltk500hd1829_cmd *init; + unsigned int num_init; +}; + struct ltk500hd1829 { struct device *dev; struct drm_panel panel; struct gpio_desc *reset_gpio; struct regulator *vcc; struct regulator *iovcc; + const struct ltk500hd1829_desc *panel_desc; bool prepared; }; -struct ltk500hd1829_cmd { - char cmd; - char data; +static const struct ltk500hd1829_cmd ltk101b4029w_init[] = { + /* Page0 */ + { 0xE0, 0x00 }, + /* PASSWORD */ + { 0xE1, 0x93 }, + { 0xE2, 0x65 }, + { 0xE3, 0xF8 }, + { 0x80, 0x03 }, /* 0X03:4-LANE; 0X02:3-LANE; 0X01:2-LANE */ + /* Page1 */ + { 0xE0, 0x01 }, + /* Set VCOM */ + { 0x00, 0x00 }, + { 0x01, 0x6F }, + /* Set Gamma Power, VGMP,VGMN,VGSP,VGSN */ + { 0x17, 0x00 }, + { 0x18, 0xAF }, /* 4.3V */ + { 0x19, 0x01 }, /* 0.3V */ + { 0x1A, 0x00 }, + { 0x1B, 0xAF }, /* 4.3V */ + { 0x1C, 0x01 }, /* 0.3V */ + /* Set Gate Power */ + { 0x1F, 0x3E }, /* VGH_R = 15V */ + { 0x20, 0x28 }, /* VGL_R = -12V */ + { 0x21, 0x28 }, /* VGL_R2 = -12V */ + { 0x22, 0x7E }, + /* SETPANEL */ + { 0x35, 0x26 }, + { 0x37, 0x09 }, + /* SET RGBCYC */ + { 0x38, 0x04 }, + { 0x39, 0x00 }, + { 0x3A, 0x01 }, + { 0x3C, 0x7C }, + { 0x3D, 0xFF }, + { 0x3E, 0xFF }, + { 0x3F, 0x7F }, + /* Set TCON */ + { 0x40, 0x06 }, /* RSO = 800 RGB */ + { 0x41, 0xA0 }, /* LN = 640->1280 line */ + { 0x42, 0x81 }, + { 0x43, 0x08 }, /* VFP = 8 */ + { 0x44, 0x0B }, /* VBP = 12 */ + { 0x45, 0x28 }, /* HBP = 40 */ + /* power voltage */ + { 0x55, 0x0F }, /* DCDCM = 0001, JD PWR_IC */ + { 0x57, 0x69 }, + { 0x59, 0x0A }, /* VCL = -2.9V */ + { 0x5A, 0x28 }, /* VGH = 15V */ + { 0x5B, 0x14 }, /* VGL = -11V */ + /* Gamma */ + { 0x5D, 0x7C }, + { 0x5E, 0x65 }, + { 0x5F, 0x55 }, + { 0x60, 0x47 }, + { 0x61, 0x43 }, + { 0x62, 0x32 }, + { 0x63, 0x34 }, + { 0x64, 0x1C }, + { 0x65, 0x33 }, + { 0x66, 0x31 }, + { 0x67, 0x30 }, + { 0x68, 0x4E }, + { 0x69, 0x3C }, + { 0x6A, 0x44 }, + { 0x6B, 0x35 }, + { 0x6C, 0x31 }, + { 0x6D, 0x23 }, + { 0x6E, 0x11 }, + { 0x6F, 0x00 }, + { 0x70, 0x7C }, + { 0x71, 0x65 }, + { 0x72, 0x55 }, + { 0x73, 0x47 }, + { 0x74, 0x43 }, + { 0x75, 0x32 }, + { 0x76, 0x34 }, + { 0x77, 0x1C }, + { 0x78, 0x33 }, + { 0x79, 0x31 }, + { 0x7A, 0x30 }, + { 0x7B, 0x4E }, + { 0x7C, 0x3C }, + { 0x7D, 0x44 }, + { 0x7E, 0x35 }, + { 0x7F, 0x31 }, + { 0x80, 0x23 }, + { 0x81, 0x11 }, + { 0x82, 0x00 }, + /* Page2, for GIP */ + { 0xE0, 0x02 }, + /* GIP_L Pin mapping */ + { 0x00, 0x1E }, + { 0x01, 0x1E }, + { 0x02, 0x41 }, + { 0x03, 0x41 }, + { 0x04, 0x43 }, + { 0x05, 0x43 }, + { 0x06, 0x1F }, + { 0x07, 0x1F }, + { 0x08, 0x35 }, + { 0x09, 0x1F }, + { 0x0A, 0x15 }, + { 0x0B, 0x15 }, + { 0x0C, 0x1F }, + { 0x0D, 0x47 }, + { 0x0E, 0x47 }, + { 0x0F, 0x45 }, + { 0x10, 0x45 }, + { 0x11, 0x4B }, + { 0x12, 0x4B }, + { 0x13, 0x49 }, + { 0x14, 0x49 }, + { 0x15, 0x1F }, + /* GIP_R Pin mapping */ + { 0x16, 0x1E }, + { 0x17, 0x1E }, + { 0x18, 0x40 }, + { 0x19, 0x40 }, + { 0x1A, 0x42 }, + { 0x1B, 0x42 }, + { 0x1C, 0x1F }, + { 0x1D, 0x1F }, + { 0x1E, 0x35 }, + { 0x1F, 0x1F }, + { 0x20, 0x15 }, + { 0x21, 0x15 }, + { 0x22, 0x1f }, + { 0x23, 0x46 }, + { 0x24, 0x46 }, + { 0x25, 0x44 }, + { 0x26, 0x44 }, + { 0x27, 0x4A }, + { 0x28, 0x4A }, + { 0x29, 0x48 }, + { 0x2A, 0x48 }, + { 0x2B, 0x1F }, + /* GIP Timing */ + { 0x58, 0x40 }, + { 0x5B, 0x30 }, + { 0x5C, 0x03 }, + { 0x5D, 0x30 }, + { 0x5E, 0x01 }, + { 0x5F, 0x02 }, + { 0x63, 0x14 }, + { 0x64, 0x6A }, + { 0x67, 0x73 }, + { 0x68, 0x05 }, + { 0x69, 0x14 }, + { 0x6A, 0x6A }, + { 0x6B, 0x08 }, + { 0x6C, 0x00 }, + { 0x6D, 0x00 }, + { 0x6E, 0x00 }, + { 0x6F, 0x88 }, + { 0x77, 0xDD }, + { 0x79, 0x0E }, + { 0x7A, 0x03 }, + { 0x7D, 0x14 }, + { 0x7E, 0x6A }, + /* Page4 */ + { 0xE0, 0x04 }, + { 0x09, 0x11 }, + { 0x0E, 0x48 }, + { 0x2B, 0x2B }, + { 0x2D, 0x03 }, + { 0x2E, 0x44 }, + /* Page0 */ + { 0xE0, 0x00 }, + { 0xE6, 0x02 }, + { 0xE7, 0x0C }, +}; + +static const struct drm_display_mode ltk101b4029w_mode = { + .hdisplay = 800, + .hsync_start = 800 + 18, + .hsync_end = 800 + 18 + 18, + .htotal = 800 + 18 + 18 + 18, + .vdisplay = 1280, + .vsync_start = 1280 + 24, + .vsync_end = 1280 + 24 + 4, + .vtotal = 1280 + 24 + 4 + 8, + .clock = 67330, + .width_mm = 136, + .height_mm = 218, +}; + +static const struct ltk500hd1829_desc ltk101b4029w_data = { + .mode = <k101b4029w_mode, + .init = ltk101b4029w_init, + .num_init = ARRAY_SIZE(ltk101b4029w_init), }; /* * There is no description in the Reference Manual about these commands. * We received them from the vendor, so just use them as is. */ -static const struct ltk500hd1829_cmd init_code[] = { +static const struct ltk500hd1829_cmd ltk500hd1829_init[] = { { 0xE0, 0x00 }, { 0xE1, 0x93 }, { 0xE2, 0x65 }, @@ -260,6 +460,26 @@ static const struct ltk500hd1829_cmd init_code[] = { { 0x35, 0x00 }, }; +static const struct drm_display_mode ltk500hd1829_mode = { + .hdisplay = 720, + .hsync_start = 720 + 50, + .hsync_end = 720 + 50 + 50, + .htotal = 720 + 50 + 50 + 50, + .vdisplay = 1280, + .vsync_start = 1280 + 30, + .vsync_end = 1280 + 30 + 4, + .vtotal = 1280 + 30 + 4 + 12, + .clock = 69217, + .width_mm = 62, + .height_mm = 110, +}; + +static const struct ltk500hd1829_desc ltk500hd1829_data = { + .mode = <k500hd1829_mode, + .init = ltk500hd1829_init, + .num_init = ARRAY_SIZE(ltk500hd1829_init), +}; + static inline struct ltk500hd1829 *panel_to_ltk500hd1829(struct drm_panel *panel) { @@ -324,8 +544,8 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) /* tRT: >= 5ms */ usleep_range(5000, 6000); - for (i = 0; i < ARRAY_SIZE(init_code); i++) { - ret = mipi_dsi_generic_write(dsi, &init_code[i], + for (i = 0; i < ctx->panel_desc->num_init; i++) { + ret = mipi_dsi_generic_write(dsi, &ctx->panel_desc->init[i], sizeof(struct ltk500hd1829_cmd)); if (ret < 0) { dev_err(panel->dev, "failed to write init cmds: %d\n", ret); @@ -359,31 +579,17 @@ disable_vcc: return ret; } -static const struct drm_display_mode default_mode = { - .hdisplay = 720, - .hsync_start = 720 + 50, - .hsync_end = 720 + 50 + 50, - .htotal = 720 + 50 + 50 + 50, - .vdisplay = 1280, - .vsync_start = 1280 + 30, - .vsync_end = 1280 + 30 + 4, - .vtotal = 1280 + 30 + 4 + 12, - .clock = 69217, - .width_mm = 62, - .height_mm = 110, -}; - static int ltk500hd1829_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, &default_mode); + mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode); if (!mode) { dev_err(ctx->dev, "failed to add mode %ux%u@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + ctx->panel_desc->mode->hdisplay, ctx->panel_desc->mode->vdisplay, + drm_mode_vrefresh(ctx->panel_desc->mode)); return -ENOMEM; } @@ -413,6 +619,10 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) if (!ctx) return -ENOMEM; + ctx->panel_desc = of_device_get_match_data(dev); + if (!ctx->panel_desc) + return -EINVAL; + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset gpio\n"); @@ -492,7 +702,14 @@ static void ltk500hd1829_remove(struct mipi_dsi_device *dsi) } static const struct of_device_id ltk500hd1829_of_match[] = { - { .compatible = "leadtek,ltk500hd1829", }, + { + .compatible = "leadtek,ltk101b4029w", + .data = <k101b4029w_data, + }, + { + .compatible = "leadtek,ltk500hd1829", + .data = <k500hd1829_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ltk500hd1829_of_match); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 83a9cf53d2..d3bfdfc9cf 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -36,6 +36,9 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> +#define NT35510_CMD_CORRECT_GAMMA BIT(0) +#define NT35510_CMD_CONTROL_DISPLAY BIT(1) + #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ #define MCS_CMD_READ_ID1 0xDA #define MCS_CMD_READ_ID2 0xDB @@ -112,18 +115,33 @@ /* AVDD and AVEE setting 3 bytes */ #define NT35510_P1_AVDD_LEN 3 #define NT35510_P1_AVEE_LEN 3 +#define NT35510_P1_VCL_LEN 3 #define NT35510_P1_VGH_LEN 3 #define NT35510_P1_VGL_LEN 3 #define NT35510_P1_VGP_LEN 3 #define NT35510_P1_VGN_LEN 3 +#define NT35510_P1_VCMOFF_LEN 2 /* BT1CTR thru BT5CTR setting 3 bytes */ #define NT35510_P1_BT1CTR_LEN 3 #define NT35510_P1_BT2CTR_LEN 3 +#define NT35510_P1_BT3CTR_LEN 3 #define NT35510_P1_BT4CTR_LEN 3 #define NT35510_P1_BT5CTR_LEN 3 /* 52 gamma parameters times two per color: positive and negative */ #define NT35510_P1_GAMMA_LEN 52 +#define NT35510_WRCTRLD_BCTRL BIT(5) +#define NT35510_WRCTRLD_A BIT(4) +#define NT35510_WRCTRLD_DD BIT(3) +#define NT35510_WRCTRLD_BL BIT(2) +#define NT35510_WRCTRLD_DB BIT(1) +#define NT35510_WRCTRLD_G BIT(0) + +#define NT35510_WRCABC_OFF 0 +#define NT35510_WRCABC_UI_MODE 1 +#define NT35510_WRCABC_STILL_MODE 2 +#define NT35510_WRCABC_MOVING_MODE 3 + /** * struct nt35510_config - the display-specific NT35510 configuration * @@ -172,6 +190,14 @@ struct nt35510_config { */ const struct drm_display_mode mode; /** + * @mode_flags: DSI operation mode related flags + */ + unsigned long mode_flags; + /** + * @cmds: enable DSI commands + */ + u32 cmds; + /** * @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V * in 0.1V steps the default is 0x05 which means 6.0V */ @@ -221,6 +247,25 @@ struct nt35510_config { */ u8 bt2ctr[NT35510_P1_BT2CTR_LEN]; /** + * @vcl: setting for VCL ranging from 0x00 = -2.5V to 0x11 = -4.0V + * in 1V steps, the default is 0x00 which means -2.5V + */ + u8 vcl[NT35510_P1_VCL_LEN]; + /** + * @bt3ctr: setting for boost power control for the VCL step-up + * circuit (3) + * bits 0..2 in the lower nibble controls CLCK, the booster clock + * frequency, the values are the same as for PCK in @bt1ctr. + * bits 4..5 in the upper nibble controls BTCL, the boosting + * amplification for the step-up circuit. + * 0 = Disable + * 1 = -0.5 x VDDB + * 2 = -1 x VDDB + * 3 = -2 x VDDB + * The defaults are 4 and 2 yielding 0x24 + */ + u8 bt3ctr[NT35510_P1_BT3CTR_LEN]; + /** * @vgh: setting for VGH ranging from 0x00 = 7.0V to 0x0B = 18.0V * in 1V steps, the default is 0x08 which means 15V */ @@ -274,6 +319,113 @@ struct nt35510_config { */ u8 vgn[NT35510_P1_VGN_LEN]; /** + * @vcmoff: setting the DC VCOM offset voltage + * The first byte contains bit 8 of VCM in bit 0 and VCMOFFSEL in bit 4. + * The second byte contains bits 0..7 of VCM. + * VCMOFFSEL the common voltage offset mode. + * VCMOFFSEL 0x00 = VCOM .. 0x01 Gamma. + * The default is 0x00. + * VCM the VCOM output voltage (VCMOFFSEL = 0) or the internal register + * offset for gamma voltage (VCMOFFSEL = 1). + * VCM 0x00 = 0V/0 .. 0x118 = 3.5V/280 in steps of 12.5mV/1step + * The default is 0x00 = 0V/0. + */ + u8 vcmoff[NT35510_P1_VCMOFF_LEN]; + /** + * @dopctr: setting optional control for display + * ERR bits 0..1 in the first byte is the ERR pin output signal setting. + * 0 = Disable, ERR pin output low + * 1 = ERR pin output CRC error only + * 2 = ERR pin output ECC error only + * 3 = ERR pin output CRC and ECC error + * The default is 0. + * N565 bit 2 in the first byte is the 16-bit/pixel format selection. + * 0 = R[4:0] + G[5:3] & G[2:0] + B[4:0] + * 1 = G[2:0] + R[4:0] & B[4:0] + G[5:3] + * The default is 0. + * DIS_EoTP_HS bit 3 in the first byte is "DSI protocol violation" error + * reporting. + * 0 = reporting when error + * 1 = not reporting when error + * DSIM bit 4 in the first byte is the video mode data type enable + * 0 = Video mode data type disable + * 1 = Video mode data type enable + * The default is 0. + * DSIG bit 5 int the first byte is the generic r/w data type enable + * 0 = Generic r/w disable + * 1 = Generic r/w enable + * The default is 0. + * DSITE bit 6 in the first byte is TE line enable + * 0 = TE line is disabled + * 1 = TE line is enabled + * The default is 0. + * RAMKP bit 7 in the first byte is the frame memory keep/loss in + * sleep-in mode + * 0 = contents loss in sleep-in + * 1 = contents keep in sleep-in + * The default is 0. + * CRL bit 1 in the second byte is the source driver data shift + * direction selection. This bit is XOR operation with bit RSMX + * of 3600h command. + * 0 (RMSX = 0) = S1 -> S1440 + * 0 (RMSX = 1) = S1440 -> S1 + * 1 (RMSX = 0) = S1440 -> S1 + * 1 (RMSX = 1) = S1 -> S1440 + * The default is 0. + * CTB bit 2 in the second byte is the vertical scanning direction + * selection for gate control signals. This bit is XOR operation + * with bit ML of 3600h command. + * 0 (ML = 0) = Forward (top -> bottom) + * 0 (ML = 1) = Reverse (bottom -> top) + * 1 (ML = 0) = Reverse (bottom -> top) + * 1 (ML = 1) = Forward (top -> bottom) + * The default is 0. + * CRGB bit 3 in the second byte is RGB-BGR order selection. This + * bit is XOR operation with bit RGB of 3600h command. + * 0 (RGB = 0) = RGB/Normal + * 0 (RGB = 1) = BGR/RB swap + * 1 (RGB = 0) = BGR/RB swap + * 1 (RGB = 1) = RGB/Normal + * The default is 0. + * TE_PWR_SEL bit 4 in the second byte is the TE output voltage + * level selection (only valid when DSTB_SEL = 0 or DSTB_SEL = 1, + * VSEL = High and VDDI = 1.665~3.3V). + * 0 = TE output voltage level is VDDI + * 1 = TE output voltage level is VDDA + * The default is 0. + */ + u8 dopctr[NT35510_P0_DOPCTR_LEN]; + /** + * @madctl: Memory data access control + * RSMY bit 0 is flip vertical. Flips the display image top to down. + * RSMX bit 1 is flip horizontal. Flips the display image left to right. + * MH bit 2 is the horizontal refresh order. + * RGB bit 3 is the RGB-BGR order. + * 0 = RGB color sequence + * 1 = BGR color sequence + * ML bit 4 is the vertical refresh order. + * MV bit 5 is the row/column exchange. + * MX bit 6 is the column address order. + * MY bit 7 is the row address order. + */ + u8 madctl; + /** + * @sdhdtctr: source output data hold time + * 0x00..0x3F = 0..31.5us in steps of 0.5us + * The default is 0x05 = 2.5us. + */ + u8 sdhdtctr; + /** + * @gseqctr: EQ control for gate signals + * GFEQ_XX[3:0]: time setting of EQ step for falling edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + * GREQ_XX[7:4]: time setting of EQ step for rising edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + */ + u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; + /** * @sdeqctr: Source driver control settings, first byte is * 0 for mode 1 and 1 for mode 2. Mode 1 uses two steps and * mode 2 uses three steps meaning EQS3 is not used in mode @@ -343,6 +495,43 @@ struct nt35510_config { * @gamma_corr_neg_b: Blue gamma correction parameters, negative */ u8 gamma_corr_neg_b[NT35510_P1_GAMMA_LEN]; + /** + * @wrdisbv: write display brightness + * 0x00 value means the lowest brightness and 0xff value means + * the highest brightness. + * The default is 0x00. + */ + u8 wrdisbv; + /** + * @wrctrld: write control display + * G bit 0 selects gamma curve: 0 = Manual, 1 = Automatic + * DB bit 1 selects display brightness: 0 = Manual, 1 = Automatic + * BL bit 2 controls backlight control: 0 = Off, 1 = On + * DD bit 3 controls display dimming: 0 = Off, 1 = On + * A bit 4 controls LABC block: 0 = Off, 1 = On + * BCTRL bit 5 controls brightness block: 0 = Off, 1 = On + */ + u8 wrctrld; + /** + * @wrcabc: write content adaptive brightness control + * There is possible to use 4 different modes for content adaptive + * image functionality: + * 0: Off + * 1: User Interface Image (UI-Mode) + * 2: Still Picture Image (Still-Mode) + * 3: Moving Picture Image (Moving-Mode) + * The default is 0 + */ + u8 wrcabc; + /** + * @wrcabcmb: write CABC minimum brightness + * Set the minimum brightness value of the display for CABC + * function. + * 0x00 value means the lowest brightness for CABC and 0xff + * value means the highest brightness for CABC. + * The default is 0x00. + */ + u8 wrcabcmb; }; /** @@ -486,6 +675,16 @@ static int nt35510_setup_power(struct nt35510 *nt) nt->conf->bt2ctr); if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCL, + NT35510_P1_VCL_LEN, + nt->conf->vcl); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_BT3CTR, + NT35510_P1_BT3CTR_LEN, + nt->conf->bt3ctr); + if (ret) + return ret; ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGH, NT35510_P1_VGH_LEN, nt->conf->vgh); @@ -522,6 +721,12 @@ static int nt35510_setup_power(struct nt35510 *nt) if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCMOFF, + NT35510_P1_VCMOFF_LEN, + nt->conf->vcmoff); + if (ret) + return ret; + /* Typically 10 ms */ usleep_range(10000, 20000); @@ -536,46 +741,28 @@ static int nt35510_setup_display(struct nt35510 *nt) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); const struct nt35510_config *conf = nt->conf; - u8 dopctr[NT35510_P0_DOPCTR_LEN]; - u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; u8 dpfrctr[NT35510_P0_DPFRCTR1_LEN]; - /* FIXME: set up any rotation (assume none for now) */ - u8 addr_mode = NT35510_ROTATE_0_SETTING; - u8 val; int ret; - /* Enable TE, EoTP and RGB pixel format */ - dopctr[0] = NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | - NT35510_DOPCTR_0_N565; - dopctr[1] = NT35510_DOPCTR_1_CTB; ret = nt35510_send_long(nt, dsi, NT35510_P0_DOPCTR, NT35510_P0_DOPCTR_LEN, - dopctr); + conf->dopctr); if (ret) return ret; - ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &addr_mode, - sizeof(addr_mode)); + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &conf->madctl, + sizeof(conf->madctl)); if (ret < 0) return ret; - /* - * Source data hold time, default 0x05 = 2.5us - * 0x00..0x3F = 0 .. 31.5us in steps of 0.5us - * 0x0A = 5us - */ - val = 0x0A; - ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &val, - sizeof(val)); + ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &conf->sdhdtctr, + sizeof(conf->sdhdtctr)); if (ret < 0) return ret; - /* EQ control for gate signals, 0x00 = 0 us */ - gseqctr[0] = 0x00; - gseqctr[1] = 0x00; ret = nt35510_send_long(nt, dsi, NT35510_P0_GSEQCTR, NT35510_P0_GSEQCTR_LEN, - gseqctr); + conf->gseqctr); if (ret) return ret; @@ -719,36 +906,38 @@ static int nt35510_power_on(struct nt35510 *nt) if (ret) return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_b); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_b); - if (ret) - return ret; + if (nt->conf->cmds & NT35510_CMD_CORRECT_GAMMA) { + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_b); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_b); + if (ret) + return ret; + } /* Set up stuff in manufacturer control, page 0 */ ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR, @@ -827,6 +1016,26 @@ static int nt35510_prepare(struct drm_panel *panel) /* Up to 120 ms */ usleep_range(120000, 150000); + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) { + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &nt->conf->wrctrld, + sizeof(nt->conf->wrctrld)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE, + &nt->conf->wrcabc, + sizeof(nt->conf->wrcabc)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, + &nt->conf->wrcabcmb, + sizeof(nt->conf->wrcabcmb)); + if (ret < 0) + return ret; + } + ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { dev_err(nt->dev, "failed to turn display on (%d)\n", ret); @@ -896,7 +1105,6 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) */ dsi->hs_rate = 349440000; dsi->lp_rate = 9600000; - dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; /* * Every new incarnation of this display must have a unique @@ -908,6 +1116,8 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return -ENODEV; } + dsi->mode_flags = nt->conf->mode_flags; + nt->supplies[0].supply = "vdd"; /* 2.3-4.8 V */ nt->supplies[1].supply = "vddi"; /* 1.65-3.3V */ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->supplies), @@ -923,7 +1133,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(nt->reset_gpio)) { dev_err(dev, "error getting RESET GPIO\n"); return PTR_ERR(nt->reset_gpio); @@ -952,7 +1162,10 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return PTR_ERR(bl); } bl->props.max_brightness = 255; - bl->props.brightness = 255; + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) + bl->props.brightness = nt->conf->wrdisbv; + else + bl->props.brightness = 255; bl->props.power = FB_BLANK_POWERDOWN; nt->panel.backlight = bl; } @@ -1030,6 +1243,8 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vtotal = 800 + 2 + 0 + 5, /* VBP = 5 */ .flags = 0, }, + .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS, + .cmds = NT35510_CMD_CORRECT_GAMMA, /* 0x09: AVDD = 5.6V */ .avdd = { 0x09, 0x09, 0x09 }, /* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */ @@ -1038,6 +1253,10 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .avee = { 0x09, 0x09, 0x09 }, /* 0x24: NCK = Hsync/2, BTN = -2 x VDDB */ .bt2ctr = { 0x24, 0x24, 0x24 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -2.5V */ + .vcl = { 0x00, 0x00, 0x00 }, + /* 0x24: CLCK = Hsync/2, BTN = -1 x VDDB */ + .bt3ctr = { 0x24, 0x24, 0x24 }, /* 0x05 = 12V */ .vgh = { 0x05, 0x05, 0x05 }, /* 0x24: NCKA = Hsync/2, VGH = 2 x AVDD - AVEE */ @@ -1050,6 +1269,16 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vgp = { 0x00, 0xA3, 0x00 }, /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ .vgn = { 0x00, 0xA3, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = 0V */ + .vcmoff = { 0x00, 0x00 }, + /* Enable TE, EoTP and RGB pixel format */ + .dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | + NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB }, + .madctl = NT35510_ROTATE_0_SETTING, + /* 0x0A: SDT = 5 us */ + .sdhdtctr = 0x0A, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, /* SDEQCTR: source driver EQ mode 2, 2.5 us rise time on each step */ .sdeqctr = { 0x01, 0x05, 0x05, 0x05 }, /* SDVPCTR: Normal operation off color during v porch */ @@ -1073,8 +1302,89 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .gamma_corr_neg_b = { NT35510_GAMMA_NEG_DEFAULT }, }; +static const struct nt35510_config nt35510_frida_frd400b25025 = { + .width_mm = 52, + .height_mm = 86, + .mode = { + .clock = 23000, + .hdisplay = 480, + .hsync_start = 480 + 34, /* HFP = 34 */ + .hsync_end = 480 + 34 + 2, /* HSync = 2 */ + .htotal = 480 + 34 + 2 + 34, /* HBP = 34 */ + .vdisplay = 800, + .vsync_start = 800 + 15, /* VFP = 15 */ + .vsync_end = 800 + 15 + 12, /* VSync = 12 */ + .vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */ + .flags = 0, + }, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM, + .cmds = NT35510_CMD_CONTROL_DISPLAY, + /* 0x03: AVDD = 6.2V */ + .avdd = { 0x03, 0x03, 0x03 }, + /* 0x46: PCK = 2 x Hsync, BTP = 2.5 x VDDB */ + .bt1ctr = { 0x46, 0x46, 0x46 }, + /* 0x03: AVEE = -6.2V */ + .avee = { 0x03, 0x03, 0x03 }, + /* 0x36: PCK = 2 x Hsync, BTP = 2 x VDDB */ + .bt2ctr = { 0x36, 0x36, 0x36 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -3.5V */ + .vcl = { 0x00, 0x00, 0x02 }, + /* 0x26: CLCK = 2 x Hsync, BTN = -1 x VDDB */ + .bt3ctr = { 0x26, 0x26, 0x26 }, + /* 0x09 = 16V */ + .vgh = { 0x09, 0x09, 0x09 }, + /* 0x36: HCK = 2 x Hsync, VGH = 2 x AVDD - AVEE */ + .bt4ctr = { 0x36, 0x36, 0x36 }, + /* 0x08 = -10V */ + .vgl = { 0x08, 0x08, 0x08 }, + /* 0x26: LCK = 2 x Hsync, VGL = AVDD + VCL - AVDD */ + .bt5ctr = { 0x26, 0x26, 0x26 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgp = { 0x00, 0x80, 0x00 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgn = { 0x00, 0x80, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = -1V */ + .vcmoff = { 0x00, 0x50 }, + .dopctr = { NT35510_DOPCTR_0_RAMKP | NT35510_DOPCTR_0_DSITE | + NT35510_DOPCTR_0_DSIG | NT35510_DOPCTR_0_DSIM | + NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, 0 }, + .madctl = NT35510_ROTATE_180_SETTING, + /* 0x03: SDT = 1.5 us */ + .sdhdtctr = 0x03, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, + /* SDEQCTR: source driver EQ mode 2, 1 us rise time on each step */ + .sdeqctr = { 0x01, 0x02, 0x02, 0x02 }, + /* SDVPCTR: Normal operation off color during v porch */ + .sdvpctr = 0x01, + /* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */ + .t1 = 0x0184, + /* VBP: vertical back porch toward the panel */ + .vbp = 0x1C, + /* VFP: vertical front porch toward the panel */ + .vfp = 0x1C, + /* PSEL: divide pixel clock 23MHz with 1 (no clock downscaling) */ + .psel = 0, + /* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */ + .dpmctr12 = { 0x03, 0x00, 0x00, }, + /* write display brightness */ + .wrdisbv = 0x7f, + /* write control display */ + .wrctrld = NT35510_WRCTRLD_BCTRL | NT35510_WRCTRLD_DD | + NT35510_WRCTRLD_BL, + /* write content adaptive brightness control */ + .wrcabc = NT35510_WRCABC_STILL_MODE, + /* write CABC minimum brightness */ + .wrcabcmb = 0xff, +}; + static const struct of_device_id nt35510_of_match[] = { { + .compatible = "frida,frd400b25025", + .data = &nt35510_frida_frd400b25025, + }, + { .compatible = "hydis,hva40wv1", .data = &nt35510_hydis_hva40wv1, }, diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index a189ce2363..18bd2ee712 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -933,8 +933,7 @@ static int j606f_boe_init_sequence(struct panel_info *pinfo) static const struct drm_display_mode elish_boe_modes[] = { { - /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ - .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 104 / 1000, + .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 120 / 1000, .hdisplay = 1600, .hsync_start = 1600 + 60, .hsync_end = 1600 + 60 + 8, @@ -948,8 +947,7 @@ static const struct drm_display_mode elish_boe_modes[] = { static const struct drm_display_mode elish_csot_modes[] = { { - /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ - .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 104 / 1000, + .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 120 / 1000, .hdisplay = 1600, .hsync_start = 1600 + 200, .hsync_end = 1600 + 200 + 40, @@ -1270,6 +1268,8 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) return ret; } + pinfo->panel.prepare_prev_first = true; + if (pinfo->desc->has_dcs_backlight) { pinfo->panel.backlight = nt36523_create_backlight(dsi); if (IS_ERR(pinfo->panel.backlight)) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c new file mode 100644 index 0000000000..c39fe0fc5d --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +static const char * const regulator_names[] = { + "vddi", + "avdd", + "avee", +}; + +static const unsigned long regulator_enable_loads[] = { + 62000, + 100000, + 100000, +}; + +static const unsigned long regulator_disable_loads[] = { + 80, + 100, + 100, +}; + +struct panel_desc { + const struct drm_display_mode *display_mode; + u32 width_mm; + u32 height_mm; + unsigned long mode_flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; + const char *panel_name; + int (*init_sequence)(struct mipi_dsi_device *dsi); +}; + +struct nt36672e_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[3]; + const struct panel_desc *desc; +}; + +static inline struct nt36672e_panel *to_nt36672e_panel(struct drm_panel *panel) +{ + return container_of(panel, struct nt36672e_panel, panel); +} + +static int nt36672e_1080x2408_60hz_init(struct mipi_dsi_device *dsi) +{ + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x89, 0x28, 0x00, 0x08, 0x00, 0xaa, 0x02, + 0x0e, 0x00, 0x2b, 0x00, 0x07, 0x0d, 0xb7, 0x0c, 0xb7); + + mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x1b, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x66); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x38); + mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x83); + mipi_dsi_dcs_write_seq(dsi, 0x69, 0x91); + mipi_dsi_dcs_write_seq(dsi, 0x95, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0x96, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0xf2, 0x64); + mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x54); + mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x64); + mipi_dsi_dcs_write_seq(dsi, 0xf5, 0x54); + mipi_dsi_dcs_write_seq(dsi, 0xf6, 0x64); + mipi_dsi_dcs_write_seq(dsi, 0xf7, 0x54); + mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x64); + mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x54); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x2f); + mipi_dsi_dcs_write_seq(dsi, 0x09, 0x2e); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x2d); + mipi_dsi_dcs_write_seq(dsi, 0x0b, 0x2c); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x13, 0x15); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x2f); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x2e); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x2d); + mipi_dsi_dcs_write_seq(dsi, 0x23, 0x2c); + mipi_dsi_dcs_write_seq(dsi, 0x29, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x15); + mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0x30, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0x31, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0x32, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x35, 0x1f); + mipi_dsi_dcs_write_seq(dsi, 0x36, 0x1f); + mipi_dsi_dcs_write_seq(dsi, 0x4d, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0x4e, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x4f, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x53, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x71, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0x79, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x7a, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0x7b, 0x8f); + mipi_dsi_dcs_write_seq(dsi, 0x7d, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x80, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x81, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x82, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x84, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0x85, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x86, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x87, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x90, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x92, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0x93, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x94, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x95, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x9c, 0xf4); + mipi_dsi_dcs_write_seq(dsi, 0x9d, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xa0, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0xa2, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0xa3, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0xa4, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xa5, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xc0); + mipi_dsi_dcs_write_seq(dsi, 0xc9, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xd9, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xe9, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x18, 0x22); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0xe4); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x66, 0xd8); + mipi_dsi_dcs_write_seq(dsi, 0x68, 0x50); + mipi_dsi_dcs_write_seq(dsi, 0x69, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x6b, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x0d); + mipi_dsi_dcs_write_seq(dsi, 0x6e, 0x48); + mipi_dsi_dcs_write_seq(dsi, 0x72, 0x41); + mipi_dsi_dcs_write_seq(dsi, 0x73, 0x4a); + mipi_dsi_dcs_write_seq(dsi, 0x74, 0xd0); + mipi_dsi_dcs_write_seq(dsi, 0x77, 0x62); + mipi_dsi_dcs_write_seq(dsi, 0x79, 0x7e); + mipi_dsi_dcs_write_seq(dsi, 0x7d, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x15); + mipi_dsi_dcs_write_seq(dsi, 0x7f, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x84, 0x4d); + mipi_dsi_dcs_write_seq(dsi, 0xcf, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xd7, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xef, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x84); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x83, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x84, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x85, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x86, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x87, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0x8a, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0x8b, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x8c, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x42); + mipi_dsi_dcs_write_seq(dsi, 0x8f, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x90, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x91, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x9a, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x9b, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x9c, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x9d, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x9e, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x27); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x81); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x6a); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x81); + mipi_dsi_dcs_write_seq(dsi, 0x26, 0x94); + mipi_dsi_dcs_write_seq(dsi, 0x6e, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x70, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x71, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x72, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x75, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x76, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x77, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x7d, 0x09); + mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x67); + mipi_dsi_dcs_write_seq(dsi, 0x80, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0x82, 0x09); + mipi_dsi_dcs_write_seq(dsi, 0x83, 0x67); + mipi_dsi_dcs_write_seq(dsi, 0x88, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x89, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xa5, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xa6, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0xa7, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0xe6, 0xd3); + mipi_dsi_dcs_write_seq(dsi, 0xeb, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0xec, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x91); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x50); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0xe0); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0xa4); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x78); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x3e); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x3e); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x3e); + mipi_dsi_dcs_write_seq(dsi, 0x28, 0xfd); + mipi_dsi_dcs_write_seq(dsi, 0x29, 0x12); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0xe1); + mipi_dsi_dcs_write_seq(dsi, 0x2d, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x30, 0x49); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x96); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0x35, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x36, 0xde); + mipi_dsi_dcs_write_seq(dsi, 0x37, 0xf9); + mipi_dsi_dcs_write_seq(dsi, 0x38, 0x45); + mipi_dsi_dcs_write_seq(dsi, 0x39, 0xd9); + mipi_dsi_dcs_write_seq(dsi, 0x3a, 0x49); + mipi_dsi_dcs_write_seq(dsi, 0x4a, 0xf0); + mipi_dsi_dcs_write_seq(dsi, 0x7a, 0x09); + mipi_dsi_dcs_write_seq(dsi, 0x7b, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x7f, 0xf0); + mipi_dsi_dcs_write_seq(dsi, 0x83, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x84, 0xa4); + mipi_dsi_dcs_write_seq(dsi, 0x87, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x88, 0x78); + mipi_dsi_dcs_write_seq(dsi, 0x89, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0x8b, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x8c, 0x7d); + mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x7d); + mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x7d); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x00, 0x00, 0x17, 0x00, 0x49, 0x00, + 0x6a, 0x00, 0x89, 0x00, 0x9f, 0x00, 0xb6, 0x00, 0xc8); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xd9, 0x01, 0x10, 0x01, 0x3a, 0x01, + 0x7a, 0x01, 0xa9, 0x01, 0xf2, 0x02, 0x2d, 0x02, 0x2e); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x64, 0x02, 0xa3, 0x02, 0xca, 0x03, + 0x00, 0x03, 0x1e, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a); + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00, + 0x71, 0x00, 0x90, 0x00, 0xa7, 0x00, 0xbf, 0x00, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xe2, 0x01, 0x1a, 0x01, 0x43, 0x01, + 0x83, 0x01, 0xb2, 0x01, 0xfa, 0x02, 0x34, 0x02, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x6b, 0x02, 0xa8, 0x02, 0xd0, 0x03, + 0x03, 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5b, 0x03, 0x6b); + mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x7e, 0x03, 0x94, 0x03, 0xac, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00, + 0x72, 0x00, 0x92, 0x00, 0xa8, 0x00, 0xbf, 0x00, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xe2, 0x01, 0x18, 0x01, 0x42, 0x01, + 0x81, 0x01, 0xaf, 0x01, 0xf5, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x68, 0x02, 0xa6, 0x02, 0xcd, 0x03, + 0x01, 0x03, 0x1f, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a); + mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x21); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x00, 0x00, 0x17, 0x00, 0x49, 0x00, + 0x6a, 0x00, 0x89, 0x00, 0x9f, 0x00, 0xb6, 0x00, 0xc8); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xd9, 0x01, 0x10, 0x01, 0x3a, 0x01, + 0x7a, 0x01, 0xa9, 0x01, 0xf2, 0x02, 0x2d, 0x02, 0x2e); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x64, 0x02, 0xa3, 0x02, 0xca, 0x03, + 0x00, 0x03, 0x1e, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a); + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00, + 0x71, 0x00, 0x90, 0x00, 0xa7, 0x00, 0xbf, 0x00, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xe2, 0x01, 0x1a, 0x01, 0x43, 0x01, + 0x83, 0x01, 0xb2, 0x01, 0xfa, 0x02, 0x34, 0x02, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x6b, 0x02, 0xa8, 0x02, 0xd0, 0x03, + 0x03, 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5b, 0x03, 0x6b); + mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x7e, 0x03, 0x94, 0x03, 0xac, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00, + 0x72, 0x00, 0x92, 0x00, 0xa8, 0x00, 0xbf, 0x00, 0xd1); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xe2, 0x01, 0x18, 0x01, 0x42, 0x01, + 0x81, 0x01, 0xaf, 0x01, 0xf5, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x68, 0x02, 0xa6, 0x02, 0xcd, 0x03, + 0x01, 0x03, 0x1f, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a); + mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03, + 0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2c); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x61, 0x1f); + mipi_dsi_dcs_write_seq(dsi, 0x62, 0x1f); + mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x6a, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0x6b, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x36); + mipi_dsi_dcs_write_seq(dsi, 0x53, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x54, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x55, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x56, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x58, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x59, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0xf0); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x00); + + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x51, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0x53, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0x55, 0x01); + + return 0; +} + +static int nt36672e_power_on(struct nt36672e_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { + ret = regulator_set_load(ctx->supplies[i].consumer, + regulator_enable_loads[i]); + if (ret) { + dev_err(&dsi->dev, "regulator set load failed for supply %s: %d\n", + ctx->supplies[i].supply, ret); + return ret; + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret); + return ret; + } + + /* + * Reset sequence of nt36672e panel requires the panel to be out of reset + * for 10ms, followed by being held in reset for 10ms and then out again. + */ + gpiod_set_value(ctx->reset_gpio, 1); + usleep_range(10000, 20000); + gpiod_set_value(ctx->reset_gpio, 0); + usleep_range(10000, 20000); + gpiod_set_value(ctx->reset_gpio, 1); + usleep_range(10000, 20000); + + return 0; +} + +static int nt36672e_power_off(struct nt36672e_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + int ret = 0; + int i; + + gpiod_set_value(ctx->reset_gpio, 0); + + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { + ret = regulator_set_load(ctx->supplies[i].consumer, + regulator_disable_loads[i]); + if (ret) { + dev_err(&dsi->dev, "regulator set load failed for supply %s: %d\n", + ctx->supplies[i].supply, ret); + return ret; + } + } + + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret) + dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret); + + return ret; +} + +static int nt36672e_on(struct nt36672e_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + const struct panel_desc *desc = ctx->desc; + int ret = 0; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + if (desc->init_sequence) { + ret = desc->init_sequence(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "panel init sequence failed: %d\n", ret); + return ret; + } + } + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(120); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to set display on: %d\n", ret); + return ret; + } + msleep(100); + + return 0; +} + +static int nt36672e_off(struct nt36672e_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + int ret = 0; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(20); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(60); + + return 0; +} + +static int nt36672e_panel_prepare(struct drm_panel *panel) +{ + struct nt36672e_panel *ctx = to_nt36672e_panel(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + int ret = 0; + + ret = nt36672e_power_on(ctx); + if (ret < 0) + return ret; + + ret = nt36672e_on(ctx); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to initialize panel: %d\n", ret); + if (nt36672e_power_off(ctx)) + dev_err(&dsi->dev, "power off failed\n"); + return ret; + } + + return 0; +} + +static int nt36672e_panel_unprepare(struct drm_panel *panel) +{ + struct nt36672e_panel *ctx = to_nt36672e_panel(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + int ret = 0; + + ret = nt36672e_off(ctx); + if (ret < 0) + dev_err(&dsi->dev, "Failed to un-initialize panel: %d\n", ret); + + ret = nt36672e_power_off(ctx); + if (ret < 0) + dev_err(&dsi->dev, "power off failed: %d\n", ret); + + return 0; +} + +static const struct drm_display_mode nt36672e_1080x2408_60hz = { + .name = "1080x2408", + .clock = 181690, + .hdisplay = 1080, + .hsync_start = 1080 + 76, + .hsync_end = 1080 + 76 + 12, + .htotal = 1080 + 76 + 12 + 56, + .vdisplay = 2408, + .vsync_start = 2408 + 46, + .vsync_end = 2408 + 46 + 10, + .vtotal = 2408 + 46 + 10 + 10, + .flags = 0, +}; + +static const struct panel_desc nt36672e_panel_desc = { + .display_mode = &nt36672e_1080x2408_60hz, + .width_mm = 74, + .height_mm = 131, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, + .panel_name = "nt36672e fhd plus panel", + .init_sequence = nt36672e_1080x2408_60hz_init, +}; + +static int nt36672e_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector) +{ + struct nt36672e_panel *ctx = to_nt36672e_panel(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, ctx->desc->display_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = ctx->desc->width_mm; + connector->display_info.height_mm = ctx->desc->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs nt36672e_drm_funcs = { + .prepare = nt36672e_panel_prepare, + .unprepare = nt36672e_panel_unprepare, + .get_modes = nt36672e_panel_get_modes, +}; + +static int nt36672e_panel_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct nt36672e_panel *ctx; + int i, ret = 0; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->desc = of_device_get_match_data(dev); + if (!ctx->desc) { + dev_err(dev, "missing device configuration\n"); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) + ctx->supplies[i].supply = regulator_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = ctx->desc->lanes; + dsi->format = ctx->desc->format; + dsi->mode_flags = ctx->desc->mode_flags; + + drm_panel_init(&ctx->panel, dev, &nt36672e_drm_funcs, DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + ctx->panel.prepare_prev_first = true; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + goto err_dsi_attach; + } + + return 0; + +err_dsi_attach: + drm_panel_remove(&ctx->panel); + return ret; +} + +static void nt36672e_panel_remove(struct mipi_dsi_device *dsi) +{ + struct nt36672e_panel *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(ctx->dsi); + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id nt36672e_of_match[] = { + { + .compatible = "novatek,nt36672e", + .data = &nt36672e_panel_desc, + }, + { } +}; +MODULE_DEVICE_TABLE(of, nt36672e_of_match); + +static struct mipi_dsi_driver nt36672e_panel_driver = { + .driver = { + .name = "panel-novatek-nt36672e", + .of_match_table = nt36672e_of_match, + }, + .probe = nt36672e_panel_probe, + .remove = nt36672e_panel_remove, +}; +module_mipi_dsi_driver(nt36672e_panel_driver); + +MODULE_AUTHOR("Ritesh Kumar <quic_riteshk@quicinc.com>"); +MODULE_DESCRIPTION("Novatek NT36672E DSI Panel Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 228c5c48e1..e8fe5a6945 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1997,6 +1997,33 @@ static const struct panel_desc edt_etml0700y5dha = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing edt_etml1010g3dra_timing = { + .pixelclock = { 66300000, 72400000, 78900000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 12, 72, 132 }, + .hback_porch = { 86, 86, 86 }, + .hsync_len = { 2, 2, 2 }, + .vactive = { 800, 800, 800 }, + .vfront_porch = { 1, 15, 49 }, + .vback_porch = { 21, 21, 21 }, + .vsync_len = { 2, 2, 2 }, + .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc edt_etml1010g3dra = { + .timings = &edt_etml1010g3dra_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 216, + .height = 135, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode edt_etmv570g2dhu_mode = { .clock = 25175, .hdisplay = 640, @@ -2774,21 +2801,21 @@ static const struct panel_desc lemaker_bl035_rgb_002 = { .bus_flags = DRM_BUS_FLAG_DE_LOW, }; -static const struct drm_display_mode lg_lb070wv8_mode = { - .clock = 33246, - .hdisplay = 800, - .hsync_start = 800 + 88, - .hsync_end = 800 + 88 + 80, - .htotal = 800 + 88 + 80 + 88, - .vdisplay = 480, - .vsync_start = 480 + 10, - .vsync_end = 480 + 10 + 25, - .vtotal = 480 + 10 + 25 + 10, +static const struct display_timing lg_lb070wv8_timing = { + .pixelclock = { 31950000, 33260000, 34600000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 88, 88, 88 }, + .hback_porch = { 88, 88, 88 }, + .hsync_len = { 80, 80, 80 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 10, 10, 10 }, + .vback_porch = { 10, 10, 10 }, + .vsync_len = { 25, 25, 25 }, }; static const struct panel_desc lg_lb070wv8 = { - .modes = &lg_lb070wv8_mode, - .num_modes = 1, + .timings = &lg_lb070wv8_timing, + .num_timings = 1, .bpc = 8, .size = { .width = 151, @@ -3536,14 +3563,15 @@ static const struct display_timing rocktech_rk043fn48h_timing = { .pixelclock = { 6000000, 9000000, 12000000 }, .hactive = { 480, 480, 480 }, .hback_porch = { 8, 43, 43 }, - .hfront_porch = { 2, 8, 8 }, + .hfront_porch = { 2, 8, 10 }, .hsync_len = { 1, 1, 1 }, .vactive = { 272, 272, 272 }, - .vback_porch = { 2, 12, 12 }, + .vback_porch = { 2, 12, 26 }, .vfront_porch = { 1, 4, 4 }, .vsync_len = { 1, 10, 10 }, .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW | - DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE, + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, }; static const struct panel_desc rocktech_rk043fn48h = { @@ -4447,6 +4475,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "edt,etml0700y5dha", .data = &edt_etml0700y5dha, }, { + .compatible = "edt,etml1010g3dra", + .data = &edt_etml1010g3dra, + }, { .compatible = "edt,etmv570g2dhu", .data = &edt_etmv570g2dhu, }, { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index b55bafd1a8..a3e142f156 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -62,6 +62,7 @@ struct st7703 { struct dentry *debugfs; const struct st7703_panel_desc *desc; + enum drm_panel_orientation orientation; }; struct st7703_panel_desc { @@ -521,6 +522,96 @@ static const struct st7703_panel_desc rgb30panel_desc = { .init_sequence = rgb30panel_init_sequence, }; +static int rgb10max3_panel_init_sequence(struct st7703 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */ + + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda, + 0x80); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28, + 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x04, 0x04); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x78, 0x78); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0, + 0x63); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9, + 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00, + 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50, + 0x00, 0x00, 0x12, 0x70, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32, + 0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77, + 0x77); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff, + 0x00, 0xff); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e, + 0x02); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07, + 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e, + 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04, + 0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, + 0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, + 0xc0, 0x10); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00, + 0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86, + 0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01); + + return 0; +} + +static const struct drm_display_mode rgb10max3_panel_mode = { + .hdisplay = 720, + .hsync_start = 720 + 40, + .hsync_end = 720 + 40 + 10, + .htotal = 720 + 40 + 10 + 40, + .vdisplay = 1280, + .vsync_start = 1280 + 16, + .vsync_end = 1280 + 16 + 4, + .vtotal = 1280 + 16 + 4 + 14, + .clock = 63800, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 62, + .height_mm = 109, +}; + +static const struct st7703_panel_desc rgb10max3_panel_desc = { + .mode = &rgb10max3_panel_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = rgb10max3_panel_init_sequence, +}; + static int st7703_enable(struct drm_panel *panel) { struct st7703 *ctx = panel_to_st7703(panel); @@ -653,12 +744,20 @@ static int st7703_get_modes(struct drm_panel *panel, return 1; } +static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel) +{ + struct st7703 *st7703 = panel_to_st7703(panel); + + return st7703->orientation; +} + static const struct drm_panel_funcs st7703_drm_funcs = { .disable = st7703_disable, .unprepare = st7703_unprepare, .prepare = st7703_prepare, .enable = st7703_enable, .get_modes = st7703_get_modes, + .get_orientation = st7703_get_orientation, }; static int allpixelson_set(void *data, u64 val) @@ -727,6 +826,10 @@ static int st7703_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->iovcc), "Failed to request iovcc regulator\n"); + ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation); + if (ret < 0) + return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n"); + drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs, DRM_MODE_CONNECTOR_DSI); @@ -784,6 +887,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi) static const struct of_device_id st7703_of_match[] = { { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc }, + { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc }, { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc }, { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc }, { .compatible = "xingbangda,xbd599", .data = &xbd599_desc }, diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 88e80fe981..28bfc48a91 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -282,15 +282,15 @@ static const struct drm_display_mode et028013dma_mode = { static const struct drm_display_mode jt240mhqs_hwt_ek_e3_mode = { .clock = 6000, .hdisplay = 240, - .hsync_start = 240 + 28, - .hsync_end = 240 + 28 + 10, - .htotal = 240 + 28 + 10 + 10, + .hsync_start = 240 + 38, + .hsync_end = 240 + 38 + 10, + .htotal = 240 + 38 + 10 + 10, .vdisplay = 280, - .vsync_start = 280 + 8, - .vsync_end = 280 + 8 + 4, - .vtotal = 280 + 8 + 4 + 4, - .width_mm = 43, - .height_mm = 37, + .vsync_start = 280 + 48, + .vsync_end = 280 + 48 + 4, + .vtotal = 280 + 48 + 4 + 4, + .width_mm = 37, + .height_mm = 43, .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, }; @@ -643,7 +643,9 @@ static int st7789v_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n"); - of_drm_get_panel_orientation(spi->dev.of_node, &ctx->orientation); + ret = of_drm_get_panel_orientation(spi->dev.of_node, &ctx->orientation); + if (ret) + return dev_err_probe(&spi->dev, ret, "Failed to get orientation\n"); drm_panel_add(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-visionox-r66451.c b/drivers/gpu/drm/panel/panel-visionox-r66451.c index fbb73464de..493f2a6076 100644 --- a/drivers/gpu/drm/panel/panel-visionox-r66451.c +++ b/drivers/gpu/drm/panel/panel-visionox-r66451.c @@ -322,6 +322,7 @@ static int visionox_r66451_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; + ctx->panel.prepare_prev_first = true; drm_panel_init(&ctx->panel, dev, &visionox_r66451_funcs, DRM_MODE_CONNECTOR_DSI); ctx->panel.backlight = visionox_r66451_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c index a23407b9f6..540099253e 100644 --- a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c +++ b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c @@ -287,6 +287,7 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; + ctx->panel.prepare_prev_first = true; drm_panel_init(&ctx->panel, dev, &visionox_vtdr6130_panel_funcs, DRM_MODE_CONNECTOR_DSI); |