xf86-video-intel: 3 commits - src/drmmode_display.c

Zhenyu Wang zhen at kemper.freedesktop.org
Mon Jun 15 20:28:48 PDT 2009


 src/drmmode_display.c |  189 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 188 insertions(+), 1 deletion(-)

New commits:
commit 246cec965958e94babf5377e6f221522b05fb458
Author: Zhao Yakui <yakui.zhao at intel.com>
Date:   Wed Jun 10 11:17:28 2009 +0800

    Fix EDID for LVDS output device to add the default modes
    
    Fix the EDID for the LVDS output device to add the default modes.This is
    similar to what we have done in UMS mode.
    a. When there exists the EDID, either find the DS_RANGES block or replace
    a DS_VENDOR block, smashing it into a DS_RANGES block with open refresh
    to match all the defaults modes.
    b. When there is no EDID, we will construct a bogus EDID and add a DS_RANGES
    block with the open refresh to match all the default modes.
    
    http://bugs.freedesktop.org/show_bug.cgi?id=20801
    http://bugs.freedesktop.org/show_bug.cgi?id=21094
    http://bugs.freedesktop.org/show_bug.cgi?id=21346
    http://bugs.freedesktop.org/show_bug.cgi?id=21417
    http://bugs.freedesktop.org/show_bug.cgi?id=21671
    
    Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index aee885a..02a71ae 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -489,6 +489,132 @@ drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
 	return MODE_OK;
 }
 
+static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon,
+					DisplayModePtr mode)
+{
+	struct detailed_timings *timing = &det_mon->section.d_timings;
+
+	det_mon->type = DT;
+	timing->clock = mode->Clock * 1000;
+	timing->h_active = mode->HDisplay;
+	timing->h_blanking = mode->HTotal - mode->HDisplay;
+	timing->v_active = mode->VDisplay;
+	timing->v_blanking = mode->VTotal - mode->VDisplay;
+	timing->h_sync_off = mode->HSyncStart - mode->HDisplay;
+	timing->h_sync_width = mode->HSyncEnd - mode->HSyncStart;
+	timing->v_sync_off = mode->VSyncStart - mode->VDisplay;
+	timing->v_sync_width = mode->VSyncEnd - mode->VSyncStart;
+
+	if (mode->Flags & V_PVSYNC)
+		timing->misc |= 0x02;
+
+	if (mode->Flags & V_PHSYNC)
+		timing->misc |= 0x01;
+}
+
+static int drmmode_output_lvds_edid(xf86OutputPtr output,
+				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;
+	}
+	/*
+	 * 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
+	 */
+	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;
+	}
+	/* 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
+	 */
+	j = 0;
+	for (i = 0; i < koutput->count_modes; i++) {
+		mode_ptr = &koutput->modes[i];
+		if ((mode_ptr->hdisplay == p_lvds->hdisplay) &&
+			(mode_ptr->vdisplay == p_lvds->vdisplay)) {
+			/* find the fixed panel mode */
+			j = i;
+			break;
+		}
+	}
+	pmode = xnfalloc(sizeof(DisplayModeRec));
+	drmmode_ConvertFromKMode(output->scrn, &koutput->modes[j], pmode);
+	/*support DPM, instead of DPMS*/
+	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
+		 */
+		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;
+}
+
 static DisplayModePtr
 drmmode_output_get_modes(xf86OutputPtr output)
 {
@@ -555,6 +681,7 @@ 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);
 	}
 	return Modes;
 }
commit 5d1dc7677004d445a7a781decd8c1ef9747c14fb
Author: Zhao Yakui <yakui.zhao at intel.com>
Date:   Wed Jun 10 11:17:27 2009 +0800

    Get the LVDS panel limit and check whether the given modeline is valid
    
    When the connector type is LVDS, it will traverse the mode list returned by
    KMS kernel to get the LVDS panel limit. Then it will use the panel limit to
    check whether the given modeline is valid. If the given modeline exceeds
    the LVDS panel limit, it will be invalid.
    
    http://bugs.freedesktop.org/show_bug.cgi?id=20801
    http://bugs.freedesktop.org/show_bug.cgi?id=21094
    http://bugs.freedesktop.org/show_bug.cgi?id=21346
    http://bugs.freedesktop.org/show_bug.cgi?id=21417
    http://bugs.freedesktop.org/show_bug.cgi?id=21671
    
    Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index c9e15a4..aee885a 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -471,6 +471,21 @@ drmmode_output_detect(xf86OutputPtr output)
 static Bool
 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
 {
+	drmmode_output_private_ptr drmmode_output = output->driver_private;
+	drmModeConnectorPtr koutput = drmmode_output->mode_output;
+	struct fixed_panel_lvds *p_lvds = drmmode_output->private_data;
+
+	/*
+	 * If the connector type is LVDS, we will use the panel limit to
+	 * verfiy whether the mode is valid.
+	 */
+	if ((koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) && p_lvds) {
+		if (pModes->HDisplay > p_lvds->hdisplay ||
+			pModes->VDisplay > p_lvds->vdisplay)
+			return MODE_PANEL;
+		else
+			return MODE_OK;
+	}
 	return MODE_OK;
 }
 
@@ -483,6 +498,8 @@ drmmode_output_get_modes(xf86OutputPtr output)
 	int i;
 	DisplayModePtr Modes = NULL, Mode;
 	drmModePropertyPtr props;
+	struct fixed_panel_lvds *p_lvds;
+	drmModeModeInfo *mode_ptr;
 
 	/* look for an EDID property */
 	for (i = 0; i < koutput->count_props; i++) {
@@ -518,6 +535,27 @@ drmmode_output_get_modes(xf86OutputPtr output)
 		Modes = xf86ModesAdd(Modes, Mode);
 
 	}
+	p_lvds = drmmode_output->private_data;
+	/*
+	 * If the connector type is LVDS, we will traverse the kernel mode to
+	 * get the panel limit.
+	 * If it is incorrect, please fix me.
+	 */
+	if ((koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) && p_lvds) {
+		p_lvds->hdisplay = 0;
+		p_lvds->vdisplay = 0;
+		for (i = 0; i < koutput->count_modes; i++) {
+			mode_ptr = &koutput->modes[i];
+			if ((mode_ptr->hdisplay >= p_lvds->hdisplay) &&
+				(mode_ptr->vdisplay >= p_lvds->vdisplay)) {
+				p_lvds->hdisplay = mode_ptr->hdisplay;
+				p_lvds->vdisplay = mode_ptr->vdisplay;
+			}
+		}
+		if (!p_lvds->hdisplay || !p_lvds->vdisplay)
+			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+				"Incorrect KMS mode.\n");
+	}
 	return Modes;
 }
 
commit 115e28639fbf6a1eba636dafac02fadd83036c75
Author: Zhao Yakui <yakui.zhao at intel.com>
Date:   Wed Jun 10 11:17:26 2009 +0800

    Add the private data for the LVDS connector
    
    Add the private data when the connector type is LVDS.
    We can use the private_data to store the LVDS panel limit.
    For example: Hdisplay, Vdisplay.
    
    http://bugs.freedesktop.org/show_bug.cgi?id=20801
    http://bugs.freedesktop.org/show_bug.cgi?id=21094
    http://bugs.freedesktop.org/show_bug.cgi?id=21346
    http://bugs.freedesktop.org/show_bug.cgi?id=21417
    http://bugs.freedesktop.org/show_bug.cgi?id=21671
    
    Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 24e0e26..c9e15a4 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -58,6 +58,10 @@ typedef struct {
     Atom *atoms;
 } drmmode_prop_rec, *drmmode_prop_ptr;
 
+struct fixed_panel_lvds {
+	int hdisplay;
+	int vdisplay;
+};
 typedef struct {
     drmmode_ptr drmmode;
     int output_id;
@@ -66,6 +70,8 @@ typedef struct {
     drmModePropertyBlobPtr edid_blob;
     int num_props;
     drmmode_prop_ptr props;
+    void *private_data;
+	/* this is used to store private data */
 } drmmode_output_private_rec, *drmmode_output_private_ptr;
 
 static void
@@ -529,6 +535,10 @@ drmmode_output_destroy(xf86OutputPtr output)
 	}
 	xfree(drmmode_output->props);
 	drmModeFreeConnector(drmmode_output->mode_output);
+	if (drmmode_output->private_data) {
+		xfree(drmmode_output->private_data);
+		drmmode_output->private_data = NULL;
+	}
 	xfree(drmmode_output);
 	output->driver_private = NULL;
 }
@@ -792,7 +802,19 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
 		drmModeFreeEncoder(kencoder);
 		return;
 	}
-
+	/*
+	 * If the connector type of the output device is LVDS, we will
+	 * allocate the private_data to store the panel limit.
+	 * For example: hdisplay, vdisplay
+	 */
+	drmmode_output->private_data = NULL;
+	if (koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) {
+		drmmode_output->private_data = xcalloc(
+				sizeof(struct fixed_panel_lvds), 1);
+		if (!drmmode_output->private_data)
+			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+				"Can't allocate private memory for LVDS.\n");
+	}
 	drmmode_output->output_id = drmmode->mode_res->connectors[num];
 	drmmode_output->mode_output = koutput;
 	drmmode_output->mode_encoder = kencoder;


More information about the xorg-commit mailing list