[Intel-gfx] [PATCH 1/2] drm/i915: factor out GMCH panel fitting code and use for eDP v2

Mika Kuoppala mika.kuoppala at linux.intel.com
Wed Apr 24 17:05:54 CEST 2013


Jesse Barnes <jbarnes at virtuousgeek.org> writes:

> This gets the panel fitter working on eDP on VLV, and should also apply
> to eDP panels on G4x chipsets (if we ever detect and mark an all-in-one
> panel as eDP anyway).
>
> A few cleanups are still possible on top of this, for example the LVDS
> border control could be placed in the LVDS encoder structure and updated
> based on the result of the panel fitter calculation.
>
> Multi-pipe fitting isn't handled correctly either if we ever get a config
> that wants to try the panel fitter on more than one output at a time.
>
> v2: use pipe_config for storing pfit values (Daniel)
>     add i9xx_pfit_enable function for use by 9xx and VLV (Daniel)
>
> Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
> ---
>  drivers/gpu/drm/i915/intel_display.c |   33 ++++++
>  drivers/gpu/drm/i915/intel_dp.c      |   11 +-
>  drivers/gpu/drm/i915/intel_drv.h     |    6 +
>  drivers/gpu/drm/i915/intel_lvds.c    |  208 +---------------------------------
>  drivers/gpu/drm/i915/intel_panel.c   |  190 +++++++++++++++++++++++++++++++
>  5 files changed, 240 insertions(+), 208 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 3fadd33..085a3ef 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3692,6 +3692,33 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe)
>  	}
>  }
>  
> +static void i9xx_pfit_enable(struct intel_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc_config *pipe_config = &crtc->config;
> +
> +	if (!(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
> +	      intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)))
> +		return;
> +
> +	WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
> +	assert_pipe_disabled(dev_priv, crtc->pipe);
> +
> +	/*
> +	 * Enable automatic panel scaling so that non-native modes
> +	 * fill the screen.  The panel fitter should only be
> +	 * adjusted whilst the pipe is disabled, according to
> +	 * register description and PRM.
> +	 */
> +	DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
> +		      pipe_config->pfit_control,
> +		      pipe_config->pfit_pgm_ratios);
> +
> +	I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios);
> +	I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control);
> +}
> +
>  static void valleyview_crtc_enable(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
> @@ -3725,6 +3752,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
>  	for_each_encoder_on_crtc(dev, crtc, encoder)
>  		encoder->enable(encoder);
>  
> +	/* Enable panel fitting for eDP */
> +	i9xx_pfit_enable(intel_crtc);
> +
>  	intel_enable_pipe(dev_priv, pipe, false);
>  	intel_enable_plane(dev_priv, plane, pipe);
>  
> @@ -3761,6 +3791,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
>  		if (encoder->pre_enable)
>  			encoder->pre_enable(encoder);
>  
> +	/* Enable panel fitting for LVDS */
> +	i9xx_pfit_enable(intel_crtc);
> +
>  	intel_enable_pipe(dev_priv, pipe, false);
>  	intel_enable_plane(dev_priv, plane, pipe);
>  	if (IS_G4X(dev))
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 0580026..cb562ab 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -669,6 +669,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
>  	struct drm_display_mode *mode = &pipe_config->requested_mode;
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct intel_crtc *intel_crtc = encoder->new_crtc;
>  	struct intel_connector *intel_connector = intel_dp->attached_connector;
>  	int lane_count, clock;
>  	int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> @@ -685,9 +686,13 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
>  		intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
>  				       adjusted_mode);
> -		intel_pch_panel_fitting(dev,
> -					intel_connector->panel.fitting_mode,
> -					mode, adjusted_mode);
> +		if (!HAS_PCH_SPLIT(dev))
> +			intel_gmch_panel_fitting(intel_crtc, pipe_config,
> +						 intel_connector->panel.fitting_mode);
> +		else
> +			intel_pch_panel_fitting(dev,
> +						intel_connector->panel.fitting_mode,
> +						mode, adjusted_mode);
>  	}
>  	/* We need to take the panel's fixed mode into account. */
>  	target_clock = adjusted_mode->clock;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 63264ed..8b45527 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -224,6 +224,9 @@ struct intel_crtc_config {
>  	int pixel_target_clock;
>  	/* Used by SDVO (and if we ever fix it, HDMI). */
>  	unsigned pixel_multiplier;
> +
> +	/* Panel fitter controls for gen2-gen4 + VLV */
> +	u32 pfit_control, pfit_pgm_ratios;
>  };
>  
>  struct intel_crtc {
> @@ -540,6 +543,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
>  				    int fitting_mode,
>  				    const struct drm_display_mode *mode,
>  				    struct drm_display_mode *adjusted_mode);
> +extern void intel_gmch_panel_fitting(struct intel_crtc *crtc,
> +				     struct intel_crtc_config *pipe_config,
> +				     int fitting_mode);
>  extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
>  extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
>  extern int intel_panel_setup_backlight(struct drm_connector *connector);
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
> index 563f505..cb0066a 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -49,8 +49,6 @@ struct intel_lvds_connector {
>  struct intel_lvds_encoder {
>  	struct intel_encoder base;
>  
> -	u32 pfit_control;
> -	u32 pfit_pgm_ratios;
>  	bool is_dual_link;
>  	u32 reg;
>  
> @@ -150,32 +148,6 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
>  	I915_WRITE(lvds_encoder->reg, temp);
>  }
>  
> -static void intel_pre_enable_lvds(struct intel_encoder *encoder)
> -{
> -	struct drm_device *dev = encoder->base.dev;
> -	struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base);
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -
> -	if (HAS_PCH_SPLIT(dev) || !enc->pfit_control)
> -		return;
> -
> -	WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
> -	assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe);
> -
> -	/*
> -	 * Enable automatic panel scaling so that non-native modes
> -	 * fill the screen.  The panel fitter should only be
> -	 * adjusted whilst the pipe is disabled, according to
> -	 * register description and PRM.
> -	 */
> -	DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
> -		      enc->pfit_control,
> -		      enc->pfit_pgm_ratios);
> -
> -	I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios);
> -	I915_WRITE(PFIT_CONTROL, enc->pfit_control);
> -}
> -
>  /**
>   * Sets the power state for the panel.
>   */
> @@ -244,62 +216,6 @@ static int intel_lvds_mode_valid(struct drm_connector *connector,
>  	return MODE_OK;
>  }
>  
> -static void
> -centre_horizontally(struct drm_display_mode *mode,
> -		    int width)
> -{
> -	u32 border, sync_pos, blank_width, sync_width;
> -
> -	/* keep the hsync and hblank widths constant */
> -	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
> -	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
> -	sync_pos = (blank_width - sync_width + 1) / 2;
> -
> -	border = (mode->hdisplay - width + 1) / 2;
> -	border += border & 1; /* make the border even */
> -
> -	mode->crtc_hdisplay = width;
> -	mode->crtc_hblank_start = width + border;
> -	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
> -
> -	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
> -	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
> -}
> -
> -static void
> -centre_vertically(struct drm_display_mode *mode,
> -		  int height)
> -{
> -	u32 border, sync_pos, blank_width, sync_width;
> -
> -	/* keep the vsync and vblank widths constant */
> -	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
> -	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
> -	sync_pos = (blank_width - sync_width + 1) / 2;
> -
> -	border = (mode->vdisplay - height + 1) / 2;
> -
> -	mode->crtc_vdisplay = height;
> -	mode->crtc_vblank_start = height + border;
> -	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
> -
> -	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
> -	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
> -}
> -
> -static inline u32 panel_fitter_scaling(u32 source, u32 target)
> -{
> -	/*
> -	 * Floating point operation is not supported. So the FACTOR
> -	 * is defined, which can avoid the floating point computation
> -	 * when calculating the panel ratio.
> -	 */
> -#define ACCURACY 12
> -#define FACTOR (1 << ACCURACY)
> -	u32 ratio = source * FACTOR / target;
> -	return (FACTOR * ratio + FACTOR/2) / FACTOR;
> -}
> -
>  static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
>  				      struct intel_crtc_config *pipe_config)
>  {
> @@ -312,7 +228,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
>  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
>  	struct drm_display_mode *mode = &pipe_config->requested_mode;
>  	struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
> -	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
>  	unsigned int lvds_bpp;
>  	int pipe;
>  
> @@ -352,18 +267,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
>  					intel_connector->panel.fitting_mode,
>  					mode, adjusted_mode);
>  		return true;
> +	} else {
> +		intel_gmch_panel_fitting(intel_crtc, pipe_config,
> +					 intel_connector->panel.fitting_mode);
>  	}
>  
> -	/* Native modes don't need fitting */
> -	if (adjusted_mode->hdisplay == mode->hdisplay &&
> -	    adjusted_mode->vdisplay == mode->vdisplay)
> -		goto out;
> -
> -	/* 965+ wants fuzzy fitting */
> -	if (INTEL_INFO(dev)->gen >= 4)
> -		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
> -				 PFIT_FILTER_FUZZY);
> -
>  	/*
>  	 * Enable automatic panel scaling for non-native modes so that they fill
>  	 * the screen.  Should be enabled before the pipe is enabled, according
> @@ -376,111 +284,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
>  	drm_mode_set_crtcinfo(adjusted_mode, 0);
>  	pipe_config->timings_set = true;
>  
> -	switch (intel_connector->panel.fitting_mode) {
> -	case DRM_MODE_SCALE_CENTER:
> -		/*
> -		 * For centered modes, we have to calculate border widths &
> -		 * heights and modify the values programmed into the CRTC.
> -		 */
> -		centre_horizontally(adjusted_mode, mode->hdisplay);
> -		centre_vertically(adjusted_mode, mode->vdisplay);
> -		border = LVDS_BORDER_ENABLE;
> -		break;
> -
> -	case DRM_MODE_SCALE_ASPECT:
> -		/* Scale but preserve the aspect ratio */
> -		if (INTEL_INFO(dev)->gen >= 4) {
> -			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
> -			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
> -
> -			/* 965+ is easy, it does everything in hw */
> -			if (scaled_width > scaled_height)
> -				pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR;
> -			else if (scaled_width < scaled_height)
> -				pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER;
> -			else if (adjusted_mode->hdisplay != mode->hdisplay)
> -				pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
> -		} else {
> -			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
> -			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
> -			/*
> -			 * For earlier chips we have to calculate the scaling
> -			 * ratio by hand and program it into the
> -			 * PFIT_PGM_RATIO register
> -			 */
> -			if (scaled_width > scaled_height) { /* pillar */
> -				centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay);
> -
> -				border = LVDS_BORDER_ENABLE;
> -				if (mode->vdisplay != adjusted_mode->vdisplay) {
> -					u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
> -					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
> -							    bits << PFIT_VERT_SCALE_SHIFT);
> -					pfit_control |= (PFIT_ENABLE |
> -							 VERT_INTERP_BILINEAR |
> -							 HORIZ_INTERP_BILINEAR);
> -				}
> -			} else if (scaled_width < scaled_height) { /* letter */
> -				centre_vertically(adjusted_mode, scaled_width / mode->hdisplay);
> -
> -				border = LVDS_BORDER_ENABLE;
> -				if (mode->hdisplay != adjusted_mode->hdisplay) {
> -					u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
> -					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
> -							    bits << PFIT_VERT_SCALE_SHIFT);
> -					pfit_control |= (PFIT_ENABLE |
> -							 VERT_INTERP_BILINEAR |
> -							 HORIZ_INTERP_BILINEAR);
> -				}
> -			} else
> -				/* Aspects match, Let hw scale both directions */
> -				pfit_control |= (PFIT_ENABLE |
> -						 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
> -						 VERT_INTERP_BILINEAR |
> -						 HORIZ_INTERP_BILINEAR);
> -		}
> -		break;
> -
> -	case DRM_MODE_SCALE_FULLSCREEN:
> -		/*
> -		 * Full scaling, even if it changes the aspect ratio.
> -		 * Fortunately this is all done for us in hw.
> -		 */
> -		if (mode->vdisplay != adjusted_mode->vdisplay ||
> -		    mode->hdisplay != adjusted_mode->hdisplay) {
> -			pfit_control |= PFIT_ENABLE;
> -			if (INTEL_INFO(dev)->gen >= 4)
> -				pfit_control |= PFIT_SCALING_AUTO;
> -			else
> -				pfit_control |= (VERT_AUTO_SCALE |
> -						 VERT_INTERP_BILINEAR |
> -						 HORIZ_AUTO_SCALE |
> -						 HORIZ_INTERP_BILINEAR);
> -		}
> -		break;
> -
> -	default:
> -		break;
> -	}
> -
> -out:
> -	/* If not enabling scaling, be consistent and always use 0. */
> -	if ((pfit_control & PFIT_ENABLE) == 0) {
> -		pfit_control = 0;
> -		pfit_pgm_ratios = 0;
> -	}
> -
> -	/* Make sure pre-965 set dither correctly */
> -	if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
> -		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> -
> -	if (pfit_control != lvds_encoder->pfit_control ||
> -	    pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) {
> -		lvds_encoder->pfit_control = pfit_control;
> -		lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios;
> -	}
> -	dev_priv->lvds_border_bits = border;
> -
>  	/*
>  	 * XXX: It would be nice to support lower refresh rates on the
>  	 * panels to reduce power consumption, and perhaps match the
> @@ -1110,10 +913,6 @@ bool intel_lvds_init(struct drm_device *dev)
>  
>  	lvds_encoder->attached_connector = lvds_connector;
>  
> -	if (!HAS_PCH_SPLIT(dev)) {
> -		lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL);
> -	}
> -
>  	intel_encoder = &lvds_encoder->base;
>  	encoder = &intel_encoder->base;
>  	intel_connector = &lvds_connector->base;
> @@ -1125,7 +924,6 @@ bool intel_lvds_init(struct drm_device *dev)
>  			 DRM_MODE_ENCODER_LVDS);
>  
>  	intel_encoder->enable = intel_enable_lvds;
> -	intel_encoder->pre_enable = intel_pre_enable_lvds;
>  	intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
>  	intel_encoder->compute_config = intel_lvds_compute_config;
>  	intel_encoder->disable = intel_disable_lvds;
> diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
> index eb5e6e9..d434a8d 100644
> --- a/drivers/gpu/drm/i915/intel_panel.c
> +++ b/drivers/gpu/drm/i915/intel_panel.c
> @@ -117,6 +117,196 @@ done:
>  	dev_priv->pch_pf_size = (width << 16) | height;
>  }
>  
> +static void
> +centre_horizontally(struct drm_display_mode *mode,
> +		    int width)
> +{
> +	u32 border, sync_pos, blank_width, sync_width;
> +
> +	/* keep the hsync and hblank widths constant */
> +	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
> +	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
> +	sync_pos = (blank_width - sync_width + 1) / 2;
> +
> +	border = (mode->hdisplay - width + 1) / 2;
> +	border += border & 1; /* make the border even */
> +
> +	mode->crtc_hdisplay = width;
> +	mode->crtc_hblank_start = width + border;
> +	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
> +
> +	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
> +	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
> +}
> +
> +static void
> +centre_vertically(struct drm_display_mode *mode,
> +		  int height)
> +{
> +	u32 border, sync_pos, blank_width, sync_width;
> +
> +	/* keep the vsync and vblank widths constant */
> +	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
> +	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
> +	sync_pos = (blank_width - sync_width + 1) / 2;
> +
> +	border = (mode->vdisplay - height + 1) / 2;
> +
> +	mode->crtc_vdisplay = height;
> +	mode->crtc_vblank_start = height + border;
> +	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
> +
> +	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
> +	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
> +}
> +
> +static inline u32 panel_fitter_scaling(u32 source, u32 target)
> +{
> +	/*
> +	 * Floating point operation is not supported. So the FACTOR
> +	 * is defined, which can avoid the floating point computation
> +	 * when calculating the panel ratio.
> +	 */
> +#define ACCURACY 12
> +#define FACTOR (1 << ACCURACY)
> +	u32 ratio = source * FACTOR / target;
> +	return (FACTOR * ratio + FACTOR/2) / FACTOR;
> +}
> +
> +void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
> +			      struct intel_crtc_config *pipe_config,
> +			      int fitting_mode)
> +{
> +	struct drm_device *dev = intel_crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
> +	struct drm_display_mode *mode, *adjusted_mode;
> +
> +	mode = &pipe_config->requested_mode;
> +	adjusted_mode = &pipe_config->adjusted_mode;
> +
> +	/* Native modes don't need fitting */
> +	if (adjusted_mode->hdisplay == mode->hdisplay &&
> +	    adjusted_mode->vdisplay == mode->vdisplay)
> +		goto out;
> +
> +	switch (fitting_mode) {
> +	case DRM_MODE_SCALE_CENTER:
> +		/*
> +		 * For centered modes, we have to calculate border widths &
> +		 * heights and modify the values programmed into the CRTC.
> +		 */
> +		centre_horizontally(adjusted_mode, mode->hdisplay);
> +		centre_vertically(adjusted_mode, mode->vdisplay);
> +		break;
> +	case DRM_MODE_SCALE_ASPECT:
> +		/* Scale but preserve the aspect ratio */
> +		if (INTEL_INFO(dev)->gen >= 4) {
> +			u32 scaled_width = adjusted_mode->hdisplay *
> +				mode->vdisplay;
> +			u32 scaled_height = mode->hdisplay *
> +				adjusted_mode->vdisplay;
> +
> +			/* 965+ is easy, it does everything in hw */
> +			if (scaled_width > scaled_height)
> +				pfit_control |= PFIT_ENABLE |
> +					PFIT_SCALING_PILLAR;
> +			else if (scaled_width < scaled_height)
> +				pfit_control |= PFIT_ENABLE |
> +					PFIT_SCALING_LETTER;
> +			else if (adjusted_mode->hdisplay != mode->hdisplay)
> +				pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
> +		} else {
> +			u32 scaled_width = adjusted_mode->hdisplay *
> +				mode->vdisplay;
> +			u32 scaled_height = mode->hdisplay *
> +				adjusted_mode->vdisplay;
> +			/*
> +			 * For earlier chips we have to calculate the scaling
> +			 * ratio by hand and program it into the
> +			 * PFIT_PGM_RATIO register
> +			 */
> +			if (scaled_width > scaled_height) { /* pillar */
> +				centre_horizontally(adjusted_mode,
> +						    scaled_height /
> +						    mode->vdisplay);
> +
> +				border = LVDS_BORDER_ENABLE;
> +				if (mode->vdisplay != adjusted_mode->vdisplay) {
> +					u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
> +					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
> +							    bits << PFIT_VERT_SCALE_SHIFT);
> +					pfit_control |= (PFIT_ENABLE |
> +							 VERT_INTERP_BILINEAR |
> +							 HORIZ_INTERP_BILINEAR);
> +				}
> +			} else if (scaled_width < scaled_height) { /* letter */
> +				centre_vertically(adjusted_mode,
> +						  scaled_width /
> +						  mode->hdisplay);
> +
> +				border = LVDS_BORDER_ENABLE;
> +				if (mode->hdisplay != adjusted_mode->hdisplay) {
> +					u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
> +					pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
> +							    bits << PFIT_VERT_SCALE_SHIFT);
> +					pfit_control |= (PFIT_ENABLE |
> +							 VERT_INTERP_BILINEAR |
> +							 HORIZ_INTERP_BILINEAR);
> +				}
> +			} else {
> +				/* Aspects match, Let hw scale both directions */
> +				pfit_control |= (PFIT_ENABLE |
> +						 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
> +						 VERT_INTERP_BILINEAR |
> +						 HORIZ_INTERP_BILINEAR);
> +			}
> +		}
> +		break;
> +	default:
> +	case DRM_MODE_SCALE_FULLSCREEN:
        ^^

This is different than it was in lvds_compute_config. If we get called
with DRM_MODE_SCALE_NONE we go to fullscreen instead.
Is this intentional?

--Mika

> +		/*
> +		 * Full scaling, even if it changes the aspect ratio.
> +		 * Fortunately this is all done for us in hw.
> +		 */
> +		if (mode->vdisplay != adjusted_mode->vdisplay ||
> +		    mode->hdisplay != adjusted_mode->hdisplay) {
> +			pfit_control |= PFIT_ENABLE;
> +			if (INTEL_INFO(dev)->gen >= 4)
> +				pfit_control |= PFIT_SCALING_AUTO;
> +			else
> +				pfit_control |= (VERT_AUTO_SCALE |
> +						 VERT_INTERP_BILINEAR |
> +						 HORIZ_AUTO_SCALE |
> +						 HORIZ_INTERP_BILINEAR);
> +		}
> +		break;
> +	}
> +
> +	/* 965+ wants fuzzy fitting */
> +	/* FIXME: handle multiple panels by failing gracefully */
> +	if (INTEL_INFO(dev)->gen >= 4)
> +		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
> +				 PFIT_FILTER_FUZZY);
> +
> +out:
> +	if ((pfit_control & PFIT_ENABLE) == 0) {
> +		pfit_control = 0;
> +		pfit_pgm_ratios = 0;
> +	}
> +
> +	/* Make sure pre-965 set dither correctly */
> +	if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
> +		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> +
> +	if (pfit_control != pipe_config->pfit_control ||
> +	    pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) {
> +		pipe_config->pfit_control = pfit_control;
> +		pipe_config->pfit_pgm_ratios = pfit_pgm_ratios;
> +	}
> +	dev_priv->lvds_border_bits = border;
> +}
> +
>  static int is_backlight_combination_mode(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -- 
> 1.7.10.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



More information about the Intel-gfx mailing list