diff mbox

kms: fix the LVDS mode list construction

Message ID 1260366702-13201-1-git-send-email-yakui.zhao@intel.com (mailing list archive)
State Deferred, archived
Headers show

Commit Message

Zhao, Yakui Dec. 9, 2009, 1:51 p.m. UTC
None
diff mbox

Patch

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a469f6c..7b4ce2f 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -682,65 +682,48 @@  static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon,
 		timing->misc |= 0x01;
 }
 
-static int drmmode_output_lvds_edid(xf86OutputPtr output,
-				struct fixed_panel_lvds *p_lvds)
+static DisplayModePtr
+drmmode_output_lvds_edid(xf86OutputPtr output,
+	DisplayModePtr modes, struct fixed_panel_lvds *p_lvds)
 {
-	drmmode_output_private_ptr drmmode_output = output->driver_private;
-	drmModeConnectorPtr koutput = drmmode_output->mode_output;
-	int i, j;
-	DisplayModePtr pmode;
-	xf86MonPtr	edid_mon;
-	drmModeModeInfo *mode_ptr;
-	struct detailed_monitor_section *det_mon;
-
-	if (output->MonInfo) {
-		/*
-		 * If there exists the EDID, we will either find a DS_RANGES
-		 * or replace a DS_VENDOR block, smashing it into a DS_RANGES
-		 * block with opern refresh to match all the default modes.
-		 */
-		int edid_det_block_num;
-		edid_mon = output->MonInfo;
-		edid_mon->features.msc |= 0x01;
-		j = -1;
-		edid_det_block_num = sizeof(edid_mon->det_mon) /
-					sizeof(edid_mon->det_mon[0]);
-		for (i = 0; i < edid_det_block_num; i++) {
-			if (edid_mon->det_mon[i].type >= DS_VENDOR && j == -1)
-				j = i;
-			if (edid_mon->det_mon[i].type == DS_RANGES) {
-				j = i;
-				break;
-			}
-		}
-		if (j != -1) {
-			struct monitor_ranges	*ranges =
-				&edid_mon->det_mon[j].section.ranges;
-			edid_mon->det_mon[j].type = DS_RANGES;
-			ranges->min_v = 0;
-			ranges->max_v = 200;
-			ranges->min_h = 0;
-			ranges->max_h = 200;
-		}
-		return 0;
-	}
+    drmmode_output_private_ptr drmmode_output = output->driver_private;
+    drmModeConnectorPtr koutput = drmmode_output->mode_output;
+
+    xf86MonPtr edid_mon = output->MonInfo;
+    int i, j, flags;
+    DisplayModePtr pmode, m;
+    drmModeModeInfo *mode_ptr;
+    struct detailed_monitor_section *det_mon;
+
+     pmode = xnfalloc(sizeof(DisplayModeRec));
+     drmmode_ConvertFromKMode(output->scrn, &koutput->modes[j], pmode);
+
+     if (edid_mon) {
 	/*
-	 * If there is no EDID, we will construct a bogus EDID for LVDS output
-	 * device. This is similar to what we have done in i830_lvds.c
+	 * when there exists the EDID, we will clear the GTF flag to avoid
+	 * that the xf86GetDefaultModes will be called again in xserver
+	 */
+	edid_mon->features.msc &= ~(0x01);
+     } else {
+	/*
+	 * When there is no EDID, we will construct the bogus EDID and not
+	 * set the GTF flag. This is also to avoid that the xf86GetDefaultModes
+	 * will be called again in xserver
 	 */
 	edid_mon = NULL;
 	edid_mon = xcalloc(1, sizeof(xf86Monitor));
 	if (!edid_mon) {
 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 			"Can't allocate memory for edid_mon.\n");
-		return 0;
+		return modes;
 	}
-	/* Find the fixed panel mode.
+	/*
+	 * Find the fixed panel mode.
 	 * In theory when there is no EDID, KMS kernel will return only one
 	 * mode. And this can be regarded as fixed lvds panel mode.
 	 * But it will be better to traverse the mode list to get the fixed
 	 * lvds panel mode again as we don't know whether some new modes
-	 * are added for the LVDS output device
+	 * are added for the LVDS output device.
 	 */
 	j = 0;
 	for (i = 0; i < koutput->count_modes; i++) {
@@ -758,31 +741,38 @@  static int drmmode_output_lvds_edid(xf86OutputPtr output,
 	edid_mon->features.dpms |= 0x1;
 	/*defaultly support RGB color display*/
 	edid_mon->features.display_type |= 0x1;
-	/*defaultly display support continuous-freqencey*/
-	edid_mon->features.msc |= 0x1;
 	/*defaultly  the EDID version is 1.4 */
 	edid_mon->ver.version = 1;
 	edid_mon->ver.revision = 4;
 	det_mon = edid_mon->det_mon;
 	if (pmode) {
-		/* now we construct new EDID monitor,
-		 * so filled one detailed timing block
-		 */
+		/* construct bogus EDID and filled one detailed timing block */
 		fill_detailed_lvds_block(det_mon, pmode);
 		/* the filed timing block should be set preferred*/
 		edid_mon->features.msc |= 0x2;
-		det_mon = det_mon + 1;
 	}
-	/* Set wide sync ranges so we get all modes
-	 * handed to valid_mode for checking
-	 */
-	det_mon->type = DS_RANGES;
-	det_mon->section.ranges.min_v = 0;
-	det_mon->section.ranges.max_v = 200;
-	det_mon->section.ranges.min_h = 0;
-	det_mon->section.ranges.max_h = 200;
 	output->MonInfo = edid_mon;
-	return 0;
+	if (pmode)
+		xfree(pmode);
+    }
+    /*
+     * Always add the default mode for LVDS and invalidate the mode which is
+     * beyond the range of hdisplay/vdisplay
+     */
+    m = xf86GetDefaultModes();
+    /* validate the default mode list by checking panel size */
+    xf86ValidateModesSize(output->scrn, m, p_lvds->hdisplay,
+						p_lvds->vdisplay, 0);
+
+    /* mark the invalid mode by checking flag(Interface/doublescan) */
+    flags = (output->interlaceAllowed ? V_INTERLACE : 0) |
+			(output->doubleScanAllowed ? V_DBLSCAN : 0);
+    xf86ValidateModesFlags(output->scrn, m, flags);
+    /* remove the invalid mode */
+    xf86PruneInvalidModes(output->scrn, &m, 1);
+    modes = xf86ModesAdd(modes, m);
+
+    return modes;
 }
 
 static DisplayModePtr
@@ -854,8 +844,9 @@  drmmode_output_get_modes(xf86OutputPtr output)
 		if (!p_lvds->hdisplay || !p_lvds->vdisplay)
 			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 				"Incorrect KMS mode.\n");
-		drmmode_output_lvds_edid(output, p_lvds);
+		Modes = drmmode_output_lvds_edid(output, Modes, p_lvds);
 	}
+
 	return Modes;
 }