diff options
Diffstat (limited to 'drivers/gpu/drm/panel')
112 files changed, 5901 insertions, 2216 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index e059b06e0239..09b9f7ff9340 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -67,6 +67,15 @@ 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_TD4320 + tristate "BOE TD4320 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 BOE TD4320 1080x2340 + video mode panel found in Xiaomi Redmi Note 7 smartphones. + config DRM_PANEL_BOE_TH101MB31UIG002_28A tristate "Boe TH101MB31UIG002-28A panel" depends on OF @@ -154,6 +163,17 @@ config DRM_PANEL_LVDS 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_HX8279 + tristate "Himax HX8279-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 + Himax HX8279 controller, such as the Startek KD070FHFID078 + 7.0" 1200x1920 IPS LCD panel that uses a MIPI-DSI interface + and others. + config DRM_PANEL_HIMAX_HX83102 tristate "Himax HX83102-based panels" depends on OF @@ -173,6 +193,16 @@ config DRM_PANEL_HIMAX_HX83112A 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_HX83112B + tristate "Himax HX83112B-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 HX83112B-based + display panels, such as the one found in the Fairphone 3 smartphone. + config DRM_PANEL_HIMAX_HX8394 tristate "HIMAX HX8394 MIPI-DSI LCD panels" depends on OF @@ -497,6 +527,18 @@ config DRM_PANEL_NOVATEK_NT36672E LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit RGB per pixel. +config DRM_PANEL_NOVATEK_NT37801 + tristate "Novatek NT37801/NT37810 AMOLED DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DSC_HELPER + select DRM_DISPLAY_HELPER + help + Say Y here if you want to enable support for Novatek NT37801 (or + NT37810) AMOLED DSI Video Mode LCD panel module with 1440x3200 + resolution. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI @@ -615,6 +657,32 @@ config DRM_PANEL_RAYDIUM_RM69380 This panel controller can be found in the Lenovo Xiaoxin Pad Pro 2021 in combination with an EDO OLED panel. +config DRM_PANEL_RENESAS_R61307 + tristate "Renesas R61307 DSI video mode 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 KOE tx13d100vm0eaa + IPS-LCD module with Renesas R69328 IC. The panel has a 1024x768 + resolution and uses 24 bit RGB per pixel. + + This panel controller can be found in LG Optimus Vu P895 smartphone + in combination with LCD panel. + +config DRM_PANEL_RENESAS_R69328 + tristate "Renesas R69328 720x1280 DSI video mode 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 dx12d100vm0eaa + IPS-LCD module with Renesas R69328 IC. The panel has a 720x1280 + resolution and uses 24 bit RGB per pixel. + + This panel controller can be found in LG Optimus 4X P895 smartphone + in combination with LCD panel. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF @@ -996,6 +1064,15 @@ 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_G2647FB105 + tristate "Visionox G2647FB105" + 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 Visionox + G2647FB105 (2340x1080@60Hz) AMOLED DSI cmd mode panel. + config DRM_PANEL_VISIONOX_R66451 tristate "Visionox R66451" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 1bb8ae46b59b..957555b49996 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_TD4320) += panel-boe-td4320.o obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o @@ -16,8 +17,10 @@ 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_HX8279) += panel-himax-hx8279.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o +obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.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 @@ -49,6 +52,7 @@ 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_NT37801) += panel-novatek-nt37801.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 @@ -62,6 +66,8 @@ obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67200) += panel-raydium-rm67200.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o +obj-$(CONFIG_DRM_PANEL_RENESAS_R61307) += panel-renesas-r61307.o +obj-$(CONFIG_DRM_PANEL_RENESAS_R69328) += panel-renesas-r69328.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS581VF01) += panel-samsung-ams581vf01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS639RQ08) += panel-samsung-ams639rq08.o @@ -101,6 +107,7 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_VISIONOX_G2647FB105) += panel-visionox-g2647fb105.o obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o obj-$(CONFIG_DRM_PANEL_VISIONOX_RM692E5) += panel-visionox-rm692e5.o obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o diff --git a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c index 4692c36fe217..87fb0fd29658 100644 --- a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c +++ b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c @@ -279,9 +279,10 @@ static int y030xx067a_probe(struct spi_device *spi) struct y030xx067a *priv; int err; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_panel_alloc(dev, struct y030xx067a, panel, + &y030xx067a_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(priv)) + return PTR_ERR(priv); priv->spi = spi; spi_set_drvdata(spi, priv); @@ -306,9 +307,6 @@ static int y030xx067a_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n"); - drm_panel_init(&priv->panel, dev, &y030xx067a_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&priv->panel); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index 503ecea72c5e..ea5119018df4 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -306,9 +306,11 @@ static int versatile_panel_probe(struct platform_device *pdev) return PTR_ERR(map); } - vpanel = devm_kzalloc(dev, sizeof(*vpanel), GFP_KERNEL); - if (!vpanel) - return -ENOMEM; + vpanel = devm_drm_panel_alloc(dev, struct versatile_panel, panel, + &versatile_panel_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(vpanel)) + return PTR_ERR(vpanel); ret = regmap_read(map, SYS_CLCD, &val); if (ret) { @@ -348,9 +350,6 @@ static int versatile_panel_probe(struct platform_device *pdev) dev_info(dev, "panel mounted on IB2 daughterboard\n"); } - drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&vpanel->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c index b05a663c134c..db006576d704 100644 --- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c +++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c @@ -224,9 +224,11 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) struct tm5p5_nt35596 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct tm5p5_nt35596, panel, + &tm5p5_nt35596_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "vdd"; ctx->supplies[1].supply = "vddio"; @@ -253,9 +255,6 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&ctx->panel, dev, &tm5p5_nt35596_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->panel.backlight = tm5p5_nt35596_create_backlight(dsi); if (IS_ERR(ctx->panel.backlight)) { ret = PTR_ERR(ctx->panel.backlight); diff --git a/drivers/gpu/drm/panel/panel-auo-a030jtn01.c b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c index 77604d6a4e72..6e52bf6830e1 100644 --- a/drivers/gpu/drm/panel/panel-auo-a030jtn01.c +++ b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c @@ -200,9 +200,10 @@ static int a030jtn01_probe(struct spi_device *spi) spi->mode |= SPI_MODE_3 | SPI_3WIRE; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_panel_alloc(dev, struct a030jtn01, panel, + &a030jtn01_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(priv)) + return PTR_ERR(priv); priv->spi = spi; spi_set_drvdata(spi, priv); @@ -223,9 +224,6 @@ static int a030jtn01_probe(struct spi_device *spi) if (IS_ERR(priv->reset_gpio)) return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO"); - drm_panel_init(&priv->panel, dev, &a030jtn01_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&priv->panel); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c index 7e66db4a88bb..84c21c62a43e 100644 --- a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c +++ b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c @@ -55,77 +55,56 @@ static void boe_bf060y8m_aj0_reset(struct boe_bf060y8m_aj0 *boe) static int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe) { struct mipi_dsi_device *dsi = boe->dsi; - struct device *dev = &dsi->dev; - int ret; - - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE); - mipi_dsi_dcs_write_seq(dsi, 0xf8, - 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d); - - 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(30); - - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xc0, - 0x08, 0x48, 0x65, 0x33, 0x33, 0x33, - 0x2a, 0x31, 0x39, 0x20, 0x09); - mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); - mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92, - 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83, - 0x5c, 0x5c, 0x5c); - mipi_dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e); - - msleep(30); - - 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; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0xa5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x00, 0x4c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_3D_CONTROL, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, + 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d); + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 30); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0xa5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x08, 0x48, 0x65, 0x33, 0x33, 0x33, + 0x2a, 0x31, 0x39, 0x20, 0x09); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92, + 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83, + 0x5c, 0x5c, 0x5c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e); + + mipi_dsi_msleep(&dsi_ctx, 30); + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + + return dsi_ctx.accum_err; } -static int boe_bf060y8m_aj0_off(struct boe_bf060y8m_aj0 *boe) +static void boe_bf060y8m_aj0_off(struct boe_bf060y8m_aj0 *boe) { struct mipi_dsi_device *dsi = boe->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; /* OFF commands sent in HS mode */ 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); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 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; - } - usleep_range(1000, 2000); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); dsi->mode_flags |= MIPI_DSI_MODE_LPM; - - return 0; } static int boe_bf060y8m_aj0_prepare(struct drm_panel *panel) { struct boe_bf060y8m_aj0 *boe = to_boe_bf060y8m_aj0(panel); - struct device *dev = &boe->dsi->dev; int ret; /* @@ -157,13 +136,14 @@ static int boe_bf060y8m_aj0_prepare(struct drm_panel *panel) ret = boe_bf060y8m_aj0_on(boe); if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); gpiod_set_value_cansleep(boe->reset_gpio, 1); - return ret; + goto err_on; } return 0; +err_on: + regulator_disable(boe->vregs[BF060Y8M_VREG_VCI].consumer); err_vci: regulator_disable(boe->vregs[BF060Y8M_VREG_VDDIO].consumer); err_vddio: @@ -178,15 +158,11 @@ err_elvss: static int boe_bf060y8m_aj0_unprepare(struct drm_panel *panel) { struct boe_bf060y8m_aj0 *boe = to_boe_bf060y8m_aj0(panel); - struct device *dev = &boe->dsi->dev; - int ret; - ret = boe_bf060y8m_aj0_off(boe); - if (ret < 0) - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + boe_bf060y8m_aj0_off(boe); gpiod_set_value_cansleep(boe->reset_gpio, 1); - ret = regulator_bulk_disable(ARRAY_SIZE(boe->vregs), boe->vregs); + regulator_bulk_disable(ARRAY_SIZE(boe->vregs), boe->vregs); return 0; } @@ -234,13 +210,11 @@ static int boe_bf060y8m_aj0_bl_update_status(struct backlight_device *bl) { struct mipi_dsi_device *dsi = bl_get_data(bl); u16 brightness = backlight_get_brightness(bl); - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); - if (ret < 0) - return ret; + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, brightness); - return 0; + return dsi_ctx.accum_err; } static int boe_bf060y8m_aj0_bl_get_brightness(struct backlight_device *bl) @@ -350,9 +324,11 @@ static int boe_bf060y8m_aj0_probe(struct mipi_dsi_device *dsi) struct boe_bf060y8m_aj0 *boe; int ret; - boe = devm_kzalloc(dev, sizeof(*boe), GFP_KERNEL); - if (!boe) - return -ENOMEM; + boe = devm_drm_panel_alloc(dev, struct boe_bf060y8m_aj0, panel, + &boe_bf060y8m_aj0_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(boe)) + return PTR_ERR(boe); ret = boe_bf060y8m_aj0_init_vregs(boe, dev); if (ret) @@ -374,9 +350,6 @@ static int boe_bf060y8m_aj0_probe(struct mipi_dsi_device *dsi) MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&boe->panel, dev, &boe_bf060y8m_aj0_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - boe->panel.prepare_prev_first = true; boe->panel.backlight = boe_bf060y8m_aj0_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c index df746baae301..4a8560b4b899 100644 --- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -847,9 +847,6 @@ static int panel_add(struct panel_info *pinfo) "failed to get enable gpio\n"); } - drm_panel_init(&pinfo->base, dev, &panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&pinfo->base); if (ret) return ret; @@ -865,9 +862,11 @@ static int panel_probe(struct mipi_dsi_device *dsi) const struct panel_desc *desc; int err; - pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) - return -ENOMEM; + pinfo = devm_drm_panel_alloc(&dsi->dev, __typeof(*pinfo), base, + &panel_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(pinfo)) + return PTR_ERR(pinfo); desc = of_device_get_match_data(&dsi->dev); dsi->mode_flags = desc->mode_flags; diff --git a/drivers/gpu/drm/panel/panel-boe-td4320.c b/drivers/gpu/drm/panel/panel-boe-td4320.c new file mode 100644 index 000000000000..1956daa2c71b --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-td4320.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2024 Barnabas Czeman <barnabas.czeman@mainlining.org> +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +struct boe_td4320 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; +}; + +static const struct regulator_bulk_data boe_td4320_supplies[] = { + { .supply = "iovcc" }, + { .supply = "vsn" }, + { .supply = "vsp" }, +}; + +static inline struct boe_td4320 *to_boe_td4320(struct drm_panel *panel) +{ + return container_of(panel, struct boe_td4320, panel); +} + +static void boe_td4320_reset(struct boe_td4320 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(30); +} + +static int boe_td4320_on(struct boe_td4320 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x04); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, + 0x19, 0x55, 0x00, 0xbe, 0x00, 0x00, + 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, + 0x4d, 0x55, 0x05, 0xe6, 0x00, 0x02, + 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, + 0x9b, 0x5b, 0x07, 0xe6, 0x00, 0x13, + 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, + 0x44, 0x3f, 0x00, 0x8d, 0xbf); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, + 0x5d, 0x00, 0x0f, 0x1f, 0x2f, 0x3f, + 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, + 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff, + 0x04, 0x00, 0x02, 0x02, 0x42, 0x01, + 0x69, 0x5a, 0x40, 0x40, 0x00, 0x00, + 0x04, 0xfa, 0x00); + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00b8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x00); + mipi_dsi_msleep(&dsi_ctx, 96); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00); + mipi_dsi_msleep(&dsi_ctx, 20); + + return dsi_ctx.accum_err; +} + +static int boe_td4320_off(struct boe_td4320 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int boe_td4320_prepare(struct drm_panel *panel) +{ + struct boe_td4320 *ctx = to_boe_td4320(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(boe_td4320_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + boe_td4320_reset(ctx); + + ret = boe_td4320_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(boe_td4320_supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int boe_td4320_unprepare(struct drm_panel *panel) +{ + struct boe_td4320 *ctx = to_boe_td4320(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = boe_td4320_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(boe_td4320_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode boe_td4320_mode = { + .clock = (1080 + 86 + 2 + 100) * (2340 + 4 + 4 + 60) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 86, + .hsync_end = 1080 + 86 + 2, + .htotal = 1080 + 86 + 2 + 100, + .vdisplay = 2340, + .vsync_start = 2340 + 4, + .vsync_end = 2340 + 4 + 4, + .vtotal = 2340 + 4 + 4 + 60, + .width_mm = 67, + .height_mm = 145, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int boe_td4320_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &boe_td4320_mode); +} + +static const struct drm_panel_funcs boe_td4320_panel_funcs = { + .prepare = boe_td4320_prepare, + .unprepare = boe_td4320_unprepare, + .get_modes = boe_td4320_get_modes, +}; + +static int boe_td4320_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct boe_td4320 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct boe_td4320, panel, + &boe_td4320_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(boe_td4320_supplies), + boe_td4320_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + 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_CLOCK_NON_CONTINUOUS; + + 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) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void boe_td4320_remove(struct mipi_dsi_device *dsi) +{ + struct boe_td4320 *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 boe_td4320_of_match[] = { + { .compatible = "boe,td4320" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, boe_td4320_of_match); + +static struct mipi_dsi_driver boe_td4320_driver = { + .probe = boe_td4320_probe, + .remove = boe_td4320_remove, + .driver = { + .name = "panel-boe-td4320", + .of_match_table = boe_td4320_of_match, + }, +}; +module_mipi_dsi_driver(boe_td4320_driver); + +MODULE_AUTHOR("Barnabas Czeman <barnabas.czeman@mainlining.org>"); +MODULE_DESCRIPTION("DRM driver for boe td4320 fhdplus video mode dsi panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c index 0b87f1e6ecae..f33d4f855929 100644 --- a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c +++ b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c @@ -349,9 +349,11 @@ static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi) const struct panel_desc *desc; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct boe_th101mb31ig002, panel, + &boe_th101mb31ig002_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; @@ -383,9 +385,6 @@ static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi) 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; diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c index 50e4a5341bc6..20b6e11a7d84 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c @@ -166,9 +166,11 @@ static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi) struct boe_tv101wum_ll2 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct boe_tv101wum_ll2, panel, + &boe_tv101wum_ll2_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(&dsi->dev, ARRAY_SIZE(boe_tv101wum_ll2_supplies), @@ -190,8 +192,6 @@ static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_HSE; - drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ret = drm_panel_of_backlight(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index 3e5b0d8636d0..d5fe105bdbdd 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -1720,8 +1720,6 @@ static int boe_panel_add(struct boe_panel *boe) boe->base.prepare_prev_first = true; - drm_panel_init(&boe->base, dev, &boe_panel_funcs, - DRM_MODE_CONNECTOR_DSI); err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); if (err < 0) { dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); @@ -1746,9 +1744,11 @@ static int boe_panel_probe(struct mipi_dsi_device *dsi) int ret; const struct panel_desc *desc; - boe = devm_kzalloc(&dsi->dev, sizeof(*boe), GFP_KERNEL); - if (!boe) - return -ENOMEM; + boe = devm_drm_panel_alloc(&dsi->dev, __typeof(*boe), base, + &boe_panel_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(boe)) + return PTR_ERR(boe); desc = of_device_get_match_data(&dsi->dev); dsi->lanes = desc->lanes; diff --git a/drivers/gpu/drm/panel/panel-dsi-cm.c b/drivers/gpu/drm/panel/panel-dsi-cm.c index 6b3f4d664d2a..ae6e9ffc46cb 100644 --- a/drivers/gpu/drm/panel/panel-dsi-cm.c +++ b/drivers/gpu/drm/panel/panel-dsi-cm.c @@ -511,9 +511,10 @@ static int dsicm_probe(struct mipi_dsi_device *dsi) dev_dbg(dev, "probe\n"); - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; + ddata = devm_drm_panel_alloc(dev, struct panel_drv_data, panel, + &dsicm_panel_funcs, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ddata)) + return PTR_ERR(ddata); mipi_dsi_set_drvdata(dsi, ddata); ddata->dsi = dsi; @@ -530,9 +531,6 @@ static int dsicm_probe(struct mipi_dsi_device *dsi) dsicm_hw_reset(ddata); - drm_panel_init(&ddata->panel, dev, &dsicm_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - if (ddata->use_dsi_backlight) { struct backlight_properties props = { 0 }; props.max_brightness = 255; diff --git a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c index 0bfed0ec0bbc..fb9f9f42be4f 100644 --- a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c +++ b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c @@ -163,9 +163,11 @@ static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi) struct ebbg_ft8719 *ctx; int i, ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ebbg_ft8719, panel, + &ebbg_ft8719_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) ctx->supplies[i].supply = regulator_names[i]; @@ -196,9 +198,6 @@ static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &ebbg_ft8719_panel_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"); diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 52028c8f8988..9a56e208cbdd 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -113,7 +113,7 @@ struct panel_delay { * // do fixed enable delay * // enforce prepare_to_enable min time * - * This is not specified in a standard way on eDP timing diagrams. + * This is usually (T4+T5+T6+T8)-min on eDP timing diagrams. * It is effectively the time from HPD going high till you can * turn on the backlight. */ @@ -839,9 +839,10 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, struct device_node *ddc; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct panel_edp, base, + &panel_edp_funcs, DRM_MODE_CONNECTOR_eDP); + if (IS_ERR(panel)) + return PTR_ERR(panel); panel->prepared_time = 0; panel->desc = desc; @@ -886,8 +887,6 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, dev_set_drvdata(dev, panel); - drm_panel_init(&panel->base, dev, &panel_edp_funcs, DRM_MODE_CONNECTOR_eDP); - err = drm_panel_of_backlight(&panel->base); if (err) goto err_finished_ddc_init; @@ -1763,6 +1762,13 @@ static const struct panel_delay delay_80_500_e50 = { .enable = 50, }; +static const struct panel_delay delay_80_500_e80_p2e200 = { + .hpd_absent = 80, + .unprepare = 500, + .enable = 80, + .prepare_to_enable = 200, +}; + static const struct panel_delay delay_100_500_e200 = { .hpd_absent = 100, .unprepare = 500, @@ -1863,6 +1869,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"), 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', 0x30ed, &delay_200_500_e50, "G156HAN03.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAN04.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", @@ -1878,6 +1885,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0xa199, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xc4b4, &delay_200_500_e50, "B116XAT04.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xc9a8, &delay_200_500_e50, "B140QAN08.H"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), @@ -1916,6 +1924,7 @@ static const struct edp_panel_entry edp_panels[] = { 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', 0x0964, &delay_200_500_e50, "NV133WUM-N61"), 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"), @@ -1930,6 +1939,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ae8, &delay_200_500_e50_p2e80, "NV140WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"), 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"), @@ -1938,6 +1948,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"), 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"), @@ -1957,6 +1968,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), 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"), @@ -1965,6 +1977,7 @@ static const struct edp_panel_entry edp_panels[] = { 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', 'M', 'N', 0x162b, &delay_200_500_e80_d50, "N160JCE-ELL"), EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_p2e200, "MNC207QS1-1"), EDP_PANEL_ENTRY('C', 'S', 'O', 0x1413, &delay_200_500_e50_p2e200, "MNE007JA1-2"), @@ -1973,6 +1986,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'S', 'W', 0x1103, &delay_200_500_e80_d50, "MNB601LS1-3"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50, "MNB601LS1-4"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1448, &delay_200_500_e50, "MNE007QS3-7"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1457, &delay_80_500_e80_p2e200, "MNE007QS3-8"), EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), @@ -1996,6 +2010,7 @@ static const struct edp_panel_entry edp_panels[] = { 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('K', 'D', 'C', 0x1220, &delay_200_500_e50, "KD116N3730A05"), 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"), diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index b904d5437444..1f177834d629 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -206,9 +206,10 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) struct kd35t133 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct kd35t133, panel, + &kd35t133_funcs, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { @@ -248,9 +249,6 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, &dsi->dev, &kd35t133_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c index 986e3e192881..6225501cb174 100644 --- a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c +++ b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c @@ -443,9 +443,11 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) unsigned int i; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct k101_im2ba02, panel, + &k101_im2ba02_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; @@ -463,9 +465,6 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), "Couldn't get our reset GPIO\n"); - drm_panel_init(&ctx->panel, &dsi->dev, &k101_im2ba02_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index 48e3acaecdf3..4f8d6d8c07e4 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -189,16 +189,14 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) struct feiyang *ctx; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct feiyang, panel, + &feiyang_funcs, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; - drm_panel_init(&ctx->panel, &dsi->dev, &feiyang_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); if (IS_ERR(ctx->dvdd)) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->dvdd), diff --git a/drivers/gpu/drm/panel/panel-himax-hx8279.c b/drivers/gpu/drm/panel/panel-himax-hx8279.c new file mode 100644 index 000000000000..fb302d1f91b9 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-himax-hx8279.c @@ -0,0 +1,1296 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Himax HX8279 DriverIC panels driver + * + * Copyright (c) 2025 Collabora Ltd. + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +/* Page selection */ +#define HX8279_REG_PAGE 0xb0 + #define HX8279_PAGE_SEL GENMASK(3, 0) + +/* Page 0 - Driver/Module Configuration */ +#define HX8279_P0_VGHS 0xbf +#define HX8279_P0_VGLS 0xc0 +#define HX8279_P0_VGPHS 0xc2 +#define HX8279_P0_VGNHS 0xc4 + #define HX8279_P0_VG_SEL GENMASK(4, 0) + #define HX8279_VGH_MIN_MV 8700 + #define HX8279_VGH_STEP_MV 300 + #define HX8279_VGL_MIN_MV 6700 + #define HX8279_VGL_STEP_MV 300 + #define HX8279_VGPNH_MIN_MV 4000 + #define HX8279_VGPNX_STEP_MV 50 + #define HX8279_VGH_VOLT_SEL(x) ((x - HX8279_VGH_MIN_MV) / HX8279_VGH_STEP_MV) + #define HX8279_VGL_VOLT_SEL(x) ((x - HX8279_VGL_MIN_MV) / HX8279_VGL_STEP_MV) + #define HX8279_VGPN_VOLT_SEL(x) ((x - HX8279_VGPNH_MIN_MV) / HX8279_VGPNX_STEP_MV) + +/* Page 1 - Gate driver On Array (GOA) Mux */ +#define HX8279_P1_REG_GOA_L 0xc0 +#define HX8279_P1_REG_GOUTL(x) (HX8279_P1_REG_GOA_L + (x)) +#define HX8279_P1_REG_GOA_R 0xd4 +#define HX8279_P1_REG_GOUTR(x) (HX8279_P1_REG_GOA_R + (x)) + #define HX8279_GOUT_STB GENMASK(7, 6) + #define HX8279_GOUT_SEL GENMASK(5, 0) + +/* Page 2 - Analog Gamma Configuration */ +#define HX8279_P2_REG_ANALOG_GAMMA 0xc0 + #define HX8279_P2_REG_GAMMA_T_PVP(x) (HX8279_P2_REG_ANALOG_GAMMA + (x)) /* 0..16 */ + #define HX8279_P2_REG_GAMMA_T_PVN(x) (HX8279_P2_REG_GAMMA_T_PVP(17) + (x)) /* 0..16 */ + +/* Page 3 - Gate driver On Array (GOA) Configuration */ +#define HX8279_P3_REG_UNKNOWN_BA 0xba +#define HX8279_P3_REG_GOA_CKV_FALL_PREC 0xbc +#define HX8279_P3_REG_GOA_TIMING_ODD 0xc2 + #define HX8279_P3_REG_GOA_TO(x) (HX8279_P3_REG_GOA_TIMING_ODD + x) /* GOA_T0..5 */ +#define HX8279_P3_REG_GOA_STVL 0xc8 + #define HX8279_P3_GOA_STV_LEAD GENMASK(4, 0) +#define HX8279_P3_REG_GOA_CKVL 0xc9 + #define HX8279_P3_GOA_CKV_LEAD GENMASK(4, 0) +#define HX8279_P3_REG_GOA_CKVD 0xca + #define HX8279_P3_GOA_CKV_NONOVERLAP BIT(7) + #define HX8279_P3_GOA_CKV_RESERVED BIT(6) + #define HX8279_P3_GOA_CKV_DUMMY GENMASK(5, 0) +#define HX8279_P3_REG_GOA_CKV_RISE_PREC 0xcb +#define HX8279_P3_REG_GOA_CLR1_W_ADJ 0xd2 +#define HX8279_P3_REG_GOA_CLR234_W_ADJ 0xd3 +#define HX8279_P3_REG_GOA_CLR1_CFG 0xd4 +#define HX8279_P3_REG_GOA_CLR_CFG(x) (HX8279_P3_REG_GOA_CLR1_CFG + (x)) /* CLR1..4 */ + #define HX8279_P3_GOA_CLR_CFG_POLARITY BIT(7) + #define HX8279_P3_GOA_CLR_CFG_STARTPOS GENMASK(6, 0) +#define HX8279_P3_REG_GOA_TIMING_EVEN 0xdd + #define HX8279_P3_REG_GOA_TE(x) (HX8279_P3_REG_GOA_TIMING_EVEN + x) +#define HX8279_P3_REG_UNKNOWN_E4 0xe4 +#define HX8279_P3_REG_UNKNOWN_E5 0xe5 + +/* Page 5 - MIPI */ +#define HX8279_P5_REG_TIMING 0xb3 + #define HX8279_P5_TIMING_THS_SETTLE GENMASK(7, 5) + #define HX8279_P5_TIMING_LHS_SETTLE BIT(4) + #define HX8279_P5_TIMING_TLPX GENMASK(3, 0) +#define HX8279_P5_REG_UNKNOWN_B8 0xb8 +#define HX8279_P5_REG_UNKNOWN_BC 0xbc +#define HX8279_P5_REG_UNKNOWN_D6 0xd6 + +/* Page 6 - Engineer */ +#define HX8279_P6_REG_ENGINEER_PWD 0xb8 +#define HX8279_P6_REG_INHOUSE_FUNC 0xc0 + #define HX8279_P6_ENG_UNLOCK_WORD 0xa5 +#define HX8279_P6_REG_GAMMA_CHOPPER 0xbc + #define HX8279_P6_GAMMA_POCGM_CTL GENMASK(6, 4) + #define HX8279_P6_GAMMA_POGCMD_CTL GENMASK(2, 0) +#define HX8279_P6_REG_VOLT_ADJ 0xc7 + /* For VCCIFS and VCCS - 0: 1450, 1: 1500, 2: 1550, 3: 1600 uV */ + #define HX8279_P6_VOLT_ADJ_VCCIFS GENMASK(3, 2) + #define HX8279_P6_VOLT_ADJ_VCCS GENMASK(1, 0) +#define HX8279_P6_REG_DLY_TIME_ADJ 0xd5 + +/* Page 7...12 - Digital Gamma Adjustment */ +#define HX8279_PG_DIGITAL_GAMMA 0xb1 +#define HX8279_DGAMMA_DGMA1_HI GENMASK(7, 6) +#define HX8279_DGAMMA_DGMA2_HI GENMASK(5, 4) +#define HX8279_DGAMMA_DGMA3_HI GENMASK(3, 2) +#define HX8279_DGAMMA_DGMA4_HI GENMASK(1, 0) +#define HX8279_PG_DGAMMA_NUM_LO_BYTES 24 +#define HX8279_PG_DGAMMA_NUM_HI_BYTES 6 + +struct hx8279 { + struct drm_panel panel; + struct mipi_dsi_device *dsi[2]; + struct regulator_bulk_data vregs[2]; + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + const struct hx8279_panel_desc *desc; + u8 last_page; + bool skip_voltage_config; + bool skip_goa_config; + bool skip_goa_timing; + bool skip_goa_even_timing; + bool skip_mipi_timing; +}; + +struct hx8279_panel_mode { + const struct drm_display_mode mode; + u8 bpc; + bool is_video_mode; +}; + +/** + * struct hx8279_goa_mux - Gate driver On Array Muxer + * @gout_l: Mux GOA signal to GOUT Left pin + * @gout_r: Mux GOA signal to GOUT Right pin + */ +struct hx8279_goa_mux { + u8 gout_l[20]; + u8 gout_r[20]; +}; + +/** + * struct hx8279_analog_gamma - Analog Gamma Adjustment + * @pos: Positive gamma op's input voltage, adjusted by VGP(H/L) + * @neg: Negative gamma op's input voltage, adjusted by VGN(H/L) + * + * Analog Gamma correction is performed with 17+17 reference voltages, + * changed with resistor streams, and defined with 17 register values + * for positive and 17 for negative. + * + * Each register holds resistance values, in 8.5ohms per unit, for the + * following gamma levels: + * 0, 8, 16, 28, 40, 56, 80, 128, 176, 200, 216, 228, 240, 248, 252, 255. + */ +struct hx8279_analog_gamma { + u8 pos[17]; + u8 neg[17]; +}; + +/** + * struct hx8279_digital_gamma - Digital Gamma Adjustment + * @r: Adjustment for red component + * @g: Adjustment for green component + * @b: Adjustment for blue component + * + * The layout of this structure follows the register layout to simplify + * both the handling and the declaration of those values in the driver. + * Gamma correction is internally done with a 24 segment piecewise + * linear interpolation; those segments are defined with 24 ten bits + * values of which: + * - The LOW eight bits for the first 24 registers start at the first + * register (at 0xb1) of the Digital Gamma Adjustment page; + * - The HIGH two bits for each of the 24 registers are contained + * in the last six registers; + * - The last six registers contain four groups of two-bits HI values + * for each of the first 24 registers, but in an inverted fashion, + * this means that the first two bits relate to the last register + * of a set of four. + * + * The 24 segments refer to the following gamma levels: + * 0, 1, 3, 7, 11, 15, 23, 31, 47, 63, 95, 127, 128, 160, + * 192, 208, 224, 232, 240, 244, 248, 252, 254, 255 + */ +struct hx8279_digital_gamma { + u8 r[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES]; + u8 g[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES]; + u8 b[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES]; +}; + +struct hx8279_panel_desc { + const struct mipi_dsi_device_info dsi_info; + const struct hx8279_panel_mode *mode_data; + u8 num_lanes; + u8 num_modes; + + /* Page 0 */ + unsigned int vgh_mv; + unsigned int vgl_mv; + unsigned int vgph_mv; + unsigned int vgnh_mv; + + /* Page 1 */ + const struct hx8279_goa_mux *gmux; + + /* Page 2 */ + const struct hx8279_analog_gamma *agamma; + + /* Page 3 */ + u8 goa_unk_ba; + u8 goa_odd_timing[6]; + u8 goa_even_timing[6]; + u8 goa_stv_lead_time_ck; + u8 goa_ckv_lead_time_ck; + u8 goa_ckv_dummy_vblank_num; + u8 goa_ckv_rise_precharge; + u8 goa_ckv_fall_precharge; + bool goa_ckv_non_overlap_ctl; + u8 goa_clr1_width_adj; + u8 goa_clr234_width_adj; + s8 goa_clr_polarity[4]; + int goa_clr_start_pos[4]; + u8 goa_unk_e4; + u8 goa_unk_e5; + + /* Page 5 */ + u8 bta_tlpx; + bool lhs_settle_time_by_osc25; + u8 ths_settle_time; + u8 timing_unk_b8; + u8 timing_unk_bc; + u8 timing_unk_d6; + + /* Page 6 */ + u8 gamma_ctl; + u8 volt_adj; + u8 src_delay_time_adj_ck; + + /* Page 7..12 */ + const struct hx8279_digital_gamma *dgamma; +}; + +static inline struct hx8279 *to_hx8279(struct drm_panel *panel) +{ + return container_of(panel, struct hx8279, panel); +} + +static void hx8279_set_page(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx, u8 page) +{ + const u8 cmd_set_page[] = { HX8279_REG_PAGE, page }; + + if (hx->last_page == page) + return; + + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_page, ARRAY_SIZE(cmd_set_page)); + if (!dsi_ctx->accum_err) + hx->last_page = page; +} + +static void hx8279_set_module_config(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_panel_desc *desc = hx->desc; + u8 cmd_set_voltage[2]; + + if (hx->skip_voltage_config) + return; + + /* Page 0 - Driver/Module Configuration */ + hx8279_set_page(hx, dsi_ctx, 0); + + if (desc->vgh_mv) { + cmd_set_voltage[0] = HX8279_P0_VGHS; + cmd_set_voltage[1] = HX8279_VGH_VOLT_SEL(desc->vgh_mv); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage, + ARRAY_SIZE(cmd_set_voltage)); + } + + if (desc->vgl_mv) { + cmd_set_voltage[0] = HX8279_P0_VGLS; + cmd_set_voltage[1] = HX8279_VGL_VOLT_SEL(desc->vgl_mv); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage, + ARRAY_SIZE(cmd_set_voltage)); + } + + if (desc->vgph_mv) { + cmd_set_voltage[0] = HX8279_P0_VGPHS; + cmd_set_voltage[1] = HX8279_VGPN_VOLT_SEL(desc->vgph_mv); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage, + ARRAY_SIZE(cmd_set_voltage)); + } + + if (desc->vgnh_mv) { + cmd_set_voltage[0] = HX8279_P0_VGNHS; + cmd_set_voltage[1] = HX8279_VGPN_VOLT_SEL(desc->vgnh_mv); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage, + ARRAY_SIZE(cmd_set_voltage)); + } +} + +static void hx8279_set_gmux(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_goa_mux *gmux = hx->desc->gmux; + u8 cmd_set_gmux[2]; + int i; + + if (!gmux) + return; + + hx8279_set_page(hx, dsi_ctx, 1); + + for (i = 0; i < ARRAY_SIZE(gmux->gout_l); i++) { + cmd_set_gmux[0] = HX8279_P1_REG_GOUTL(i); + cmd_set_gmux[1] = gmux->gout_l[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gmux, + ARRAY_SIZE(cmd_set_gmux)); + } + + for (i = 0; i < ARRAY_SIZE(gmux->gout_r); i++) { + cmd_set_gmux[0] = HX8279_P1_REG_GOUTR(i); + cmd_set_gmux[1] = gmux->gout_r[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gmux, + ARRAY_SIZE(cmd_set_gmux)); + } +} + +static void hx8279_set_analog_gamma(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_analog_gamma *agamma = hx->desc->agamma; + u8 cmd_set_ana_gamma[2]; + int i; + + if (!agamma) + return; + + hx8279_set_page(hx, dsi_ctx, 2); + + for (i = 0; i < ARRAY_SIZE(agamma->pos); i++) { + cmd_set_ana_gamma[0] = HX8279_P2_REG_GAMMA_T_PVP(i); + cmd_set_ana_gamma[1] = agamma->pos[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_ana_gamma, + ARRAY_SIZE(cmd_set_ana_gamma)); + } + + for (i = 0; i < ARRAY_SIZE(agamma->neg); i++) { + cmd_set_ana_gamma[0] = HX8279_P2_REG_GAMMA_T_PVN(i); + cmd_set_ana_gamma[1] = agamma->neg[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_ana_gamma, + ARRAY_SIZE(cmd_set_ana_gamma)); + } +} + +static void hx8279_set_goa_timing(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_panel_desc *desc = hx->desc; + u8 cmd_set_goa_t[2]; + int i; + + if (hx->skip_goa_timing) + return; + + hx8279_set_page(hx, dsi_ctx, 3); + + for (i = 0; i < ARRAY_SIZE(desc->goa_odd_timing); i++) { + cmd_set_goa_t[0] = HX8279_P3_REG_GOA_TO(i); + cmd_set_goa_t[1] = desc->goa_odd_timing[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa_t, + ARRAY_SIZE(cmd_set_goa_t)); + } + + for (i = 0; i < ARRAY_SIZE(desc->goa_even_timing); i++) { + cmd_set_goa_t[0] = HX8279_P3_REG_GOA_TE(i); + cmd_set_goa_t[1] = desc->goa_odd_timing[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa_t, + ARRAY_SIZE(cmd_set_goa_t)); + } +} + +static void hx8279_set_goa_cfg(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_panel_desc *desc = hx->desc; + u8 cmd_set_goa[2]; + int i; + + if (hx->skip_goa_config) + return; + + hx8279_set_page(hx, dsi_ctx, 3); + + if (desc->goa_unk_ba) { + cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_BA; + cmd_set_goa[1] = desc->goa_unk_ba; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_stv_lead_time_ck) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_STVL; + cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_STV_LEAD, + desc->goa_stv_lead_time_ck); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_ckv_lead_time_ck) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_CKVL; + cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CKV_DUMMY, + desc->goa_ckv_lead_time_ck); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_ckv_dummy_vblank_num) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_CKVD; + cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CKV_LEAD, + desc->goa_ckv_dummy_vblank_num); + cmd_set_goa[1] |= FIELD_PREP(HX8279_P3_GOA_CKV_NONOVERLAP, + desc->goa_ckv_non_overlap_ctl); + /* RESERVED must be always set */ + cmd_set_goa[1] |= HX8279_P3_GOA_CKV_RESERVED; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + /* + * One of the two being more than zero means that we want to write + * both of them. Anyway, the register default is zero in this case. + */ + if (desc->goa_ckv_rise_precharge || desc->goa_ckv_fall_precharge) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_CKV_RISE_PREC; + cmd_set_goa[1] = desc->goa_ckv_rise_precharge; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + + cmd_set_goa[0] = HX8279_P3_REG_GOA_CKV_FALL_PREC; + cmd_set_goa[1] = desc->goa_ckv_fall_precharge; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_clr1_width_adj) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR1_W_ADJ; + cmd_set_goa[1] = desc->goa_clr1_width_adj; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_clr234_width_adj) { + cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR234_W_ADJ; + cmd_set_goa[1] = desc->goa_clr234_width_adj; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + /* Polarity and Start Position arrays are of the same size */ + for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) { + if (desc->goa_clr_polarity[i] < 0 || desc->goa_clr_start_pos[i] < 0) + continue; + + cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR_CFG(i); + cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CLR_CFG_STARTPOS, + desc->goa_clr_start_pos[i]); + cmd_set_goa[1] |= FIELD_PREP(HX8279_P3_GOA_CLR_CFG_POLARITY, + desc->goa_clr_polarity[i]); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + if (desc->goa_unk_e4) { + cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_E4; + cmd_set_goa[1] = desc->goa_unk_e4; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); + } + + cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_E5; + cmd_set_goa[1] = desc->goa_unk_e5; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa, + ARRAY_SIZE(cmd_set_goa)); +} + +static void hx8279_set_mipi_cfg(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_panel_desc *desc = hx->desc; + u8 cmd_set_mipi[2]; + + if (hx->skip_mipi_timing) + return; + + hx8279_set_page(hx, dsi_ctx, 5); + + if (desc->bta_tlpx || desc->ths_settle_time || desc->lhs_settle_time_by_osc25) { + cmd_set_mipi[0] = HX8279_P5_REG_TIMING; + cmd_set_mipi[1] = FIELD_PREP(HX8279_P5_TIMING_TLPX, desc->bta_tlpx); + cmd_set_mipi[1] |= FIELD_PREP(HX8279_P5_TIMING_THS_SETTLE, + desc->ths_settle_time); + cmd_set_mipi[1] |= FIELD_PREP(HX8279_P5_TIMING_LHS_SETTLE, + desc->lhs_settle_time_by_osc25); + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi, + ARRAY_SIZE(cmd_set_mipi)); + } + + if (desc->timing_unk_b8) { + cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_B8; + cmd_set_mipi[1] = desc->timing_unk_b8; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi, + ARRAY_SIZE(cmd_set_mipi)); + } + + if (desc->timing_unk_bc) { + cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_BC; + cmd_set_mipi[1] = desc->timing_unk_bc; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi, + ARRAY_SIZE(cmd_set_mipi)); + } + + if (desc->timing_unk_d6) { + cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_D6; + cmd_set_mipi[1] = desc->timing_unk_d6; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi, + ARRAY_SIZE(cmd_set_mipi)); + } +} + +static void hx8279_set_adv_cfg(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_panel_desc *desc = hx->desc; + const u8 cmd_set_dly[] = { HX8279_P6_REG_DLY_TIME_ADJ, desc->src_delay_time_adj_ck }; + const u8 cmd_set_gamma[] = { HX8279_P6_REG_GAMMA_CHOPPER, desc->gamma_ctl }; + const u8 cmd_set_volt_adj[] = { HX8279_P6_REG_VOLT_ADJ, desc->volt_adj }; + u8 cmd_set_eng[] = { HX8279_P6_REG_ENGINEER_PWD, HX8279_P6_ENG_UNLOCK_WORD }; + + if (!desc->gamma_ctl && !desc->src_delay_time_adj_ck && !desc->volt_adj) + return; + + hx8279_set_page(hx, dsi_ctx, 6); + + /* Unlock ENG settings: write same word to both ENGINEER_PWD and INHOUSE_FUNC */ + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng)); + + cmd_set_eng[0] = HX8279_P6_REG_INHOUSE_FUNC; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng)); + + /* Set Gamma Chopper and Gamma buffer Chopper control */ + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gamma, ARRAY_SIZE(cmd_set_gamma)); + + /* Set Source delay time adjustment (CKV falling to Source off) */ + if (desc->src_delay_time_adj_ck) + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dly, + ARRAY_SIZE(cmd_set_dly)); + + /* Set voltage adjustment */ + if (desc->volt_adj) + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_volt_adj, + ARRAY_SIZE(cmd_set_volt_adj)); + + /* Lock ENG settings again */ + cmd_set_eng[0] = HX8279_P6_REG_ENGINEER_PWD; + cmd_set_eng[1] = 0; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng)); + + cmd_set_eng[0] = HX8279_P6_REG_INHOUSE_FUNC; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng)); +} + +static void hx8279_set_digital_gamma(struct hx8279 *hx, + struct mipi_dsi_multi_context *dsi_ctx) +{ + const struct hx8279_digital_gamma *dgamma = hx->desc->dgamma; + u8 cmd_set_dig_gamma[2]; + int i; + + if (!dgamma) + return; + + /* + * Pages 7..9 are for RGB Positive, 10..12 are for RGB Negative: + * The first iteration sets all positive component registers, + * the second one sets all negatives. + */ + for (i = 0; i < 2; i++) { + u8 pg_neg = i * 3; + + hx8279_set_page(hx, dsi_ctx, 7 + pg_neg); + + for (i = 0; i < ARRAY_SIZE(dgamma->r); i++) { + cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i; + cmd_set_dig_gamma[1] = dgamma->r[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma, + ARRAY_SIZE(cmd_set_dig_gamma)); + } + + hx8279_set_page(hx, dsi_ctx, 8 + pg_neg); + + for (i = 0; i < ARRAY_SIZE(dgamma->g); i++) { + cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i; + cmd_set_dig_gamma[1] = dgamma->g[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma, + ARRAY_SIZE(cmd_set_dig_gamma)); + } + + hx8279_set_page(hx, dsi_ctx, 9 + pg_neg); + + for (i = 0; i < ARRAY_SIZE(dgamma->b); i++) { + cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i; + cmd_set_dig_gamma[1] = dgamma->b[i]; + mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma, + ARRAY_SIZE(cmd_set_dig_gamma)); + } + } +} + +static int hx8279_on(struct hx8279 *hx) +{ + struct mipi_dsi_device *dsi = hx->dsi[0]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + /* Page 5 */ + hx8279_set_mipi_cfg(hx, &dsi_ctx); + + /* Page 1 */ + hx8279_set_gmux(hx, &dsi_ctx); + + /* Page 2 */ + hx8279_set_analog_gamma(hx, &dsi_ctx); + + /* Page 3 */ + hx8279_set_goa_cfg(hx, &dsi_ctx); + hx8279_set_goa_timing(hx, &dsi_ctx); + + /* Page 0 - Driver/Module Configuration */ + hx8279_set_module_config(hx, &dsi_ctx); + + /* Page 6 */ + hx8279_set_adv_cfg(hx, &dsi_ctx); + + /* Pages 7..12 */ + hx8279_set_digital_gamma(hx, &dsi_ctx); + + return dsi_ctx.accum_err; +} + +static void hx8279_power_off(struct hx8279 *hx) +{ + gpiod_set_value_cansleep(hx->reset_gpio, 0); + usleep_range(100, 500); + gpiod_set_value_cansleep(hx->enable_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(hx->vregs), hx->vregs); +} + +static int hx8279_disable(struct drm_panel *panel) +{ + struct hx8279 *hx = to_hx8279(panel); + struct mipi_dsi_device *dsi = hx->dsi[0]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + + return 0; +} + +static int hx8279_enable(struct drm_panel *panel) +{ + struct hx8279 *hx = to_hx8279(panel); + struct mipi_dsi_device *dsi = hx->dsi[0]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return 0; +} + +static int hx8279_prepare(struct drm_panel *panel) +{ + struct hx8279 *hx = to_hx8279(panel); + struct mipi_dsi_device *dsi = hx->dsi[0]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(hx->vregs), hx->vregs); + if (ret) + return ret; + + gpiod_set_value_cansleep(hx->enable_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(hx->reset_gpio, 1); + usleep_range(6000, 7000); + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + if (hx->dsi[1]) + hx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; + + ret = hx8279_on(hx); + if (ret) { + hx8279_power_off(hx); + return ret; + } + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 130); + + return dsi_ctx.accum_err; +} + +static int hx8279_unprepare(struct drm_panel *panel) +{ + struct hx8279 *hx = to_hx8279(panel); + struct mipi_dsi_device *dsi = hx->dsi[0]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 130); + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + if (hx->dsi[1]) + hx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM; + + hx8279_power_off(hx); + + return dsi_ctx.accum_err; +} + +static int hx8279_get_modes(struct drm_panel *panel, struct drm_connector *connector) +{ + struct hx8279 *hx = to_hx8279(panel); + int i; + + for (i = 0; i < hx->desc->num_modes; i++) { + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &hx->desc->mode_data[i].mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type |= DRM_MODE_TYPE_DRIVER; + if (hx->desc->num_modes == 1) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, mode); + } + + connector->display_info.bpc = hx->desc->mode_data[0].bpc; + connector->display_info.height_mm = hx->desc->mode_data[0].mode.height_mm; + connector->display_info.width_mm = hx->desc->mode_data[0].mode.width_mm; + + return hx->desc->num_modes; +} + +static const struct drm_panel_funcs hx8279_panel_funcs = { + .disable = hx8279_disable, + .unprepare = hx8279_unprepare, + .prepare = hx8279_prepare, + .enable = hx8279_enable, + .get_modes = hx8279_get_modes, +}; + +static int hx8279_init_vregs(struct hx8279 *hx, struct device *dev) +{ + int ret; + + hx->vregs[0].supply = "vdd"; + hx->vregs[1].supply = "iovcc"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->vregs), + hx->vregs); + if (ret < 0) + return ret; + + ret = regulator_is_supported_voltage(hx->vregs[0].consumer, + 3000000, 5000000); + if (!ret) + return -EINVAL; + + ret = regulator_is_supported_voltage(hx->vregs[1].consumer, + 1700000, 1900000); + if (!ret) + return -EINVAL; + + return 0; +} + +static int hx8279_check_gmux_config(struct hx8279 *hx, struct device *dev) +{ + const struct hx8279_panel_desc *desc = hx->desc; + const struct hx8279_goa_mux *gmux = desc->gmux; + int i; + + /* No gmux defined means we simply skip the GOA mux configuration */ + if (!gmux) + return 0; + + for (i = 0; i < ARRAY_SIZE(gmux->gout_l); i++) { + if (gmux->gout_l[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL)) + return dev_err_probe(dev, -EINVAL, + "Invalid value found in gout_l[%d]\n", i); + } + + for (i = 0; i < ARRAY_SIZE(gmux->gout_r); i++) { + if (gmux->gout_r[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL)) + return dev_err_probe(dev, -EINVAL, + "Invalid value found in gout_r[%d]\n", i); + } + + return 0; +} + +static int hx8279_check_goa_config(struct hx8279 *hx, struct device *dev) +{ + const struct hx8279_panel_desc *desc = hx->desc; + bool goa_odd_valid, goa_even_valid; + int i, num_zero, num_clr = 0; + + /* Up to 4 zero values is a valid configuration. Check them all. */ + num_zero = 1; + for (i = 0; i < ARRAY_SIZE(desc->goa_odd_timing); i++) { + if (desc->goa_odd_timing[i]) + num_zero++; + } + + goa_odd_valid = (num_zero != ARRAY_SIZE(desc->goa_odd_timing)); + + /* Up to 3 zeroes is a valid config. Check them all. */ + num_zero = 1; + for (i = 0; i < ARRAY_SIZE(desc->goa_even_timing); i++) { + if (desc->goa_even_timing[i]) + num_zero++; + } + + goa_even_valid = (num_zero != ARRAY_SIZE(desc->goa_even_timing)); + + /* Programming one without the other would make no sense! */ + if (goa_odd_valid != goa_even_valid) + return -EINVAL; + + /* We know that both are either true or false now, check just one */ + if (!goa_odd_valid) + hx->skip_goa_timing = true; + + if (!desc->goa_unk_ba && !desc->goa_stv_lead_time_ck && + !desc->goa_ckv_lead_time_ck && !desc->goa_ckv_dummy_vblank_num && + !desc->goa_ckv_rise_precharge && !desc->goa_ckv_fall_precharge && + !desc->goa_clr1_width_adj && !desc->goa_clr234_width_adj && + !desc->goa_unk_e4 && !desc->goa_unk_e5) { + hx->skip_goa_config = true; + return 0; + } + + if ((desc->goa_stv_lead_time_ck > HX8279_P3_GOA_STV_LEAD) || + (desc->goa_ckv_lead_time_ck > HX8279_P3_GOA_CKV_LEAD) || + (desc->goa_ckv_dummy_vblank_num > HX8279_P3_GOA_CKV_DUMMY)) + return dev_err_probe(dev, -EINVAL, + "Invalid lead timings in GOA config\n"); + + /* + * Don't perform zero check for polarity and start position, as + * both pol=0 and start=0 are valid configuration values. + */ + for (i = 0; i < ARRAY_SIZE(desc->goa_clr_start_pos); i++) { + if (desc->goa_clr_start_pos[i] < 0) + continue; + else if (desc->goa_clr_start_pos[i] > HX8279_P3_GOA_CLR_CFG_STARTPOS) + return dev_err_probe(dev, -EINVAL, + "Invalid start position for CLR%d\n", i + 1); + else + num_clr++; + } + if (!num_clr) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) { + if (num_clr < 0) + return -EINVAL; + + if (desc->goa_clr_polarity[i] < 0) + continue; + else if (desc->goa_clr_polarity[i] > 1) + return dev_err_probe(dev, -EINVAL, + "Invalid polarity for CLR%d\n", i + 1); + else + num_clr--; + } + + return 0; +} + +static int hx8279_check_dig_gamma(struct hx8279 *hx, struct device *dev, const u8 *component) +{ + u8 gamma_high_bits[4]; + u16 prev_val = 0; + int i, j, k, x; + + /* + * The gamma values are 10 bits long and shall be incremental + * to form a digital gamma correction reference curve. + * + * As for the registers format: the first 24 bytes contain each the + * lowest 8 bits for each of the gamma level references, and the last + * 6 bytes contain the high two bits of 4 registers at a time, where + * the first two bits are relative to the last register, and the last + * two are relative to the first register. + * + * Another way of saying, those are the first four LOW values: + * DGMA1_LO = 0xb1, DGMA2_LO = 0xb2, DGMA3_LO = 0xb3, DGMA4_LO = 0xb4 + * + * The high values for those four are at DGMA1_4_HI = 0xc9; + * ...and DGMA1_4_HI's data contains the following bits: + * [1:0] = DGMA4_HI, [3:2] = DGMA3_HI, [5:4] = DGMA2_HI, [7:6] = DGMA1_HI + */ + for (i = 0; i < HX8279_PG_DGAMMA_NUM_HI_BYTES; i++) { + k = HX8279_PG_DGAMMA_NUM_LO_BYTES + i; + j = i * 4; + x = 0; + + gamma_high_bits[0] = FIELD_GET(HX8279_DGAMMA_DGMA1_HI, component[k]); + gamma_high_bits[1] = FIELD_GET(HX8279_DGAMMA_DGMA2_HI, component[k]); + gamma_high_bits[2] = FIELD_GET(HX8279_DGAMMA_DGMA3_HI, component[k]); + gamma_high_bits[3] = FIELD_GET(HX8279_DGAMMA_DGMA4_HI, component[k]); + + do { + u16 cur_val = component[j] | (gamma_high_bits[x] << 8); + + if (cur_val < prev_val) + return dev_err_probe(dev, -EINVAL, + "Invalid dgamma values: %u < %u!\n", + cur_val, prev_val); + prev_val = cur_val; + j++; + x++; + } while (x < 4); + }; + + return 0; +} + +static int hx8279_check_params(struct hx8279 *hx, struct device *dev) +{ + const struct hx8279_panel_desc *desc = hx->desc; + int ret; + + /* Voltages config validation */ + if (!desc->vgh_mv && !desc->vgl_mv && !desc->vgph_mv && !desc->vgnh_mv) + hx->skip_voltage_config = true; + else if ((desc->vgh_mv && desc->vgh_mv < HX8279_VGH_MIN_MV) || + (desc->vgl_mv && desc->vgl_mv < HX8279_VGL_MIN_MV) || + (desc->vgph_mv && desc->vgph_mv < HX8279_VGPNH_MIN_MV) || + (desc->vgnh_mv && desc->vgnh_mv < HX8279_VGPNH_MIN_MV)) + return -EINVAL; + + /* GOA Muxing validation */ + ret = hx8279_check_gmux_config(hx, dev); + if (ret) + return ret; + + /* GOA Configuration validation */ + ret = hx8279_check_goa_config(hx, dev); + if (ret) + return ret; + + /* MIPI Configuration validation */ + if (!desc->bta_tlpx && !desc->lhs_settle_time_by_osc25 && + !desc->ths_settle_time && !desc->timing_unk_b8 && + !desc->timing_unk_bc && !desc->timing_unk_d6) + hx->skip_mipi_timing = true; + + /* ENG/Gamma Configuration validation */ + if (desc->gamma_ctl > (HX8279_P6_GAMMA_POCGM_CTL | HX8279_P6_GAMMA_POGCMD_CTL)) + return -EINVAL; + + /* Digital Gamma values validation */ + if (desc->dgamma) { + ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->r); + if (ret) + return ret; + + ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->g); + if (ret) + return ret; + + ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->b); + if (ret) + return ret; + } + + return 0; +} + +static int hx8279_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct device_node *dsi_r; + struct hx8279 *hx; + int i, ret; + + hx = devm_drm_panel_alloc(dev, struct hx8279, panel, + &hx8279_panel_funcs, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(hx)) + return PTR_ERR(hx); + + ret = hx8279_init_vregs(hx, dev); + if (ret) + return ret; + + hx->desc = device_get_match_data(dev); + if (!hx->desc) + return -ENODEV; + + /* + * In some DriverICs some or all fields may be OTP: perform a + * basic configuration check before writing to help avoiding + * irreparable mistakes. + * + * Please note that this is not perfect and will only check if + * the values may be plausible; values that are wrong for a + * specific display, but still plausible for DrIC config will + * be accepted. + */ + ret = hx8279_check_params(hx, dev); + if (ret) + return dev_err_probe(dev, ret, "Invalid DriverIC configuration\n"); + + /* The enable line may be always tied to VCCIO, so this is optional */ + hx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS); + if (IS_ERR(hx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(hx->enable_gpio), + "Failed to get enable GPIO\n"); + + hx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); + if (IS_ERR(hx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(hx->reset_gpio), + "Failed to get reset GPIO\n"); + + /* If the panel is connected on two DSIs then DSI0 left, DSI1 right */ + dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); + if (dsi_r) { + const struct mipi_dsi_device_info *info = &hx->desc->dsi_info; + struct mipi_dsi_host *dsi_r_host; + + dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r); + of_node_put(dsi_r); + if (!dsi_r_host) + return dev_err_probe(dev, -EPROBE_DEFER, + "Cannot get secondary DSI host\n"); + + hx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi_r_host, info); + if (IS_ERR(hx->dsi[1])) + return dev_err_probe(dev, PTR_ERR(hx->dsi[1]), + "Cannot get secondary DSI node\n"); + mipi_dsi_set_drvdata(hx->dsi[1], hx); + } + + hx->dsi[0] = dsi; + mipi_dsi_set_drvdata(dsi, hx); + + ret = drm_panel_of_backlight(&hx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&hx->panel); + + for (i = 0; i < 2; i++) { + if (!hx->dsi[i]) + continue; + + hx->dsi[i]->lanes = hx->desc->num_lanes; + hx->dsi[i]->format = MIPI_DSI_FMT_RGB888; + + hx->dsi[i]->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_LPM; + + if (hx->desc->mode_data[0].is_video_mode) + hx->dsi[i]->mode_flags |= MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + + ret = devm_mipi_dsi_attach(dev, hx->dsi[i]); + if (ret < 0) { + drm_panel_remove(&hx->panel); + return dev_err_probe(dev, ret, + "Cannot attach to DSI%d host.\n", i); + } + } + + return 0; +} + +static void hx8279_remove(struct mipi_dsi_device *dsi) +{ + struct hx8279 *hx = mipi_dsi_get_drvdata(dsi); + + drm_panel_remove(&hx->panel); +} + +static const struct hx8279_panel_mode aoly_sl101pm1794fog_v15_modes[] = { + { + .mode = { + .clock = 159420, + .hdisplay = 1200, + .hsync_start = 1200 + 80, + .hsync_end = 1200 + 80 + 60, + .htotal = 1200 + 80 + 60 + 24, + .vdisplay = 1920, + .vsync_start = 1920 + 10, + .vsync_end = 1920 + 10 + 14, + .vtotal = 1920 + 10 + 14 + 4, + .width_mm = 136, + .height_mm = 217, + .type = DRM_MODE_TYPE_DRIVER + }, + .bpc = 8, + .is_video_mode = true, + }, +}; + +static const struct hx8279_panel_mode startek_kd070fhfid078_modes[] = { + { + .mode = { + .clock = 156458, + .hdisplay = 1200, + .hsync_start = 1200 + 50, + .hsync_end = 1200 + 50 + 24, + .htotal = 1200 + 50 + 24 + 66, + .vdisplay = 1920, + .vsync_start = 1920 + 14, + .vsync_end = 1920 + 14 + 2, + .vtotal = 1920 + 14 + 2 + 10, + .width_mm = 95, + .height_mm = 151, + .type = DRM_MODE_TYPE_DRIVER + }, + .bpc = 8, + .is_video_mode = true, + }, +}; + +static const struct hx8279_goa_mux aoly_sl101pm1794fog_v15_gmux = { + .gout_l = { 0x5, 0x5, 0xb, 0xb, 0x9, 0x9, 0x16, 0x16, 0xe, 0xe, + 0x7, 0x7, 0x26, 0x26, 0x15, 0x15, 0x1, 0x1, 0x3, 0x3 }, + .gout_r = { 0x6, 0x6, 0xc, 0xc, 0xa, 0xa, 0x16, 0x16, 0xe, 0xe, + 0x8, 0x8, 0x26, 0x26, 0x15, 0x15, 0x2, 0x2, 0x4, 0x4 }, +}; + +static const struct hx8279_analog_gamma aoly_sl101pm1794fog_v15_ana_gamma = { + .pos = { 0x0, 0xd, 0x17, 0x26, 0x31, 0x1c, 0x2c, 0x33, 0x31, + 0x37, 0x37, 0x37, 0x39, 0x2e, 0x2f, 0x2f, 0x7 }, + .neg = { 0x0, 0xd, 0x17, 0x26, 0x31, 0x3f, 0x3f, 0x3f, 0x3f, + 0x37, 0x37, 0x37, 0x39, 0x2e, 0x2f, 0x2f, 0x7 }, +}; + +static const struct hx8279_digital_gamma aoly_sl101pm1794fog_v15_dig_gamma = { + .r = { 0x0, 0x5, 0x10, 0x22, 0x36, 0x4a, 0x6c, 0x9a, 0xd7, 0x17, + 0x92, 0x15, 0x18, 0x8c, 0x0, 0x3a, 0x72, 0x8c, 0xa5, 0xb1, + 0xbe, 0xca, 0xd1, 0xd4, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff }, + .g = { 0x4, 0x5, 0x11, 0x24, 0x39, 0x4e, 0x72, 0xa3, 0xe1, 0x25, + 0xa8, 0x2e, 0x32, 0xad, 0x28, 0x63, 0x9b, 0xb5, 0xcf, 0xdb, + 0xe8, 0xf5, 0xfa, 0xfc, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff }, + .b = { 0x4, 0x4, 0xf, 0x22, 0x37, 0x4d, 0x71, 0xa2, 0xe1, 0x26, + 0xa9, 0x2f, 0x33, 0xac, 0x24, 0x5d, 0x94, 0xac, 0xc5, 0xd1, + 0xdc, 0xe8, 0xed, 0xf0, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff }, +}; + +static const struct hx8279_panel_desc aoly_sl101pm1794fog_v15 = { + .dsi_info = { + .type = "L101PM1794FOG-V15", + .channel = 0, + .node = NULL, + }, + .mode_data = aoly_sl101pm1794fog_v15_modes, + .num_modes = ARRAY_SIZE(aoly_sl101pm1794fog_v15_modes), + .num_lanes = 4, + + /* Driver/Module Configuration: LC Matrix voltages */ + .vgh_mv = 16500, + .vgl_mv = 11200, + .vgph_mv = 4600, + .vgnh_mv = 4600, + + /* Analog Gamma correction */ + .agamma = &aoly_sl101pm1794fog_v15_ana_gamma, + + /* Gate driver On Array (GOA) Muxing */ + .gmux = &aoly_sl101pm1794fog_v15_gmux, + + /* Gate driver On Array (GOA) Mux Config */ + .goa_unk_ba = 0xf0, + .goa_odd_timing = { 0, 0, 0, 42, 0, 0 }, + .goa_even_timing = { 1, 42, 0, 0 }, + .goa_stv_lead_time_ck = 11, + .goa_ckv_lead_time_ck = 7, + .goa_ckv_dummy_vblank_num = 3, + .goa_ckv_rise_precharge = 1, + .goa_clr1_width_adj = 0, + .goa_clr234_width_adj = 0, + .goa_clr_polarity = { 1, 0, 0, 0 }, + .goa_clr_start_pos = { 8, 9, 3, 4 }, + .goa_unk_e4 = 0xc0, + .goa_unk_e5 = 0x0d, + + /* MIPI Configuration */ + .bta_tlpx = 2, + .lhs_settle_time_by_osc25 = true, + .ths_settle_time = 2, + .timing_unk_b8 = 0xa5, + .timing_unk_bc = 0x20, + .timing_unk_d6 = 0x7f, + + /* ENG/Gamma Configuration */ + .gamma_ctl = 0, + .volt_adj = FIELD_PREP_CONST(HX8279_P6_VOLT_ADJ_VCCIFS, 3) | + FIELD_PREP_CONST(HX8279_P6_VOLT_ADJ_VCCS, 3), + .src_delay_time_adj_ck = 50, + + /* Digital Gamma Adjustment */ + .dgamma = &aoly_sl101pm1794fog_v15_dig_gamma, +}; + +static const struct hx8279_goa_mux startek_kd070fhfid078_gmux = { + .gout_l = { 0xd, 0xd, 0x6, 0x6, 0x8, 0x8, 0xa, 0xa, 0xc, 0xc, + 0x0, 0x0, 0xe, 0xe, 0x1, 0x1, 0x4, 0x4, 0x0, 0x0 }, + .gout_r = { 0xd, 0xd, 0x5, 0x5, 0x7, 0x7, 0x9, 0x9, 0xb, 0xb, + 0x0, 0x0, 0xe, 0xe, 0x1, 0x1, 0x3, 0x3, 0x0, 0x0 }, +}; + +static const struct hx8279_panel_desc startek_kd070fhfid078 = { + .dsi_info = { + .type = "KD070FHFID078", + .channel = 0, + .node = NULL, + }, + .mode_data = startek_kd070fhfid078_modes, + .num_modes = ARRAY_SIZE(startek_kd070fhfid078_modes), + .num_lanes = 4, + + /* Driver/Module Configuration: LC Matrix voltages */ + .vgh_mv = 18000, + .vgl_mv = 12100, + .vgph_mv = 5500, + .vgnh_mv = 5500, + + /* Gate driver On Array (GOA) Mux Config */ + .gmux = &startek_kd070fhfid078_gmux, + + /* Gate driver On Array (GOA) Configuration */ + .goa_unk_ba = 0xf0, + .goa_stv_lead_time_ck = 7, + .goa_ckv_lead_time_ck = 3, + .goa_ckv_dummy_vblank_num = 1, + .goa_ckv_rise_precharge = 0, + .goa_ckv_fall_precharge = 0, + .goa_clr1_width_adj = 1, + .goa_clr234_width_adj = 5, + .goa_clr_polarity = { 0, 1, -1, -1 }, + .goa_clr_start_pos = { 5, 10, -1, -1 }, + .goa_unk_e4 = 0xc0, + .goa_unk_e5 = 0x00, + + /* MIPI Configuration */ + .bta_tlpx = 2, + .lhs_settle_time_by_osc25 = true, + .ths_settle_time = 2, + .timing_unk_b8 = 0x7f, + .timing_unk_bc = 0x20, + .timing_unk_d6 = 0x7f, + + /* ENG/Gamma Configuration */ + .gamma_ctl = FIELD_PREP_CONST(HX8279_P6_GAMMA_POCGM_CTL, 1) | + FIELD_PREP_CONST(HX8279_P6_GAMMA_POGCMD_CTL, 1), + .src_delay_time_adj_ck = 72, +}; + +static const struct of_device_id hx8279_of_match[] = { + { .compatible = "aoly,sl101pm1794fog-v15", .data = &aoly_sl101pm1794fog_v15 }, + { .compatible = "startek,kd070fhfid078", .data = &startek_kd070fhfid078 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hx8279_of_match); + +static struct mipi_dsi_driver hx8279_driver = { + .probe = hx8279_probe, + .remove = hx8279_remove, + .driver = { + .name = "panel-himax-hx8279", + .of_match_table = hx8279_of_match, + }, +}; +module_mipi_dsi_driver(hx8279_driver); + +MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); +MODULE_DESCRIPTION("Himax HX8279 DriverIC panels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-himax-hx83102.c b/drivers/gpu/drm/panel/panel-himax-hx83102.c index 66abfc44e424..4c432d207634 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83102.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83102.c @@ -989,8 +989,6 @@ static int hx83102_panel_add(struct hx83102 *ctx) ctx->base.prepare_prev_first = true; - drm_panel_init(&ctx->base, dev, &hx83102_drm_funcs, - DRM_MODE_CONNECTOR_DSI); err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); if (err < 0) return dev_err_probe(dev, err, "failed to get orientation\n"); @@ -1013,9 +1011,11 @@ static int hx83102_probe(struct mipi_dsi_device *dsi) int ret; const struct hx83102_panel_desc *desc; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, __typeof(*ctx), base, + &hx83102_drm_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); desc = of_device_get_match_data(&dsi->dev); dsi->lanes = 4; diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112a.c b/drivers/gpu/drm/panel/panel-himax-hx83112a.c index 47bce087e339..142cb1cc067a 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83112a.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83112a.c @@ -269,9 +269,11 @@ static int hx83112a_probe(struct mipi_dsi_device *dsi) struct hx83112a_panel *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct hx83112a_panel, panel, + &hx83112a_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "vdd1"; ctx->supplies[1].supply = "vsn"; @@ -295,8 +297,6 @@ static int hx83112a_probe(struct mipi_dsi_device *dsi) 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); diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112b.c b/drivers/gpu/drm/panel/panel-himax-hx83112b.c new file mode 100644 index 000000000000..263f79a967de --- /dev/null +++ b/drivers/gpu/drm/panel/panel-himax-hx83112b.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2025 Luca Weiss <luca@lucaweiss.eu> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.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 HX83112B_SETPOWER1 0xb1 +#define HX83112B_SETDISP 0xb2 +#define HX83112B_SETDRV 0xb4 +#define HX83112B_SETEXTC 0xb9 +#define HX83112B_SETBANK 0xbd +#define HX83112B_SETDGCLUT 0xc1 +#define HX83112B_SETDISMO 0xc2 +#define HX83112B_UNKNOWN1 0xc6 +#define HX83112B_SETPANEL 0xcc +#define HX83112B_UNKNOWN2 0xd1 +#define HX83112B_SETPOWER2 0xd2 +#define HX83112B_SETGIP0 0xd3 +#define HX83112B_SETGIP1 0xd5 +#define HX83112B_SETGIP2 0xd6 +#define HX83112B_SETGIP3 0xd8 +#define HX83112B_SETIDLE 0xdd +#define HX83112B_UNKNOWN3 0xe7 +#define HX83112B_UNKNOWN4 0xe9 + +struct hx83112b_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; +}; + +static const struct regulator_bulk_data hx83112b_supplies[] = { + { .supply = "iovcc" }, + { .supply = "vsn" }, + { .supply = "vsp" }, +}; + +static inline struct hx83112b_panel *to_hx83112b_panel(struct drm_panel *panel) +{ + return container_of(panel, struct hx83112b_panel, panel); +} + +static void hx83112b_reset(struct hx83112b_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int hx83112b_on(struct hx83112b_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETEXTC, 0x83, 0x11, 0x2b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0x08, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x04, 0x38, 0x08, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER1, + 0xf8, 0x27, 0x27, 0x00, 0x00, 0x0b, 0x0e, + 0x0b, 0x0e, 0x33); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER2, 0x2d, 0x2d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, + 0x80, 0x02, 0x18, 0x80, 0x70, 0x00, 0x08, + 0x1c, 0x08, 0x11, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x00, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0xb5, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETIDLE, + 0x00, 0x00, 0x08, 0x1c, 0x08, 0x34, 0x34, + 0x88); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, + 0x65, 0x6b, 0x00, 0x00, 0xd0, 0xd4, 0x36, + 0xcf, 0x06, 0xce, 0x00, 0xce, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x2a, 0x07, 0x01, 0x07, + 0x00, 0x00, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 0x01, 0x67, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0xc8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPANEL, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, + 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x13, 0x40, 0x04, 0x09, + 0x09, 0x0b, 0x0b, 0x32, 0x10, 0x08, 0x00, + 0x08, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, + 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x0a, + 0x08, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0x6e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xef); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0xa1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP1, + 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x18, + 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, + 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, + 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xfc, + 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP2, + 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x19, + 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, + 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, + 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, + 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, + 0xab, 0xaf, 0xef, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaf, 0xea, 0xaa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, + 0xaa, 0xaa, 0xab, 0xaf, 0xea, 0xaa, 0xaa, + 0xaa, 0xae, 0xaf, 0xea, 0xaa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, + 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaf, 0xea, 0xaa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, + 0xba, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xba, 0xaa, + 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaf, 0xea, 0xaa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xe4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x17, 0x69); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, + 0x09, 0x09, 0x00, 0x07, 0xe8, 0x00, 0x26, + 0x00, 0x07, 0x00, 0x00, 0xe8, 0x32, 0x00, + 0xe9, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x12, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, + 0x02, 0x00, 0x01, 0x20, 0x01, 0x18, 0x08, + 0xa8, 0x09); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x20, 0x20, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, + 0x00, 0xdc, 0x11, 0x70, 0x00, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, + 0x2a, 0xce, 0x02, 0x70, 0x01, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN2, 0x27); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x24); + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + + return dsi_ctx.accum_err; +} + +static int hx83112b_off(struct hx83112b_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int hx83112b_prepare(struct drm_panel *panel) +{ + struct hx83112b_panel *ctx = to_hx83112b_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + hx83112b_reset(ctx); + + ret = hx83112b_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(hx83112b_supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int hx83112b_unprepare(struct drm_panel *panel) +{ + struct hx83112b_panel *ctx = to_hx83112b_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = hx83112b_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode hx83112b_mode = { + .clock = (1080 + 40 + 4 + 12) * (2160 + 32 + 2 + 2) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 40, + .hsync_end = 1080 + 40 + 4, + .htotal = 1080 + 40 + 4 + 12, + .vdisplay = 2160, + .vsync_start = 2160 + 32, + .vsync_end = 2160 + 32 + 2, + .vtotal = 2160 + 32 + 2 + 2, + .width_mm = 65, + .height_mm = 128, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int hx83112b_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &hx83112b_mode); +} + +static const struct drm_panel_funcs hx83112b_panel_funcs = { + .prepare = hx83112b_prepare, + .unprepare = hx83112b_unprepare, + .get_modes = hx83112b_get_modes, +}; + +static int hx83112b_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static const struct backlight_ops hx83112b_bl_ops = { + .update_status = hx83112b_bl_update_status, +}; + +static struct backlight_device * +hx83112b_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &hx83112b_bl_ops, &props); +} + +static int hx83112b_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct hx83112b_panel *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct hx83112b_panel, panel, + &hx83112b_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(hx83112b_supplies), + hx83112b_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + 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_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_LPM; + + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = hx83112b_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void hx83112b_remove(struct mipi_dsi_device *dsi) +{ + struct hx83112b_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 hx83112b_of_match[] = { + { .compatible = "djn,98-03057-6598b-i" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hx83112b_of_match); + +static struct mipi_dsi_driver hx83112b_driver = { + .probe = hx83112b_probe, + .remove = hx83112b_remove, + .driver = { + .name = "panel-himax-hx83112b", + .of_match_table = hx83112b_of_match, + }, +}; +module_mipi_dsi_driver(hx83112b_driver); + +MODULE_DESCRIPTION("DRM driver for hx83112b-equipped DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index 92b03a2f65a3..c4d3e09a228d 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -80,7 +80,7 @@ struct hx8394_panel_desc { unsigned int lanes; unsigned long mode_flags; enum mipi_dsi_pixel_format format; - int (*init_sequence)(struct hx8394 *ctx); + void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx); }; static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel) @@ -88,98 +88,94 @@ static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel) return container_of(panel, struct hx8394, panel); } -static int hsd060bhw4_init_sequence(struct hx8394 *ctx) +static void hsd060bhw4_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - /* 5.19.8 SETEXTC: Set extension command (B9h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, - 0xff, 0x83, 0x94); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, + 0xff, 0x83, 0x94); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30); /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, - 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, + 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); /* 5.19.3 SETDISP: Set display related register (B2h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, - 0x00, 0x80, 0x78, 0x0c, 0x07); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x78, 0x0c, 0x07); /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, - 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, - 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, - 0x7c); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, + 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, + 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, + 0x7c); /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, - 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, - 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, - 0x00, 0x0c, 0x40); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, + 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, + 0x00, 0x0c, 0x40); /* 5.19.20 Set GIP Option1 (D5h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, - 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, + 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); /* 5.19.21 Set GIP Option2 (D6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, - 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, + 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, - 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, - 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, - 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, - 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, - 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, - 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, - 0x4a, 0x4c, 0x4b, 0x7f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, + 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, + 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, + 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, + 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, + 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, + 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, + 0x4a, 0x4c, 0x4b, 0x7f); /* 5.19.17 SETPANEL (CCh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, - 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, + 0x0b); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, - 0x1f, 0x31); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, + 0x1f, 0x31); /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, - 0x7d, 0x7d); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, + 0x7d, 0x7d); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, - 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, + 0x02); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x01); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x00); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, - 0xed); - - return 0; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, + 0xed); } static const struct drm_display_mode hsd060bhw4_mode = { @@ -205,114 +201,110 @@ static const struct hx8394_panel_desc hsd060bhw4_desc = { .init_sequence = hsd060bhw4_init_sequence, }; -static int powkiddy_x55_init_sequence(struct hx8394 *ctx) +static void powkiddy_x55_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - /* 5.19.8 SETEXTC: Set extension command (B9h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, - 0xff, 0x83, 0x94); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, + 0xff, 0x83, 0x94); /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, - 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, + 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); /* 5.19.3 SETDISP: Set display related register (B2h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, - 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, - 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, - 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, - 0x86); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, + 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, + 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, + 0x86); /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, - 0x6e, 0x6e); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, + 0x6e, 0x6e); /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, - 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, - 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, - 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, - 0x07, 0x0c, 0x40); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, + 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, + 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, + 0x07, 0x0c, 0x40); /* 5.19.20 Set GIP Option1 (D5h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, - 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, - 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, - 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, + 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, + 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, + 0x18, 0x18, 0x18, 0x18); /* 5.19.21 Set GIP Option2 (D6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, - 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, - 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, - 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, - 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, + 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, + 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, + 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, + 0x18, 0x18, 0x18, 0x18); /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, - 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, - 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, - 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, - 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, - 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, - 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, + 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, + 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, + 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, + 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, + 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, + 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, - 0x1f, 0x31); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, + 0x1f, 0x31); /* 5.19.17 SETPANEL (CCh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, - 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, + 0x0b); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, - 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, + 0x02); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x02); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x01); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x00); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN5, - 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN5, + 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); /* Unknown command, not listed in the HX8394-F datasheet */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2, - 0xed); - - return 0; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, + 0xed); } static const struct drm_display_mode powkiddy_x55_mode = { @@ -339,131 +331,127 @@ static const struct hx8394_panel_desc powkiddy_x55_desc = { .init_sequence = powkiddy_x55_init_sequence, }; -static int mchp_ac40t08a_init_sequence(struct hx8394 *ctx) +static void mchp_ac40t08a_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - /* DCS commands do not seem to be sent correclty without this delay */ - msleep(20); + mipi_dsi_msleep(dsi_ctx, 20); /* 5.19.8 SETEXTC: Set extension command (B9h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, - 0xff, 0x83, 0x94); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, + 0xff, 0x83, 0x94); /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, - 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, + 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, - 0x71, 0x71, 0x57, 0x47); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, + 0x71, 0x71, 0x57, 0x47); /* 5.19.3 SETDISP: Set display related register (B2h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, - 0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f); /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, - 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, - 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, - 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, - 0x01, 0x0c, 0x86); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, + 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, + 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, + 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, + 0x01, 0x0c, 0x86); /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, - 0x6e, 0x6e); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, + 0x6e, 0x6e); /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, - 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, - 0x0c, 0x00, 0x08, 0x10, 0x08, 0x00, - 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, - 0x02, 0x15, 0x06, 0x05, 0x06, 0x47, - 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, - 0x07, 0x0c, 0x40); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, + 0x0c, 0x00, 0x08, 0x10, 0x08, 0x00, + 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, + 0x02, 0x15, 0x06, 0x05, 0x06, 0x47, + 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, + 0x07, 0x0c, 0x40); /* 5.19.20 Set GIP Option1 (D5h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, - 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, - 0x18, 0x18, 0x26, 0x27, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x20, 0x21, 0x18, 0x18, - 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, + 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, + 0x18, 0x18, 0x26, 0x27, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x20, 0x21, 0x18, 0x18, + 0x18, 0x18); /* 5.19.21 Set GIP Option2 (D6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, - 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, - 0x18, 0x18, 0x27, 0x26, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x25, 0x24, 0x18, 0x18, - 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, + 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, + 0x18, 0x18, 0x27, 0x26, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x25, 0x24, 0x18, 0x18, + 0x18, 0x18); /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, - 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, - 0x24, 0x22, 0x47, 0x56, 0x65, 0x66, - 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, - 0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61, - 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, - 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, - 0x22, 0x47, 0x56, 0x65, 0x65, 0x6e, - 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, - 0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67, - 0x6b, 0x72, 0x7f, 0x7f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, + 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, + 0x24, 0x22, 0x47, 0x56, 0x65, 0x66, + 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, + 0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61, + 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, + 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, + 0x22, 0x47, 0x56, 0x65, 0x65, 0x6e, + 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, + 0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67, + 0x6b, 0x72, 0x7f, 0x7f); /* Unknown command, not listed in the HX8394-F datasheet (C0H) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, - 0x1f, 0x73); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, + 0x1f, 0x73); /* Set CABC control (C9h)*/ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCABC, - 0x76, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCABC, + 0x76, 0x00, 0x30); /* 5.19.17 SETPANEL (CCh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, - 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, + 0x0b); /* Unknown command, not listed in the HX8394-F datasheet (D4h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, - 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, + 0x02); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x02); /* 5.19.11 Set register bank (D8h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x01); /* 5.19.2 SETPOWER: Set power (B1h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x00); /* 5.19.11 Set register bank (BDh) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, - 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); /* Unknown command, not listed in the HX8394-F datasheet (C6h) */ - mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2, - 0xed); - - return 0; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, + 0xed); } static const struct drm_display_mode mchp_ac40t08a_mode = { @@ -489,39 +477,176 @@ static const struct hx8394_panel_desc mchp_ac40t08a_desc = { .init_sequence = mchp_ac40t08a_init_sequence, }; +/* + * HL055FHAV028C is based on Himax HX8399, so datasheet pages are + * slightly different than HX8394 based panels. + */ +static void hl055fhav028c_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) +{ + /* 6.3.6 SETEXTC: Set extension command (B9h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, + 0xff, 0x83, 0x99); + + /* 6.3.17 SETOFFSET: Set offset voltage (D2h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETOFFSET, + 0x77); + + /* 6.3.1 SETPOWER: Set power (B1h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, + 0x02, 0x04, 0x74, 0x94, 0x01, 0x32, + 0x33, 0x11, 0x11, 0xab, 0x4d, 0x56, + 0x73, 0x02, 0x02); + + /* 6.3.2 SETDISP: Set display related register (B2h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x80, 0xae, 0x05, 0x07, + 0x5a, 0x11, 0x00, 0x00, 0x10, 0x1e, + 0x70, 0x03, 0xd4); + + /* 6.3.3 SETCYC: Set display waveform cycles (B4h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, + 0x00, 0xff, 0x02, 0xc0, 0x02, 0xc0, + 0x00, 0x00, 0x08, 0x00, 0x04, 0x06, + 0x00, 0x32, 0x04, 0x0a, 0x08, 0x21, + 0x03, 0x01, 0x00, 0x0f, 0xb8, 0x8b, + 0x02, 0xc0, 0x02, 0xc0, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x06, 0x00, 0x32, + 0x04, 0x0a, 0x08, 0x01, 0x00, 0x0f, + 0xb8, 0x01); + + /* 6.3.18 SETGIP0: Set GIP Option0 (D3h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x10, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x05, 0x05, 0x07, 0x00, 0x00, + 0x00, 0x05, 0x40); + + /* 6.3.19 Set GIP Option1 (D5h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, + 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, + 0x21, 0x20, 0x01, 0x00, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x2f, 0x2f, + 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, + 0x18, 0x18); + + /* 6.3.20 Set GIP Option2 (D6h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, + 0x18, 0x18, 0x19, 0x19, 0x40, 0x40, + 0x20, 0x21, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x00, 0x01, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x2f, 0x2f, + 0x30, 0x30, 0x31, 0x31, 0x40, 0x40, + 0x40, 0x40); + + /* 6.3.21 Set GIP Option3 (D8h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, + 0xa2, 0xaa, 0x02, 0xa0, 0xa2, 0xa8, + 0x02, 0xa0, 0xb0, 0x00, 0x00, 0x00, + 0xb0, 0x00, 0x00, 0x00); + + /* 6.3.9 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x01); + + /* 6.3.21 Set GIP Option3 (D8h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, + 0xb0, 0x00, 0x00, 0x00, 0xb0, 0x00, + 0x00, 0x00, 0xe2, 0xaa, 0x03, 0xf0, + 0xe2, 0xaa, 0x03, 0xf0); + + /* 6.3.9 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x02); + + /* 6.3.21 Set GIP Option3 (D8h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, + 0xe2, 0xaa, 0x03, 0xf0, 0xe2, 0xaa, + 0x03, 0xf0); + + /* 6.3.9 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, + 0x00); + + /* 6.3.4 SETVCOM: Set VCOM voltage (B6h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, + 0x7a, 0x7a); + + /* 6.3.26 SETGAMMA: Set gamma curve related setting (E0h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, + 0x00, 0x18, 0x27, 0x24, 0x5a, 0x68, + 0x79, 0x78, 0x81, 0x8a, 0x92, 0x99, + 0x9e, 0xa7, 0xaf, 0xb4, 0xb9, 0xc3, + 0xc7, 0xd1, 0xc6, 0xd4, 0xd5, 0x6c, + 0x67, 0x71, 0x77, 0x00, 0x00, 0x18, + 0x27, 0x24, 0x5a, 0x68, 0x79, 0x78, + 0x81, 0x8a, 0x92, 0x99, 0x9e, 0xa7, + 0xaf, 0xb4, 0xb9, 0xc3, 0xc7, 0xd1, + 0xc6, 0xd4, 0xd5, 0x6c, 0x67, 0x77); + + /* Unknown command, not listed in the HX8399-C datasheet (C6h) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, + 0xff, 0xf9); + + /* 6.3.16 SETPANEL (CCh) */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, + 0x08); +} + +static const struct drm_display_mode hl055fhav028c_mode = { + .hdisplay = 1080, + .hsync_start = 1080 + 32, + .hsync_end = 1080 + 32 + 8, + .htotal = 1080 + 32 + 8 + 32, + .vdisplay = 1920, + .vsync_start = 1920 + 16, + .vsync_end = 1920 + 16 + 2, + .vtotal = 1920 + 16 + 2 + 14, + .clock = 134920, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 70, + .height_mm = 127, +}; + +static const struct hx8394_panel_desc hl055fhav028c_desc = { + .mode = &hl055fhav028c_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = hl055fhav028c_init_sequence, +}; + static int hx8394_enable(struct drm_panel *panel) { struct hx8394 *ctx = panel_to_hx8394(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; int ret; - ret = ctx->desc->init_sequence(ctx); - if (ret) { - dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); - return ret; - } + ctx->desc->init_sequence(&dsi_ctx); - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret) { - dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + if (dsi_ctx.accum_err) + return dsi_ctx.accum_err; /* Panel is operational 120 msec after reset */ msleep(120); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret) { - dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + if (dsi_ctx.accum_err) goto sleep_in; - } return 0; sleep_in: + ret = dsi_ctx.accum_err; + dsi_ctx.accum_err = 0; + /* This will probably fail, but let's try orderly power off anyway. */ - if (!mipi_dsi_dcs_enter_sleep_mode(dsi)) - msleep(50); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); return ret; } @@ -530,17 +655,12 @@ static int hx8394_disable(struct drm_panel *panel) { struct hx8394 *ctx = panel_to_hx8394(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - int ret; - - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret) { - dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); - return ret; - } + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - msleep(50); /* about 3 frames */ + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); /* about 3 frames */ - return 0; + return dsi_ctx.accum_err; } static int hx8394_unprepare(struct drm_panel *panel) @@ -632,9 +752,11 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) struct hx8394 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct hx8394, panel, + &hx8394_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) @@ -666,9 +788,6 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->iovcc), "Failed to request iovcc regulator\n"); - drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; @@ -704,6 +823,7 @@ static void hx8394_remove(struct mipi_dsi_device *dsi) static const struct of_device_id hx8394_of_match[] = { { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, + { .compatible = "huiling,hl055fhav028c", .data = &hl055fhav028c_desc }, { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, { .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc }, { /* sentinel */ } diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 94b7dfef3b5e..6ed544a83bdd 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -722,9 +722,10 @@ static int ili9322_probe(struct spi_device *spi) int ret; int i; - ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL); - if (!ili) - return -ENOMEM; + ili = devm_drm_panel_alloc(dev, struct ili9322, panel, + &ili9322_drm_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ili)) + return PTR_ERR(ili); spi_set_drvdata(spi, ili); @@ -883,9 +884,6 @@ static int ili9322_probe(struct spi_device *spi) ili->input = ili->conf->input; } - drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&ili->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index ff39f5dd4097..f7425dfaa50d 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -173,7 +173,6 @@ struct ili9341_config { }; struct ili9341 { - struct device *dev; const struct ili9341_config *conf; struct drm_panel panel; struct gpio_desc *reset_gpio; @@ -490,9 +489,11 @@ static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc, struct ili9341 *ili; int ret; - ili = devm_kzalloc(dev, sizeof(struct ili9341), GFP_KERNEL); - if (!ili) - return -ENOMEM; + ili = devm_drm_panel_alloc(dev, struct ili9341, panel, + &ili9341_dpi_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ili)) + return PTR_ERR(ili); ili->dbi = devm_kzalloc(dev, sizeof(struct mipi_dbi), GFP_KERNEL); @@ -526,8 +527,6 @@ static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc, } ili->max_spi_speed = ili->conf->max_spi_speed; - drm_panel_init(&ili->panel, dev, &ili9341_dpi_funcs, - DRM_MODE_CONNECTOR_DPI); drm_panel_add(&ili->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9805.c b/drivers/gpu/drm/panel/panel-ilitek-ili9805.c index 1cbc25758bd2..e6c483851f1f 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9805.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9805.c @@ -307,9 +307,12 @@ static int ili9805_dsi_probe(struct mipi_dsi_device *dsi) struct ili9805 *ctx; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct ili9805, panel, + &ili9805_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; ctx->desc = of_device_get_match_data(&dsi->dev); @@ -320,9 +323,6 @@ static int ili9805_dsi_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET; dsi->lanes = 2; - drm_panel_init(&ctx->panel, &dsi->dev, &ili9805_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); if (IS_ERR(ctx->dvdd)) return PTR_ERR(ctx->dvdd); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c index a3c79ad99d0b..18aa6222b0c5 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c @@ -166,9 +166,10 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) struct ili9806e_panel *ctx; int i, ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ili9806e_panel, panel, &ili9806e_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->desc = device_get_match_data(dev); @@ -192,9 +193,6 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) dsi->format = ctx->desc->format; dsi->lanes = ctx->desc->lanes; - drm_panel_init(&ctx->panel, dev, &ili9806e_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); if (ret) return dev_err_probe(dev, ret, "Failed to get orientation\n"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 28cd7560e5db..ac433345a179 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -43,6 +43,7 @@ struct ili9881c_desc { const struct drm_display_mode *mode; const unsigned long mode_flags; u8 default_address_mode; + unsigned int lanes; }; struct ili9881c { @@ -1223,6 +1224,199 @@ static const struct ili9881c_instr am8001280g_init[] = { ILI9881C_COMMAND_INSTR(MIPI_DCS_WRITE_POWER_SAVE, 0x00), }; +static const struct ili9881c_instr rpi_7inch_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0a), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x61), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x01), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x61), + ILI9881C_COMMAND_INSTR(0x10, 0x61), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0x40), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3c), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x00), + ILI9881C_COMMAND_INSTR(0x3b, 0x00), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x10), + ILI9881C_COMMAND_INSTR(0x51, 0x32), + ILI9881C_COMMAND_INSTR(0x52, 0x54), + ILI9881C_COMMAND_INSTR(0x53, 0x76), + ILI9881C_COMMAND_INSTR(0x54, 0x98), + ILI9881C_COMMAND_INSTR(0x55, 0xba), + ILI9881C_COMMAND_INSTR(0x56, 0x10), + ILI9881C_COMMAND_INSTR(0x57, 0x32), + ILI9881C_COMMAND_INSTR(0x58, 0x54), + ILI9881C_COMMAND_INSTR(0x59, 0x76), + ILI9881C_COMMAND_INSTR(0x5a, 0x98), + ILI9881C_COMMAND_INSTR(0x5b, 0xba), + ILI9881C_COMMAND_INSTR(0x5c, 0xdc), + ILI9881C_COMMAND_INSTR(0x5d, 0xfe), + ILI9881C_COMMAND_INSTR(0x5e, 0x00), + ILI9881C_COMMAND_INSTR(0x5f, 0x0e), + ILI9881C_COMMAND_INSTR(0x60, 0x0f), + ILI9881C_COMMAND_INSTR(0x61, 0x0c), + ILI9881C_COMMAND_INSTR(0x62, 0x0d), + ILI9881C_COMMAND_INSTR(0x63, 0x06), + ILI9881C_COMMAND_INSTR(0x64, 0x07), + ILI9881C_COMMAND_INSTR(0x65, 0x02), + ILI9881C_COMMAND_INSTR(0x66, 0x02), + ILI9881C_COMMAND_INSTR(0x67, 0x02), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x01), + ILI9881C_COMMAND_INSTR(0x6a, 0x00), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6d, 0x14), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x0e), + ILI9881C_COMMAND_INSTR(0x76, 0x0f), + ILI9881C_COMMAND_INSTR(0x77, 0x0c), + ILI9881C_COMMAND_INSTR(0x78, 0x0d), + ILI9881C_COMMAND_INSTR(0x79, 0x06), + ILI9881C_COMMAND_INSTR(0x7a, 0x07), + ILI9881C_COMMAND_INSTR(0x7b, 0x02), + ILI9881C_COMMAND_INSTR(0x7c, 0x02), + ILI9881C_COMMAND_INSTR(0x7d, 0x02), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x01), + ILI9881C_COMMAND_INSTR(0x80, 0x00), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x14), + ILI9881C_COMMAND_INSTR(0x83, 0x15), + ILI9881C_COMMAND_INSTR(0x84, 0x02), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6C, 0x15), + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), + ILI9881C_COMMAND_INSTR(0x6F, 0x33), + ILI9881C_COMMAND_INSTR(0x3B, 0x98), + ILI9881C_COMMAND_INSTR(0x3a, 0x94), + ILI9881C_COMMAND_INSTR(0x8D, 0x14), + ILI9881C_COMMAND_INSTR(0x87, 0xBA), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), + ILI9881C_COMMAND_INSTR(0xB5, 0x06), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x53, 0x7d), + ILI9881C_COMMAND_INSTR(0x55, 0x8f), + ILI9881C_COMMAND_INSTR(0x40, 0x33), + ILI9881C_COMMAND_INSTR(0x50, 0x96), + ILI9881C_COMMAND_INSTR(0x51, 0x96), + ILI9881C_COMMAND_INSTR(0x60, 0x23), + ILI9881C_COMMAND_INSTR(0xA0, 0x08), + ILI9881C_COMMAND_INSTR(0xA1, 0x1d), + ILI9881C_COMMAND_INSTR(0xA2, 0x2a), + ILI9881C_COMMAND_INSTR(0xA3, 0x10), + ILI9881C_COMMAND_INSTR(0xA4, 0x15), + ILI9881C_COMMAND_INSTR(0xA5, 0x28), + ILI9881C_COMMAND_INSTR(0xA6, 0x1c), + ILI9881C_COMMAND_INSTR(0xA7, 0x1d), + ILI9881C_COMMAND_INSTR(0xA8, 0x7e), + ILI9881C_COMMAND_INSTR(0xA9, 0x1d), + ILI9881C_COMMAND_INSTR(0xAA, 0x29), + ILI9881C_COMMAND_INSTR(0xAB, 0x6b), + ILI9881C_COMMAND_INSTR(0xAC, 0x1a), + ILI9881C_COMMAND_INSTR(0xAD, 0x18), + ILI9881C_COMMAND_INSTR(0xAE, 0x4b), + ILI9881C_COMMAND_INSTR(0xAF, 0x20), + ILI9881C_COMMAND_INSTR(0xB0, 0x27), + ILI9881C_COMMAND_INSTR(0xB1, 0x50), + ILI9881C_COMMAND_INSTR(0xB2, 0x64), + ILI9881C_COMMAND_INSTR(0xB3, 0x39), + ILI9881C_COMMAND_INSTR(0xC0, 0x08), + ILI9881C_COMMAND_INSTR(0xC1, 0x1d), + ILI9881C_COMMAND_INSTR(0xC2, 0x2a), + ILI9881C_COMMAND_INSTR(0xC3, 0x10), + ILI9881C_COMMAND_INSTR(0xC4, 0x15), + ILI9881C_COMMAND_INSTR(0xC5, 0x28), + ILI9881C_COMMAND_INSTR(0xC6, 0x1c), + ILI9881C_COMMAND_INSTR(0xC7, 0x1d), + ILI9881C_COMMAND_INSTR(0xC8, 0x7e), + ILI9881C_COMMAND_INSTR(0xC9, 0x1d), + ILI9881C_COMMAND_INSTR(0xCA, 0x29), + ILI9881C_COMMAND_INSTR(0xCB, 0x6b), + ILI9881C_COMMAND_INSTR(0xCC, 0x1a), + ILI9881C_COMMAND_INSTR(0xCD, 0x18), + ILI9881C_COMMAND_INSTR(0xCE, 0x4b), + ILI9881C_COMMAND_INSTR(0xCF, 0x20), + ILI9881C_COMMAND_INSTR(0xD0, 0x27), + ILI9881C_COMMAND_INSTR(0xD1, 0x50), + ILI9881C_COMMAND_INSTR(0xD2, 0x64), + ILI9881C_COMMAND_INSTR(0xD3, 0x39), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -1449,6 +1643,23 @@ static const struct drm_display_mode am8001280g_default_mode = { .height_mm = 151, }; +static const struct drm_display_mode rpi_7inch_default_mode = { + .clock = 83330, + + .hdisplay = 720, + .hsync_start = 720 + 239, + .hsync_end = 720 + 239 + 33, + .htotal = 720 + 239 + 33 + 50, + + .vdisplay = 1280, + .vsync_start = 1280 + 20, + .vsync_end = 1280 + 20 + 2, + .vtotal = 1280 + 20 + 2 + 30, + + .width_mm = 90, + .height_mm = 151, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -1506,16 +1717,15 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) struct ili9881c *ctx; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct ili9881c, panel, &ili9881c_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; ctx->desc = of_device_get_match_data(&dsi->dev); - drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->power = devm_regulator_get(&dsi->dev, "power"); if (IS_ERR(ctx->power)) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), @@ -1549,7 +1759,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = ctx->desc->mode_flags; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = 4; + dsi->lanes = ctx->desc->lanes; return mipi_dsi_attach(dsi); } @@ -1567,6 +1777,7 @@ static const struct ili9881c_desc lhr050h41_desc = { .init_length = ARRAY_SIZE(lhr050h41_init), .mode = &lhr050h41_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .lanes = 4, }; static const struct ili9881c_desc k101_im2byl02_desc = { @@ -1574,6 +1785,7 @@ static const struct ili9881c_desc k101_im2byl02_desc = { .init_length = ARRAY_SIZE(k101_im2byl02_init), .mode = &k101_im2byl02_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .lanes = 4, }; static const struct ili9881c_desc kd050hdfia020_desc = { @@ -1599,6 +1811,7 @@ static const struct ili9881c_desc w552946aba_desc = { .mode = &w552946aba_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, + .lanes = 4, }; static const struct ili9881c_desc am8001280g_desc = { @@ -1609,6 +1822,14 @@ static const struct ili9881c_desc am8001280g_desc = { MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, }; +static const struct ili9881c_desc rpi_7inch_desc = { + .init = rpi_7inch_init, + .init_length = ARRAY_SIZE(rpi_7inch_init), + .mode = &rpi_7inch_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, + .lanes = 2, +}; + static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, @@ -1616,6 +1837,7 @@ static const struct of_device_id ili9881c_of_match[] = { { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, { .compatible = "ampire,am8001280g", .data = &am8001280g_desc }, + { .compatible = "raspberrypi,dsi-7inch", &rpi_7inch_desc }, { } }; MODULE_DEVICE_TABLE(of, ili9881c_of_match); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c index 3c24a63b6be8..85c7059be214 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c @@ -614,8 +614,6 @@ static int ili9882t_add(struct ili9882t *ili) gpiod_set_value(ili->enable_gpio, 0); - drm_panel_init(&ili->base, dev, &ili9882t_funcs, - DRM_MODE_CONNECTOR_DSI); err = of_drm_get_panel_orientation(dev->of_node, &ili->orientation); if (err < 0) { dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); @@ -640,9 +638,11 @@ static int ili9882t_probe(struct mipi_dsi_device *dsi) int ret; const struct panel_desc *desc; - ili = devm_kzalloc(&dsi->dev, sizeof(*ili), GFP_KERNEL); - if (!ili) - return -ENOMEM; + ili = devm_drm_panel_alloc(&dsi->dev, __typeof(*ili), base, + &ili9882t_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ili)) + return PTR_ERR(ili); desc = of_device_get_match_data(&dsi->dev); dsi->lanes = desc->lanes; diff --git a/drivers/gpu/drm/panel/panel-innolux-ej030na.c b/drivers/gpu/drm/panel/panel-innolux-ej030na.c index f85b7a4cbb42..b2309900873b 100644 --- a/drivers/gpu/drm/panel/panel-innolux-ej030na.c +++ b/drivers/gpu/drm/panel/panel-innolux-ej030na.c @@ -204,9 +204,11 @@ static int ej030na_probe(struct spi_device *spi) struct ej030na *priv; int err; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_panel_alloc(dev, struct ej030na, panel, + &ej030na_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(priv)) + return PTR_ERR(priv); priv->spi = spi; spi_set_drvdata(spi, priv); @@ -231,9 +233,6 @@ static int ej030na_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n"); - drm_panel_init(&priv->panel, dev, &ej030na_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&priv->panel); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index d95c0d4f3e35..80afeeab9475 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -382,9 +382,11 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, struct device *dev = &dsi->dev; int err, i; - innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); - if (!innolux) - return -ENOMEM; + innolux = devm_drm_panel_alloc(dev, struct innolux_panel, base, + &innolux_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(innolux)) + return PTR_ERR(innolux); innolux->desc = desc; @@ -410,9 +412,6 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, innolux->enable_gpio = NULL; } - drm_panel_init(&innolux->base, dev, &innolux_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&innolux->base); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c index eb0f8373258c..5c2530598ddb 100644 --- a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c +++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c @@ -1120,9 +1120,10 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi) struct jadard *jadard; int ret; - jadard = devm_kzalloc(&dsi->dev, sizeof(*jadard), GFP_KERNEL); - if (!jadard) - return -ENOMEM; + jadard = devm_drm_panel_alloc(dev, struct jadard, panel, &jadard_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(jadard)) + return PTR_ERR(jadard); desc = of_device_get_match_data(dev); dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -1148,9 +1149,6 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi) return PTR_ERR(jadard->vccio); } - drm_panel_init(&jadard->panel, dev, &jadard_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = of_drm_get_panel_orientation(dev->of_node, &jadard->orientation); if (ret < 0) return dev_err_probe(dev, ret, "failed to get orientation\n"); diff --git a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c index 4eb71e85e9e9..cbe354b51bce 100644 --- a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c +++ b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c @@ -175,9 +175,11 @@ static int jdi_fhd_r63452_probe(struct mipi_dsi_device *dsi) struct jdi_fhd_r63452 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct jdi_fhd_r63452, panel, + &jdi_fhd_r63452_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) @@ -192,8 +194,6 @@ static int jdi_fhd_r63452_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &jdi_fhd_r63452_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ret = drm_panel_of_backlight(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c index 5b5082efb282..5f897e143758 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -435,9 +435,6 @@ static int jdi_panel_add(struct jdi_panel *jdi) return dev_err_probe(dev, PTR_ERR(jdi->backlight), "failed to create backlight\n"); - drm_panel_init(&jdi->base, &jdi->link1->dev, &jdi_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&jdi->base); return 0; @@ -475,10 +472,13 @@ static int jdi_panel_dsi_probe(struct mipi_dsi_device *dsi) /* register a panel for only the DSI-LINK1 interface */ if (secondary) { - jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); - if (!jdi) { + jdi = devm_drm_panel_alloc(&dsi->dev, __typeof(*jdi), + base, &jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(jdi)) { put_device(&secondary->dev); - return -ENOMEM; + return PTR_ERR(jdi); } mipi_dsi_set_drvdata(dsi, jdi); diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index b1ce186de261..3513e5c4dd8c 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -402,9 +402,6 @@ static int jdi_panel_add(struct jdi_panel *jdi) return dev_err_probe(dev, PTR_ERR(jdi->backlight), "failed to register backlight %d\n", ret); - drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&jdi->base); return 0; @@ -426,9 +423,11 @@ static int jdi_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS; - jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); - if (!jdi) - return -ENOMEM; + jdi = devm_drm_panel_alloc(&dsi->dev, __typeof(*jdi), base, + &jdi_panel_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(jdi)) + return PTR_ERR(jdi); mipi_dsi_set_drvdata(dsi, jdi); diff --git a/drivers/gpu/drm/panel/panel-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index 0e5e8e57bd1e..67ca055f06f3 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -821,9 +821,6 @@ static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050) return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio), "failed to get enable gpio"); - drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev, - &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&khadas_ts050->base); if (err) return err; @@ -850,10 +847,12 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050), - GFP_KERNEL); - if (!khadas_ts050) - return -ENOMEM; + khadas_ts050 = devm_drm_panel_alloc(&dsi->dev, __typeof(*khadas_ts050), + base, &khadas_ts050_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(khadas_ts050)) + return PTR_ERR(khadas_ts050); khadas_ts050->panel_data = (struct khadas_ts050_panel_data *)data; mipi_dsi_set_drvdata(dsi, khadas_ts050); diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c index d6b912277196..2fc7b0779b37 100644 --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c @@ -337,9 +337,6 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) kingdisplay->enable_gpio = NULL; } - drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev, - &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&kingdisplay->base); if (err) return err; @@ -364,9 +361,12 @@ static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; - kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL); - if (!kingdisplay) - return -ENOMEM; + kingdisplay = devm_drm_panel_alloc(&dsi->dev, __typeof(*kingdisplay), base, + &kingdisplay_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(kingdisplay)) + return PTR_ERR(kingdisplay); mipi_dsi_set_drvdata(dsi, kingdisplay); kingdisplay->link = dsi; diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 77f74e6c467e..0856df5a6ee2 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -548,9 +548,11 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) struct ltk050h3146w *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ltk050h3146w, panel, + <k050h3146w_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->panel_desc = of_device_get_match_data(dev); if (!ctx->panel_desc) @@ -577,9 +579,6 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = ctx->panel_desc->mode_flags; - drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c index 6b18cf00fd4a..7f19fd5b8060 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -604,9 +604,11 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) struct device *dev = &dsi->dev; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ltk500hd1829, panel, + <k500hd1829_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->panel_desc = of_device_get_match_data(dev); if (!ctx->panel_desc) @@ -643,9 +645,6 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - drm_panel_init(&ctx->panel, &dsi->dev, <k500hd1829_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c index 9d0d4faa3f58..b2be6727bf73 100644 --- a/drivers/gpu/drm/panel/panel-lg-lb035q02.c +++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c @@ -178,9 +178,10 @@ static int lb035q02_probe(struct spi_device *spi) struct lb035q02_device *lcd; int ret; - lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&spi->dev, struct lb035q02_device, panel, + &lb035q02_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); spi_set_drvdata(spi, lcd); lcd->spi = spi; @@ -195,9 +196,6 @@ static int lb035q02_probe(struct spi_device *spi) if (ret < 0) return ret; - drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&lcd->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index cf246d15b7b6..dec619902c15 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -243,9 +243,11 @@ static int lg4573_probe(struct spi_device *spi) struct lg4573 *ctx; int ret; - ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&spi->dev, struct lg4573, panel, + &lg4573_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->spi = spi; @@ -258,9 +260,6 @@ static int lg4573_probe(struct spi_device *spi) return ret; } - drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&ctx->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c index f3dcc39670ea..46a56ea92ad9 100644 --- a/drivers/gpu/drm/panel/panel-lg-sw43408.c +++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c @@ -246,8 +246,6 @@ static int sw43408_add(struct sw43408_panel *ctx) ctx->base.prepare_prev_first = true; - drm_panel_init(&ctx->base, dev, &sw43408_funcs, DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&ctx->base); return ret; } @@ -257,9 +255,11 @@ static int sw43408_probe(struct mipi_dsi_device *dsi) struct sw43408_panel *ctx; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, __typeof(*ctx), base, + &sw43408_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); dsi->mode_flags = MIPI_DSI_MODE_LPM; dsi->format = MIPI_DSI_FMT_RGB888; diff --git a/drivers/gpu/drm/panel/panel-lincolntech-lcd197.c b/drivers/gpu/drm/panel/panel-lincolntech-lcd197.c index 032c542aab0f..24b34443ace0 100644 --- a/drivers/gpu/drm/panel/panel-lincolntech-lcd197.c +++ b/drivers/gpu/drm/panel/panel-lincolntech-lcd197.c @@ -190,9 +190,11 @@ static int lincoln_lcd197_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST); - lcd = devm_kzalloc(&dsi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(dev, struct lincoln_lcd197_panel, panel, + &lincoln_lcd197_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); mipi_dsi_set_drvdata(dsi, lcd); lcd->dsi = dsi; @@ -214,9 +216,6 @@ static int lincoln_lcd197_panel_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(lcd->reset_gpio), "failed to get reset gpio"); - drm_panel_init(&lcd->panel, dev, - &lincoln_lcd197_panel_funcs, DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&lcd->panel); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index ba6c015aabba..23fd535d8f47 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c @@ -164,9 +164,11 @@ static int panel_lvds_probe(struct platform_device *pdev) struct panel_lvds *lvds; int ret; - lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); - if (!lvds) - return -ENOMEM; + lvds = devm_drm_panel_alloc(&pdev->dev, struct panel_lvds, panel, + &panel_lvds_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (IS_ERR(lvds)) + return PTR_ERR(lvds); lvds->dev = &pdev->dev; @@ -214,10 +216,6 @@ static int panel_lvds_probe(struct platform_device *pdev) * driver. */ - /* Register the panel. */ - drm_panel_init(&lvds->panel, lvds->dev, &panel_lvds_funcs, - DRM_MODE_CONNECTOR_LVDS); - ret = drm_panel_of_backlight(&lvds->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c b/drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c index 799c2161fc85..cde168ec631c 100644 --- a/drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c +++ b/drivers/gpu/drm/panel/panel-magnachip-d53e6ea8966.c @@ -370,9 +370,11 @@ static int d53e6ea8966_probe(struct spi_device *spi) .node = NULL, }; - db = devm_kzalloc(dev, sizeof(*db), GFP_KERNEL); - if (!db) - return -ENOMEM; + db = devm_drm_panel_alloc(dev, struct d53e6ea8966, panel, + &d53e6ea8966_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(db)) + return PTR_ERR(db); spi_set_drvdata(spi, db); @@ -425,9 +427,6 @@ static int d53e6ea8966_probe(struct spi_device *spi) db->dsi_dev->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - drm_panel_init(&db->panel, dev, &d53e6ea8966_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - if (db->panel_info->backlight_register) { ret = db->panel_info->backlight_register(db); if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c index 4db852ffb0f6..55664f5d5aa5 100644 --- a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c +++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c @@ -234,9 +234,11 @@ static int mantix_probe(struct mipi_dsi_device *dsi) struct mantix *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct mantix, panel, &mantix_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ctx->default_mode = of_device_get_match_data(dev); ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); @@ -271,9 +273,6 @@ static int mantix_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vddi)) return dev_err_probe(dev, PTR_ERR(ctx->vddi), "Failed to request vddi regulator\n"); - drm_panel_init(&ctx->panel, dev, &mantix_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c index 81c5c541a351..d5c7210de4af 100644 --- a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c @@ -178,9 +178,10 @@ static int nl8048_probe(struct spi_device *spi) struct nl8048_panel *lcd; int ret; - lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&spi->dev, struct nl8048_panel, panel, + &nl8048_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); spi_set_drvdata(spi, lcd); lcd->spi = spi; @@ -204,9 +205,6 @@ static int nl8048_probe(struct spi_device *spi) if (ret < 0) return ret; - drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&lcd->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index 5d115ecd5dd4..22560384e48e 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -361,9 +361,11 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) struct panel_nv3051d *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct panel_nv3051d, panel, + &panel_nv3051d_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->dev = dev; @@ -391,9 +393,6 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = ctx->panel_info->mode_flags; - drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; @@ -413,15 +412,10 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) static void panel_nv3051d_shutdown(struct mipi_dsi_device *dsi) { struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); + drm_panel_unprepare(&ctx->panel); - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); + drm_panel_disable(&ctx->panel); } static void panel_nv3051d_remove(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index 06e16a7c14a7..0db9cadd868e 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -777,9 +777,10 @@ static int nv3052c_probe(struct spi_device *spi) struct nv3052c *priv; int err; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_panel_alloc(dev, struct nv3052c, panel, &nv3052c_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(priv)) + return PTR_ERR(priv); priv->dev = dev; @@ -803,9 +804,6 @@ static int nv3052c_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); - drm_panel_init(&priv->panel, dev, &nv3052c_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&priv->panel); if (err) return dev_err_probe(dev, err, "Failed to attach backlight\n"); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 549b86f2cc28..3189d89c7ca0 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -1087,9 +1087,12 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) struct nt35510 *nt; int ret; - nt = devm_kzalloc(dev, sizeof(struct nt35510), GFP_KERNEL); - if (!nt) - return -ENOMEM; + nt = devm_drm_panel_alloc(dev, struct nt35510, panel, + &nt35510_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(nt)) + return PTR_ERR(nt); + mipi_dsi_set_drvdata(dsi, nt); nt->dev = dev; @@ -1142,9 +1145,6 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return PTR_ERR(nt->reset_gpio); } - drm_panel_init(&nt->panel, dev, &nt35510_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - /* * First, try to locate an external backlight (such as on GPIO) * if this fails, assume we will want to use the internal backlight diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 5bbea734123b..98f0782c8411 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -456,9 +456,12 @@ static int nt35560_probe(struct mipi_dsi_device *dsi) struct nt35560 *nt; int ret; - nt = devm_kzalloc(dev, sizeof(struct nt35560), GFP_KERNEL); - if (!nt) - return -ENOMEM; + nt = devm_drm_panel_alloc(dev, struct nt35560, panel, + &nt35560_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(nt)) + return PTR_ERR(nt); + nt->video_mode = of_property_read_bool(dev->of_node, "enforce-video-mode"); @@ -502,9 +505,6 @@ static int nt35560_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(nt->reset_gpio), "failed to request GPIO\n"); - drm_panel_init(&nt->panel, dev, &nt35560_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - nt->panel.backlight = devm_backlight_device_register(dev, "nt35560", dev, nt, &nt35560_bl_ops, &nt35560_bl_props); if (IS_ERR(nt->panel.backlight)) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c index 08b22b592ab0..94aa6489d99f 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c @@ -449,9 +449,10 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) const struct mipi_dsi_device_info *info; int i, num_dsis = 1, ret; - nt = devm_kzalloc(dev, sizeof(*nt), GFP_KERNEL); - if (!nt) - return -ENOMEM; + nt = devm_drm_panel_alloc(dev, struct nt35950, panel, &nt35950_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(nt)) + return PTR_ERR(nt); ret = nt35950_sharp_init_vregs(nt, dev); if (ret) @@ -491,9 +492,6 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) nt->dsi[0] = dsi; mipi_dsi_set_drvdata(dsi, nt); - drm_panel_init(&nt->panel, dev, &nt35950_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&nt->panel); if (ret) { if (num_dsis == 2) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index 04f1d2676c78..32cf64c7c18b 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -23,10 +23,12 @@ #define DSI_NUM_MIN 1 -#define mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, cmd, seq...) \ - do { \ - mipi_dsi_dcs_write_seq(dsi0, cmd, seq); \ - mipi_dsi_dcs_write_seq(dsi1, cmd, seq); \ +#define mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, cmd, seq...) \ + do { \ + dsi_ctx.dsi = dsi0; \ + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, cmd, seq); \ + dsi_ctx.dsi = dsi1; \ + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, cmd, seq); \ } while (0) struct panel_info { @@ -67,868 +69,829 @@ static int elish_boe_init_sequence(struct panel_info *pinfo) { struct mipi_dsi_device *dsi0 = pinfo->dsi[0]; struct mipi_dsi_device *dsi1 = pinfo->dsi[1]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = NULL }; /* No datasheet, so write magic init sequence directly */ - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x05); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x18, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x00, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x01, 0x84); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x05, 0x2d); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x06, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x07, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x08, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x09, 0x45); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x11, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x12, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x15, 0x83); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x16, 0x0c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x29, 0x0a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x30, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x31, 0xfe); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x32, 0xfd); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x33, 0xfb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x34, 0xf8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x35, 0xf5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x36, 0xf3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x37, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x38, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x39, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3a, 0xef); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3b, 0xec); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3d, 0xe9); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3f, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x40, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x41, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2a, 0x13); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x45, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x46, 0xf4); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x47, 0xe7); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x48, 0xda); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x49, 0xcd); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4a, 0xc0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4b, 0xb3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4c, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4d, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4e, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4f, 0x99); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x50, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x68); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x52, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x53, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x54, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2b, 0x0e); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x58, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x59, 0xfb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5a, 0xf7); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5b, 0xf3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5c, 0xef); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5d, 0xe3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5e, 0xda); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5f, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x60, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x61, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x62, 0xcb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x63, 0xbf); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x64, 0xb3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x65, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x66, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x67, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x25, 0x47); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x30, 0x47); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x39, 0x47); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x19, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1a, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1b, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1c, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2a, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2b, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x84, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x85, 0x0c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x91, 0x1f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x92, 0x0f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x93, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x94, 0x18); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x95, 0x03); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x96, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb0, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x19, 0x1f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1b, 0x1b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x24); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb8, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x27); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd0, 0x31); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd1, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd2, 0x30); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd4, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xde, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xdf, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x00, 0x81); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9f, 0x50); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x6f, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x70, 0x11); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x73, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x74, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x76, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x77, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xa0, 0x3f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xa9, 0x50); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xaa, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xab, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xad, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb8, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xba, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbb, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbe, 0x04); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbf, 0x49); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc0, 0x04); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc1, 0x59); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc2, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc5, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc6, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc7, 0x48); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xca, 0x43); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xcb, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xce, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xcf, 0x43); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd0, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd3, 0x43); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd4, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd7, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xdc, 0x43); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xdd, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xe1, 0x43); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xe2, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xf2, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xf3, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xf4, 0x48); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x13, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x14, 0x23); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbc, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbd, 0x23); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x97, 0x3c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x98, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x99, 0x95); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9a, 0x03); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9b, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9c, 0x0b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9d, 0x0a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9e, 0x90); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9f, 0x50); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xa3, 0x50); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x14, 0x60); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x16, 0xc0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4f, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3a, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xd0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x02, 0xaf); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x09, 0xee); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1c, 0x99); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1d, 0x09); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x0f, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x53, 0x2c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x35, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbb, 0x13); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x11); - msleep(70); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x29); - - return 0; + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x05); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x18, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0x84); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x05, 0x2d); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x06, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x07, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x08, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0x45); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x12, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x15, 0x83); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x31, 0xfe); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x32, 0xfd); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x33, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x34, 0xf8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0xf5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x36, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x37, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x38, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0xec); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x40, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x41, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x45, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x46, 0xf4); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x47, 0xe7); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x48, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x49, 0xcd); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x50, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x68); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x52, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x54, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x59, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5c, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5e, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x60, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x61, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x62, 0xcb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x63, 0xbf); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x64, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x65, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x66, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x67, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x25, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x84, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x85, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x91, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x92, 0x0f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x93, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x94, 0x18); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x95, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x96, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb0, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x24); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x27); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x31); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd1, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd2, 0x30); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xde, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdf, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x81); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9f, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x6f, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x70, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x73, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x74, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x76, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x77, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa9, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xaa, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xab, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xad, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xba, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbe, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbf, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc0, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc1, 0x59); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc5, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc6, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc7, 0x48); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xca, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcb, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xce, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcf, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd3, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd7, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdc, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdd, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xe1, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xe2, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf3, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf4, 0x48); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x13, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x14, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbc, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbd, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x97, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x98, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x99, 0x95); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9a, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9b, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9c, 0x0b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9d, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9e, 0x90); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9f, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa3, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x14, 0x60); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xd0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x02, 0xaf); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0xee); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1d, 0x09); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x2c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11); + mipi_dsi_msleep(&dsi_ctx, 70); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29); + + return dsi_ctx.accum_err; } static int elish_csot_init_sequence(struct panel_info *pinfo) { struct mipi_dsi_device *dsi0 = pinfo->dsi[0]; struct mipi_dsi_device *dsi1 = pinfo->dsi[1]; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = NULL }; /* No datasheet, so write magic init sequence directly */ - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x05); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x18, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xd0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x02, 0xaf); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x00, 0x30); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x09, 0xee); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1c, 0x99); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1d, 0x09); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3a, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4f, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x58, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x35, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x00, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x01, 0x84); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x05, 0x2d); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x06, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x07, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x08, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x09, 0x45); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x11, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x12, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x15, 0x83); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x16, 0x0c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x29, 0x0a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x30, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x31, 0xfe); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x32, 0xfd); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x33, 0xfb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x34, 0xf8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x35, 0xf5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x36, 0xf3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x37, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x38, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x39, 0xf2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3a, 0xef); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3b, 0xec); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3d, 0xe9); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3f, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x40, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x41, 0xe5); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2a, 0x13); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x45, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x46, 0xf4); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x47, 0xe7); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x48, 0xda); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x49, 0xcd); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4a, 0xc0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4b, 0xb3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4c, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4d, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4e, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x4f, 0x99); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x50, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x68); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x52, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x53, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x54, 0x66); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2b, 0x0e); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x58, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x59, 0xfb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5a, 0xf7); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5b, 0xf3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5c, 0xef); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5d, 0xe3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5e, 0xda); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x5f, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x60, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x61, 0xd8); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x62, 0xcb); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x63, 0xbf); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x64, 0xb3); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x65, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x66, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x67, 0xb2); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x0f, 0xff); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x53, 0x2c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x55, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbb, 0x13); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x25, 0x46); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x30, 0x46); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x39, 0x46); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x19, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1a, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1b, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1c, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2a, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x2b, 0xe0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x84, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x85, 0x0c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x51, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x91, 0x1f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x92, 0x0f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x93, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x94, 0x18); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x95, 0x03); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x96, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb0, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x19, 0x1f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x1b, 0x1b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x24); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb8, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x27); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd0, 0x31); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd1, 0x20); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd4, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xde, 0x80); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xdf, 0x02); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x00, 0x81); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x6f, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x70, 0x11); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x73, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x74, 0x4d); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xa0, 0x3f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xa9, 0x50); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xaa, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xab, 0x28); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xad, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb8, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xb9, 0x4b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xba, 0x96); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbb, 0x4b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbe, 0x07); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbf, 0x4b); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc0, 0x07); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc1, 0x5c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc2, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc5, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc6, 0x3f); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xc7, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xca, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xcb, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xce, 0x00); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xcf, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd0, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd3, 0x08); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xd4, 0x40); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbc, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xbd, 0x1c); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x9a, 0x03); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x11); - msleep(70); - mipi_dsi_dual_dcs_write_seq(dsi0, dsi1, 0x29); - - return 0; + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x05); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x18, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xd0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x02, 0xaf); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x30); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0xee); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1d, 0x09); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0x84); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x05, 0x2d); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x06, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x07, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x08, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0x45); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x12, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x15, 0x83); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x31, 0xfe); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x32, 0xfd); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x33, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x34, 0xf8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0xf5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x36, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x37, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x38, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0xec); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x40, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x41, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x45, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x46, 0xf4); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x47, 0xe7); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x48, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x49, 0xcd); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x50, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x68); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x52, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x54, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x59, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5c, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5e, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x60, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x61, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x62, 0xcb); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x63, 0xbf); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x64, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x65, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x66, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x67, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x2c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x55, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x25, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x84, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x85, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x91, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x92, 0x0f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x93, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x94, 0x18); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x95, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x96, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb0, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x24); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x27); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x31); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd1, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xde, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdf, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x81); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x6f, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x70, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x73, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x74, 0x4d); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa9, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xaa, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xab, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xad, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xba, 0x96); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbe, 0x07); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbf, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc0, 0x07); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc1, 0x5c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc5, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc6, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc7, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xca, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcb, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xce, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcf, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd3, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbc, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbd, 0x1c); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9a, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11); + mipi_dsi_msleep(&dsi_ctx, 70); + mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29); + + return dsi_ctx.accum_err; } static int j606f_boe_init_sequence(struct panel_info *pinfo) { struct mipi_dsi_device *dsi = pinfo->dsi[0]; - struct device *dev = &dsi->dev; - int ret; - - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x05, 0xd9); - mipi_dsi_dcs_write_seq(dsi, 0x07, 0x78); - mipi_dsi_dcs_write_seq(dsi, 0x08, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x63); - mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x91); - mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x73); - mipi_dsi_dcs_write_seq(dsi, 0x95, 0xeb); - mipi_dsi_dcs_write_seq(dsi, 0x96, 0xeb); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x11); - mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x66); - mipi_dsi_dcs_write_seq(dsi, 0x75, 0xa2); - mipi_dsi_dcs_write_seq(dsi, 0x77, 0xb3); - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, - 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); - mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, - 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, - 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); - mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, - 0xfd, 0x03, 0xff); - mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, - 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); - mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, - 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, - 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); - mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, - 0xfd, 0x03, 0xff); - mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, - 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, - 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); - mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, - 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); - mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, - 0xfd, 0x03, 0xff); - 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, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, - 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); - mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, - 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, - 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); - mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, - 0xf5, 0x03, 0xf7); - mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, - 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); - mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, - 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, - 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); - mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, - 0xf5, 0x03, 0xf7); - mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, - 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, - 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); - mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, - 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); - mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, - 0xf5, 0x03, 0xf7); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x23); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x00, 0x80); - mipi_dsi_dcs_write_seq(dsi, 0x07, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x11, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x12, 0x77); - mipi_dsi_dcs_write_seq(dsi, 0x15, 0x07); - mipi_dsi_dcs_write_seq(dsi, 0x16, 0x07); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x01, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x02, 0x1c); - mipi_dsi_dcs_write_seq(dsi, 0x03, 0x1c); - mipi_dsi_dcs_write_seq(dsi, 0x04, 0x1d); - mipi_dsi_dcs_write_seq(dsi, 0x05, 0x1d); - mipi_dsi_dcs_write_seq(dsi, 0x06, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x07, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x08, 0x0f); - mipi_dsi_dcs_write_seq(dsi, 0x09, 0x0f); - mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x0e); - mipi_dsi_dcs_write_seq(dsi, 0x0b, 0x0e); - mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x0d); - mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0d); - mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x0c); - mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0c); - mipi_dsi_dcs_write_seq(dsi, 0x10, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x11, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x12, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x13, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x14, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x16, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x17, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x18, 0x1c); - mipi_dsi_dcs_write_seq(dsi, 0x19, 0x1c); - mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x1d); - mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x1d); - mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x0f); - mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x0f); - mipi_dsi_dcs_write_seq(dsi, 0x20, 0x0e); - mipi_dsi_dcs_write_seq(dsi, 0x21, 0x0e); - mipi_dsi_dcs_write_seq(dsi, 0x22, 0x0d); - mipi_dsi_dcs_write_seq(dsi, 0x23, 0x0d); - mipi_dsi_dcs_write_seq(dsi, 0x24, 0x0c); - mipi_dsi_dcs_write_seq(dsi, 0x25, 0x0c); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x27, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x28, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x20); - mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x0a); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x44); - mipi_dsi_dcs_write_seq(dsi, 0x33, 0x0c); - mipi_dsi_dcs_write_seq(dsi, 0x34, 0x32); - mipi_dsi_dcs_write_seq(dsi, 0x37, 0x44); - mipi_dsi_dcs_write_seq(dsi, 0x38, 0x40); - mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00); - - ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x9a); - if (ret < 0) { - dev_err(dev, "Failed to set pixel format: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0x3b, 0xa0); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x42); - mipi_dsi_dcs_write_seq(dsi, 0x3f, 0x06); - mipi_dsi_dcs_write_seq(dsi, 0x43, 0x06); - mipi_dsi_dcs_write_seq(dsi, 0x47, 0x66); - mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x9a); - mipi_dsi_dcs_write_seq(dsi, 0x4b, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0x4c, 0x91); - mipi_dsi_dcs_write_seq(dsi, 0x4d, 0x21); - mipi_dsi_dcs_write_seq(dsi, 0x4e, 0x43); - - ret = mipi_dsi_dcs_set_display_brightness(dsi, 18); - if (ret < 0) { - dev_err(dev, "Failed to set display brightness: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0x52, 0x34); - mipi_dsi_dcs_write_seq(dsi, 0x55, 0x82, 0x02); - mipi_dsi_dcs_write_seq(dsi, 0x56, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x58, 0x21); - mipi_dsi_dcs_write_seq(dsi, 0x59, 0x30); - mipi_dsi_dcs_write_seq(dsi, 0x5a, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x5b, 0xa0); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00, 0x06); - mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x82); - mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x20); - mipi_dsi_dcs_write_seq(dsi, 0x7f, 0x3c); - mipi_dsi_dcs_write_seq(dsi, 0x82, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0x97, 0xc0); - mipi_dsi_dcs_write_seq(dsi, 0xb6, - 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, - 0x05, 0x00, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x92, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0x93, 0x1a); - mipi_dsi_dcs_write_seq(dsi, 0x94, 0x5f); - mipi_dsi_dcs_write_seq(dsi, 0xd7, 0x55); - mipi_dsi_dcs_write_seq(dsi, 0xda, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0xde, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xdc, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22); - mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe0, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe2, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe4, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe6, 0xc4); - mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x88); - mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x88); - mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x90); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x05, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x19, 0x07); - mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x20, 0xa0); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x27, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0x33, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x34, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0x3f, 0xe0); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_VSYNC_TIMING, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_GET_SCANLINE, 0x40); - mipi_dsi_dcs_write_seq(dsi, 0x48, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x49, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0xd0); - mipi_dsi_dcs_write_seq(dsi, 0x61, 0xba); - mipi_dsi_dcs_write_seq(dsi, 0x62, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0xf1, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x64, 0x16); - mipi_dsi_dcs_write_seq(dsi, 0x67, 0x16); - mipi_dsi_dcs_write_seq(dsi, 0x6a, 0x16); - mipi_dsi_dcs_write_seq(dsi, 0x70, 0x30); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_START, 0xf3); - mipi_dsi_dcs_write_seq(dsi, 0xa3, 0xff); - mipi_dsi_dcs_write_seq(dsi, 0xa4, 0xff); - mipi_dsi_dcs_write_seq(dsi, 0xa5, 0xff); - mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x00, 0xa1); - mipi_dsi_dcs_write_seq(dsi, 0x0a, 0xf2); - mipi_dsi_dcs_write_seq(dsi, 0x04, 0x28); - mipi_dsi_dcs_write_seq(dsi, 0x06, 0x30); - mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x13); - mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0x11, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x12, 0x50); - mipi_dsi_dcs_write_seq(dsi, 0x13, 0x51); - mipi_dsi_dcs_write_seq(dsi, 0x14, 0x65); - mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x16, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0x17, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0x18, 0x86); - mipi_dsi_dcs_write_seq(dsi, 0x19, 0x11); - mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7b); - mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0x1c, 0xbb); - mipi_dsi_dcs_write_seq(dsi, 0x22, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x23, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x11); - mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7b); - mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x1e, 0xc3); - mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xc3); - mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3); - mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x05); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0xc3); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x32, 0xc3); - mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00); - - ret = mipi_dsi_dcs_set_pixel_format(dsi, 0xc3); - if (ret < 0) { - dev_err(dev, "Failed to set pixel format: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0x20, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x33, 0x11); - mipi_dsi_dcs_write_seq(dsi, 0x34, 0x78); - mipi_dsi_dcs_write_seq(dsi, 0x35, 0x16); - mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0xc9, 0x82); - mipi_dsi_dcs_write_seq(dsi, 0xca, 0x4e); - mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x00); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_CONTINUE, 0x4c); - mipi_dsi_dcs_write_seq(dsi, 0xaa, 0x47); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x27); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x56, 0x06); - mipi_dsi_dcs_write_seq(dsi, 0x58, 0x80); - mipi_dsi_dcs_write_seq(dsi, 0x59, 0x53); - mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x14); - mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x01); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x20); - mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0x60, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x61, 0x1d); - mipi_dsi_dcs_write_seq(dsi, 0x62, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x63, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x64, 0x24); - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x1c); - mipi_dsi_dcs_write_seq(dsi, 0x66, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x67, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x68, 0x25); - mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x78, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x24); - mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x30); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x22, 0x2f); - mipi_dsi_dcs_write_seq(dsi, 0x23, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xf8); - mipi_dsi_dcs_write_seq(dsi, 0x27, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x28, 0x1a); - mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x1a); - mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x1a); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0xe0); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x14, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x16, 0xc0); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0xf0); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - - ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x08); - if (ret < 0) { - dev_err(dev, "Failed to set pixel format: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - - ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x5d); - if (ret < 0) { - dev_err(dev, "Failed to set pixel format: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x5d); - mipi_dsi_dcs_write_seq(dsi, 0x4b, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x91, 0x44); - mipi_dsi_dcs_write_seq(dsi, 0x92, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xdc, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22); - mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe4, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0xe6, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x20, 0x60); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x27, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x33, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x34, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x48, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x49, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x61, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0x62, 0x60); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x02, 0x31); - mipi_dsi_dcs_write_seq(dsi, 0x19, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7f); - mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x0c); - mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7f); - mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x75); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x05); - mipi_dsi_dcs_write_seq(dsi, 0x32, 0x8d); - - ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x75); - if (ret < 0) { - dev_err(dev, "Failed to set pixel format: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0x18, 0x40); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x02); - - ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (ret < 0) { - dev_err(dev, "Failed to set tear on: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13); - mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x03, 0x5f, 0x1a, 0x04, 0x04); - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); - usleep_range(10000, 11000); - mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); - - ret = mipi_dsi_dcs_set_display_brightness(dsi, 0); - if (ret < 0) { - dev_err(dev, "Failed to set display brightness: %d\n", ret); - return ret; - } - - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0x68, 0x05, 0x01); - - 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(100); - - 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(30); - - return 0; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0xd9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x78); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x5a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x63); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x91); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x73); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x95, 0xeb); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x96, 0xeb); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x66); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xa2); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0xb3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, + 0x00, 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, + 0x01, 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, + 0x03, 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, + 0x03, 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, + 0x00, 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, + 0x01, 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, + 0x03, 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb7, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, + 0x03, 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, + 0x00, 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, + 0x01, 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, + 0x03, 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, + 0x03, 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, + 0x00, 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, + 0x01, 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, + 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, + 0x03, 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, + 0x00, 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, + 0x01, 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, + 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb7, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, + 0x03, 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, + 0x00, 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, + 0x01, 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, + 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, + 0x03, 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x23); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x77); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x07); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x07); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x24); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_LUT, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0x44); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x32); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x44); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x00); + + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0x9a); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_3D_CONTROL, 0x42); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x06); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x06); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x66); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x9a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x91); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x43); + + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 18); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x34); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x82, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00, 0x06); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x82); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x3c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0xc0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, + 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x05, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x93, 0x1a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x5f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd7, 0x55); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xda, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdb, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdc, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdd, 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe4, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe5, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0xc4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x88); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8d, 0x88); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8e, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x25); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x07); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0xe0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_VSYNC_TIMING, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_GET_SCANLINE, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0xd0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0xba); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x16); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x16); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x16); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_READ_PPS_START, 0xf3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa3, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa4, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa5, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd6, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x26); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0xf2); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x28); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x13); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x50); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x51); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x65); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x86); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0xbb); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x7b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x00); + + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0xc3); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x78); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x16); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc9, 0x82); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0x4e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_READ_PPS_CONTINUE, 0x4c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xaa, 0x47); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x27); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x06); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x53); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x24); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x25); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd1, 0x24); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x2f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0xf8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x1a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x1a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_LUT, 0x1a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xe0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0xc0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0x08); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x24); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0x5d); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x5d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x44); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdb, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdc, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdd, 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe4, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe5, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8e, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x25); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x26); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x31); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x7f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x7f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x8d); + + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0x75); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x75); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x02); + + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, 0x13); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x03, 0x5f, 0x1a, 0x04, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x10); + mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x05, 0x01); + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 100); + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 30); + + return dsi_ctx.accum_err; } static const struct drm_display_mode elish_boe_modes[] = { @@ -1063,18 +1026,18 @@ static int nt36523_prepare(struct drm_panel *panel) static int nt36523_disable(struct drm_panel *panel) { struct panel_info *pinfo = to_panel_info(panel); - int i, ret; + int i; for (i = 0; i < DSI_NUM_MIN + pinfo->desc->is_dual_dsi; i++) { - ret = mipi_dsi_dcs_set_display_off(pinfo->dsi[i]); - if (ret < 0) - dev_err(&pinfo->dsi[i]->dev, "failed to set display off: %d\n", ret); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->dsi[i]}; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); } for (i = 0; i < DSI_NUM_MIN + pinfo->desc->is_dual_dsi; i++) { - ret = mipi_dsi_dcs_enter_sleep_mode(pinfo->dsi[i]); - if (ret < 0) - dev_err(&pinfo->dsi[i]->dev, "failed to enter sleep mode: %d\n", ret); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->dsi[i]}; + + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); } msleep(70); @@ -1208,9 +1171,11 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) const struct mipi_dsi_device_info *info; int i, ret; - pinfo = devm_kzalloc(dev, sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) - return -ENOMEM; + pinfo = devm_drm_panel_alloc(dev, struct panel_info, panel, + &nt36523_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(pinfo)) + return PTR_ERR(pinfo); pinfo->vddio = devm_regulator_get(dev, "vddio"); if (IS_ERR(pinfo->vddio)) @@ -1248,7 +1213,6 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) pinfo->dsi[0] = dsi; mipi_dsi_set_drvdata(dsi, pinfo); - drm_panel_init(&pinfo->panel, dev, &nt36523_panel_funcs, DRM_MODE_CONNECTOR_DSI); ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation); if (ret < 0) { diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c index c2abd20e0734..29e1f6aea480 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c @@ -608,8 +608,6 @@ static int nt36672a_panel_add(struct nt36672a_panel *pinfo) return dev_err_probe(dev, PTR_ERR(pinfo->reset_gpio), "failed to get reset gpio from DT\n"); - drm_panel_init(&pinfo->base, dev, &panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&pinfo->base); if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n"); @@ -625,9 +623,11 @@ static int nt36672a_panel_probe(struct mipi_dsi_device *dsi) const struct nt36672a_panel_desc *desc; int err; - pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) - return -ENOMEM; + pinfo = devm_drm_panel_alloc(&dsi->dev, __typeof(*pinfo), base, + &panel_funcs, DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(pinfo)) + return PTR_ERR(pinfo); desc = of_device_get_match_data(&dsi->dev); dsi->mode_flags = desc->mode_flags; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c index 8c9e04207ba9..c5e00eb55722 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c @@ -522,9 +522,11 @@ static int nt36672e_panel_probe(struct mipi_dsi_device *dsi) struct nt36672e_panel *ctx; int i, ret = 0; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct nt36672e_panel, panel, + &nt36672e_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->desc = of_device_get_match_data(dev); if (!ctx->desc) { @@ -553,8 +555,6 @@ static int nt36672e_panel_probe(struct mipi_dsi_device *dsi) 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"); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c new file mode 100644 index 000000000000..d6a37d7e0cc6 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2024 Linaro Limited + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> + +#include <drm/display/drm_dsc.h> +#include <drm/display/drm_dsc_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +#include <video/mipi_display.h> + +struct novatek_nt37801 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; +}; + +static const struct regulator_bulk_data novatek_nt37801_supplies[] = { + { .supply = "vddio" }, + { .supply = "vci" }, + { .supply = "vdd" }, +}; + +static inline struct novatek_nt37801 *to_novatek_nt37801(struct drm_panel *panel) +{ + return container_of(panel, struct novatek_nt37801, panel); +} + +static void novatek_nt37801_reset(struct novatek_nt37801 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 21000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 21000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 21000); +} + +#define NT37801_DCS_SWITCH_PAGE 0xf0 + +#define novatek_nt37801_switch_page(dsi_ctx, page) \ + mipi_dsi_dcs_write_seq_multi((dsi_ctx), NT37801_DCS_SWITCH_PAGE, \ + 0x55, 0xaa, 0x52, 0x08, (page)) + +static int novatek_nt37801_on(struct novatek_nt37801 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + novatek_nt37801_switch_page(&dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x55); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x18); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x00); + mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x059f); + mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0c7f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, + 0x89, 0x28, 0x00, 0x28, 0xc2, 0x00, 0x02, + 0x68, 0x04, 0x6c, 0x00, 0x0a, 0x02, 0x77, + 0x01, 0xe9, 0x10, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x23); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, + 0x00, 0x01, 0x00, 0x11, 0x33, 0x33, 0x33, + 0x55, 0x57, 0xd0, 0x00, 0x00, 0x44, 0x56, + 0x77, 0x78, 0x9a, 0xbc, 0xdd, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xdc); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, + 0x07, 0xff, 0x07, 0xff, 0x0f, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9c, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00); + + novatek_nt37801_switch_page(&dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + + return dsi_ctx.accum_err; +} + +static int novatek_nt37801_off(struct novatek_nt37801 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int novatek_nt37801_prepare(struct drm_panel *panel) +{ + struct novatek_nt37801 *ctx = to_novatek_nt37801(panel); + struct device *dev = &ctx->dsi->dev; + struct drm_dsc_picture_parameter_set pps; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(novatek_nt37801_supplies), + ctx->supplies); + if (ret < 0) + return ret; + + novatek_nt37801_reset(ctx); + + ret = novatek_nt37801_on(ctx); + if (ret < 0) + goto err; + + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); + + ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); + if (ret < 0) { + dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); + goto err; + } + + ret = mipi_dsi_compression_mode(ctx->dsi, true); + if (ret < 0) { + dev_err(dev, "failed to enable compression mode: %d\n", ret); + goto err; + } + + msleep(28); + + return 0; + +err: + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(novatek_nt37801_supplies), + ctx->supplies); + + return ret; +} + +static int novatek_nt37801_unprepare(struct drm_panel *panel) +{ + struct novatek_nt37801 *ctx = to_novatek_nt37801(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = novatek_nt37801_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(novatek_nt37801_supplies), + ctx->supplies); + + return 0; +} + +static const struct drm_display_mode novatek_nt37801_mode = { + .clock = (1440 + 20 + 4 + 20) * (3200 + 20 + 2 + 18) * 120 / 1000, + .hdisplay = 1440, + .hsync_start = 1440 + 20, + .hsync_end = 1440 + 20 + 4, + .htotal = 1440 + 20 + 4 + 20, + .vdisplay = 3200, + .vsync_start = 3200 + 20, + .vsync_end = 3200 + 20 + 2, + .vtotal = 3200 + 20 + 2 + 18, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int novatek_nt37801_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, + &novatek_nt37801_mode); +} + +static const struct drm_panel_funcs novatek_nt37801_panel_funcs = { + .prepare = novatek_nt37801_prepare, + .unprepare = novatek_nt37801_unprepare, + .get_modes = novatek_nt37801_get_modes, +}; + +static int novatek_nt37801_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static const struct backlight_ops novatek_nt37801_bl_ops = { + .update_status = novatek_nt37801_bl_update_status, +}; + +static struct backlight_device * +novatek_nt37801_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &novatek_nt37801_bl_ops, &props); +} + +static int novatek_nt37801_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct novatek_nt37801 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct novatek_nt37801, panel, + &novatek_nt37801_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(novatek_nt37801_supplies), + novatek_nt37801_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 = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ctx->panel.prepare_prev_first = true; + ctx->panel.backlight = novatek_nt37801_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + ctx->dsc.slice_height = 40; + ctx->dsc.slice_width = 720; + ctx->dsc.slice_count = 1440 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 8; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void novatek_nt37801_remove(struct mipi_dsi_device *dsi) +{ + struct novatek_nt37801 *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 novatek_nt37801_of_match[] = { + { .compatible = "novatek,nt37801" }, + {} +}; +MODULE_DEVICE_TABLE(of, novatek_nt37801_of_match); + +static struct mipi_dsi_driver novatek_nt37801_driver = { + .probe = novatek_nt37801_probe, + .remove = novatek_nt37801_remove, + .driver = { + .name = "panel-novatek-nt37801", + .of_match_table = novatek_nt37801_of_match, + }, +}; +module_mipi_dsi_driver(novatek_nt37801_driver); + +MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); +MODULE_DESCRIPTION("Panel driver for the Novatek NT37801/NT37810 AMOLED DSI panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c index 9fa7654e2b67..a629976bae54 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c @@ -246,9 +246,10 @@ static int nt39016_probe(struct spi_device *spi) struct nt39016 *panel; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct nt39016, drm_panel, &nt39016_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(panel)) + return PTR_ERR(panel); spi_set_drvdata(spi, panel); @@ -279,9 +280,6 @@ static int nt39016_probe(struct spi_device *spi) return PTR_ERR(panel->map); } - drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&panel->drm_panel); if (err) return dev_err_probe(dev, err, "Failed to get backlight handle\n"); diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c index 94ae8c8270b8..66f99982f360 100644 --- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c +++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c @@ -175,9 +175,11 @@ static int lcd_olinuxino_probe(struct i2c_client *client) I2C_FUNC_SMBUS_READ_I2C_BLOCK)) return -ENODEV; - lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(dev, struct lcd_olinuxino, panel, + &lcd_olinuxino_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); i2c_set_clientdata(client, lcd); lcd->dev = dev; @@ -234,9 +236,6 @@ static int lcd_olinuxino_probe(struct i2c_client *client) if (IS_ERR(lcd->enable_gpio)) return PTR_ERR(lcd->enable_gpio); - drm_panel_init(&lcd->panel, dev, &lcd_olinuxino_funcs, - DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_of_backlight(&lcd->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c index fc87f61d4400..3231e84dc66c 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c @@ -237,9 +237,11 @@ static int ota5601a_probe(struct spi_device *spi) struct ota5601a *panel; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct ota5601a, drm_panel, + &ota5601a_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(panel)) + return PTR_ERR(panel); spi_set_drvdata(spi, panel); @@ -273,9 +275,6 @@ static int ota5601a_probe(struct spi_device *spi) return PTR_ERR(panel->map); } - drm_panel_init(&panel->drm_panel, dev, &ota5601a_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&panel->drm_panel); if (err) { if (err != -EPROBE_DEFER) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 87bbb25d119a..a0f58c3b73f6 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -424,9 +424,11 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) struct otm8009a *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct otm8009a, panel, + &otm8009a_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { @@ -451,9 +453,6 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &otm8009a_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev), dev, ctx, &otm8009a_backlight_ops, diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index dbea84f51514..2334b77f348c 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -132,9 +132,6 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587) if (IS_ERR(osd101t2587->supply)) return PTR_ERR(osd101t2587->supply); - drm_panel_init(&osd101t2587->base, &osd101t2587->dsi->dev, - &osd101t2587_panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&osd101t2587->base); if (ret) return ret; @@ -161,9 +158,12 @@ static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET; - osd101t2587 = devm_kzalloc(&dsi->dev, sizeof(*osd101t2587), GFP_KERNEL); - if (!osd101t2587) - return -ENOMEM; + osd101t2587 = devm_drm_panel_alloc(&dsi->dev, __typeof(*osd101t2587), base, + &osd101t2587_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(osd101t2587)) + return PTR_ERR(osd101t2587); mipi_dsi_set_drvdata(dsi, osd101t2587); diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index d1c5c9bc3c56..3c3308fc55df 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -166,9 +166,6 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt) if (IS_ERR(wuxga_nt->supply)) return PTR_ERR(wuxga_nt->supply); - drm_panel_init(&wuxga_nt->base, &wuxga_nt->dsi->dev, - &wuxga_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&wuxga_nt->base); if (ret) return ret; @@ -196,9 +193,12 @@ static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi) MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL); - if (!wuxga_nt) - return -ENOMEM; + wuxga_nt = devm_drm_panel_alloc(&dsi->dev, __typeof(*wuxga_nt), base, + &wuxga_nt_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(wuxga_nt)) + return PTR_ERR(wuxga_nt); mipi_dsi_set_drvdata(dsi, wuxga_nt); diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index e10e469aa7a6..dc4bb8ad9131 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -373,9 +373,12 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c) .node = NULL, }; - ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); - if (!ts) - return -ENOMEM; + ts = devm_drm_panel_alloc(dev, __typeof(*ts), base, + &rpi_touchscreen_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ts)) + return PTR_ERR(ts); i2c_set_clientdata(i2c, ts); @@ -428,9 +431,6 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c) return PTR_ERR(ts->dsi); } - drm_panel_init(&ts->base, dev, &rpi_touchscreen_funcs, - DRM_MODE_CONNECTOR_DSI); - /* This appears last, as it's what will unblock the DSI host * driver's component bind function. */ diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c index b2029e035635..2af6aa47a551 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c @@ -527,9 +527,11 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi) int ret; u32 video_mode; - panel = devm_kzalloc(&dsi->dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct rad_panel, panel, + &rad_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(panel)) + return PTR_ERR(panel); mipi_dsi_set_drvdata(dsi, panel); @@ -586,8 +588,6 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - drm_panel_init(&panel->panel, dev, &rad_panel_funcs, - DRM_MODE_CONNECTOR_DSI); dev_set_drvdata(dev, panel); drm_panel_add(&panel->panel); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67200.c b/drivers/gpu/drm/panel/panel-raydium-rm67200.c index 64b685dc11f6..333faed62da7 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67200.c @@ -36,12 +36,14 @@ static inline struct raydium_rm67200 *to_raydium_rm67200(struct drm_panel *panel static void raydium_rm67200_reset(struct raydium_rm67200 *ctx) { - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - msleep(60); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - msleep(60); - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - msleep(60); + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(60); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(60); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(60); + } } static void raydium_rm67200_write(struct mipi_dsi_multi_context *ctx, @@ -318,6 +320,7 @@ static void w552793baa_setup(struct mipi_dsi_multi_context *ctx) static int raydium_rm67200_prepare(struct drm_panel *panel) { struct raydium_rm67200 *ctx = to_raydium_rm67200(panel); + struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi }; int ret; ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies); @@ -328,6 +331,12 @@ static int raydium_rm67200_prepare(struct drm_panel *panel) msleep(60); + ctx->panel_info->panel_setup(&mctx); + mipi_dsi_dcs_exit_sleep_mode_multi(&mctx); + mipi_dsi_msleep(&mctx, 120); + mipi_dsi_dcs_set_display_on_multi(&mctx); + mipi_dsi_msleep(&mctx, 30); + return 0; } @@ -343,20 +352,6 @@ static int raydium_rm67200_unprepare(struct drm_panel *panel) return 0; } -static int raydium_rm67200_enable(struct drm_panel *panel) -{ - struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel); - struct mipi_dsi_multi_context ctx = { .dsi = rm67200->dsi }; - - rm67200->panel_info->panel_setup(&ctx); - mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); - mipi_dsi_msleep(&ctx, 120); - mipi_dsi_dcs_set_display_on_multi(&ctx); - mipi_dsi_msleep(&ctx, 30); - - return ctx.accum_err; -} - static int raydium_rm67200_disable(struct drm_panel *panel) { struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel); @@ -381,7 +376,6 @@ static const struct drm_panel_funcs raydium_rm67200_funcs = { .prepare = raydium_rm67200_prepare, .unprepare = raydium_rm67200_unprepare, .get_modes = raydium_rm67200_get_modes, - .enable = raydium_rm67200_enable, .disable = raydium_rm67200_disable, }; @@ -391,9 +385,11 @@ static int raydium_rm67200_probe(struct mipi_dsi_device *dsi) struct raydium_rm67200 *ctx; int ret = 0; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct raydium_rm67200, panel, + &raydium_rm67200_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->panel_info = device_get_match_data(dev); if (!ctx->panel_info) @@ -407,7 +403,7 @@ static int raydium_rm67200_probe(struct mipi_dsi_device *dsi) if (ret < 0) return ret; - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + ctx->reset_gpio = devm_gpiod_get_optional(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"); @@ -421,9 +417,6 @@ static int raydium_rm67200_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_LPM; ctx->panel.prepare_prev_first = true; - drm_panel_init(&ctx->panel, dev, &raydium_rm67200_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; @@ -471,6 +464,7 @@ static const struct raydium_rm67200_panel_info w552793baa_info = { .vtotal = 1952, .width_mm = 68, /* 68.04mm */ .height_mm = 121, /* 120.96mm */ + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, .type = DRM_MODE_TYPE_DRIVER, }, .regulators = w552793baa_regulators, diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 7b7fe987e292..669b5f5c1ad9 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -327,9 +327,11 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) struct rm68200 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct rm68200, panel, + &rm68200_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { @@ -355,9 +357,6 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm692e5.c b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c index ea1b728e85a2..8e9484768657 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm692e5.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c @@ -281,9 +281,11 @@ static int rm692e5_probe(struct mipi_dsi_device *dsi) struct rm692e5_panel *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct rm692e5_panel, panel, + &rm692e5_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "vddio"; ctx->supplies[1].supply = "dvdd"; @@ -306,8 +308,6 @@ static int rm692e5_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &rm692e5_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = rm692e5_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm69380.c b/drivers/gpu/drm/panel/panel-raydium-rm69380.c index d3071c01aaea..86769cadec97 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm69380.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm69380.c @@ -208,9 +208,11 @@ static int rm69380_probe(struct mipi_dsi_device *dsi) struct device_node *dsi_sec; int ret, i; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct rm69380_panel, panel, + &rm69380_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "vddio"; ctx->supplies[1].supply = "avdd"; @@ -248,8 +250,6 @@ static int rm69380_probe(struct mipi_dsi_device *dsi) ctx->dsi[0] = dsi; mipi_dsi_set_drvdata(dsi, ctx); - drm_panel_init(&ctx->panel, dev, &rm69380_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = rm69380_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-renesas-r61307.c b/drivers/gpu/drm/panel/panel-renesas-r61307.c new file mode 100644 index 000000000000..319415194839 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-renesas-r61307.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/array_size.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define R61307_MACP 0xb0 /* Manufacturer CMD Protect */ +#define R61307_MACP_ON 0x03 +#define R61307_MACP_OFF 0x04 + +#define R61307_INVERSION 0xc1 +#define R61307_GAMMA_SET_A 0xc8 /* Gamma Setting A */ +#define R61307_GAMMA_SET_B 0xc9 /* Gamma Setting B */ +#define R61307_GAMMA_SET_C 0xca /* Gamma Setting C */ +#define R61307_CONTRAST_SET 0xcc + +struct renesas_r61307 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + + struct regulator *vcc_supply; + struct regulator *iovcc_supply; + + struct gpio_desc *reset_gpio; + + bool prepared; + + bool dig_cont_adj; + bool inversion; + u32 gamma; +}; + +static const u8 gamma_setting[][25] = { + { /* sentinel */ }, + { + R61307_GAMMA_SET_A, + 0x00, 0x06, 0x0a, 0x0f, + 0x14, 0x1f, 0x1f, 0x17, + 0x12, 0x0c, 0x09, 0x06, + 0x00, 0x06, 0x0a, 0x0f, + 0x14, 0x1f, 0x1f, 0x17, + 0x12, 0x0c, 0x09, 0x06 + }, + { + R61307_GAMMA_SET_A, + 0x00, 0x05, 0x0b, 0x0f, + 0x11, 0x1d, 0x20, 0x18, + 0x18, 0x09, 0x07, 0x06, + 0x00, 0x05, 0x0b, 0x0f, + 0x11, 0x1d, 0x20, 0x18, + 0x18, 0x09, 0x07, 0x06 + }, + { + R61307_GAMMA_SET_A, + 0x0b, 0x0d, 0x10, 0x14, + 0x13, 0x1d, 0x20, 0x18, + 0x12, 0x09, 0x07, 0x06, + 0x0a, 0x0c, 0x10, 0x14, + 0x13, 0x1d, 0x20, 0x18, + 0x12, 0x09, 0x07, 0x06 + }, +}; + +static inline struct renesas_r61307 *to_renesas_r61307(struct drm_panel *panel) +{ + return container_of(panel, struct renesas_r61307, panel); +} + +static void renesas_r61307_reset(struct renesas_r61307 *priv) +{ + gpiod_set_value_cansleep(priv->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(priv->reset_gpio, 0); + usleep_range(2000, 3000); +} + +static int renesas_r61307_prepare(struct drm_panel *panel) +{ + struct renesas_r61307 *priv = to_renesas_r61307(panel); + struct device *dev = &priv->dsi->dev; + int ret; + + if (priv->prepared) + return 0; + + ret = regulator_enable(priv->vcc_supply); + if (ret) { + dev_err(dev, "failed to enable vcc power supply\n"); + return ret; + } + + usleep_range(2000, 3000); + + ret = regulator_enable(priv->iovcc_supply); + if (ret) { + dev_err(dev, "failed to enable iovcc power supply\n"); + return ret; + } + + usleep_range(2000, 3000); + + renesas_r61307_reset(priv); + + priv->prepared = true; + return 0; +} + +static int renesas_r61307_enable(struct drm_panel *panel) +{ + struct renesas_r61307 *priv = to_renesas_r61307(panel); + struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi }; + + mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); + mipi_dsi_msleep(&ctx, 80); + + mipi_dsi_dcs_write_seq_multi(&ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + mipi_dsi_msleep(&ctx, 20); + + mipi_dsi_dcs_set_pixel_format_multi(&ctx, MIPI_DCS_PIXEL_FMT_24BIT << 4); + + /* MACP Off */ + mipi_dsi_generic_write_seq_multi(&ctx, R61307_MACP, R61307_MACP_OFF); + + if (priv->dig_cont_adj) + mipi_dsi_generic_write_seq_multi(&ctx, R61307_CONTRAST_SET, + 0xdc, 0xb4, 0xff); + + if (priv->gamma) + mipi_dsi_generic_write_multi(&ctx, gamma_setting[priv->gamma], + sizeof(gamma_setting[priv->gamma])); + + if (priv->inversion) + mipi_dsi_generic_write_seq_multi(&ctx, R61307_INVERSION, + 0x00, 0x50, 0x03, 0x22, + 0x16, 0x06, 0x60, 0x11); + else + mipi_dsi_generic_write_seq_multi(&ctx, R61307_INVERSION, + 0x00, 0x10, 0x03, 0x22, + 0x16, 0x06, 0x60, 0x01); + + /* MACP On */ + mipi_dsi_generic_write_seq_multi(&ctx, R61307_MACP, R61307_MACP_ON); + + mipi_dsi_dcs_set_display_on_multi(&ctx); + mipi_dsi_msleep(&ctx, 50); + + return 0; +} + +static int renesas_r61307_disable(struct drm_panel *panel) +{ + struct renesas_r61307 *priv = to_renesas_r61307(panel); + struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&ctx); + mipi_dsi_msleep(&ctx, 100); + mipi_dsi_dcs_enter_sleep_mode_multi(&ctx); + + return 0; +} + +static int renesas_r61307_unprepare(struct drm_panel *panel) +{ + struct renesas_r61307 *priv = to_renesas_r61307(panel); + + if (!priv->prepared) + return 0; + + usleep_range(10000, 11000); + + gpiod_set_value_cansleep(priv->reset_gpio, 1); + usleep_range(5000, 6000); + + regulator_disable(priv->iovcc_supply); + usleep_range(2000, 3000); + regulator_disable(priv->vcc_supply); + + priv->prepared = false; + return 0; +} + +static const struct drm_display_mode renesas_r61307_mode = { + .clock = (768 + 116 + 81 + 5) * (1024 + 24 + 8 + 2) * 60 / 1000, + .hdisplay = 768, + .hsync_start = 768 + 116, + .hsync_end = 768 + 116 + 81, + .htotal = 768 + 116 + 81 + 5, + .vdisplay = 1024, + .vsync_start = 1024 + 24, + .vsync_end = 1024 + 24 + 8, + .vtotal = 1024 + 24 + 8 + 2, + .width_mm = 76, + .height_mm = 101, +}; + +static int renesas_r61307_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &renesas_r61307_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 = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs renesas_r61307_panel_funcs = { + .prepare = renesas_r61307_prepare, + .enable = renesas_r61307_enable, + .disable = renesas_r61307_disable, + .unprepare = renesas_r61307_unprepare, + .get_modes = renesas_r61307_get_modes, +}; + +static int renesas_r61307_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct renesas_r61307 *priv; + int ret; + + priv = devm_drm_panel_alloc(dev, struct renesas_r61307, panel, + &renesas_r61307_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + priv->vcc_supply = devm_regulator_get(dev, "vcc"); + if (IS_ERR(priv->vcc_supply)) + return dev_err_probe(dev, PTR_ERR(priv->vcc_supply), + "Failed to get vcc-supply\n"); + + priv->iovcc_supply = devm_regulator_get(dev, "iovcc"); + if (IS_ERR(priv->iovcc_supply)) + return dev_err_probe(dev, PTR_ERR(priv->iovcc_supply), + "Failed to get iovcc-supply\n"); + + priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), + "Failed to get reset gpios\n"); + + if (device_property_read_bool(dev, "renesas,inversion")) + priv->inversion = true; + + if (device_property_read_bool(dev, "renesas,contrast")) + priv->dig_cont_adj = true; + + priv->gamma = 0; + device_property_read_u32(dev, "renesas,gamma", &priv->gamma); + + priv->dsi = dsi; + mipi_dsi_set_drvdata(dsi, priv); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; + + ret = drm_panel_of_backlight(&priv->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&priv->panel); + + ret = mipi_dsi_attach(dsi); + if (ret) { + drm_panel_remove(&priv->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void renesas_r61307_remove(struct mipi_dsi_device *dsi) +{ + struct renesas_r61307 *priv = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&priv->panel); +} + +static const struct of_device_id renesas_r61307_of_match[] = { + { .compatible = "hit,tx13d100vm0eaa" }, + { .compatible = "koe,tx13d100vm0eaa" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, renesas_r61307_of_match); + +static struct mipi_dsi_driver renesas_r61307_driver = { + .probe = renesas_r61307_probe, + .remove = renesas_r61307_remove, + .driver = { + .name = "panel-renesas-r61307", + .of_match_table = renesas_r61307_of_match, + }, +}; +module_mipi_dsi_driver(renesas_r61307_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("Renesas R61307-based panel driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-renesas-r69328.c b/drivers/gpu/drm/panel/panel-renesas-r69328.c new file mode 100644 index 000000000000..46287ab04c30 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-renesas-r69328.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/array_size.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define R69328_MACP 0xb0 /* Manufacturer Access CMD Protect */ +#define R69328_MACP_ON 0x03 +#define R69328_MACP_OFF 0x04 + +#define R69328_GAMMA_SET_A 0xc8 /* Gamma Setting A */ +#define R69328_GAMMA_SET_B 0xc9 /* Gamma Setting B */ +#define R69328_GAMMA_SET_C 0xca /* Gamma Setting C */ + +#define R69328_POWER_SET 0xd1 + +struct renesas_r69328 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + + struct regulator *vdd_supply; + struct regulator *vddio_supply; + struct gpio_desc *reset_gpio; + + bool prepared; +}; + +static inline struct renesas_r69328 *to_renesas_r69328(struct drm_panel *panel) +{ + return container_of(panel, struct renesas_r69328, panel); +} + +static void renesas_r69328_reset(struct renesas_r69328 *priv) +{ + gpiod_set_value_cansleep(priv->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(priv->reset_gpio, 0); + usleep_range(2000, 3000); +} + +static int renesas_r69328_prepare(struct drm_panel *panel) +{ + struct renesas_r69328 *priv = to_renesas_r69328(panel); + struct device *dev = &priv->dsi->dev; + int ret; + + if (priv->prepared) + return 0; + + ret = regulator_enable(priv->vdd_supply); + if (ret) { + dev_err(dev, "failed to enable vdd power supply\n"); + return ret; + } + + usleep_range(10000, 11000); + + ret = regulator_enable(priv->vddio_supply); + if (ret < 0) { + dev_err(dev, "failed to enable vddio power supply\n"); + return ret; + } + + usleep_range(10000, 11000); + + renesas_r69328_reset(priv); + + priv->prepared = true; + return 0; +} + +static int renesas_r69328_enable(struct drm_panel *panel) +{ + struct renesas_r69328 *priv = to_renesas_r69328(panel); + struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi }; + + /* Set address mode */ + mipi_dsi_dcs_write_seq_multi(&ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + mipi_dsi_dcs_set_pixel_format_multi(&ctx, MIPI_DCS_PIXEL_FMT_24BIT << 4); + mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); + + mipi_dsi_msleep(&ctx, 100); + + /* MACP Off */ + mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_OFF); + + mipi_dsi_generic_write_seq_multi(&ctx, R69328_POWER_SET, 0x14, 0x1d, + 0x21, 0x67, 0x11, 0x9a); + + mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_A, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00); + + mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_B, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00); + + mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_C, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a, + 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13, + 0x11, 0x18, 0x1e, 0x1c, 0x00); + + /* MACP On */ + mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_ON); + + mipi_dsi_dcs_set_display_on_multi(&ctx); + mipi_dsi_msleep(&ctx, 50); + + return 0; +} + +static int renesas_r69328_disable(struct drm_panel *panel) +{ + struct renesas_r69328 *priv = to_renesas_r69328(panel); + struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&ctx); + mipi_dsi_msleep(&ctx, 60); + mipi_dsi_dcs_enter_sleep_mode_multi(&ctx); + + return 0; +} + +static int renesas_r69328_unprepare(struct drm_panel *panel) +{ + struct renesas_r69328 *priv = to_renesas_r69328(panel); + + if (!priv->prepared) + return 0; + + gpiod_set_value_cansleep(priv->reset_gpio, 1); + + usleep_range(5000, 6000); + + regulator_disable(priv->vddio_supply); + regulator_disable(priv->vdd_supply); + + priv->prepared = false; + return 0; +} + +static const struct drm_display_mode renesas_r69328_mode = { + .clock = (720 + 92 + 62 + 4) * (1280 + 6 + 3 + 1) * 60 / 1000, + .hdisplay = 720, + .hsync_start = 720 + 92, + .hsync_end = 720 + 92 + 62, + .htotal = 720 + 92 + 62 + 4, + .vdisplay = 1280, + .vsync_start = 1280 + 6, + .vsync_end = 1280 + 6 + 3, + .vtotal = 1280 + 6 + 3 + 1, + .width_mm = 59, + .height_mm = 105, +}; + +static int renesas_r69328_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &renesas_r69328_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 = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs renesas_r69328_panel_funcs = { + .prepare = renesas_r69328_prepare, + .enable = renesas_r69328_enable, + .disable = renesas_r69328_disable, + .unprepare = renesas_r69328_unprepare, + .get_modes = renesas_r69328_get_modes, +}; + +static int renesas_r69328_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct renesas_r69328 *priv; + int ret; + + priv = devm_drm_panel_alloc(dev, struct renesas_r69328, panel, + &renesas_r69328_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + priv->vdd_supply = devm_regulator_get(dev, "vdd"); + if (IS_ERR(priv->vdd_supply)) + return dev_err_probe(dev, PTR_ERR(priv->vdd_supply), + "Failed to get vdd-supply\n"); + + priv->vddio_supply = devm_regulator_get(dev, "vddio"); + if (IS_ERR(priv->vddio_supply)) + return dev_err_probe(dev, PTR_ERR(priv->vddio_supply), + "Failed to get vddio-supply\n"); + + priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(priv->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), + "Failed to get reset-gpios\n"); + + priv->dsi = dsi; + mipi_dsi_set_drvdata(dsi, priv); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; + + ret = drm_panel_of_backlight(&priv->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&priv->panel); + + ret = mipi_dsi_attach(dsi); + if (ret) { + drm_panel_remove(&priv->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void renesas_r69328_remove(struct mipi_dsi_device *dsi) +{ + struct renesas_r69328 *priv = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&priv->panel); +} + +static const struct of_device_id renesas_r69328_of_match[] = { + { .compatible = "jdi,dx12d100vm0eaa" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, renesas_r69328_of_match); + +static struct mipi_dsi_driver renesas_r69328_driver = { + .probe = renesas_r69328_probe, + .remove = renesas_r69328_remove, + .driver = { + .name = "panel-renesas-r69328", + .of_match_table = renesas_r69328_of_match, + }, +}; +module_mipi_dsi_driver(renesas_r69328_driver); + +MODULE_AUTHOR("Maxim Schwalm <maxim.schwalm@gmail.com>"); +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("Renesas R69328-based panel driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c index 2ef5ea5eaeeb..ad35d0fb0a16 100644 --- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c +++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c @@ -143,9 +143,11 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) struct rb070d30_panel *ctx; int ret; - ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct rb070d30_panel, panel, + &rb070d30_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supply = devm_regulator_get(&dsi->dev, "vcc-lcd"); if (IS_ERR(ctx->supply)) @@ -154,9 +156,6 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; - drm_panel_init(&ctx->panel, &dsi->dev, &rb070d30_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpios.reset)) { dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); diff --git a/drivers/gpu/drm/panel/panel-samsung-ams581vf01.c b/drivers/gpu/drm/panel/panel-samsung-ams581vf01.c index cf6186312252..188dd7cf0297 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ams581vf01.c +++ b/drivers/gpu/drm/panel/panel-samsung-ams581vf01.c @@ -211,9 +211,11 @@ static int ams581vf01_probe(struct mipi_dsi_device *dsi) struct ams581vf01 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(&dsi->dev, struct ams581vf01, panel, + &ams581vf01_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(&dsi->dev, ARRAY_SIZE(ams581vf01_supplies), @@ -235,8 +237,6 @@ static int ams581vf01_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&ctx->panel, dev, &ams581vf01_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = ams581vf01_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-ams639rq08.c b/drivers/gpu/drm/panel/panel-samsung-ams639rq08.c index 817365cb5e46..f8ebbd4a530b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ams639rq08.c +++ b/drivers/gpu/drm/panel/panel-samsung-ams639rq08.c @@ -257,9 +257,11 @@ static int ams639rq08_probe(struct mipi_dsi_device *dsi) struct ams639rq08 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ams639rq08, panel, + &ams639rq08_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(&dsi->dev, ARRAY_SIZE(ams639rq08_supplies), @@ -281,8 +283,6 @@ static int ams639rq08_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&ctx->panel, dev, &ams639rq08_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = ams639rq08_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c index 9a482a744b8c..20ec27d2d6c2 100644 --- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c @@ -266,9 +266,12 @@ static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep) struct device *dev = &aux_ep->dev; int ret; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct atana33xc20_panel, base, + &atana33xc20_funcs, + DRM_MODE_CONNECTOR_eDP); + if (IS_ERR(panel)) + return PTR_ERR(panel); + dev_set_drvdata(dev, panel); panel->aux = aux_ep->aux; @@ -301,8 +304,6 @@ static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep) if (ret) return ret; - drm_panel_init(&panel->base, dev, &atana33xc20_funcs, DRM_MODE_CONNECTOR_eDP); - pm_runtime_get_sync(dev); ret = drm_panel_dp_aux_backlight(&panel->base, aux_ep->aux); pm_runtime_mark_last_busy(dev); diff --git a/drivers/gpu/drm/panel/panel-samsung-db7430.c b/drivers/gpu/drm/panel/panel-samsung-db7430.c index 14c6700e37b3..a97182f3c990 100644 --- a/drivers/gpu/drm/panel/panel-samsung-db7430.c +++ b/drivers/gpu/drm/panel/panel-samsung-db7430.c @@ -267,9 +267,11 @@ static int db7430_probe(struct spi_device *spi) struct db7430 *db; int ret; - db = devm_kzalloc(dev, sizeof(*db), GFP_KERNEL); - if (!db) - return -ENOMEM; + db = devm_drm_panel_alloc(dev, struct db7430, panel, &db7430_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(db)) + return PTR_ERR(db); + db->dev = dev; /* @@ -294,9 +296,6 @@ static int db7430_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "MIPI DBI init failed\n"); - drm_panel_init(&db->panel, dev, &db7430_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - /* FIXME: if no external backlight, use internal backlight */ ret = drm_panel_of_backlight(&db->panel); if (ret) diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c index 9f438683a6f6..c7f2241523a0 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c +++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c @@ -339,9 +339,11 @@ static int ld9040_probe(struct spi_device *spi) struct ld9040 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(struct ld9040), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct ld9040, panel, + &ld9040_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); spi_set_drvdata(spi, ctx); @@ -373,9 +375,6 @@ static int ld9040_probe(struct spi_device *spi) return ret; } - drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - bldev = devm_backlight_device_register(dev, dev_name(dev), dev, ctx, &ld9040_bl_ops, &ld9040_bl_props); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index 79f611963c61..ba1a02000bb9 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -166,9 +166,11 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) struct s6d16d0 *s6; int ret; - s6 = devm_kzalloc(dev, sizeof(struct s6d16d0), GFP_KERNEL); - if (!s6) - return -ENOMEM; + s6 = devm_drm_panel_alloc(dev, struct s6d16d0, panel, + &s6d16d0_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(s6)) + return PTR_ERR(s6); mipi_dsi_set_drvdata(dsi, s6); s6->dev = dev; @@ -200,9 +202,6 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) return ret; } - drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&s6->panel); ret = mipi_dsi_attach(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c b/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c index 2adb223a895c..300dc19bd9d1 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c @@ -247,9 +247,11 @@ static int s6d27a1_probe(struct spi_device *spi) struct s6d27a1 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6d27a1, panel, + &s6d27a1_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->dev = dev; @@ -277,9 +279,6 @@ static int s6d27a1_probe(struct spi_device *spi) ctx->dbi.read_commands = s6d27a1_dbi_read_commands; - drm_panel_init(&ctx->panel, dev, &s6d27a1_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return dev_err_probe(dev, ret, "failed to add backlight\n"); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c index f23d8832a1ad..692020081524 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c @@ -34,8 +34,8 @@ struct s6d7aa0 { struct s6d7aa0_panel_desc { unsigned int panel_type; - int (*init_func)(struct s6d7aa0 *ctx); - int (*off_func)(struct s6d7aa0 *ctx); + void (*init_func)(struct s6d7aa0 *ctx, struct mipi_dsi_multi_context *dsi_ctx); + void (*off_func)(struct mipi_dsi_multi_context *dsi_ctx); const struct drm_display_mode *drm_mode; unsigned long mode_flags; u32 bus_flags; @@ -62,93 +62,61 @@ static void s6d7aa0_reset(struct s6d7aa0 *ctx) msleep(50); } -static int s6d7aa0_lock(struct s6d7aa0 *ctx, bool lock) +static void s6d7aa0_lock(struct s6d7aa0 *ctx, struct mipi_dsi_multi_context *dsi_ctx, bool lock) { - struct mipi_dsi_device *dsi = ctx->dsi; - if (lock) { - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD1, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD2, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD1, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD2, 0xa5, 0xa5); if (ctx->desc->use_passwd3) - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD3, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD3, 0x5a, 0x5a); } else { - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD1, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD2, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD1, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD2, 0x5a, 0x5a); if (ctx->desc->use_passwd3) - mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD3, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_PASSWD3, 0xa5, 0xa5); } - - return 0; } static int s6d7aa0_on(struct s6d7aa0 *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - ret = ctx->desc->init_func(ctx); - if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - return ret; - } + ctx->desc->init_func(ctx, &dsi_ctx); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - return 0; + return dsi_ctx.accum_err; } -static int s6d7aa0_off(struct s6d7aa0 *ctx) +static void s6d7aa0_off(struct s6d7aa0 *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - ret = ctx->desc->off_func(ctx); - if (ret < 0) { - dev_err(dev, "Panel-specific off function failed: %d\n", ret); - return ret; - } + ctx->desc->off_func(&dsi_ctx); - 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(64); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 64); - 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); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); - return 0; + mipi_dsi_msleep(&dsi_ctx, 120); } static int s6d7aa0_prepare(struct drm_panel *panel) { struct s6d7aa0 *ctx = panel_to_s6d7aa0(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); + if (ret < 0) return ret; - } s6d7aa0_reset(ctx); ret = s6d7aa0_on(ctx); if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); gpiod_set_value_cansleep(ctx->reset_gpio, 1); return ret; } @@ -159,12 +127,8 @@ static int s6d7aa0_prepare(struct drm_panel *panel) static int s6d7aa0_disable(struct drm_panel *panel) { struct s6d7aa0 *ctx = panel_to_s6d7aa0(panel); - struct device *dev = &ctx->dsi->dev; - int ret; - ret = s6d7aa0_off(ctx); - if (ret < 0) - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + s6d7aa0_off(ctx); return 0; } @@ -185,13 +149,11 @@ static int s6d7aa0_bl_update_status(struct backlight_device *bl) { struct mipi_dsi_device *dsi = bl_get_data(bl); u16 brightness = backlight_get_brightness(bl); - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); - if (ret < 0) - return ret; + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, brightness); - return 0; + return dsi_ctx.accum_err; } static int s6d7aa0_bl_get_brightness(struct backlight_device *bl) @@ -228,65 +190,39 @@ s6d7aa0_create_backlight(struct mipi_dsi_device *dsi) /* Initialization code and structures for LSL080AL02 panel */ -static int s6d7aa0_lsl080al02_init(struct s6d7aa0 *ctx) +static void s6d7aa0_lsl080al02_init(struct s6d7aa0 *ctx, struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; - - usleep_range(20000, 25000); + mipi_dsi_usleep_range(dsi_ctx, 20000, 25000); - ret = s6d7aa0_lock(ctx, false); - if (ret < 0) { - dev_err(dev, "Failed to unlock registers: %d\n", ret); - return ret; - } + s6d7aa0_lock(ctx, dsi_ctx, false); - mipi_dsi_dcs_write_seq(dsi, MCS_OTP_RELOAD, 0x00, 0x10); - usleep_range(1000, 1500); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_OTP_RELOAD, 0x00, 0x10); + mipi_dsi_usleep_range(dsi_ctx, 1000, 1500); /* SEQ_B6_PARAM_8_R01 */ - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x10); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb6, 0x10); /* BL_CTL_ON */ - mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x28); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_BL_CTL, 0x40, 0x00, 0x28); - usleep_range(5000, 6000); + mipi_dsi_usleep_range(dsi_ctx, 5000, 6000); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x04); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x04); - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); - msleep(120); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + mipi_dsi_msleep(dsi_ctx, 120); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); - ret = s6d7aa0_lock(ctx, true); - if (ret < 0) { - dev_err(dev, "Failed to lock registers: %d\n", ret); - return ret; - } + s6d7aa0_lock(ctx, dsi_ctx, true); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } - - return 0; + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); } -static int s6d7aa0_lsl080al02_off(struct s6d7aa0 *ctx) +static void s6d7aa0_lsl080al02_off(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - /* BL_CTL_OFF */ - mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x20); - - return 0; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_BL_CTL, 0x40, 0x00, 0x20); } static const struct drm_display_mode s6d7aa0_lsl080al02_mode = { @@ -308,7 +244,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = { .init_func = s6d7aa0_lsl080al02_init, .off_func = s6d7aa0_lsl080al02_off, .drm_mode = &s6d7aa0_lsl080al02_mode, - .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP, + .mode_flags = MIPI_DSI_MODE_VIDEO_NO_HFP, .bus_flags = 0, .has_backlight = false, @@ -317,79 +253,51 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = { /* Initialization code and structures for LSL080AL03 panel */ -static int s6d7aa0_lsl080al03_init(struct s6d7aa0 *ctx) +static void s6d7aa0_lsl080al03_init(struct s6d7aa0 *ctx, struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + mipi_dsi_usleep_range(dsi_ctx, 20000, 25000); - usleep_range(20000, 25000); - - ret = s6d7aa0_lock(ctx, false); - if (ret < 0) { - dev_err(dev, "Failed to unlock registers: %d\n", ret); - return ret; - } + s6d7aa0_lock(ctx, dsi_ctx, false); if (ctx->desc->panel_type == S6D7AA0_PANEL_LSL080AL03) { - mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0xc7, 0x00, 0x29); - mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x01, 0x4e, 0xa0); - mipi_dsi_dcs_write_seq(dsi, 0xfd, 0x16, 0x10, 0x11, 0x23, - 0x09); - mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00, 0x02, 0x03, 0x21, - 0x80, 0x78); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_BL_CTL, 0xc7, 0x00, 0x29); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbc, 0x01, 0x4e, 0xa0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfd, 0x16, 0x10, 0x11, 0x23, + 0x09); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfe, 0x00, 0x02, 0x03, 0x21, + 0x80, 0x78); } else if (ctx->desc->panel_type == S6D7AA0_PANEL_LTL101AT01) { - mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x08); - mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x01, 0x4e, 0x0b); - mipi_dsi_dcs_write_seq(dsi, 0xfd, 0x16, 0x10, 0x11, 0x23, - 0x09); - mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00, 0x02, 0x03, 0x21, - 0x80, 0x68); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MCS_BL_CTL, 0x40, 0x00, 0x08); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbc, 0x01, 0x4e, 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfd, 0x16, 0x10, 0x11, 0x23, + 0x09); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfe, 0x00, 0x02, 0x03, 0x21, + 0x80, 0x68); } - mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x51); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); - mipi_dsi_dcs_write_seq(dsi, 0xf2, 0x02, 0x08, 0x08); - - usleep_range(10000, 11000); - - mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x80, 0x80, 0x30); - mipi_dsi_dcs_write_seq(dsi, 0xcd, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e); - mipi_dsi_dcs_write_seq(dsi, 0xce, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x03); - - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb3, 0x51); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf2, 0x02, 0x08, 0x08); - ret = s6d7aa0_lock(ctx, true); - if (ret < 0) { - dev_err(dev, "Failed to lock registers: %d\n", ret); - return ret; - } + mipi_dsi_usleep_range(dsi_ctx, 10000, 11000); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x80, 0x80, 0x30); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xce, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc1, 0x03); - return 0; + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + s6d7aa0_lock(ctx, dsi_ctx, true); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); } -static int s6d7aa0_lsl080al03_off(struct s6d7aa0 *ctx) +static void s6d7aa0_lsl080al03_off(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - - mipi_dsi_dcs_write_seq(dsi, 0x22, 0x00); - - return 0; + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x22, 0x00); } static const struct drm_display_mode s6d7aa0_lsl080al03_mode = { @@ -484,9 +392,11 @@ static int s6d7aa0_probe(struct mipi_dsi_device *dsi) struct s6d7aa0 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6d7aa0, panel, + &s6d7aa0_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->desc = of_device_get_match_data(dev); if (!ctx->desc) @@ -512,8 +422,6 @@ static int s6d7aa0_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | ctx->desc->mode_flags; - drm_panel_init(&ctx->panel, dev, &s6d7aa0_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ret = drm_panel_of_backlight(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c index 27a059b55ae5..f4d75eca3cdf 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c @@ -185,9 +185,11 @@ static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi) struct s6e3fa7_panel *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e3fa7_panel, panel, + &s6e3fa7_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) @@ -202,8 +204,6 @@ static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c index ab8b58545284..1db0c63b1131 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c @@ -681,9 +681,11 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) struct s6e3ha2 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e3ha2, panel, + &s6e3ha2_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); @@ -731,8 +733,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS; ctx->bl_dev->props.power = BACKLIGHT_POWER_OFF; - drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; drm_panel_add(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c index 64c6f7d45bed..550e9ef9bb71 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c @@ -253,9 +253,11 @@ static int s6e3ha8_amb577px01_wqhd_probe(struct mipi_dsi_device *dsi) struct s6e3ha8 *priv; int ret; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_panel_alloc(dev, struct s6e3ha8, panel, + &s6e3ha8_amb577px01_wqhd_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(priv)) + return PTR_ERR(priv); ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(s6e3ha8_supplies), s6e3ha8_supplies, @@ -279,8 +281,6 @@ static int s6e3ha8_amb577px01_wqhd_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP | MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET; - drm_panel_init(&priv->panel, dev, &s6e3ha8_amb577px01_wqhd_panel_funcs, - DRM_MODE_CONNECTOR_DSI); priv->panel.prepare_prev_first = true; drm_panel_add(&priv->panel); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index 364f1c9a16d9..6f3d39556f92 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -437,9 +437,11 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) struct s6e63j0x03 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(struct s6e63j0x03), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e63j0x03, panel, + &s6e63j0x03_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); @@ -462,8 +464,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset-gpio\n"); - drm_panel_init(&ctx->panel, dev, &s6e63j0x03_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx, diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index 6917ffda5b2b..ea241c89593b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -13,6 +13,7 @@ #include <linux/backlight.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/property.h> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c index e92e95158d1f..e91f50662997 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c @@ -687,9 +687,11 @@ static int s6e88a0_ams427ap24_probe(struct mipi_dsi_device *dsi) struct s6e88a0_ams427ap24 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e88a0_ams427ap24, panel, + &s6e88a0_ams427ap24_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(s6e88a0_ams427ap24_supplies), @@ -711,8 +713,6 @@ static int s6e88a0_ams427ap24_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_NO_HFP; - drm_panel_init(&ctx->panel, dev, &s6e88a0_ams427ap24_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->flip_horizontal = device_property_read_bool(dev, "flip-horizontal"); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c index 57b1a899bbdc..ca5cad41ff1d 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c @@ -165,9 +165,11 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi) struct s6e88a0_ams452ef01 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e88a0_ams452ef01, panel, + &s6e88a0_ams452ef01_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "vdd3"; ctx->supplies[1].supply = "vci"; @@ -192,9 +194,6 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index c51d07ec1529..1b5c500d4f4e 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -979,9 +979,11 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) struct s6e8aa0 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct s6e8aa0, panel, + &s6e8aa0_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); @@ -990,7 +992,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST - | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT; + | MIPI_DSI_MODE_VIDEO_AUTO_VERT; ret = s6e8aa0_parse_dt(ctx); if (ret < 0) @@ -1014,8 +1016,6 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) ctx->brightness = GAMMA_LEVEL_NUM - 1; - drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; drm_panel_add(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c index 04ce925b3d9d..064258217d50 100644 --- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c +++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2020 Caleb Connolly <caleb@connolly.tech> +/* Copyright (c) 2020 Casey Connolly <casey.connolly@linaro.org> * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ @@ -22,7 +22,6 @@ struct sofef00_panel { struct mipi_dsi_device *dsi; struct regulator *supply; struct gpio_desc *reset_gpio; - const struct drm_display_mode *mode; }; static inline @@ -44,66 +43,44 @@ static void sofef00_panel_reset(struct sofef00_panel *ctx) static int sofef00_panel_on(struct sofef00_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags |= MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } - usleep_range(10000, 11000); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); - ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (ret < 0) { - dev_err(dev, "Failed to set tear on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x07); - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x12); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x07); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0x12); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - return 0; + return dsi_ctx.accum_err; } static int sofef00_panel_off(struct sofef00_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 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(40); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 40); - 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(160); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 160); - return 0; + return dsi_ctx.accum_err; } static int sofef00_panel_prepare(struct drm_panel *panel) @@ -122,7 +99,6 @@ static int sofef00_panel_prepare(struct drm_panel *panel) ret = sofef00_panel_on(ctx); if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); gpiod_set_value_cansleep(ctx->reset_gpio, 1); return ret; } @@ -133,13 +109,8 @@ static int sofef00_panel_prepare(struct drm_panel *panel) static int sofef00_panel_unprepare(struct drm_panel *panel) { struct sofef00_panel *ctx = to_sofef00_panel(panel); - struct device *dev = &ctx->dsi->dev; - int ret; - - ret = sofef00_panel_off(ctx); - if (ret < 0) - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + sofef00_panel_off(ctx); regulator_disable(ctx->supply); return 0; @@ -159,26 +130,11 @@ static const struct drm_display_mode enchilada_panel_mode = { .height_mm = 145, }; -static const struct drm_display_mode fajita_panel_mode = { - .clock = (1080 + 72 + 16 + 36) * (2340 + 32 + 4 + 18) * 60 / 1000, - .hdisplay = 1080, - .hsync_start = 1080 + 72, - .hsync_end = 1080 + 72 + 16, - .htotal = 1080 + 72 + 16 + 36, - .vdisplay = 2340, - .vsync_start = 2340 + 32, - .vsync_end = 2340 + 32 + 4, - .vtotal = 2340 + 32 + 4 + 18, - .width_mm = 68, - .height_mm = 145, -}; - static int sofef00_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct drm_display_mode *mode; - struct sofef00_panel *ctx = to_sofef00_panel(panel); - mode = drm_mode_duplicate(connector->dev, ctx->mode); + mode = drm_mode_duplicate(connector->dev, &enchilada_panel_mode); if (!mode) return -ENOMEM; @@ -235,16 +191,11 @@ static int sofef00_panel_probe(struct mipi_dsi_device *dsi) struct sofef00_panel *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->mode = of_device_get_match_data(dev); - - if (!ctx->mode) { - dev_err(dev, "Missing device mode\n"); - return -ENODEV; - } + ctx = devm_drm_panel_alloc(dev, struct sofef00_panel, panel, + &sofef00_panel_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supply = devm_regulator_get(dev, "vddio"); if (IS_ERR(ctx->supply)) @@ -262,9 +213,6 @@ static int sofef00_panel_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - drm_panel_init(&ctx->panel, dev, &sofef00_panel_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->panel.backlight = sofef00_create_backlight(dsi); if (IS_ERR(ctx->panel.backlight)) return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), @@ -295,14 +243,7 @@ static void sofef00_panel_remove(struct mipi_dsi_device *dsi) } static const struct of_device_id sofef00_panel_of_match[] = { - { // OnePlus 6 / enchilada - .compatible = "samsung,sofef00", - .data = &enchilada_panel_mode, - }, - { // OnePlus 6T / fajita - .compatible = "samsung,s6e3fc2x01", - .data = &fajita_panel_mode, - }, + { .compatible = "samsung,sofef00" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sofef00_panel_of_match); @@ -318,6 +259,6 @@ static struct mipi_dsi_driver sofef00_panel_driver = { module_mipi_dsi_driver(sofef00_panel_driver); -MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>"); +MODULE_AUTHOR("Casey Connolly <casey.connolly@linaro.org>"); MODULE_DESCRIPTION("DRM driver for Samsung AMOLED DSI panels found in OnePlus 6/6T phones"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c index 7d1b421ea9dd..0935d83ee2db 100644 --- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c @@ -204,9 +204,11 @@ static int seiko_panel_probe(struct device *dev, struct seiko_panel *panel; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct seiko_panel, base, + &seiko_panel_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(panel)) + return PTR_ERR(panel); panel->desc = desc; @@ -224,9 +226,6 @@ static int seiko_panel_probe(struct device *dev, return dev_err_probe(dev, PTR_ERR(panel->enable_gpio), "failed to request GPIO\n"); - drm_panel_init(&panel->base, dev, &seiko_panel_funcs, - DRM_MODE_CONNECTOR_DPI); - err = drm_panel_of_backlight(&panel->base); if (err) return err; diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index a0d76d588da1..d159b0e4fdb6 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -279,9 +279,6 @@ static int sharp_panel_add(struct sharp_panel *sharp) if (IS_ERR(sharp->supply)) return PTR_ERR(sharp->supply); - drm_panel_init(&sharp->base, &sharp->link1->dev, &sharp_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&sharp->base); if (ret) return ret; @@ -323,10 +320,12 @@ static int sharp_panel_probe(struct mipi_dsi_device *dsi) /* register a panel for only the DSI-LINK1 interface */ if (secondary) { - sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL); - if (!sharp) { + sharp = devm_drm_panel_alloc(&dsi->dev, __typeof(*sharp), base, + &sharp_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(sharp)) { put_device(&secondary->dev); - return -ENOMEM; + return PTR_ERR(sharp); } mipi_dsi_set_drvdata(dsi, sharp); diff --git a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c index a9673a52b861..938beac4655d 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c @@ -138,9 +138,10 @@ static int ls037v7dw01_probe(struct platform_device *pdev) { struct ls037v7dw01_panel *lcd; - lcd = devm_kzalloc(&pdev->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&pdev->dev, struct ls037v7dw01_panel, panel, + &ls037v7dw01_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); platform_set_drvdata(pdev, lcd); lcd->pdev = pdev; @@ -181,9 +182,6 @@ static int ls037v7dw01_probe(struct platform_device *pdev) return PTR_ERR(lcd->ud_gpio); } - drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&lcd->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 729cbb0d8403..36abfa2e65e9 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -36,60 +36,49 @@ static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel) static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt) { struct mipi_dsi_device *dsi = sharp_nt->dsi; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags |= MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) - return ret; + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); - msleep(120); + mipi_dsi_msleep(&dsi_ctx, 120); /* Novatek two-lane operation */ - ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1); - if (ret < 0) - return ret; + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xae, 0x03); /* Set both MCU and RGB I/F to 24bpp */ - ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT | - (MIPI_DCS_PIXEL_FMT_24BIT << 4)); - if (ret < 0) - return ret; + mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, + MIPI_DCS_PIXEL_FMT_24BIT | + (MIPI_DCS_PIXEL_FMT_24BIT << 4)); - return 0; + return dsi_ctx.accum_err; } static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt) { struct mipi_dsi_device *dsi = sharp_nt->dsi; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags |= MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) - return ret; + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - return 0; + return dsi_ctx.accum_err; } static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt) { struct mipi_dsi_device *dsi = sharp_nt->dsi; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_set_display_off(dsi); - if (ret < 0) - return ret; + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret < 0) - return ret; + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); - return 0; + return dsi_ctx.accum_err; } static int sharp_nt_panel_unprepare(struct drm_panel *panel) diff --git a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c index 0b4e0983639b..0456f3d705e7 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c @@ -193,9 +193,11 @@ static int sharp_ls060_probe(struct mipi_dsi_device *dsi) struct sharp_ls060 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct sharp_ls060, panel, + &sharp_ls060_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->vddi_supply = devm_regulator_get(dev, "vddi"); if (IS_ERR(ctx->vddi_supply)) @@ -227,9 +229,6 @@ static int sharp_ls060_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &sharp_ls060_panel_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"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 33a37539de57..3333d4a07504 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -26,6 +26,7 @@ #include <linux/i2c.h> #include <linux/media-bus-format.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -136,6 +137,14 @@ struct panel_desc { int connector_type; }; +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct panel_simple { struct drm_panel base; @@ -430,10 +439,7 @@ static const struct drm_panel_funcs panel_simple_funcs = { .get_timings = panel_simple_get_timings, }; -static struct panel_desc panel_dpi; - -static int panel_dpi_probe(struct device *dev, - struct panel_simple *panel) +static struct panel_desc *panel_dpi_probe(struct device *dev) { struct display_timing *timing; const struct device_node *np; @@ -445,17 +451,17 @@ static int panel_dpi_probe(struct device *dev, np = dev->of_node; desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); if (!desc) - return -ENOMEM; + return ERR_PTR(-ENOMEM); timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); if (!timing) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ret = of_get_display_timing(np, "panel-timing", timing); if (ret < 0) { dev_err(dev, "%pOF: no panel-timing node found for \"panel-dpi\" binding\n", np); - return ret; + return ERR_PTR(ret); } desc->timings = timing; @@ -473,9 +479,7 @@ static int panel_dpi_probe(struct device *dev, /* We do not know the connector for the DT node, so guess it */ desc->connector_type = DRM_MODE_CONNECTOR_DPI; - panel->desc = desc; - - return 0; + return desc; } #define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \ @@ -570,8 +574,44 @@ static int panel_simple_override_nondefault_lvds_datamapping(struct device *dev, return 0; } -static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) +static const struct panel_desc *panel_simple_get_desc(struct device *dev) { + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI) && + dev_is_mipi_dsi(dev)) { + const struct panel_desc_dsi *dsi_desc; + + dsi_desc = of_device_get_match_data(dev); + if (!dsi_desc) + return ERR_PTR(-ENODEV); + + return &dsi_desc->desc; + } + + if (dev_is_platform(dev)) { + const struct panel_desc *desc; + + desc = of_device_get_match_data(dev); + if (!desc) { + /* + * panel-dpi probes without a descriptor and + * panel_dpi_probe() will initialize one for us + * based on the device tree. + */ + if (of_device_is_compatible(dev->of_node, "panel-dpi")) + return panel_dpi_probe(dev); + else + return ERR_PTR(-ENODEV); + } + + return desc; + } + + return ERR_PTR(-ENODEV); +} + +static struct panel_simple *panel_simple_probe(struct device *dev) +{ + const struct panel_desc *desc; struct panel_simple *panel; struct display_timing dt; struct device_node *ddc; @@ -579,26 +619,31 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) u32 bus_flags; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + desc = panel_simple_get_desc(dev); + if (IS_ERR(desc)) + return ERR_CAST(desc); + + panel = devm_drm_panel_alloc(dev, struct panel_simple, base, + &panel_simple_funcs, desc->connector_type); + if (IS_ERR(panel)) + return ERR_CAST(panel); panel->desc = desc; panel->supply = devm_regulator_get(dev, "power"); if (IS_ERR(panel->supply)) - return PTR_ERR(panel->supply); + return ERR_CAST(panel->supply); panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(panel->enable_gpio)) - return dev_err_probe(dev, PTR_ERR(panel->enable_gpio), - "failed to request GPIO\n"); + return dev_err_cast_probe(dev, panel->enable_gpio, + "failed to request GPIO\n"); err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); if (err) { dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); - return err; + return ERR_PTR(err); } ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); @@ -607,19 +652,12 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) of_node_put(ddc); if (!panel->ddc) - return -EPROBE_DEFER; + return ERR_PTR(-EPROBE_DEFER); } - if (desc == &panel_dpi) { - /* Handle the generic panel-dpi binding */ - err = panel_dpi_probe(dev, panel); - if (err) - goto free_ddc; - desc = panel->desc; - } else { - if (!of_get_display_timing(dev->of_node, "panel-timing", &dt)) - panel_simple_parse_panel_timing_node(dev, panel, &dt); - } + if (!of_device_is_compatible(dev->of_node, "panel-dpi") && + !of_get_display_timing(dev->of_node, "panel-timing", &dt)) + panel_simple_parse_panel_timing_node(dev, panel, &dt); if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { /* Optional data-mapping property for overriding bus format */ @@ -694,8 +732,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); - err = drm_panel_of_backlight(&panel->base); if (err) { dev_err_probe(dev, err, "Could not find backlight\n"); @@ -704,7 +740,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) drm_panel_add(&panel->base); - return 0; + return panel; disable_pm_runtime: pm_runtime_dont_use_autosuspend(dev); @@ -713,7 +749,7 @@ free_ddc: if (panel->ddc) put_device(&panel->ddc->dev); - return err; + return ERR_PTR(err); } static void panel_simple_shutdown(struct device *dev) @@ -1269,6 +1305,30 @@ static const struct panel_desc auo_g190ean01 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing auo_p238han01_timings = { + .pixelclock = { 107400000, 142400000, 180000000 }, + .hactive = { 1920, 1920, 1920 }, + .hfront_porch = { 30, 70, 650 }, + .hback_porch = { 30, 70, 650 }, + .hsync_len = { 20, 40, 136 }, + .vactive = { 1080, 1080, 1080 }, + .vfront_porch = { 5, 19, 318 }, + .vback_porch = { 5, 19, 318 }, + .vsync_len = { 4, 12, 120 }, +}; + +static const struct panel_desc auo_p238han01 = { + .timings = &auo_p238han01_timings, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 527, + .height = 296, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing auo_p320hvn03_timings = { .pixelclock = { 106000000, 148500000, 164000000 }, .hactive = { 1920, 1920, 1920 }, @@ -2199,13 +2259,14 @@ static const struct display_timing evervision_vgg644804_timing = { static const struct panel_desc evervision_vgg644804 = { .timings = &evervision_vgg644804_timing, .num_timings = 1, - .bpc = 8, + .bpc = 6, .size = { .width = 115, .height = 86, }, .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, }; static const struct display_timing evervision_vgg804821_timing = { @@ -3528,6 +3589,30 @@ static const struct panel_desc newhaven_nhd_43_480272ef_atxl = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode nlt_nl13676bc25_03f_mode = { + .clock = 75400, + .hdisplay = 1366, + .hsync_start = 1366 + 14, + .hsync_end = 1366 + 14 + 56, + .htotal = 1366 + 14 + 56 + 64, + .vdisplay = 768, + .vsync_start = 768 + 1, + .vsync_end = 768 + 1 + 3, + .vtotal = 768 + 1 + 3 + 22, +}; + +static const struct panel_desc nlt_nl13676bc25_03f = { + .modes = &nlt_nl13676bc25_03f_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 363, + .height = 215, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing nlt_nl192108ac18_02d_timing = { .pixelclock = { 130000000, 148350000, 163000000 }, .hactive = { 1920, 1920, 1920 }, @@ -3797,6 +3882,32 @@ static const struct panel_desc pda_91_00156_a0 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct drm_display_mode powertip_ph128800t004_zza01_mode = { + .clock = 71150, + .hdisplay = 1280, + .hsync_start = 1280 + 48, + .hsync_end = 1280 + 48 + 32, + .htotal = 1280 + 48 + 32 + 80, + .vdisplay = 800, + .vsync_start = 800 + 9, + .vsync_end = 800 + 9 + 8, + .vtotal = 800 + 9 + 8 + 6, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc powertip_ph128800t004_zza01 = { + .modes = &powertip_ph128800t004_zza01_mode, + .num_modes = 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 powertip_ph128800t006_zhc01_mode = { .clock = 66500, .hdisplay = 1280, @@ -4394,10 +4505,10 @@ static const struct panel_desc tianma_tm070jvhg33 = { }; /* - * The datasheet computes total blanking as back porch + front porch, not - * including sync pulse width. This is for both H and V. To make the total - * blanking and period correct, subtract the pulse width from the front - * porch. + * The TM070JDHG34-00 datasheet computes total blanking as back porch + + * front porch, not including sync pulse width. This is for both H and + * V. To make the total blanking and period correct, subtract the pulse + * width from the front porch. * * This works well for the Min and Typ values, but for Max values the sync * pulse width is higher than back porch + front porch, so work around that @@ -4406,6 +4517,10 @@ static const struct panel_desc tianma_tm070jvhg33 = { * * Exact datasheet values are added as a comment where they differ from the * ones implemented for the above reason. + * + * The P0700WXF1MBAA datasheet is even less detailed, only listing period + * and total blanking time, however the resulting values are the same as + * the TM070JDHG34-00. */ static const struct display_timing tianma_tm070jdhg34_00_timing = { .pixelclock = { 68400000, 71900000, 78100000 }, @@ -4428,6 +4543,30 @@ static const struct panel_desc tianma_tm070jdhg34_00 = { .width = 150, /* 149.76 */ .height = 94, /* 93.60 */ }, + .delay = { + .prepare = 15, /* Tp1 */ + .enable = 150, /* Tp2 */ + .disable = 150, /* Tp4 */ + .unprepare = 120, /* Tp3 */ + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + +static const struct panel_desc tianma_p0700wxf1mbaa = { + .timings = &tianma_tm070jdhg34_00_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 150, /* 149.76 */ + .height = 94, /* 93.60 */ + }, + .delay = { + .prepare = 18, /* Tr + Tp1 */ + .enable = 152, /* Tp2 + Tp5 */ + .disable = 152, /* Tp6 + Tp4 */ + .unprepare = 120, /* Tp3 */ + }, .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -4861,6 +5000,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "auo,g190ean01", .data = &auo_g190ean01, }, { + .compatible = "auo,p238han01", + .data = &auo_p238han01, + }, { .compatible = "auo,p320hvn03", .data = &auo_p320hvn03, }, { @@ -5122,6 +5264,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "newhaven,nhd-4.3-480272ef-atxl", .data = &newhaven_nhd_43_480272ef_atxl, }, { + .compatible = "nlt,nl13676bc25-03f", + .data = &nlt_nl13676bc25_03f, + }, { .compatible = "nlt,nl192108ac18-02d", .data = &nlt_nl192108ac18_02d, }, { @@ -5155,6 +5300,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "pda,91-00156-a0", .data = &pda_91_00156_a0, }, { + .compatible = "powertip,ph128800t004-zza01", + .data = &powertip_ph128800t004_zza01, + }, { .compatible = "powertip,ph128800t006-zhc01", .data = &powertip_ph128800t006_zhc01, }, { @@ -5215,6 +5363,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "tfc,s9700rtwv43tr-01b", .data = &tfc_s9700rtwv43tr_01b, }, { + .compatible = "tianma,p0700wxf1mbaa", + .data = &tianma_p0700wxf1mbaa, + }, { .compatible = "tianma,tm070jdhg30", .data = &tianma_tm070jdhg30, }, { @@ -5280,7 +5431,12 @@ static const struct of_device_id platform_of_match[] = { }, { /* Must be the last entry */ .compatible = "panel-dpi", - .data = &panel_dpi, + + /* + * Explicitly NULL, the panel_desc structure will be + * allocated by panel_dpi_probe(). + */ + .data = NULL, }, { /* sentinel */ } @@ -5289,13 +5445,13 @@ MODULE_DEVICE_TABLE(of, platform_of_match); static int panel_simple_platform_probe(struct platform_device *pdev) { - const struct panel_desc *desc; + struct panel_simple *panel; - desc = of_device_get_match_data(&pdev->dev); - if (!desc) - return -ENODEV; + panel = panel_simple_probe(&pdev->dev); + if (IS_ERR(panel)) + return PTR_ERR(panel); - return panel_simple_probe(&pdev->dev, desc); + return 0; } static void panel_simple_platform_remove(struct platform_device *pdev) @@ -5325,14 +5481,6 @@ static struct platform_driver panel_simple_platform_driver = { .shutdown = panel_simple_platform_shutdown, }; -struct panel_desc_dsi { - struct panel_desc desc; - - unsigned long flags; - enum mipi_dsi_pixel_format format; - unsigned int lanes; -}; - static const struct drm_display_mode auo_b080uan01_mode = { .clock = 154500, .hdisplay = 1200, @@ -5566,16 +5714,14 @@ MODULE_DEVICE_TABLE(of, dsi_of_match); static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) { const struct panel_desc_dsi *desc; + struct panel_simple *panel; int err; - desc = of_device_get_match_data(&dsi->dev); - if (!desc) - return -ENODEV; - - err = panel_simple_probe(&dsi->dev, &desc->desc); - if (err < 0) - return err; + panel = panel_simple_probe(&dsi->dev); + if (IS_ERR(panel)) + return PTR_ERR(panel); + desc = container_of(panel->desc, struct panel_desc_dsi, desc); dsi->mode_flags = desc->flags; dsi->format = desc->format; dsi->lanes = desc->lanes; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 1f72ef7ca74c..2f79ec4a2063 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -520,6 +520,28 @@ static void rg28xx_gip_sequence(struct st7701 *st7701) st7701_switch_cmd_bkx(st7701, false, 0); } +static void wf40eswaa6mnn0_gip_sequence(struct st7701 *st7701) +{ + ST7701_WRITE(st7701, 0xE0, 0x00, 0x28, 0x02); + ST7701_WRITE(st7701, 0xE1, 0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, + 0x00, 0x00, 0x44, 0x44); + ST7701_WRITE(st7701, 0xE2, 0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, + 0x00, 0xEC, 0xA0, 0x00, 0x00); + ST7701_WRITE(st7701, 0xE3, 0x00, 0x00, 0x11, 0x11); + ST7701_WRITE(st7701, 0xE4, 0x44, 0x44); + ST7701_WRITE(st7701, 0xE5, 0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, + 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0); + ST7701_WRITE(st7701, 0xE6, 0x00, 0x00, 0x11, 0x11); + ST7701_WRITE(st7701, 0xE7, 0x44, 0x44); + ST7701_WRITE(st7701, 0xE8, 0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, + 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0); + ST7701_WRITE(st7701, 0xEB, 0x00, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40); + ST7701_WRITE(st7701, 0xEC, 0x3C, 0x00); + ST7701_WRITE(st7701, 0xED, 0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA); + ST7701_WRITE(st7701, MIPI_DCS_SET_ADDRESS_MODE, 0); +} + static int st7701_prepare(struct drm_panel *panel) { struct st7701 *st7701 = panel_to_st7701(panel); @@ -1135,6 +1157,107 @@ static const struct st7701_panel_desc rg28xx_desc = { .gip_sequence = rg28xx_gip_sequence, }; +static const struct drm_display_mode wf40eswaa6mnn0_mode = { + .clock = 18306, + + .hdisplay = 480, + .hsync_start = 480 + 2, + .hsync_end = 480 + 2 + 45, + .htotal = 480 + 2 + 45 + 13, + + .vdisplay = 480, + .vsync_start = 480 + 2, + .vsync_end = 480 + 2 + 70, + .vtotal = 480 + 2 + 70 + 13, + + .width_mm = 72, + .height_mm = 70, + + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct st7701_panel_desc wf40eswaa6mnn0_desc = { + .mode = &wf40eswaa6mnn0_mode, + .lanes = 2, + .format = MIPI_DSI_FMT_RGB888, + .panel_sleep_delay = 0, + + .pv_gamma = { + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x1), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x08), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x10), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0c), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x08), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x10), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x0c), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x08), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x22), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x04), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x14), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x12), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0xb3), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x3a), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) + }, + .nv_gamma = { + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x19), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1f), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0f), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x14), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x07), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x07), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x08), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x07), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x22), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x02), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0xf), + + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x0f), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0xa3), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x29), + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x0d) + }, + .nlinv = 3, + .vop_uv = 4737500, + .vcom_uv = 662500, + .vgh_mv = 15000, + .vgl_mv = -10170, + .avdd_mv = 6600, + .avcl_mv = -4600, + .gamma_op_bias = OP_BIAS_MIDDLE, + .input_op_bias = OP_BIAS_MIDDLE, + .output_op_bias = OP_BIAS_MIN, + .t2d_ns = 1600, + .t3d_ns = 10400, + .eot_en = true, + .gip_sequence = wf40eswaa6mnn0_gip_sequence, +}; + static void st7701_cleanup(void *data) { struct st7701 *st7701 = (struct st7701 *)data; @@ -1150,9 +1273,10 @@ static int st7701_probe(struct device *dev, int connector_type) struct st7701 *st7701; int ret; - st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL); - if (!st7701) - return -ENOMEM; + st7701 = devm_drm_panel_alloc(dev, struct st7701, panel, &st7701_funcs, + connector_type); + if (IS_ERR(st7701)) + return PTR_ERR(st7701); desc = of_device_get_match_data(dev); if (!desc) @@ -1176,7 +1300,6 @@ static int st7701_probe(struct device *dev, int connector_type) if (ret < 0) return dev_err_probe(dev, ret, "Failed to get orientation\n"); - drm_panel_init(&st7701->panel, dev, &st7701_funcs, connector_type); st7701->panel.prepare_prev_first = true; /** @@ -1265,6 +1388,7 @@ static const struct of_device_id st7701_dsi_of_match[] = { { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc }, { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc }, { .compatible = "techstar,ts8550b", .data = &ts8550b_desc }, + { .compatible = "winstar,wf40eswaa6mnn0", .data = &wf40eswaa6mnn0_desc }, { } }; MODULE_DEVICE_TABLE(of, st7701_dsi_of_match); diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 67e8e45498cb..1a007a244d84 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -846,9 +846,11 @@ static int st7703_probe(struct mipi_dsi_device *dsi) struct st7703 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct st7703, panel, + &st7703_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) @@ -876,9 +878,6 @@ static int st7703_probe(struct mipi_dsi_device *dsi) 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); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 28bfc48a9127..04d91929eedd 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -612,9 +612,10 @@ static int st7789v_probe(struct spi_device *spi) struct st7789v *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct st7789v, panel, + &st7789v_drm_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); spi_set_drvdata(spi, ctx); ctx->spi = spi; @@ -626,9 +627,6 @@ static int st7789v_probe(struct spi_device *spi) ctx->info = device_get_match_data(&spi->dev); - drm_panel_init(&ctx->panel, dev, &st7789v_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - ctx->power = devm_regulator_get(dev, "power"); ret = PTR_ERR_OR_ZERO(ctx->power); if (ret) diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c index d437f5c84f5f..fe043de791b0 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c @@ -607,9 +607,10 @@ static int acx565akm_probe(struct spi_device *spi) struct acx565akm_panel *lcd; int ret; - lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&spi->dev, struct acx565akm_panel, panel, + &acx565akm_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); spi_set_drvdata(spi, lcd); spi->mode = SPI_MODE_3; @@ -635,9 +636,6 @@ static int acx565akm_probe(struct spi_device *spi) return ret; } - drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&lcd->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c index 97f4bb4e1029..7c989b70ab51 100644 --- a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c +++ b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c @@ -175,9 +175,11 @@ static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi) struct sony_td4353_jdi *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct sony_td4353_jdi, panel, + &sony_td4353_jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->type = (uintptr_t)of_device_get_match_data(dev); @@ -206,9 +208,6 @@ static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &sony_td4353_jdi_panel_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"); diff --git a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c index 104b2290560e..216a6ad8696e 100644 --- a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c +++ b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c @@ -433,9 +433,11 @@ static int truly_nt35521_probe(struct mipi_dsi_device *dsi) struct truly_nt35521 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct truly_nt35521, panel, + &truly_nt35521_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supplies[0].supply = "positive5"; ctx->supplies[1].supply = "negative5"; @@ -465,9 +467,6 @@ static int truly_nt35521_probe(struct mipi_dsi_device *dsi) MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &truly_nt35521_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->panel.backlight = truly_nt35521_create_backlight(dsi); if (IS_ERR(ctx->panel.backlight)) return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), diff --git a/drivers/gpu/drm/panel/panel-summit.c b/drivers/gpu/drm/panel/panel-summit.c index e780faee1857..4854437e2899 100644 --- a/drivers/gpu/drm/panel/panel-summit.c +++ b/drivers/gpu/drm/panel/panel-summit.c @@ -68,9 +68,11 @@ static int summit_probe(struct mipi_dsi_device *dsi) struct summit_data *s_data; int ret; - s_data = devm_kzalloc(dev, sizeof(*s_data), GFP_KERNEL); - if (!s_data) - return -ENOMEM; + s_data = devm_drm_panel_alloc(dev, struct summit_data, panel, + &summit_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(s_data)) + return PTR_ERR(s_data); mipi_dsi_set_drvdata(dsi, s_data); s_data->dsi = dsi; @@ -85,8 +87,6 @@ static int summit_probe(struct mipi_dsi_device *dsi) if (IS_ERR(s_data->bl)) return PTR_ERR(s_data->bl); - drm_panel_init(&s_data->panel, dev, &summit_panel_funcs, - DRM_MODE_CONNECTOR_DSI); drm_panel_add(&s_data->panel); return mipi_dsi_attach(dsi); diff --git a/drivers/gpu/drm/panel/panel-synaptics-r63353.c b/drivers/gpu/drm/panel/panel-synaptics-r63353.c index 17349825543f..3a74d48753d9 100644 --- a/drivers/gpu/drm/panel/panel-synaptics-r63353.c +++ b/drivers/gpu/drm/panel/panel-synaptics-r63353.c @@ -106,53 +106,34 @@ static int r63353_panel_power_off(struct r63353_panel *rpanel) static int r63353_panel_activate(struct r63353_panel *rpanel) { struct mipi_dsi_device *dsi = rpanel->dsi; - struct device *dev = &dsi->dev; - int i, ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + int i; - ret = mipi_dsi_dcs_soft_reset(dsi); - if (ret < 0) { - dev_err(dev, "Failed to do Software Reset (%d)\n", ret); - goto fail; - } + mipi_dsi_dcs_soft_reset_multi(&dsi_ctx); - usleep_range(15000, 17000); + mipi_dsi_usleep_range(&dsi_ctx, 15000, 17000); - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to enter sleep mode (%d)\n", ret); - goto fail; - } + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); for (i = 0; i < rpanel->pdata->init_length; i++) { const struct r63353_instr *instr = &rpanel->pdata->init[i]; - ret = mipi_dsi_dcs_write_buffer(dsi, instr->data, instr->len); - if (ret < 0) - goto fail; + mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, instr->data, + instr->len); } - msleep(120); + mipi_dsi_msleep(&dsi_ctx, 120); - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode (%d)\n", ret); - goto fail; - } + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); - usleep_range(5000, 10000); + mipi_dsi_usleep_range(&dsi_ctx, 5000, 10000); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display ON (%d)\n", ret); - goto fail; - } - - return 0; + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); -fail: - gpiod_set_value(rpanel->reset_gpio, 0); + if (dsi_ctx.accum_err) + gpiod_set_value(rpanel->reset_gpio, 0); - return ret; + return dsi_ctx.accum_err; } static int r63353_panel_prepare(struct drm_panel *panel) @@ -178,27 +159,16 @@ static int r63353_panel_prepare(struct drm_panel *panel) return 0; } -static int r63353_panel_deactivate(struct r63353_panel *rpanel) +static void r63353_panel_deactivate(struct r63353_panel *rpanel) { struct mipi_dsi_device *dsi = rpanel->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 display OFF (%d)\n", ret); - return ret; - } + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - usleep_range(5000, 10000); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to enter sleep mode (%d)\n", ret); - return ret; - } + mipi_dsi_usleep_range(&dsi_ctx, 5000, 10000); - return 0; + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); } static int r63353_panel_unprepare(struct drm_panel *panel) @@ -259,9 +229,11 @@ static int r63353_panel_probe(struct mipi_dsi_device *dsi) struct device *dev = &dsi->dev; struct r63353_panel *panel; - panel = devm_kzalloc(&dsi->dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct r63353_panel, base, + &r63353_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(panel)) + return PTR_ERR(panel); mipi_dsi_set_drvdata(dsi, panel); panel->dsi = dsi; @@ -288,9 +260,6 @@ static int r63353_panel_probe(struct mipi_dsi_device *dsi) return PTR_ERR(panel->reset_gpio); } - drm_panel_init(&panel->base, dev, &r63353_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - panel->base.prepare_prev_first = true; ret = drm_panel_of_backlight(&panel->base); if (ret) diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c index 4dbf8b88f264..ee86ff20c1bd 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c @@ -86,11 +86,7 @@ struct td028ttec1_panel { #define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel) -/* - * noinline_for_stack so we don't get multiple copies of tx_buf - * on the stack in case of gcc-plugin-structleak - */ -static int noinline_for_stack +static int jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err) { struct spi_device *spi = lcd->spi; @@ -322,9 +318,11 @@ static int td028ttec1_probe(struct spi_device *spi) struct td028ttec1_panel *lcd; int ret; - lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&spi->dev, struct td028ttec1_panel, panel, + &td028ttec1_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); spi_set_drvdata(spi, lcd); lcd->spi = spi; @@ -338,9 +336,6 @@ static int td028ttec1_probe(struct spi_device *spi) return ret; } - drm_panel_init(&lcd->panel, &lcd->spi->dev, &td028ttec1_funcs, - DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_of_backlight(&lcd->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c index cf4609bb9b1d..b18af526b54c 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c @@ -421,9 +421,10 @@ static int td043mtea1_probe(struct spi_device *spi) struct td043mtea1_panel *lcd; int ret; - lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (lcd == NULL) - return -ENOMEM; + lcd = devm_drm_panel_alloc(&spi->dev, struct td043mtea1_panel, panel, + &td043mtea1_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(lcd)) + return PTR_ERR(lcd); spi_set_drvdata(spi, lcd); lcd->spi = spi; @@ -455,9 +456,6 @@ static int td043mtea1_probe(struct spi_device *spi) return ret; } - drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_panel_add(&lcd->panel); return 0; diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index f6a212e542cb..0beba5c08956 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -405,9 +405,11 @@ static int tpg110_probe(struct spi_device *spi) struct tpg110 *tpg; int ret; - tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL); - if (!tpg) - return -ENOMEM; + tpg = devm_drm_panel_alloc(dev, struct tpg110, panel, + &tpg110_drm_funcs, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(tpg)) + return PTR_ERR(tpg); + tpg->dev = dev; /* We get the physical display dimensions from the DT */ @@ -438,9 +440,6 @@ static int tpg110_probe(struct spi_device *spi) if (ret) return ret; - drm_panel_init(&tpg->panel, dev, &tpg110_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_of_backlight(&tpg->panel); if (ret) return ret; diff --git a/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c b/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c new file mode 100644 index 000000000000..413849f7b4de --- /dev/null +++ b/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2025, Alexander Baransky <sanyapilot496@gmail.com> + */ + +#include <linux/backlight.h> +#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> + +struct visionox_g2647fb105 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; +}; + +static const struct regulator_bulk_data visionox_g2647fb105_supplies[] = { + { .supply = "vdd3p3" }, + { .supply = "vddio" }, + { .supply = "vsn" }, + { .supply = "vsp" }, +}; + +static inline +struct visionox_g2647fb105 *to_visionox_g2647fb105(struct drm_panel *panel) +{ + return container_of(panel, struct visionox_g2647fb105, panel); +} + +static void visionox_g2647fb105_reset(struct visionox_g2647fb105 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int visionox_g2647fb105_on(struct visionox_g2647fb105 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x32); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x17); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbf, 0xbb); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xdd); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x24); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00); + + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 100); + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int visionox_g2647fb105_off(struct visionox_g2647fb105 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + + return dsi_ctx.accum_err; +} + +static int visionox_g2647fb105_prepare(struct drm_panel *panel) +{ + struct visionox_g2647fb105 *ctx = to_visionox_g2647fb105(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(visionox_g2647fb105_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + visionox_g2647fb105_reset(ctx); + + ret = visionox_g2647fb105_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + return ret; + } + + return 0; +} + +static int visionox_g2647fb105_unprepare(struct drm_panel *panel) +{ + struct visionox_g2647fb105 *ctx = to_visionox_g2647fb105(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = visionox_g2647fb105_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(visionox_g2647fb105_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode visionox_g2647fb105_mode = { + .clock = (1080 + 28 + 4 + 36) * (2340 + 8 + 4 + 4) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 28, + .hsync_end = 1080 + 28 + 4, + .htotal = 1080 + 28 + 4 + 36, + .vdisplay = 2340, + .vsync_start = 2340 + 8, + .vsync_end = 2340 + 8 + 4, + .vtotal = 2340 + 8 + 4 + 4, + .width_mm = 69, + .height_mm = 149, +}; + +static int visionox_g2647fb105_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &visionox_g2647fb105_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 = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs visionox_g2647fb105_panel_funcs = { + .prepare = visionox_g2647fb105_prepare, + .unprepare = visionox_g2647fb105_unprepare, + .get_modes = visionox_g2647fb105_get_modes, +}; + +static int visionox_g2647fb105_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static const struct backlight_ops visionox_g2647fb105_bl_ops = { + .update_status = visionox_g2647fb105_bl_update_status, +}; + +static struct backlight_device * +visionox_g2647fb105_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 1023, + .max_brightness = 2047, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &visionox_g2647fb105_bl_ops, &props); +} + +static int visionox_g2647fb105_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct visionox_g2647fb105 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(visionox_g2647fb105_supplies), + visionox_g2647fb105_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_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; + + ctx->panel.prepare_prev_first = true; + + drm_panel_init(&ctx->panel, dev, &visionox_g2647fb105_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = visionox_g2647fb105_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void visionox_g2647fb105_remove(struct mipi_dsi_device *dsi) +{ + struct visionox_g2647fb105 *ctx = mipi_dsi_get_drvdata(dsi); + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id visionox_g2647fb105_of_match[] = { + { .compatible = "visionox,g2647fb105" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, visionox_g2647fb105_of_match); + +static struct mipi_dsi_driver visionox_g2647fb105_driver = { + .probe = visionox_g2647fb105_probe, + .remove = visionox_g2647fb105_remove, + .driver = { + .name = "panel-visionox-g2647fb105", + .of_match_table = visionox_g2647fb105_of_match, + }, +}; +module_mipi_dsi_driver(visionox_g2647fb105_driver); + +MODULE_AUTHOR("Alexander Baransky <sanyapilot496@gmail.com>"); +MODULE_DESCRIPTION("DRM driver for Visionox G2647FB105 AMOLED DSI panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-visionox-r66451.c b/drivers/gpu/drm/panel/panel-visionox-r66451.c index 3ea0a86f6e69..690cccedd438 100644 --- a/drivers/gpu/drm/panel/panel-visionox-r66451.c +++ b/drivers/gpu/drm/panel/panel-visionox-r66451.c @@ -255,9 +255,11 @@ static int visionox_r66451_probe(struct mipi_dsi_device *dsi) struct drm_dsc_config *dsc; int ret = 0; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct visionox_r66451, panel, + &visionox_r66451_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); dsc = devm_kzalloc(dev, sizeof(*dsc), GFP_KERNEL); if (!dsc) @@ -297,7 +299,6 @@ static int visionox_r66451_probe(struct mipi_dsi_device *dsi) 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); if (IS_ERR(ctx->panel.backlight)) return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index be3a9797fbce..909c280eab1f 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -5,6 +5,7 @@ #include <linux/delay.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/mod_devicetable.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> @@ -15,11 +16,138 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> +struct visionox_rm69299_panel_desc { + const struct drm_display_mode *mode; + const u8 *init_seq; + unsigned int init_seq_len; +}; + struct visionox_rm69299 { struct drm_panel panel; - struct regulator_bulk_data supplies[2]; + struct regulator_bulk_data *supplies; struct gpio_desc *reset_gpio; struct mipi_dsi_device *dsi; + const struct visionox_rm69299_panel_desc *desc; +}; + +static const struct regulator_bulk_data visionox_rm69299_supplies[] = { + { .supply = "vdda", .init_load_uA = 32000 }, + { .supply = "vdd3p3", .init_load_uA = 13200 }, +}; + +static const u8 visionox_rm69299_1080x2248_60hz_init_seq[][2] = { + { 0xfe, 0x00 }, { 0xc2, 0x08 }, { 0x35, 0x00 }, { 0x51, 0xff }, +}; + +static const u8 visionox_rm69299_1080x2160_60hz_init_seq[][2] = { + { 0xfe, 0x40 }, { 0x05, 0x04 }, { 0x06, 0x08 }, { 0x08, 0x04 }, + { 0x09, 0x08 }, { 0x0a, 0x07 }, { 0x0b, 0xcc }, { 0x0c, 0x07 }, + { 0x0d, 0x90 }, { 0x0f, 0x87 }, { 0x20, 0x8d }, { 0x21, 0x8d }, + { 0x24, 0x05 }, { 0x26, 0x05 }, { 0x28, 0x05 }, { 0x2a, 0x05 }, + { 0x2d, 0x28 }, { 0x2f, 0x28 }, { 0x30, 0x32 }, { 0x31, 0x32 }, + { 0x37, 0x80 }, { 0x38, 0x30 }, { 0x39, 0xa8 }, { 0x46, 0x48 }, + { 0x47, 0x48 }, { 0x6b, 0x10 }, { 0x6f, 0x02 }, { 0x74, 0x2b }, + { 0x80, 0x1a }, { 0xfe, 0x40 }, { 0x93, 0x10 }, { 0x16, 0x00 }, + { 0x85, 0x07 }, { 0x84, 0x01 }, { 0x86, 0x0f }, { 0x87, 0x05 }, + { 0x8c, 0x00 }, { 0x88, 0x2e }, { 0x89, 0x2e }, { 0x8b, 0x09 }, + { 0x95, 0x00 }, { 0x91, 0x00 }, { 0x90, 0x00 }, { 0x8d, 0xd0 }, + { 0x8a, 0x03 }, { 0xfe, 0xa0 }, { 0x13, 0x00 }, { 0x33, 0x00 }, + { 0x0b, 0x33 }, { 0x36, 0x1e }, { 0x31, 0x88 }, { 0x32, 0x88 }, + { 0x37, 0xf1 }, { 0xfe, 0x50 }, { 0x00, 0x00 }, { 0x01, 0x00 }, + { 0x02, 0x00 }, { 0x03, 0xe9 }, { 0x04, 0x00 }, { 0x05, 0xf6 }, + { 0x06, 0x01 }, { 0x07, 0x2c }, { 0x08, 0x01 }, { 0x09, 0x62 }, + { 0x0a, 0x01 }, { 0x0b, 0x98 }, { 0x0c, 0x01 }, { 0x0d, 0xbf }, + { 0x0e, 0x01 }, { 0x0f, 0xf6 }, { 0x10, 0x02 }, { 0x11, 0x24 }, + { 0x12, 0x02 }, { 0x13, 0x4e }, { 0x14, 0x02 }, { 0x15, 0x70 }, + { 0x16, 0x02 }, { 0x17, 0xaf }, { 0x18, 0x02 }, { 0x19, 0xe2 }, + { 0x1a, 0x03 }, { 0x1b, 0x1f }, { 0x1c, 0x03 }, { 0x1d, 0x52 }, + { 0x1e, 0x03 }, { 0x1f, 0x82 }, { 0x20, 0x03 }, { 0x21, 0xb6 }, + { 0x22, 0x03 }, { 0x23, 0xf0 }, { 0x24, 0x04 }, { 0x25, 0x1f }, + { 0x26, 0x04 }, { 0x27, 0x37 }, { 0x28, 0x04 }, { 0x29, 0x59 }, + { 0x2a, 0x04 }, { 0x2b, 0x68 }, { 0x30, 0x04 }, { 0x31, 0x85 }, + { 0x32, 0x04 }, { 0x33, 0xa2 }, { 0x34, 0x04 }, { 0x35, 0xbc }, + { 0x36, 0x04 }, { 0x37, 0xd8 }, { 0x38, 0x04 }, { 0x39, 0xf4 }, + { 0x3a, 0x05 }, { 0x3b, 0x0e }, { 0x40, 0x05 }, { 0x41, 0x13 }, + { 0x42, 0x05 }, { 0x43, 0x1f }, { 0x44, 0x05 }, { 0x45, 0x1f }, + { 0x46, 0x00 }, { 0x47, 0x00 }, { 0x48, 0x01 }, { 0x49, 0x43 }, + { 0x4a, 0x01 }, { 0x4b, 0x4c }, { 0x4c, 0x01 }, { 0x4d, 0x6f }, + { 0x4e, 0x01 }, { 0x4f, 0x92 }, { 0x50, 0x01 }, { 0x51, 0xb5 }, + { 0x52, 0x01 }, { 0x53, 0xd4 }, { 0x58, 0x02 }, { 0x59, 0x06 }, + { 0x5a, 0x02 }, { 0x5b, 0x33 }, { 0x5c, 0x02 }, { 0x5d, 0x59 }, + { 0x5e, 0x02 }, { 0x5f, 0x7d }, { 0x60, 0x02 }, { 0x61, 0xbd }, + { 0x62, 0x02 }, { 0x63, 0xf7 }, { 0x64, 0x03 }, { 0x65, 0x31 }, + { 0x66, 0x03 }, { 0x67, 0x63 }, { 0x68, 0x03 }, { 0x69, 0x9d }, + { 0x6a, 0x03 }, { 0x6b, 0xd2 }, { 0x6c, 0x04 }, { 0x6d, 0x05 }, + { 0x6e, 0x04 }, { 0x6f, 0x38 }, { 0x70, 0x04 }, { 0x71, 0x51 }, + { 0x72, 0x04 }, { 0x73, 0x70 }, { 0x74, 0x04 }, { 0x75, 0x85 }, + { 0x76, 0x04 }, { 0x77, 0xa1 }, { 0x78, 0x04 }, { 0x79, 0xc0 }, + { 0x7a, 0x04 }, { 0x7b, 0xd8 }, { 0x7c, 0x04 }, { 0x7d, 0xf2 }, + { 0x7e, 0x05 }, { 0x7f, 0x10 }, { 0x80, 0x05 }, { 0x81, 0x21 }, + { 0x82, 0x05 }, { 0x83, 0x2e }, { 0x84, 0x05 }, { 0x85, 0x3a }, + { 0x86, 0x05 }, { 0x87, 0x3e }, { 0x88, 0x00 }, { 0x89, 0x00 }, + { 0x8a, 0x01 }, { 0x8b, 0x86 }, { 0x8c, 0x01 }, { 0x8d, 0x8f }, + { 0x8e, 0x01 }, { 0x8f, 0xb3 }, { 0x90, 0x01 }, { 0x91, 0xd7 }, + { 0x92, 0x01 }, { 0x93, 0xfb }, { 0x94, 0x02 }, { 0x95, 0x18 }, + { 0x96, 0x02 }, { 0x97, 0x4f }, { 0x98, 0x02 }, { 0x99, 0x7e }, + { 0x9a, 0x02 }, { 0x9b, 0xa6 }, { 0x9c, 0x02 }, { 0x9d, 0xcf }, + { 0x9e, 0x03 }, { 0x9f, 0x14 }, { 0xa4, 0x03 }, { 0xa5, 0x52 }, + { 0xa6, 0x03 }, { 0xa7, 0x93 }, { 0xac, 0x03 }, { 0xad, 0xcf }, + { 0xae, 0x04 }, { 0xaf, 0x08 }, { 0xb0, 0x04 }, { 0xb1, 0x42 }, + { 0xb2, 0x04 }, { 0xb3, 0x7f }, { 0xb4, 0x04 }, { 0xb5, 0xb4 }, + { 0xb6, 0x04 }, { 0xb7, 0xcc }, { 0xb8, 0x04 }, { 0xb9, 0xf2 }, + { 0xba, 0x05 }, { 0xbb, 0x0c }, { 0xbc, 0x05 }, { 0xbd, 0x26 }, + { 0xbe, 0x05 }, { 0xbf, 0x4b }, { 0xc0, 0x05 }, { 0xc1, 0x64 }, + { 0xc2, 0x05 }, { 0xc3, 0x83 }, { 0xc4, 0x05 }, { 0xc5, 0xa1 }, + { 0xc6, 0x05 }, { 0xc7, 0xba }, { 0xc8, 0x05 }, { 0xc9, 0xc4 }, + { 0xca, 0x05 }, { 0xcb, 0xd5 }, { 0xcc, 0x05 }, { 0xcd, 0xd5 }, + { 0xce, 0x00 }, { 0xcf, 0xce }, { 0xd0, 0x00 }, { 0xd1, 0xdb }, + { 0xd2, 0x01 }, { 0xd3, 0x32 }, { 0xd4, 0x01 }, { 0xd5, 0x3b }, + { 0xd6, 0x01 }, { 0xd7, 0x74 }, { 0xd8, 0x01 }, { 0xd9, 0x7d }, + { 0xfe, 0x60 }, { 0x00, 0xcc }, { 0x01, 0x0f }, { 0x02, 0xff }, + { 0x03, 0x01 }, { 0x04, 0x00 }, { 0x05, 0x02 }, { 0x06, 0x00 }, + { 0x07, 0x00 }, { 0x09, 0xc4 }, { 0x0a, 0x00 }, { 0x0b, 0x04 }, + { 0x0c, 0x01 }, { 0x0d, 0x00 }, { 0x0e, 0x04 }, { 0x0f, 0x00 }, + { 0x10, 0x71 }, { 0x12, 0xc4 }, { 0x13, 0x00 }, { 0x14, 0x04 }, + { 0x15, 0x01 }, { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, + { 0x19, 0x71 }, { 0x1b, 0xc4 }, { 0x1c, 0x00 }, { 0x1d, 0x02 }, + { 0x1e, 0x00 }, { 0x1f, 0x00 }, { 0x20, 0x08 }, { 0x21, 0x66 }, + { 0x22, 0xb4 }, { 0x24, 0xc4 }, { 0x25, 0x00 }, { 0x26, 0x02 }, + { 0x27, 0x00 }, { 0x28, 0x00 }, { 0x29, 0x07 }, { 0x2a, 0x66 }, + { 0x2b, 0xb4 }, { 0x2f, 0xc4 }, { 0x30, 0x00 }, { 0x31, 0x04 }, + { 0x32, 0x01 }, { 0x33, 0x00 }, { 0x34, 0x03 }, { 0x35, 0x00 }, + { 0x36, 0x71 }, { 0x38, 0xc4 }, { 0x39, 0x00 }, { 0x3a, 0x04 }, + { 0x3b, 0x01 }, { 0x3d, 0x00 }, { 0x3f, 0x05 }, { 0x40, 0x00 }, + { 0x41, 0x71 }, { 0x83, 0xce }, { 0x84, 0x02 }, { 0x85, 0x20 }, + { 0x86, 0xdc }, { 0x87, 0x00 }, { 0x88, 0x04 }, { 0x89, 0x00 }, + { 0x8a, 0xbb }, { 0x8b, 0x80 }, { 0xc7, 0x0e }, { 0xc8, 0x05 }, + { 0xc9, 0x1f }, { 0xca, 0x06 }, { 0xcb, 0x00 }, { 0xcc, 0x03 }, + { 0xcd, 0x04 }, { 0xce, 0x1f }, { 0xcf, 0x1f }, { 0xd0, 0x1f }, + { 0xd1, 0x1f }, { 0xd2, 0x1f }, { 0xd3, 0x1f }, { 0xd4, 0x1f }, + { 0xd5, 0x1f }, { 0xd6, 0x1f }, { 0xd7, 0x17 }, { 0xd8, 0x1f }, + { 0xd9, 0x16 }, { 0xda, 0x1f }, { 0xdb, 0x0e }, { 0xdc, 0x01 }, + { 0xdd, 0x1f }, { 0xde, 0x02 }, { 0xdf, 0x00 }, { 0xe0, 0x03 }, + { 0xe1, 0x04 }, { 0xe2, 0x1f }, { 0xe3, 0x1f }, { 0xe4, 0x1f }, + { 0xe5, 0x1f }, { 0xe6, 0x1f }, { 0xe7, 0x1f }, { 0xe8, 0x1f }, + { 0xe9, 0x1f }, { 0xea, 0x1f }, { 0xeb, 0x17 }, { 0xec, 0x1f }, + { 0xed, 0x16 }, { 0xee, 0x1f }, { 0xef, 0x03 }, { 0xfe, 0x70 }, + { 0x5a, 0x0b }, { 0x5b, 0x0b }, { 0x5c, 0x55 }, { 0x5d, 0x24 }, + { 0xfe, 0x90 }, { 0x12, 0x24 }, { 0x13, 0x49 }, { 0x14, 0x92 }, + { 0x15, 0x86 }, { 0x16, 0x61 }, { 0x17, 0x18 }, { 0x18, 0x24 }, + { 0x19, 0x49 }, { 0x1a, 0x92 }, { 0x1b, 0x86 }, { 0x1c, 0x61 }, + { 0x1d, 0x18 }, { 0x1e, 0x24 }, { 0x1f, 0x49 }, { 0x20, 0x92 }, + { 0x21, 0x86 }, { 0x22, 0x61 }, { 0x23, 0x18 }, { 0xfe, 0x40 }, + { 0x0e, 0x10 }, { 0xfe, 0xa0 }, { 0x04, 0x80 }, { 0x16, 0x00 }, + { 0x26, 0x10 }, { 0x2f, 0x37 }, { 0xfe, 0xd0 }, { 0x06, 0x0f }, + { 0x4b, 0x00 }, { 0x56, 0x4a }, { 0xfe, 0x00 }, { 0xc2, 0x09 }, + { 0x35, 0x00 }, { 0xfe, 0x70 }, { 0x7d, 0x61 }, { 0x7f, 0x00 }, + { 0x7e, 0x4e }, { 0x52, 0x2c }, { 0x49, 0x00 }, { 0x4a, 0x00 }, + { 0x4b, 0x00 }, { 0x4c, 0x00 }, { 0x4d, 0xe8 }, { 0x4e, 0x25 }, + { 0x4f, 0x6e }, { 0x50, 0xae }, { 0x51, 0x2f }, { 0xad, 0xf4 }, + { 0xae, 0x8f }, { 0xaf, 0x00 }, { 0xb0, 0x54 }, { 0xb1, 0x3a }, + { 0xb2, 0x00 }, { 0xb3, 0x00 }, { 0xb4, 0x00 }, { 0xb5, 0x00 }, + { 0xb6, 0x18 }, { 0xb7, 0x30 }, { 0xb8, 0x4a }, { 0xb9, 0x98 }, + { 0xba, 0x30 }, { 0xbb, 0x60 }, { 0xbc, 0x50 }, { 0xbd, 0x00 }, + { 0xbe, 0x00 }, { 0xbf, 0x39 }, { 0xfe, 0x00 }, { 0x51, 0x66 }, }; static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel) @@ -31,7 +159,8 @@ static int visionox_rm69299_power_on(struct visionox_rm69299 *ctx) { int ret; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + ret = regulator_bulk_enable(ARRAY_SIZE(visionox_rm69299_supplies), + ctx->supplies); if (ret < 0) return ret; @@ -54,37 +183,32 @@ static int visionox_rm69299_power_off(struct visionox_rm69299 *ctx) { gpiod_set_value(ctx->reset_gpio, 0); - return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + return regulator_bulk_disable(ARRAY_SIZE(visionox_rm69299_supplies), + ctx->supplies); } static int visionox_rm69299_unprepare(struct drm_panel *panel) { struct visionox_rm69299 *ctx = panel_to_ctx(panel); - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; ctx->dsi->mode_flags = 0; - ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); - if (ret < 0) - dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); /* 120ms delay required here as per DCS spec */ - msleep(120); - - ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); - if (ret < 0) { - dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret); - } + mipi_dsi_msleep(&dsi_ctx, 120); - ret = visionox_rm69299_power_off(ctx); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); - return ret; + return visionox_rm69299_power_off(ctx); } static int visionox_rm69299_prepare(struct drm_panel *panel) { struct visionox_rm69299 *ctx = panel_to_ctx(panel); - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + int ret, i; ret = visionox_rm69299_power_on(ctx); if (ret < 0) @@ -92,52 +216,20 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); - if (ret < 0) { - dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret); - goto power_off; - } - - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); - if (ret < 0) { - dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret); - goto power_off; - } + for (i = 0; i < ctx->desc->init_seq_len; i++) + mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, &ctx->desc->init_seq[i * 2], 2); - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); - if (ret < 0) { - dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret); - goto power_off; - } - - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); - if (ret < 0) { - dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret); - goto power_off; - } - - ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); - if (ret < 0) { - dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret); - goto power_off; - } + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); /* Per DSI spec wait 120ms after sending exit sleep DCS command */ - msleep(120); + mipi_dsi_msleep(&dsi_ctx, 120); - ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); - if (ret < 0) { - dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret); - goto power_off; - } + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); /* Per DSI spec wait 120ms after sending set_display_on DCS command */ - msleep(120); + mipi_dsi_msleep(&dsi_ctx, 120); - return 0; - -power_off: - return ret; + return dsi_ctx.accum_err; } static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = { @@ -154,14 +246,26 @@ static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = { .flags = 0, }; +static const struct drm_display_mode visionox_rm69299_1080x2160_60hz = { + .clock = 158695, + .hdisplay = 1080, + .hsync_start = 1080 + 26, + .hsync_end = 1080 + 26 + 2, + .htotal = 1080 + 26 + 2 + 36, + .vdisplay = 2160, + .vsync_start = 2160 + 8, + .vsync_end = 2160 + 8 + 4, + .vtotal = 2160 + 8 + 4 + 4, + .flags = 0, +}; + static int visionox_rm69299_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct visionox_rm69299 *ctx = panel_to_ctx(panel); struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, - &visionox_rm69299_1080x2248_60hz); + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); if (!mode) { dev_err(ctx->panel.dev, "failed to create a new display mode\n"); return 0; @@ -187,20 +291,22 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) struct visionox_rm69299 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct visionox_rm69299, panel, + &visionox_rm69299_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->desc = device_get_match_data(dev); + if (!ctx->desc) + return -EINVAL; mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; - ctx->supplies[0].supply = "vdda"; - ctx->supplies[0].init_load_uA = 32000; - ctx->supplies[1].supply = "vdd3p3"; - ctx->supplies[1].init_load_uA = 13200; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies); + ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(visionox_rm69299_supplies), + visionox_rm69299_supplies, &ctx->supplies); if (ret < 0) return ret; @@ -210,8 +316,6 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) return PTR_ERR(ctx->reset_gpio); } - drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs, - DRM_MODE_CONNECTOR_DSI); drm_panel_add(&ctx->panel); dsi->lanes = 4; @@ -239,8 +343,23 @@ static void visionox_rm69299_remove(struct mipi_dsi_device *dsi) drm_panel_remove(&ctx->panel); } +const struct visionox_rm69299_panel_desc visionox_rm69299_1080p_display_desc = { + .mode = &visionox_rm69299_1080x2248_60hz, + .init_seq = (const u8 *)visionox_rm69299_1080x2248_60hz_init_seq, + .init_seq_len = ARRAY_SIZE(visionox_rm69299_1080x2248_60hz_init_seq), +}; + +const struct visionox_rm69299_panel_desc visionox_rm69299_shift_desc = { + .mode = &visionox_rm69299_1080x2160_60hz, + .init_seq = (const u8 *)visionox_rm69299_1080x2160_60hz_init_seq, + .init_seq_len = ARRAY_SIZE(visionox_rm69299_1080x2160_60hz_init_seq), +}; + static const struct of_device_id visionox_rm69299_of_match[] = { - { .compatible = "visionox,rm69299-1080p-display", }, + { .compatible = "visionox,rm69299-1080p-display", + .data = &visionox_rm69299_1080p_display_desc }, + { .compatible = "visionox,rm69299-shift", + .data = &visionox_rm69299_shift_desc }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match); diff --git a/drivers/gpu/drm/panel/panel-visionox-rm692e5.c b/drivers/gpu/drm/panel/panel-visionox-rm692e5.c index 4db7fa8d74c4..e53645d59413 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm692e5.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm692e5.c @@ -360,9 +360,11 @@ static int visionox_rm692e5_probe(struct mipi_dsi_device *dsi) struct visionox_rm692e5 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct visionox_rm692e5, panel, + &visionox_rm692e5_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(&dsi->dev, ARRAY_SIZE(visionox_rm692e5_supplies), @@ -383,8 +385,6 @@ static int visionox_rm692e5_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; - drm_panel_init(&ctx->panel, dev, &visionox_rm692e5_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = visionox_rm692e5_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c index 17b8defe79c1..97a79411e1ec 100644 --- a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c +++ b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c @@ -248,9 +248,11 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi) struct visionox_vtdr6130 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct visionox_vtdr6130, panel, + &visionox_vtdr6130_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(&dsi->dev, ARRAY_SIZE(visionox_vtdr6130_supplies), @@ -273,9 +275,6 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi) 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); - ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi); if (IS_ERR(ctx->panel.backlight)) return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), diff --git a/drivers/gpu/drm/panel/panel-widechips-ws2401.c b/drivers/gpu/drm/panel/panel-widechips-ws2401.c index 2591ff8f0d4e..dd74610bd2eb 100644 --- a/drivers/gpu/drm/panel/panel-widechips-ws2401.c +++ b/drivers/gpu/drm/panel/panel-widechips-ws2401.c @@ -347,9 +347,11 @@ static int ws2401_probe(struct spi_device *spi) struct ws2401 *ws; int ret; - ws = devm_kzalloc(dev, sizeof(*ws), GFP_KERNEL); - if (!ws) - return -ENOMEM; + ws = devm_drm_panel_alloc(dev, struct ws2401, panel, &ws2401_drm_funcs, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(ws)) + return PTR_ERR(ws); + ws->dev = dev; /* @@ -379,9 +381,6 @@ static int ws2401_probe(struct spi_device *spi) ws2401_read_mtp_id(ws); ws2401_power_off(ws); - drm_panel_init(&ws->panel, dev, &ws2401_drm_funcs, - DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_of_backlight(&ws->panel); if (ret) return dev_err_probe(dev, ret, diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c index 2b91414c2829..fc6516373b5d 100644 --- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -241,9 +241,10 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) struct xpp055c272 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, struct xpp055c272, panel, + &xpp055c272_funcs, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) @@ -269,9 +270,6 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs, - DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return ret; |