[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