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

ykzhao yakui.zhao at intel.com
Wed Oct 14 03:29:10 CEST 2009


On Wed, 2009-10-14 at 03:18 +0800, Adam Jackson wrote:
> Construct a list of modes smaller than the LVDS panel size if either:
> 
> - the panel does not have EDID or DisplayID
> - it has EDID/dID but does not claim to be continuous-frequency (in
>   which case the server would have done it for us already)
> 
> The old method would attempt to do this by mangling the EDID block and
> parsed ranges, which was unreasonably fragile, and would fail to do so
> when EDID existed but claimed only a single mode.
What is the disadvantage of the old method?
When there is no EDID for one output device, the xserver will add the
default modes for it. But the xserver will remove some modes by using
the range limit. So we will construct a bogus EDID for the LVDS panel
without EDID. In such case it can match the default modes as many as
possible.

When there exists the EDID for LVDS panel, we will set the
continuous-frequency flag bit and fix the DS_RANGE to match all the
possible default modes.

Sometimes this patch will add the default modes twice for the LVDS
panel.
   For example: No EDID. One is added in ddx driver and another is added
in xserver.
   Of course it will also add the default modes twice for the LVDS when
the continuous-frequency is supported in EDID.

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 472bc74..d045903 100644
> --- a/src/drmmode_display.c
> +++ b/src/drmmode_display.c
> @@ -681,107 +681,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
> @@ -853,8 +792,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