diff options
author | Adam Jackson <ajax@redhat.com> | 2009-12-03 17:44:38 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-04 08:53:32 +1000 |
commit | 07a5e6324abacad56a8e7bcb44dd404e84f75f57 (patch) | |
tree | 7284321ed859e29ecacb4ce1a8a6a58a4abb1942 | |
parent | 7ac96a9cb4982140e206bf3b58236efb2498ab3f (diff) |
drm/edid: Add DMT modes to the pool if the monitor is GTF-capable
See also: http://bugzilla.redhat.com/539785
Signed-off-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 999571ab0b6..cc8e6968271 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -491,16 +491,17 @@ static struct drm_display_mode drm_dmt_modes[] = { 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, }; +static const int drm_num_dmt_modes = + sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh) { - int i, count; + int i; struct drm_display_mode *ptr, *mode; - count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); mode = NULL; - for (i = 0; i < count; i++) { + for (i = 0; i < drm_num_dmt_modes; i++) { ptr = &drm_dmt_modes[i]; if (hsize == ptr->hdisplay && vsize == ptr->vdisplay && @@ -838,6 +839,64 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid return modes; } +/* + * XXX fix this for: + * - GTF secondary curve formula + * - EDID 1.4 range offsets + * - CVT extended bits + */ +static bool +mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing) +{ + struct detailed_data_monitor_range *range; + int hsync, vrefresh; + + range = &timing->data.other_data.data.range; + + hsync = drm_mode_hsync(mode); + vrefresh = drm_mode_vrefresh(mode); + + if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz) + return false; + + if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq) + return false; + + if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) { + /* be forgiving since it's in units of 10MHz */ + int max_clock = range->pixel_clock_mhz * 10 + 9; + max_clock *= 1000; + if (mode->clock > max_clock) + return false; + } + + return true; +} + +/* + * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will + * need to account for them. + */ +static int drm_gtf_modes_for_range(struct drm_connector *connector, + struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + + for (i = 0; i < drm_num_dmt_modes; i++) { + if (mode_in_range(drm_dmt_modes + i, timing)) { + newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); + if (newmode) { + drm_mode_probed_add(connector, newmode); + modes++; + } + } + } + + return modes; +} + static int add_detailed_modes(struct drm_connector *connector, struct detailed_timing *timing, struct edid *edid, u32 quirks, int preferred) @@ -845,6 +904,7 @@ static int add_detailed_modes(struct drm_connector *connector, int i, modes = 0; struct detailed_non_pixel *data = &timing->data.other_data; int timing_level = standard_timing_level(edid); + int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF); struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; @@ -863,7 +923,8 @@ static int add_detailed_modes(struct drm_connector *connector, /* other timing types */ switch (data->type) { case EDID_DETAIL_MONITOR_RANGE: - /* Get monitor range data */ + if (gtf) + modes += drm_gtf_modes_for_range(connector, timing); break; case EDID_DETAIL_STD_MODES: /* Six modes per detailed section */ |