diff mbox

[12/14] drm/edid: Strengthen the algorithm for standard mode codes

Message ID 1269899011-22519-12-git-send-email-ajax@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Adam Jackson March 29, 2010, 9:43 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 93ddc9a..8c8acfe 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -736,12 +736,12 @@  bad_std_timing(u8 a, u8 b)
  * Take the standard timing params (in this case width, aspect, and refresh)
  * and convert them into a real mode using CVT/GTF/DMT.
  */
-struct drm_display_mode *drm_mode_std(struct drm_device *dev,
-				      struct std_timing *t,
-				      int revision,
-				      int timing_level)
+static struct drm_display_mode *
+drm_mode_std(struct drm_connector *connector, struct std_timing *t,
+	     int revision, int timing_level)
 {
-	struct drm_display_mode *mode;
+	struct drm_device *dev = connector->dev;
+	struct drm_display_mode *m, *mode = NULL;
 	int hsize, vsize;
 	int vrefresh_rate;
 	unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
@@ -777,6 +777,17 @@  struct drm_display_mode *drm_mode_std(struct drm_device *dev,
 		vsize = 768;
 	}
 
+	/*
+	 * If this connector already has a mode for this size and refresh
+	 * rate (because it came from detailed or CVT info), use that
+	 * instead.  This way we don't have to guess at interlace or
+	 * reduced blanking.
+	 */
+	list_for_each_entry(m, &connector->modes, head)
+		if (m->hdisplay == hsize && m->vdisplay == vsize &&
+		    drm_mode_vrefresh(m) == vrefresh_rate)
+			return NULL;
+
 	/* HDTV hack, part 2 */
 	if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) {
 		mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
@@ -787,7 +798,6 @@  struct drm_display_mode *drm_mode_std(struct drm_device *dev,
 		return mode;
 	}
 
-	mode = NULL;
 	/* check whether it can be found in default mode table */
 	mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
 	if (mode)
@@ -1067,17 +1077,15 @@  static int standard_timing_level(struct edid *edid)
  */
 static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
 {
-	struct drm_device *dev = connector->dev;
 	int i, modes = 0;
 	int timing_level;
 
 	timing_level = standard_timing_level(edid);
 
 	for (i = 0; i < EDID_STD_TIMINGS; i++) {
-		struct std_timing *t = &edid->standard_timings[i];
 		struct drm_display_mode *newmode;
 
-		newmode = drm_mode_std(dev, &edid->standard_timings[i],
+		newmode = drm_mode_std(connector, &edid->standard_timings[i],
 				       edid->revision, timing_level);
 		if (newmode) {
 			drm_mode_probed_add(connector, newmode);
@@ -1374,7 +1382,7 @@  static int add_detailed_modes(struct drm_connector *connector,
 			struct drm_display_mode *newmode;
 
 			std = &data->data.timings[i];
-			newmode = drm_mode_std(dev, std, edid->revision,
+			newmode = drm_mode_std(connector, std, edid->revision,
 					       timing_level);
 			if (newmode) {
 				drm_mode_probed_add(connector, newmode);