From 0a0084b8621682ad96d001e798aa239b11a3cf00 Mon Sep 17 00:00:00 2001 From: Timon Skerutsch Date: Mon, 13 Nov 2023 22:53:12 +0100 Subject: [PATCH] drm/panel: add panel-dsi 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 --- drivers/gpu/drm/panel/panel-simple.c | 123 ++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -40,6 +40,7 @@ #include #include #include +#include /** * struct panel_desc - Describes a simple panel. @@ -4662,6 +4663,9 @@ static const struct panel_desc_dsi osd10 .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", @@ -4685,14 +4689,118 @@ static const struct of_device_id dsi_of_ .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; const struct of_device_id *id; int err; @@ -4700,7 +4808,20 @@ static int panel_simple_dsi_probe(struct if (!id) return -ENODEV; - desc = id->data; + if (id->data == &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; + } else { + desc = id->data; + } err = panel_simple_probe(&dsi->dev, &desc->desc); if (err < 0)