[Intel-gfx] [PATCH] kms: Fix LVDS mode list construction.

ykzhao yakui.zhao at intel.com
Thu Dec 3 02:07:20 CET 2009


On Thu, 2009-12-03 at 01:05 +0800, Adam Jackson wrote:
> 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).

In this patch we won't construct the bogus EDID. Instead we add the
default modes directly. Of course it can meet with our requirement. But
as there is no EDID for LVDS, the xserver will add the default modes
again. Dup?

Another case is that the GTF flag is set in EDID but no DS_RANGE block
is found. As the GTF flag is set in EDID, the xorg will add the default
modes. But as there is no DS_RANGE block, most default modes will be
removed by applying the range limit check.

Thanks.

> 
> Signed-off-by: Adam Jackson <ajax at redhat.com>
> ---
>  src/drmmode_display.c |  140 ++++++++++++++----------------------------------
>  1 files changed, 41 insertions(+), 99 deletions(-)
> 
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index a469f6c..d5e3c7e 100644
> --- a/src/drmmode_display.c
> +++ b/src/drmmode_display.c
> @@ -682,107 +682,46 @@ 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)
>  {
> -	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;
> -		}
> +    xf86MonPtr mon = output->MonInfo;
> +
> +    if (!mon || !GTF_SUPPORTED(mon->features.msc)) {
> +	DisplayModePtr i, m, p = NULL;
> +	int max_x = 0, max_y = 0;
> +	float max_vrefresh = 0.0;
> +
> +	for (m = modes; m; m = m->next) {
> +	    if (m->type & M_T_PREFERRED)
> +		p = m;
> +	    max_x = max(max_x, m->HDisplay);
> +	    max_y = max(max_y, m->VDisplay);
> +	    max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
>  	}
> -	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;
> +
> +	max_vrefresh = max(max_vrefresh, 60.0);
> +	max_vrefresh *= (1 + SYNC_TOLERANCE);
> +
> +	m = xf86GetDefaultModes();
> +
> +	xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
> +
> +	for (i = m; i; i = i->next) {
> +	    if (xf86ModeVRefresh(i) > max_vrefresh)
> +		i->status = MODE_VSYNC;
> +	    if (p && i->HDisplay >= p->HDisplay &&
> +		i->VDisplay >= p->VDisplay &&
> +		xf86ModeVRefresh(i) >= xf86ModeVRefresh(p))
> +		i->status = MODE_VSYNC;
>  	}
> -	/* 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;
> +
> +	xf86PruneInvalidModes(output->scrn, &m, FALSE);
> +
> +	modes = xf86ModesAdd(modes, m);
> +    }
> +
> +    return modes;
>  }
>  
>  static DisplayModePtr
> @@ -854,8 +793,11 @@ 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);
>  	}
> +
> +	if (koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS)
> +		Modes = drmmode_output_lvds_edid(output, Modes);
> +
>  	return Modes;
>  }
>  




More information about the Intel-gfx mailing list