]> Gentwo Git Trees - linux/.git/commitdiff
gpu/drm: panel: add support for LG LD070WX3-SL01 MIPI DSI panel
authorSvyatoslav Ryhel <clamor95@gmail.com>
Mon, 10 Nov 2025 09:14:32 +0000 (11:14 +0200)
committerNeil Armstrong <neil.armstrong@linaro.org>
Wed, 19 Nov 2025 16:07:51 +0000 (17:07 +0100)
The LD070WX3 is a Color Active Matrix Liquid Crystal Display with an
integral Light Emitting Diode (LED) backlight system. The matrix employs
a-Si Thin Film Transistor as the active element. It is a transmissive type
display operating in the normally Black mode. This TFT-LCD has 7.0 inches
diagonally measured active display area with WXGA resolution (800 by 1280
pixel array).

LG LD070WX3-SL01 MIPI DSI panel was treated as simple DSI panel when it is
actually not and requires proper setup for correct work. Simple panel work
relied on preliminary configuration done by bootloader.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20251110091440.5251-3-clamor95@gmail.com
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-lg-ld070wx3.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c

index ad54537d914a44f3749aa98a2ba4a7148893e5a8..cab42c1474d145f8bbdf5dbc751747468102ffc0 100644 (file)
@@ -408,6 +408,19 @@ config DRM_PANEL_LG_LB035Q02
          (found on the Gumstix Overo Palo35 board). To compile this driver as
          a module, choose M here.
 
+config DRM_PANEL_LG_LD070WX3
+       tristate "LG LD070WX3 MIPI DSI panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       select VIDEOMODE_HELPERS
+       help
+         Say Y here if you want to enable support for the LD070WX3 MIPI DSI
+         panel found in the NVIDIA Tegra Note 7 tablet.
+
+         To compile this driver as a module, choose M here: the module will
+         be called panel-lg-ld070wx3.
+
 config DRM_PANEL_LG_LG4573
        tristate "LG4573 RGB/SPI panel"
        depends on OF && SPI
index 4c4b6b4aefd079b2382c4b5fd42da527acc0a355..b9562a6fdcb38bfd0dfee9e8c11e16149ada4386 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
 obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
 obj-$(CONFIG_DRM_PANEL_LINCOLNTECH_LCD197) += panel-lincolntech-lcd197.o
 obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
+obj-$(CONFIG_DRM_PANEL_LG_LD070WX3) += panel-lg-ld070wx3.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
 obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
 obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
diff --git a/drivers/gpu/drm/panel/panel-lg-ld070wx3.c b/drivers/gpu/drm/panel/panel-lg-ld070wx3.c
new file mode 100644 (file)
index 0000000..00cbfc5
--- /dev/null
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#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>
+#include <drm/drm_probe_helper.h>
+
+static const struct regulator_bulk_data lg_ld070wx3_supplies[] = {
+       { .supply = "vdd" }, { .supply = "vcc" },
+};
+
+struct lg_ld070wx3 {
+       struct drm_panel panel;
+       struct mipi_dsi_device *dsi;
+
+       struct regulator_bulk_data *supplies;
+};
+
+static inline struct lg_ld070wx3 *to_lg_ld070wx3(struct drm_panel *panel)
+{
+       return container_of(panel, struct lg_ld070wx3, panel);
+}
+
+static int lg_ld070wx3_prepare(struct drm_panel *panel)
+{
+       struct lg_ld070wx3 *priv = to_lg_ld070wx3(panel);
+       struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
+       struct device *dev = panel->dev;
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(lg_ld070wx3_supplies), priv->supplies);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable power supplies: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * According to spec delay between enabling supply is 0,
+        * for regulators to reach required voltage ~5ms needed.
+        * MIPI interface signal for setup requires additional
+        * 110ms which in total results in 115ms.
+        */
+       mdelay(115);
+
+       mipi_dsi_dcs_soft_reset_multi(&ctx);
+       mipi_dsi_msleep(&ctx, 20);
+
+       /* Differential input impedance selection */
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xae, 0x0b);
+
+       /* Enter test mode 1 and 2*/
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xee, 0xea);
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xef, 0x5f);
+
+       /* Increased MIPI CLK driving ability */
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xf2, 0x68);
+
+       /* Exit test mode 1 and 2 */
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xee, 0x00);
+       mipi_dsi_dcs_write_seq_multi(&ctx, 0xef, 0x00);
+
+       return ctx.accum_err;
+}
+
+static int lg_ld070wx3_unprepare(struct drm_panel *panel)
+{
+       struct lg_ld070wx3 *priv = to_lg_ld070wx3(panel);
+       struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
+
+       mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
+
+       msleep(50);
+
+       regulator_bulk_disable(ARRAY_SIZE(lg_ld070wx3_supplies), priv->supplies);
+
+       /* power supply must be off for at least 1s after panel disable */
+       msleep(1000);
+
+       return 0;
+}
+
+static const struct drm_display_mode lg_ld070wx3_mode = {
+       .clock = (800 + 32 + 48 + 8) * (1280 + 5 + 3 + 1) * 60 / 1000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 32,
+       .hsync_end = 800 + 32 + 48,
+       .htotal = 800 + 32 + 48 + 8,
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 5,
+       .vsync_end = 1280 + 5 + 3,
+       .vtotal = 1280 + 5 + 3 + 1,
+       .width_mm = 94,
+       .height_mm = 151,
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int lg_ld070wx3_get_modes(struct drm_panel *panel,
+                                struct drm_connector *connector)
+{
+       return drm_connector_helper_get_modes_fixed(connector, &lg_ld070wx3_mode);
+}
+
+static const struct drm_panel_funcs lg_ld070wx3_panel_funcs = {
+       .prepare = lg_ld070wx3_prepare,
+       .unprepare = lg_ld070wx3_unprepare,
+       .get_modes = lg_ld070wx3_get_modes,
+};
+
+static int lg_ld070wx3_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct lg_ld070wx3 *priv;
+       int ret;
+
+       priv = devm_drm_panel_alloc(dev, struct lg_ld070wx3, panel,
+                                   &lg_ld070wx3_panel_funcs,
+                                   DRM_MODE_CONNECTOR_DSI);
+       if (IS_ERR(priv))
+               return PTR_ERR(priv);
+
+       ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(lg_ld070wx3_supplies),
+                                           lg_ld070wx3_supplies, &priv->supplies);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "failed to get supplies\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_LPM;
+
+       ret = drm_panel_of_backlight(&priv->panel);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "failed to get backlight\n");
+
+       drm_panel_add(&priv->panel);
+
+       ret = devm_mipi_dsi_attach(dev, dsi);
+       if (ret < 0) {
+               drm_panel_remove(&priv->panel);
+               return dev_err_probe(dev, ret, "failed to attach to DSI host\n");
+       }
+
+       return 0;
+}
+
+static void lg_ld070wx3_remove(struct mipi_dsi_device *dsi)
+{
+       struct lg_ld070wx3 *priv = mipi_dsi_get_drvdata(dsi);
+
+       drm_panel_remove(&priv->panel);
+}
+
+static const struct of_device_id lg_ld070wx3_of_match[] = {
+       { .compatible = "lg,ld070wx3-sl01" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lg_ld070wx3_of_match);
+
+static struct mipi_dsi_driver lg_ld070wx3_driver = {
+       .driver = {
+               .name = "panel-lg-ld070wx3",
+               .of_match_table = lg_ld070wx3_of_match,
+       },
+       .probe = lg_ld070wx3_probe,
+       .remove = lg_ld070wx3_remove,
+};
+module_mipi_dsi_driver(lg_ld070wx3_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("LG LD070WX3-SL01 DSI panel driver");
+MODULE_LICENSE("GPL");
index da6b71b70a463400fcc45006788f87e97b0c148c..6369e582818907252305cdbdab8ed70ef1807b5e 100644 (file)
@@ -5600,34 +5600,6 @@ static const struct panel_desc_dsi boe_tv080wum_nl0 = {
        .lanes = 4,
 };
 
-static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
-       .clock = 71000,
-       .hdisplay = 800,
-       .hsync_start = 800 + 32,
-       .hsync_end = 800 + 32 + 1,
-       .htotal = 800 + 32 + 1 + 57,
-       .vdisplay = 1280,
-       .vsync_start = 1280 + 28,
-       .vsync_end = 1280 + 28 + 1,
-       .vtotal = 1280 + 28 + 1 + 14,
-};
-
-static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
-       .desc = {
-               .modes = &lg_ld070wx3_sl01_mode,
-               .num_modes = 1,
-               .bpc = 8,
-               .size = {
-                       .width = 94,
-                       .height = 151,
-               },
-               .connector_type = DRM_MODE_CONNECTOR_DSI,
-       },
-       .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS,
-       .format = MIPI_DSI_FMT_RGB888,
-       .lanes = 4,
-};
-
 static const struct drm_display_mode lg_lh500wx1_sd03_mode = {
        .clock = 67000,
        .hdisplay = 720,
@@ -5751,9 +5723,6 @@ static const struct of_device_id dsi_of_match[] = {
        }, {
                .compatible = "boe,tv080wum-nl0",
                .data = &boe_tv080wum_nl0
-       }, {
-               .compatible = "lg,ld070wx3-sl01",
-               .data = &lg_ld070wx3_sl01
        }, {
                .compatible = "lg,lh500wx1-sd03",
                .data = &lg_lh500wx1_sd03