Many panel data sheets additionally to typical values list allowed ranges for
timings such as hsync/vsync lengths, porches, and the pixel clock rate. This
patch allows simple panels to store a struct display_timing in place of the
struct drm_display_mode used before.
The get_modes panel_ops callback calculates the drm_display_mode list from
the typical timings and the get_timings callback returns the timings to
the connected encoder for mode fixup and validation.

Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
 drivers/gpu/drm/panel/panel-simple.c | 40 ++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index c4b6167..895af09 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -33,9 +33,14 @@
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>

+#include <video/display_timing.h>
+#include <video/videomode.h>
+
 struct panel_desc {
        const struct drm_display_mode *modes;
        unsigned int num_modes;
+       const struct display_timing *timings;
+       unsigned int num_timings;

        unsigned int bpc;

@@ -92,6 +97,25 @@ static int panel_simple_get_fixed_modes(struct panel_simple 
*panel)
        if (!panel->desc)
                return 0;

+       for (i = 0; i < panel->desc->num_timings; i++) {
+               const struct display_timing *dt = &panel->desc->timings[i];
+               struct videomode vm;
+
+               videomode_from_timing(dt, &vm);
+               mode = drm_mode_create(drm);
+               if (!mode) {
+                       dev_err(drm->dev, "failed to add mode %ux%u\n",
+                               dt->hactive.typ, dt->vactive.typ);
+                       continue;
+               }
+
+               drm_display_mode_from_videomode(&vm, mode);
+               drm_mode_set_name(mode);
+
+               drm_mode_probed_add(connector, mode);
+               num++;
+       }
+
        for (i = 0; i < panel->desc->num_modes; i++) {
                const struct drm_display_mode *m = &panel->desc->modes[i];

@@ -221,12 +245,28 @@ static int panel_simple_get_modes(struct drm_panel *panel)
        return num;
 }

+static int panel_simple_get_timings(struct drm_panel *panel,
+                                   unsigned int num_timings,
+                                   struct display_timing *timings)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+       int i;
+
+       if (timings) {
+               for (i = 0; i < min(num_timings, p->desc->num_timings); i++)
+                       timings[i] = p->desc->timings[i];
+       }
+
+       return p->desc->num_timings;
+}
+
 static const struct drm_panel_funcs panel_simple_funcs = {
        .disable = panel_simple_disable,
        .unprepare = panel_simple_unprepare,
        .prepare = panel_simple_prepare,
        .enable = panel_simple_enable,
        .get_modes = panel_simple_get_modes,
+       .get_timings = panel_simple_get_timings,
 };

 static int panel_simple_probe(struct device *dev, const struct panel_desc 
*desc)
-- 
2.1.3

Reply via email to