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>
This commit is contained in:
committed by
Dave Airlie
parent
7ac96a9cb4
commit
07a5e6324a
@@ -491,16 +491,17 @@ static struct drm_display_mode drm_dmt_modes[] = {
|
|||||||
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
||||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
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,
|
static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
|
||||||
int hsize, int vsize, int fresh)
|
int hsize, int vsize, int fresh)
|
||||||
{
|
{
|
||||||
int i, count;
|
int i;
|
||||||
struct drm_display_mode *ptr, *mode;
|
struct drm_display_mode *ptr, *mode;
|
||||||
|
|
||||||
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
|
||||||
mode = NULL;
|
mode = NULL;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < drm_num_dmt_modes; i++) {
|
||||||
ptr = &drm_dmt_modes[i];
|
ptr = &drm_dmt_modes[i];
|
||||||
if (hsize == ptr->hdisplay &&
|
if (hsize == ptr->hdisplay &&
|
||||||
vsize == ptr->vdisplay &&
|
vsize == ptr->vdisplay &&
|
||||||
@@ -838,6 +839,64 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
|
|||||||
return modes;
|
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,
|
static int add_detailed_modes(struct drm_connector *connector,
|
||||||
struct detailed_timing *timing,
|
struct detailed_timing *timing,
|
||||||
struct edid *edid, u32 quirks, int preferred)
|
struct edid *edid, u32 quirks, int preferred)
|
||||||
@@ -845,6 +904,7 @@ static int add_detailed_modes(struct drm_connector *connector,
|
|||||||
int i, modes = 0;
|
int i, modes = 0;
|
||||||
struct detailed_non_pixel *data = &timing->data.other_data;
|
struct detailed_non_pixel *data = &timing->data.other_data;
|
||||||
int timing_level = standard_timing_level(edid);
|
int timing_level = standard_timing_level(edid);
|
||||||
|
int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
|
||||||
struct drm_display_mode *newmode;
|
struct drm_display_mode *newmode;
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
|
|
||||||
@@ -863,7 +923,8 @@ static int add_detailed_modes(struct drm_connector *connector,
|
|||||||
/* other timing types */
|
/* other timing types */
|
||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
case EDID_DETAIL_MONITOR_RANGE:
|
case EDID_DETAIL_MONITOR_RANGE:
|
||||||
/* Get monitor range data */
|
if (gtf)
|
||||||
|
modes += drm_gtf_modes_for_range(connector, timing);
|
||||||
break;
|
break;
|
||||||
case EDID_DETAIL_STD_MODES:
|
case EDID_DETAIL_STD_MODES:
|
||||||
/* Six modes per detailed section */
|
/* Six modes per detailed section */
|
||||||
|
Reference in New Issue
Block a user