drm/panel: add panel-dsi
authorTimon Skerutsch <kernel@diodes-delight.com>
Mon, 13 Nov 2023 21:53:12 +0000 (22:53 +0100)
committerDom Cobley <popcornmix@gmail.com>
Mon, 19 Feb 2024 11:35:18 +0000 (11:35 +0000)
Equivalent to panel-dpi for configuring a simple DSI panel with
device tree side timings and bus settings.
Motiviation is the same as for panel-dpi of wanting to support
new simple panels without needing to patch the kernel.

Signed-off-by: Timon Skerutsch <kernel@diodes-delight.com>
drivers/gpu/drm/panel/panel-simple.c

index a1cf057..035ee7a 100644 (file)
@@ -40,6 +40,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
+#include <drm/drm_of.h>
 
 /**
  * struct panel_desc - Describes a simple panel.
@@ -4857,6 +4858,9 @@ static const struct panel_desc_dsi osd101t2045_53ts = {
        .lanes = 4,
 };
 
+// for panels using generic panel-dsi binding
+static struct panel_desc_dsi panel_dsi;
+
 static const struct of_device_id dsi_of_match[] = {
        {
                .compatible = "auo,b080uan01",
@@ -4880,20 +4884,137 @@ static const struct of_device_id dsi_of_match[] = {
                .compatible = "osddisplays,osd101t2045-53ts",
                .data = &osd101t2045_53ts
        }, {
+               /* Must be the last entry */
+               .compatible = "panel-dsi",
+               .data = &panel_dsi,
+       }, {
                /* sentinel */
        }
 };
 MODULE_DEVICE_TABLE(of, dsi_of_match);
 
+
+/* Checks for DSI panel definition in device-tree, analog to panel_dpi */
+static int panel_dsi_dt_probe(struct device *dev,
+                         struct panel_desc_dsi *desc_dsi)
+{
+       struct panel_desc *desc;
+       struct display_timing *timing;
+       const struct device_node *np;
+       const char *dsi_color_format;
+       const char *dsi_mode_flags;
+       struct property *prop;
+       int dsi_lanes, ret;
+
+       np = dev->of_node;
+
+       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+
+       timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL);
+       if (!timing)
+               return -ENOMEM;
+
+       ret = of_get_display_timing(np, "panel-timing", timing);
+       if (ret < 0) {
+               dev_err(dev, "%pOF: no panel-timing node found for \"panel-dsi\" binding\n",
+                       np);
+               return ret;
+       }
+
+       desc->timings = timing;
+       desc->num_timings = 1;
+
+       of_property_read_u32(np, "width-mm", &desc->size.width);
+       of_property_read_u32(np, "height-mm", &desc->size.height);
+
+       dsi_lanes = drm_of_get_data_lanes_count_ep(np, 0, 0, 1, 4);
+
+       if (dsi_lanes < 0) {
+               dev_err(dev, "%pOF: no or too many data-lanes defined", np);
+               return dsi_lanes;
+       }
+
+       desc_dsi->lanes = dsi_lanes;
+
+       of_property_read_string(np, "dsi-color-format", &dsi_color_format);
+       if (!strcmp(dsi_color_format, "RGB888")) {
+               desc_dsi->format = MIPI_DSI_FMT_RGB888;
+               desc->bpc = 8;
+       } else if (!strcmp(dsi_color_format, "RGB565")) {
+               desc_dsi->format = MIPI_DSI_FMT_RGB565;
+               desc->bpc = 6;
+       } else if (!strcmp(dsi_color_format, "RGB666")) {
+               desc_dsi->format = MIPI_DSI_FMT_RGB666;
+               desc->bpc = 6;
+       } else if (!strcmp(dsi_color_format, "RGB666_PACKED")) {
+               desc_dsi->format = MIPI_DSI_FMT_RGB666_PACKED;
+               desc->bpc = 6;
+       } else {
+               dev_err(dev, "%pOF: no valid dsi-color-format defined", np);
+               return -EINVAL;
+       }
+
+
+       of_property_for_each_string(np, "mode", prop, dsi_mode_flags) {
+               if (!strcmp(dsi_mode_flags, "MODE_VIDEO"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_BURST"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_BURST;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_SYNC_PULSE"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_AUTO_VERT"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_AUTO_VERT;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_HSE"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_HSE;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HFP"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HFP;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HBP"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HBP;
+               else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HSA"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HSA;
+               else if (!strcmp(dsi_mode_flags, "MODE_VSYNC_FLUSH"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_VSYNC_FLUSH;
+               else if (!strcmp(dsi_mode_flags, "MODE_NO_EOT_PACKET"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_NO_EOT_PACKET;
+               else if (!strcmp(dsi_mode_flags, "CLOCK_NON_CONTINUOUS"))
+                       desc_dsi->flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
+               else if (!strcmp(dsi_mode_flags, "MODE_LPM"))
+                       desc_dsi->flags |= MIPI_DSI_MODE_LPM;
+               else if (!strcmp(dsi_mode_flags, "HS_PKT_END_ALIGNED"))
+                       desc_dsi->flags |= MIPI_DSI_HS_PKT_END_ALIGNED;
+       }
+
+       desc->connector_type = DRM_MODE_CONNECTOR_DSI;
+       desc_dsi->desc = *desc;
+
+       return 0;
+}
+
 static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
 {
        const struct panel_desc_dsi *desc;
+       struct panel_desc_dsi *dt_desc;
        int err;
 
        desc = of_device_get_match_data(&dsi->dev);
        if (!desc)
                return -ENODEV;
 
+       if (desc == &panel_dsi) {
+               /* Handle the generic panel-dsi binding */
+               dt_desc = devm_kzalloc(&dsi->dev, sizeof(*dt_desc), GFP_KERNEL);
+               if (!dt_desc)
+                       return -ENOMEM;
+
+               err = panel_dsi_dt_probe(&dsi->dev, dt_desc);
+               if (err < 0)
+                       return err;
+
+               desc = dt_desc;
+       }
+
        err = panel_simple_probe(&dsi->dev, &desc->desc);
        if (err < 0)
                return err;