drm/panel: simple: Add display timing support
authorPhilipp Zabel <p.zabel@pengutronix.de>
Thu, 11 Dec 2014 17:32:45 +0000 (18:32 +0100)
committerThierry Reding <treding@nvidia.com>
Thu, 2 Apr 2015 17:04:13 +0000 (19:04 +0200)
The simple panel driver's ->get_modes() implementation calculates the
display mode list from the typical timings and the ->get_timings()
implementation returns the timings to the connected encoder for mode
validation and fixup.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
[treding@nvidia.com: select VIDEOMODE_HELPERS]
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/panel-simple.c

index d845837..6d64c7b 100644 (file)
@@ -11,6 +11,7 @@ config DRM_PANEL_SIMPLE
        tristate "support for simple panels"
        depends on OF
        depends on BACKLIGHT_CLASS_DEVICE
+       select VIDEOMODE_HELPERS
        help
          DRM panel driver for dumb panels that need at most a regulator and
          a GPIO to be powered up. Optionally a backlight can be attached so
index d9491bc..be2c4c8 100644 (file)
 #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;
 
@@ -94,6 +99,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];
 
@@ -226,12 +250,30 @@ 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);
+       unsigned int i;
+
+       if (p->desc->num_timings < num_timings)
+               num_timings = p->desc->num_timings;
+
+       if (timings)
+               for (i = 0; i < 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)