[PATCH] drm/edid: Strengthen the algorithm for CRT default resolution

Adam Jackson ajax at redhat.com
Thu Feb 9 12:08:02 PST 2012


If a CRT doesn't deign to provide a preferred mode, we should try to
pick a mode with a vaguely reasonable DPI instead of whatever happens to
be biggest.

Bugzilla: https://bugzilla.redhat.com/522155

Signed-off-by: Adam Jackson <ajax at redhat.com>
---
 drivers/gpu/drm/drm_edid.c      |   52 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c |   14 +++++++++-
 include/drm/drm_crtc.h          |    3 ++
 3 files changed, 68 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ece03fc..7d7f4dc 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1810,3 +1810,55 @@ int drm_add_modes_noedid(struct drm_connector *connector,
 	return num_modes;
 }
 EXPORT_SYMBOL(drm_add_modes_noedid);
+
+/**
+ * drm_edid_analog_mode_guess - guess a mode somewhere near 96dpi
+ * @connector: connector to inspect
+ * @max_width: maximum width
+ * @max_height: maximum height
+ *
+ * Some old (usually CRT) monitors do not specify a preferred mode.  Usually
+ * they also expose very high resolutions, which leads to unreadably small
+ * text.  Instead pick something reasonable.
+ *
+ * Returns the supported mode closest to 96dpi within some tolerance, if any.
+ *
+ * Only looks at horizontal DPI, but, whatever.
+ */
+struct drm_display_mode *
+drm_edid_analog_mode_guess(struct drm_connector *connector,
+			   int max_width, int max_height)
+{
+	struct drm_display_mode *mode, *best = NULL;
+	int best_dpi = 0;
+	struct edid *edid;
+	
+	edid = connector->edid_blob_ptr->data;
+	if (!edid)
+		return NULL;
+
+	if ((edid->features & DRM_EDID_INPUT_DIGITAL))
+		return NULL;
+
+	if (!edid->width_cm || !edid->height_cm)
+		return NULL;
+
+	list_for_each_entry(mode, &connector->probed_modes, head) {
+		int dpi = (mode->hdisplay * 254) / (edid->width_cm * 100);
+
+		if (mode->hdisplay > max_width || mode->vdisplay > max_height)
+			continue;
+
+		if (abs(96 - dpi) < abs(96 - best_dpi)) {
+			best_dpi = dpi;
+			best = mode;
+		}
+	}
+
+	/* if we can't get anywhere near 96dpi, we probably shouldn't try */
+	if (abs(96 - best_dpi) > 10)
+		return NULL;
+
+	return best;
+}
+EXPORT_SYMBOL(drm_edid_analog_mode_guess);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index aada26f..14d544e 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1177,15 +1177,27 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
 			      fb_helper_conn->connector->base.id);
 
-		/* got for command line mode first */
+		/* go for command line mode first */
 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
+
+		/* then edid-preferred, if any */
 		if (!modes[i]) {
 			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
 				      fb_helper_conn->connector->base.id);
 			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
 		}
+
+		/* then something maybe near 96dpi if possible */
+		if (!modes[i] && fb_helper_conn->connector->edid_blob_ptr) {
+			DRM_DEBUG_KMS("looking for 96dpi mode on connector %d\n",
+				      fb_helper_conn->connector->base.id);
+			modes[i] = drm_edid_analog_mode_guess(fb_helper_conn->connector, width, height);
+		}
+
 		/* No preferred modes, pick one off the list */
 		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
+			DRM_DEBUG_KMS("guessing mode on connector %d\n",
+				      fb_helper_conn->connector->base.id);
 			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
 				break;
 		}
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4cd4be2..1d04589 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -993,6 +993,9 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
 				int GTF_2C, int GTF_K, int GTF_2J);
 extern int drm_add_modes_noedid(struct drm_connector *connector,
 				int hdisplay, int vdisplay);
+extern struct drm_display_mode *drm_edid_analog_mode_guess(
+				struct drm_connector *connector,
+				int max_width, int max_height);
 
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
-- 
1.7.7.6



More information about the dri-devel mailing list