Patchwork [05/10] drm/edid: Generate modes from extra_modes for range descriptors

login
register
mail settings
Submitter Dave Chiluk
Date Jan. 30, 2013, 5:28 a.m.
Message ID <1359523711-5875-6-git-send-email-chiluk@canonical.com>
Download mbox | patch
Permalink /patch/216793/
State New
Headers show

Comments

Dave Chiluk - Jan. 30, 2013, 5:28 a.m.
From: Adam Jackson <ajax@redhat.com>

BugLink: http://bugs.launchpad.net/bugs/1109112

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>
(cherry picked from commit b309bd37a1357bd4391dace247cceb9d9121d20a)

Signed-off-by: David Chiluk <chiluk@canonical.com>
---
 drivers/gpu/drm/drm_edid.c |   73 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

Patch

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 3a61d32..b30fa70 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1052,11 +1052,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;
@@ -1064,6 +1114,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