[Intel-gfx] [Patch 2/3_v2]: [DRM/I915] : Sync the panel fitting property with 2D driver

Eric Anholt eric at anholt.net
Wed Apr 1 22:31:51 CEST 2009


On Mon, 2009-03-23 at 11:21 +0800, yakui_zhao wrote:
> Subject: DRM/I915: Sync the panel fitting property with 2D driver
> From: Zhao Yakui <yakui.zhao at intel.com>
> 
>      Sync the panel fitting property with 2D driver
>      This covers:
>      a. create the scaling mode property and attach it to LVDS
>      b. add the support of panel fitting property for LVDS
>      c. update the display mode according to the panel fitting mode
> 
>     Fix the code-style based on Eric's suggestion.

checkpatch.pl, commit message in your email is mangled (compare your
output to git send-email.  Or just use git send-email), and please keep
using kzalloc/kfree.
 
> 
> Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |   16 ++
>  drivers/gpu/drm/i915/intel_lvds.c |  282 +++++++++++++++++++++++++++++++++++---
>  2 files changed, 277 insertions(+), 21 deletions(-)
> 
> Index: linux-2.6/drivers/gpu/drm/i915/i915_reg.h
> ===================================================================
> --- linux-2.6.orig/drivers/gpu/drm/i915/i915_reg.h	2009-03-23 11:08:45.000000000 +0800
> +++ linux-2.6/drivers/gpu/drm/i915/i915_reg.h	2009-03-23 11:09:37.000000000 +0800
> @@ -808,9 +808,25 @@
>  #define   HORIZ_INTERP_MASK	(3 << 6)
>  #define   HORIZ_AUTO_SCALE	(1 << 5)
>  #define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
> +#define   PFIT_FILTER_FUZZY	(0 << 24)
> +#define   PFIT_SCALING_AUTO	(0 << 26)
> +#define   PFIT_SCALING_PROGRAMMED (1 << 26)
> +#define   PFIT_SCALING_PILLAR	(2 << 26)
> +#define   PFIT_SCALING_LETTER	(3 << 26)
>  #define PFIT_PGM_RATIOS	0x61234
>  #define   PFIT_VERT_SCALE_MASK			0xfff00000
>  #define   PFIT_HORIZ_SCALE_MASK			0x0000fff0
> +/* Pre-965 */
> +#define		PFIT_VERT_SCALE_SHIFT		20
> +#define		PFIT_VERT_SCALE_MASK		0xfff00000
> +#define		PFIT_HORIZ_SCALE_SHIFT		4
> +#define		PFIT_HORIZ_SCALE_MASK		0x0000fff0
> +/* 965+ */
> +#define		PFIT_VERT_SCALE_SHIFT_965	16
> +#define		PFIT_VERT_SCALE_MASK_965	0x1fff0000
> +#define		PFIT_HORIZ_SCALE_SHIFT_965	0
> +#define		PFIT_HORIZ_SCALE_MASK_965	0x00001fff
> +
>  #define PFIT_AUTO_RATIOS 0x61238
>  
>  /* Backlight control */
> Index: linux-2.6/drivers/gpu/drm/i915/intel_lvds.c
> ===================================================================
> --- linux-2.6.orig/drivers/gpu/drm/i915/intel_lvds.c	2009-03-23 11:08:45.000000000 +0800
> +++ linux-2.6/drivers/gpu/drm/i915/intel_lvds.c	2009-03-23 11:19:40.000000000 +0800
> @@ -37,6 +37,21 @@
>  #include "i915_drm.h"
>  #include "i915_drv.h"
>  
> +/*
> + * the following four scaling options are defined.
> + * #define DRM_MODE_SCALE_NON_GPU	0
> + * #define DRM_MODE_SCALE_FULLSCREEN	1
> + * #define DRM_MODE_SCALE_NO_SCALE	2
> + * #define DRM_MODE_SCALE_ASPECT	3
> + */
> +
> +/* Private structure for the integrated LVDS support */
> +struct intel_lvds_priv {
> +	int fitting_mode;
> +	u32 pfit_control;
> +	u32 pfit_pgm_ratios;
> +};
> +
>  /**
>   * Sets the backlight level.
>   *
> @@ -160,10 +175,24 @@
>  				  struct drm_display_mode *mode,
>  				  struct drm_display_mode *adjusted_mode)
>  {
> +	/*
> +	 * float point operation is not supported . So the PANEL_RATIO_FACTOR
> +	 * is defined, which can avoid the float point computation when
> +	 * calculating the panel ratio.
> +	 */
> +#define PANEL_RATIO_FACTOR 8192
>  	struct drm_device *dev = encoder->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
>  	struct drm_encoder *tmp_encoder;
> +	struct intel_output *intel_output = enc_to_intel_output(encoder);
> +	struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
> +	u32 pfit_control = 0, pfit_pgm_ratios = 0;
> +	int left_border = 0, right_border = 0, top_border = 0;
> +	int bottom_border = 0;
> +	bool border = 0;
> +	int panel_ratio, desired_ratio, vert_scale, horiz_scale;
> +	int horiz_ratio, vert_ratio;
>  
>  	/* Should never happen!! */
>  	if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
> @@ -179,7 +208,9 @@
>  			return false;
>  		}
>  	}
> -
> +	/* If we don't have a panel mode, there is nothing we can do */
> +	if (dev_priv->panel_fixed_mode == NULL)
> +		return true;
>  	/*
>  	 * If we have timings from the BIOS for the panel, put them in
>  	 * to the adjusted mode.  The CRTC will be set up for this mode,
> @@ -203,6 +234,191 @@
>  		drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
>  	}
>  
> +	/* Make sure pre-965s set dither correctly */
> +	if (!IS_I965G(dev)) {
> +		if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
> +			pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> +	}
> +
> +	/* Native modes don't need fitting */
> +	if (adjusted_mode->hdisplay == mode->hdisplay &&
> +			adjusted_mode->vdisplay == mode->vdisplay) {
> +		pfit_pgm_ratios = 0;
> +		border = 0;
> +		goto out;
> +	}
> +
> +	/* 965+ wants fuzzy fitting */
> +	if (IS_I965G(dev))
> +		pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
> +					PFIT_FILTER_FUZZY;
> +
> +	/*
> +	 * Deal with panel fitting options. Figure out how to stretch the
> +	 * image based on its aspect ratio & the current panel fitting mode.
> +	 */
> +	panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
> +				adjusted_mode->vdisplay;
> +	desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
> +				mode->vdisplay;
> +	/*
> +	 * Enable automatic panel scaling for non-native modes so that they fill
> +	 * the screen.  Should be enabled before the pipe is enabled, according
> +	 * to register description and PRM.
> +	 * Change the value here to see the borders for debugging
> +	 */
> +	I915_WRITE(BCLRPAT_A, 0);
> +	I915_WRITE(BCLRPAT_B, 0);
> +
> +	switch (lvds_priv->fitting_mode) {
> +	case DRM_MODE_SCALE_NO_SCALE:
> +		/*
> +		 * For centered modes, we have to calculate border widths &
> +		 * heights and modify the values programmed into the CRTC.
> +		 */
> +		left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
> +		right_border = left_border;
> +		if (mode->hdisplay & 1)
> +			right_border++;
> +		top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
> +		bottom_border = top_border;
> +		if (mode->vdisplay & 1)
> +			bottom_border++;
> +		/* Set active & border values */
> +		adjusted_mode->crtc_hdisplay = mode->hdisplay;
> +		adjusted_mode->crtc_hblank_start = mode->hdisplay +
> +						right_border - 1;
> +		adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal -
> +						left_border - 1;
> +		adjusted_mode->crtc_hsync_start =
> +				adjusted_mode->crtc_hblank_start;
> +		adjusted_mode->crtc_hsync_end =
> +				adjusted_mode->crtc_hblank_end;
> +		adjusted_mode->crtc_vdisplay = mode->vdisplay;
> +		adjusted_mode->crtc_vblank_start = mode->vdisplay +
> +						bottom_border - 1;
> +		adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal -
> +						top_border - 1;
> +		adjusted_mode->crtc_vsync_start =
> +				adjusted_mode->crtc_vblank_start;
> +		adjusted_mode->crtc_vsync_end =
> +				adjusted_mode->crtc_vblank_end;
> +		border = 1;
> +		break;
> +	case DRM_MODE_SCALE_ASPECT:
> +		/* Scale but preserve the spect ratio */
> +		pfit_control |= PFIT_ENABLE;
> +		if (IS_I965G(dev)) {
> +			/* 965+ is easy, it does everything in hw */
> +			if (panel_ratio > desired_ratio)
> +				pfit_control |= PFIT_SCALING_PILLAR;
> +			else if (panel_ratio < desired_ratio)
> +				pfit_control |= PFIT_SCALING_LETTER;
> +			else
> +				pfit_control |= PFIT_SCALING_AUTO;
> +		} else {
> +			/*
> +			 * For earlier chips we have to calculate the scaling
> +			 * ratio by hand and program it into the
> +			 * PFIT_PGM_RATIO register
> +			 */
> +			u32 horiz_bits, vert_bits, bits = 12;
> +			horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
> +						adjusted_mode->hdisplay;
> +			vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
> +						adjusted_mode->vdisplay;
> +			horiz_scale = adjusted_mode->hdisplay *
> +					PANEL_RATIO_FACTOR / mode->hdisplay;
> +			vert_scale = adjusted_mode->vdisplay *
> +					PANEL_RATIO_FACTOR / mode->vdisplay;
> +
> +			/* retain aspect ratio */
> +			if (panel_ratio > desired_ratio) { /* Pillar */
> +				u32 scaled_width;
> +				scaled_width = mode->hdisplay * vert_scale /
> +						PANEL_RATIO_FACTOR;
> +				horiz_ratio = vert_ratio;
> +				pfit_control |= (VERT_AUTO_SCALE |
> +						 VERT_INTERP_BILINEAR |
> +						 HORIZ_INTERP_BILINEAR);
> +				/* Pillar will have left/right borders */
> +				left_border = (adjusted_mode->hdisplay -
> +						scaled_width) / 2;
> +				right_border = left_border;
> +				if (mode->hdisplay & 1) /* odd resolutions */
> +					right_border++;
> +				adjusted_mode->crtc_hdisplay = scaled_width;
> +				adjusted_mode->crtc_hblank_start =
> +					scaled_width + right_border - 1;
> +				adjusted_mode->crtc_hblank_end =
> +				 adjusted_mode->crtc_htotal - left_border - 1;
> +				adjusted_mode->crtc_hsync_start =
> +					adjusted_mode->crtc_hblank_start;
> +				adjusted_mode->crtc_hsync_end =
> +					adjusted_mode->crtc_hblank_end;
> +				border = 1;
> +			} else if (panel_ratio < desired_ratio) { /* letter */
> +				u32 scaled_height = mode->vdisplay *
> +					horiz_scale / PANEL_RATIO_FACTOR;
> +				vert_ratio = horiz_ratio;
> +				pfit_control |= (HORIZ_AUTO_SCALE |
> +						 VERT_INTERP_BILINEAR |
> +						 HORIZ_INTERP_BILINEAR);
> +				/* Letterbox will have top/bottom border */
> +				top_border = (adjusted_mode->vdisplay -
> +					scaled_height) / 2;
> +				bottom_border = top_border;
> +				if (mode->vdisplay & 1)
> +					bottom_border++;
> +				adjusted_mode->crtc_vdisplay = scaled_height;
> +				adjusted_mode->crtc_vblank_start =
> +					scaled_height + bottom_border - 1;
> +				adjusted_mode->crtc_vblank_end =
> +				 adjusted_mode->crtc_vtotal - top_border - 1;
> +				adjusted_mode->crtc_vsync_start =
> +					adjusted_mode->crtc_vblank_start;
> +				adjusted_mode->crtc_vsync_end =
> +					adjusted_mode->crtc_vblank_end;
> +				border = 1;
> +			} else {
> +			/* Aspects match, Let hw scale both directions */
> +				pfit_control |= (VERT_AUTO_SCALE |
> +						 HORIZ_AUTO_SCALE |
> +				 		 VERT_INTERP_BILINEAR |
> +						 HORIZ_INTERP_BILINEAR);
> +			}
> +			horiz_bits = (1 << bits) * horiz_ratio /
> +					PANEL_RATIO_FACTOR;
> +			vert_bits = (1 << bits) * vert_ratio /
> +					PANEL_RATIO_FACTOR;
> +			pfit_pgm_ratios =
> +				((vert_bits << PFIT_VERT_SCALE_SHIFT) &
> +						PFIT_VERT_SCALE_MASK) |
> +				((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
> +						PFIT_HORIZ_SCALE_MASK);
> +		}
> +		break;
> +
> +	case DRM_MODE_SCALE_FULLSCREEN:
> +		/*
> +		 * Full scaling, even if it changes the aspect ratio.
> +		 * Fortunately this is all done for us in hw.
> +		 */
> +		pfit_control |= PFIT_ENABLE;
> +		if (IS_I965G(dev))
> +			pfit_control |= PFIT_SCALING_AUTO;
> +		else
> +			pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
> +					 VERT_INTERP_BILINEAR |
> +					 HORIZ_INTERP_BILINEAR);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +out:
> +	lvds_priv->pfit_control = pfit_control;
> +	lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
>  	/*
>  	 * XXX: It would be nice to support lower refresh rates on the
>  	 * panels to reduce power consumption, and perhaps match the
> @@ -242,8 +458,8 @@
>  {
>  	struct drm_device *dev = encoder->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
> -	u32 pfit_control;
> +	struct intel_output *intel_output = enc_to_intel_output(encoder);
> +	struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
>  
>  	/*
>  	 * The LVDS pin pair will already have been turned on in the
> @@ -256,22 +472,8 @@
>  	 * screen.  Should be enabled before the pipe is enabled, according to
>  	 * register description and PRM.
>  	 */
> -	if (mode->hdisplay != adjusted_mode->hdisplay ||
> -	    mode->vdisplay != adjusted_mode->vdisplay)
> -		pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
> -				HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
> -				HORIZ_INTERP_BILINEAR);
> -	else
> -		pfit_control = 0;
> -
> -	if (!IS_I965G(dev)) {
> -		if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
> -			pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> -	}
> -	else
> -		pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
> -
> -	I915_WRITE(PFIT_CONTROL, pfit_control);
> +	I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
> +	I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
>  }
>  
>  /**
> @@ -344,10 +546,34 @@
>  				   uint64_t value)
>  {
>  	struct drm_device *dev = connector->dev;
> +	struct intel_output *intel_output =
> +			to_intel_output(connector);
>  
>  	if (property == dev->mode_config.dpms_property && connector->encoder)
>  		intel_lvds_dpms(connector->encoder, (uint32_t)(value & 0xf));
>  
> +	if (property == dev->mode_config.scaling_mode_property &&
> +			connector->encoder) {
> +		struct drm_crtc *crtc = connector->encoder->crtc;
> +		struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
> +		if (value == DRM_MODE_SCALE_NON_GPU) {
> +			DRM_DEBUG("non_GPU property is unsupported.\n");
> +			return 0;
> +		}
> +
> +		if (lvds_priv->fitting_mode == value)
> +			return 0;
> +
> +		lvds_priv->fitting_mode = value;
> +		if (crtc && crtc->enabled) {
> +			/*
> +			 * If the CRTC is enabled, the display will be changed
> +			 * according to the new panel fitting mode.
> +			 */
> +			drm_crtc_helper_set_mode(crtc, &crtc->mode,
> +						 crtc->x, crtc->y, crtc->fb);
> +		}
> +	}
>  	return 0;
>  }
>  
> @@ -401,6 +627,7 @@
>  	struct drm_encoder *encoder;
>  	struct drm_display_mode *scan; /* *modes, *bios_mode; */
>  	struct drm_crtc *crtc;
> +	struct intel_lvds_priv *lvds_priv;
>  	u32 lvds;
>  	int pipe;
>  
> @@ -419,7 +646,8 @@
>  		return;
>  	}
>  
> -	intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
> +	intel_output = drm_calloc(1, sizeof(struct intel_output) +
> +				sizeof(struct intel_lvds_priv), DRM_MEM_DRIVER);
>  	if (!intel_output) {
>  		return;
>  	}
> @@ -441,7 +669,18 @@
>  	connector->interlace_allowed = false;
>  	connector->doublescan_allowed = false;
>  
> +	lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
> +	intel_output->dev_priv = lvds_priv;
> +	/* create the scaling mode property */
> +	drm_mode_create_scaling_mode_property(dev);
> +	/*
> +	 * the initial panel fitting mode will be FULL_ASPECT
> +	 */
>  
> +	drm_connector_attach_property(&intel_output->base,
> +				      dev->mode_config.scaling_mode_property,
> +				      DRM_MODE_SCALE_ASPECT);
> +	lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT;
>  	/*
>  	 * LVDS discovery:
>  	 * 1) check for EDID on DDC
> @@ -521,5 +760,6 @@
>  	if (intel_output->ddc_bus)
>  		intel_i2c_destroy(intel_output->ddc_bus);
>  	drm_connector_cleanup(connector);
> -	kfree(connector);
> +	drm_free(intel_output, sizeof(struct intel_output) +
> +		 sizeof(struct intel_lvds_priv), DRM_MEM_DRIVER);
>  }
> 
> 
-- 
Eric Anholt
eric at anholt.net                         eric.anholt at intel.com


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20090401/a309f524/attachment.sig>


More information about the Intel-gfx mailing list