[Intel-gfx] [PATCH] kms: fix the LVDS mode list construction

yakui.zhao at intel.com yakui.zhao at intel.com
Wed Dec 9 14:51:42 CET 2009


From: Zhao Yakui <yakui.zhao at intel.com>

This is based on Ajax's patch. But I add the following contents:
   a. When there exists the EDID for LVDS, we will clear the GTF flag to
avoid that the function of xf86GetDefaultModes is called again in xserver.
   b. When there is no EDID for LVDS, we will construct the bogus EDID.
We won't set the GTF flag in the bogus EDID. This is also to avoid that
the function of xf86GetDefaultModes is called again in xserver.
   c. It will validate the default mode list not only by checking the panel
size, but also by checking the output flag(Interlace/doublescan).

Rather than mangle the EDID block and hope the server does the right
thing, just build a sensible mode list up front.  Do this for LVDS where
there is no EDID or where it does not claim to be continuous-frequency
(since in the latter case, the server will add reasonable modes for us).

cc: Adam Jackson <ajax at redhat.com>
Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
---
 src/drmmode_display.c |  115 ++++++++++++++++++++++--------------------------
 1 files changed, 53 insertions(+), 62 deletions(-)

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;
 }
 
-- 
1.5.4.5




More information about the Intel-gfx mailing list