Commit 07a5e632 authored by Adam Jackson's avatar Adam Jackson Committed by Dave Airlie
Browse files

drm/edid: Add DMT modes to the pool if the monitor is GTF-capable

parent 7ac96a9c
Loading
Loading
Loading
Loading
+65 −4
Original line number Diff line number Diff line
@@ -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 */