drm/edid: Generate modes from extra_modes for range descriptors
authorAdam Jackson <ajax@redhat.com>
Fri, 13 Apr 2012 20:33:40 +0000 (16:33 -0400)
committerDave Airlie <airlied@redhat.com>
Fri, 20 Apr 2012 11:57:56 +0000 (12:57 +0100)
Signed-off-by: Adam Jackson <ajax@redhat.com>
Tested-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_edid.c

index 9363349fa0341fb1f6e946ef7110b8e4a4bc7719..38ee2f22304cfa7b8d152fbd4008fd86073231b9 100644 (file)
@@ -1037,11 +1037,61 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
        return modes;
 }
 
+static int
+drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+                       struct detailed_timing *timing)
+{
+       int i, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+
+       for (i = 0; i < num_extra_modes; i++) {
+               const struct minimode *m = &extra_modes[i];
+               newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0);
+
+               if (!mode_in_range(newmode, edid, timing)) {
+                       drm_mode_destroy(dev, newmode);
+                       continue;
+               }
+
+               drm_mode_probed_add(connector, newmode);
+               modes++;
+       }
+
+       return modes;
+}
+
+static int
+drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
+                       struct detailed_timing *timing)
+{
+       int i, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+       bool rb = drm_monitor_supports_rb(edid);
+
+       for (i = 0; i < num_extra_modes; i++) {
+               const struct minimode *m = &extra_modes[i];
+               newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0);
+
+               if (!mode_in_range(newmode, edid, timing)) {
+                       drm_mode_destroy(dev, newmode);
+                       continue;
+               }
+
+               drm_mode_probed_add(connector, newmode);
+               modes++;
+       }
+
+       return modes;
+}
+
 static void
 do_inferred_modes(struct detailed_timing *timing, void *c)
 {
        struct detailed_mode_closure *closure = c;
        struct detailed_non_pixel *data = &timing->data.other_data;
+       struct detailed_data_monitor_range *range = &data->data.range;
 
        if (data->type != EDID_DETAIL_MONITOR_RANGE)
                return;
@@ -1049,6 +1099,29 @@ do_inferred_modes(struct detailed_timing *timing, void *c)
        closure->modes += drm_dmt_modes_for_range(closure->connector,
                                                  closure->edid,
                                                  timing);
+       
+       if (!version_greater(closure->edid, 1, 1))
+               return; /* GTF not defined yet */
+
+       switch (range->flags) {
+       case 0x02: /* secondary gtf, XXX could do more */
+       case 0x00: /* default gtf */
+               closure->modes += drm_gtf_modes_for_range(closure->connector,
+                                                         closure->edid,
+                                                         timing);
+               break;
+       case 0x04: /* cvt, only in 1.4+ */
+               if (!version_greater(closure->edid, 1, 3))
+                       break;
+
+               closure->modes += drm_cvt_modes_for_range(closure->connector,
+                                                         closure->edid,
+                                                         timing);
+               break;
+       case 0x01: /* just the ranges, no formula */
+       default:
+               break;
+       }
 }
 
 static int