[PATCH 5/5] drm/i915: Add full pipe rotation

Sagar Arun Kamble sagar.a.kamble at intel.com
Wed Feb 19 02:25:58 PST 2014


Reviewed-by: Sagar Kamble <sagar.a.kamble at intel.com>

On Wed, 2014-02-12 at 23:15 +0200, ville.syrjala at linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> We can pretend that we can rotate the entire pipe by rotating all the
> planes and adjusting their positions appropriately. Add a "rotation"
> property on the crtc which will do this.
> 
> The main upshot of doing the full pipe rotation instead of rotating all
> the planes individually is that the plane positions turn out correct
> automagically. So userspace doesn't need to do anything except toggle
> the property and continue as if nothing had changed.
> 
> The actual implementation is pretty much trivial thanks to drm_rect
> and drm_rotation_chain() ;)
> 
> Cc: Sagar Kamble <sagar.a.kamble at intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_dma.c      |   6 ++
>  drivers/gpu/drm/i915/intel_display.c | 154 +++++++++++++++++++++++++++++++----
>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>  drivers/gpu/drm/i915/intel_pm.c      |   6 +-
>  drivers/gpu/drm/i915/intel_sprite.c  |  21 +++--
>  5 files changed, 164 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 3dd9abb..b59bff1 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1914,6 +1914,12 @@ void i915_driver_lastclose(struct drm_device * dev)
>  						dev_priv->rotation_property,
>  						plane->rotation);
>  		}
> +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
> +			crtc->pipe_rotation = BIT(DRM_ROTATE_0);
> +			drm_object_property_set_value(&crtc->base.base,
> +						      dev_priv->rotation_property,
> +						      crtc->pipe_rotation);
> +		}
>  	}
>  
>  	if (dev_priv->cursor_rotation_property) {
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e94167b..1b74d24 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -39,6 +39,7 @@
>  #include "i915_trace.h"
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_rect.h>
>  #include <linux/dma_remapping.h>
>  
>  static void intel_increase_pllclock(struct drm_crtc *crtc);
> @@ -2060,6 +2061,8 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	u32 dspcntr;
>  	u32 reg;
>  	int pixel_size;
> +	unsigned int rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +						   intel_crtc->primary_rotation);
>  
>  	switch (plane) {
>  	case 0:
> @@ -2133,7 +2136,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  		intel_crtc->dspaddr_offset = linear_offset;
>  	}
>  
> -	if (intel_crtc->primary_rotation == BIT(DRM_ROTATE_180)) {
> +	if (rotation == BIT(DRM_ROTATE_180)) {
>  		dspcntr |= DISPPLANE_ROTATE_180;
>  
>  		x += (intel_crtc->config.pipe_src_w - 1);
> @@ -2173,6 +2176,8 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
>  	u32 dspcntr;
>  	u32 reg;
>  	int pixel_size;
> +	unsigned int rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +						   intel_crtc->primary_rotation);
>  
>  	switch (plane) {
>  	case 0:
> @@ -2238,7 +2243,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
>  					       fb->pitches[0]);
>  	linear_offset -= intel_crtc->dspaddr_offset;
>  
> -	if (intel_crtc->primary_rotation == BIT(DRM_ROTATE_180)) {
> +	if (rotation == BIT(DRM_ROTATE_180)) {
>  		dspcntr |= DISPPLANE_ROTATE_180;
>  
>  		if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
> @@ -7468,6 +7473,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool force)
>  	bool visible = base != 0;
>  
>  	if (force || intel_crtc->cursor_visible != visible) {
> +		unsigned int rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +							   intel_crtc->cursor_rotation);
>  		uint32_t cntl = I915_READ(CURCNTR(pipe));
>  		if (base) {
>  			cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
> @@ -7477,7 +7484,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool force)
>  			cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
>  			cntl |= CURSOR_MODE_DISABLE;
>  		}
> -		if (intel_crtc->cursor_rotation == BIT(DRM_ROTATE_180))
> +		if (rotation == BIT(DRM_ROTATE_180))
>  			cntl |= CURSOR_ROTATE_180;
>  		else
>  			cntl &= ~CURSOR_ROTATE_180;
> @@ -7500,6 +7507,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base, bool force)
>  	bool visible = base != 0;
>  
>  	if (force || intel_crtc->cursor_visible != visible) {
> +		unsigned int rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +							   intel_crtc->cursor_rotation);
>  		uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
>  		if (base) {
>  			cntl &= ~CURSOR_MODE;
> @@ -7512,7 +7521,7 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base, bool force)
>  			cntl |= CURSOR_PIPE_CSC_ENABLE;
>  			cntl &= ~CURSOR_TRICKLE_FEED_DISABLE;
>  		}
> -		if (intel_crtc->cursor_rotation == BIT(DRM_ROTATE_180))
> +		if (rotation == BIT(DRM_ROTATE_180))
>  			cntl |= CURSOR_ROTATE_180;
>  		else
>  			cntl &= ~CURSOR_ROTATE_180;
> @@ -7538,10 +7547,24 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>  	int y = intel_crtc->cursor_y;
>  	u32 base = 0, pos = 0;
>  	bool visible;
> +	struct drm_rect r = {
> +		.x1 = x,
> +		.x2 = x + intel_crtc->cursor_width,
> +		.y1 = y,
> +		.y2 = y + intel_crtc->cursor_height,
> +	};
>  
>  	if (on)
>  		base = intel_crtc->cursor_addr;
>  
> +	drm_rect_rotate(&r,
> +			intel_crtc->config.pipe_src_w,
> +			intel_crtc->config.pipe_src_h,
> +			intel_crtc->pipe_rotation);
> +
> +	x = r.x1;
> +	y = r.y1;
> +
>  	if (x >= intel_crtc->config.pipe_src_w)
>  		base = 0;
>  
> @@ -8818,6 +8841,66 @@ free_work:
>  	return ret;
>  }
>  
> +static int intel_set_primary_plane_rotation(struct intel_crtc *crtc,
> +					    unsigned int rotation)
> +{
> +	struct drm_device *dev = crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	unsigned int old_rotation;
> +	int ret = 0;
> +
> +	old_rotation = crtc->primary_rotation;
> +	crtc->primary_rotation = rotation;
> +
> +	if (!crtc->active)
> +		return 0;
> +
> +	rotation = drm_rotation_chain(crtc->pipe_rotation,
> +				      crtc->primary_rotation);
> +
> +	intel_crtc_wait_for_pending_flips(&crtc->base);
> +
> +	/* FBC does not work on some platforms for rotated planes */
> +	if (dev_priv->fbc.plane == crtc->plane &&
> +	    INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
> +	    rotation != BIT(DRM_ROTATE_0))
> +		intel_disable_fbc(dev);
> +
> +	ret = dev_priv->display.update_plane(&crtc->base, crtc->base.fb, 0, 0);
> +	if (ret)
> +		crtc->primary_rotation = old_rotation;
> +
> +	return ret;
> +}
> +
> +static void intel_set_cursor_plane_rotation(struct intel_crtc *crtc,
> +					    unsigned int rotation)
> +{
> +	crtc->cursor_rotation = rotation;
> +
> +	if (crtc->active)
> +		intel_crtc_update_cursor(&crtc->base, true, true);
> +}
> +
> +static int intel_update_planes(struct intel_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->base.dev;
> +	struct intel_plane *plane;
> +
> +	list_for_each_entry(plane, &dev->mode_config.plane_list, base.head) {
> +		int ret;
> +
> +		if (plane->pipe != crtc->pipe)
> +			continue;
> +
> +		ret = intel_plane_restore(&plane->base);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int intel_crtc_set_property(struct drm_crtc *crtc,
>  				    struct drm_property *prop,
>  				    uint64_t val)
> @@ -8828,27 +8911,51 @@ static int intel_crtc_set_property(struct drm_crtc *crtc,
>  	uint64_t old_val;
>  	int ret = -ENOENT;
>  
> -	if (prop == dev_priv->plane_rotation_property) {
> +	if (prop == dev_priv->rotation_property) {
>  		/* exactly one rotation angle please */
>  		if (hweight32(val & 0xf) != 1)
>  			return -EINVAL;
>  
> -		old_val = intel_crtc->primary_rotation;
> -		intel_crtc->primary_rotation = val;
> +		old_val = intel_crtc->pipe_rotation;
> +		intel_crtc->pipe_rotation = val;
>  
> -		if (intel_crtc->active) {
> -			intel_crtc_wait_for_pending_flips(crtc);
> -
> -			/* FBC does not work on some platforms for rotated planes */
> -			if (dev_priv->fbc.plane == intel_crtc->plane &&
> -			    INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
> -			    intel_crtc->primary_rotation != BIT(DRM_ROTATE_0))
> -				intel_disable_fbc(dev);
> +		ret = intel_set_primary_plane_rotation(intel_crtc,
> +						       intel_crtc->primary_rotation);
> +		if (ret) {
> +			intel_crtc->pipe_rotation = old_val;
> +			return ret;
> +		}
>  
> -			ret = dev_priv->display.update_plane(crtc, crtc->fb, 0, 0);
> -			if (ret)
> -				intel_crtc->primary_rotation = old_val;
> +		ret = intel_update_planes(intel_crtc);
> +		if (ret) {
> +			intel_crtc->pipe_rotation = old_val;
> +
> +			if (intel_set_primary_plane_rotation(intel_crtc,
> +							     intel_crtc->primary_rotation))
> +				DRM_ERROR("failed to restore primary plane rotation\n");
> +			if (intel_update_planes(intel_crtc))
> +				DRM_ERROR("failed to restore sprite plane rotation\n");
> +			return ret;
>  		}
> +
> +		intel_set_cursor_plane_rotation(intel_crtc,
> +						intel_crtc->cursor_rotation);
> +
> +		return 0;
> +	} else if (prop == dev_priv->cursor_rotation_property) {
> +		/* exactly one rotation angle please */
> +		if (hweight32(val & 0xf) != 1)
> +			return -EINVAL;
> +
> +		intel_set_cursor_plane_rotation(intel_crtc, val);
> +
> +		return 0;
> +	} else if (prop == dev_priv->plane_rotation_property) {
> +		/* exactly one rotation angle please */
> +		if (hweight32(val & 0xf) != 1)
> +			return -EINVAL;
> +
> +		return intel_set_primary_plane_rotation(intel_crtc, val);
>  	}
>  
>  	return ret;
> @@ -10397,6 +10504,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  	intel_crtc->plane = pipe;
>  	intel_crtc->primary_rotation = BIT(DRM_ROTATE_0);
>  	intel_crtc->cursor_rotation = BIT(DRM_ROTATE_0);
> +	intel_crtc->pipe_rotation = BIT(DRM_ROTATE_0);
>  	if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) {
>  		DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
>  		intel_crtc->plane = !pipe;
> @@ -10427,6 +10535,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  			drm_object_attach_property(&intel_crtc->base.base,
>  						dev_priv->cursor_rotation_property,
>  						intel_crtc->cursor_rotation);
> +
> +		if (!dev_priv->rotation_property)
> +			dev_priv->rotation_property =
> +				drm_mode_create_rotation_property(dev, "rotation",
> +								  BIT(DRM_ROTATE_0) |
> +								  BIT(DRM_ROTATE_180));
> +		if (dev_priv->rotation_property)
> +			drm_object_attach_property(&intel_crtc->base.base,
> +						   dev_priv->rotation_property,
> +						   intel_crtc->pipe_rotation);
>  	}
>  
>  	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 4a7f4f1..f967abf 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -333,6 +333,7 @@ struct intel_crtc {
>  	enum plane plane;
>  	unsigned int primary_rotation; /* primary plane in relation to the pipe */
>  	unsigned int cursor_rotation; /* cursor plane in relation to the pipe */
> +	unsigned int pipe_rotation; /* entire pipe */
>  
>  	u8 lut_r[256], lut_g[256], lut_b[256];
>  	/*
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 5ebeb78..3735815 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -463,6 +463,7 @@ void intel_update_fbc(struct drm_device *dev)
>  	struct drm_i915_gem_object *obj;
>  	const struct drm_display_mode *adjusted_mode;
>  	unsigned int max_width, max_height;
> +	unsigned int rotation;
>  
>  	if (!HAS_FBC(dev)) {
>  		set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
> @@ -557,8 +558,11 @@ void intel_update_fbc(struct drm_device *dev)
>  		goto out_disable;
>  	}
>  
> +	rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +				      intel_crtc->primary_rotation);
> +
>  	if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
> -	    intel_crtc->primary_rotation != BIT(DRM_ROTATE_0)) {
> +	    rotation != BIT(DRM_ROTATE_0)) {
>  		if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
>  			DRM_DEBUG_KMS("mode incompatible with compression, "
>  				      "disabling\n");
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 2936007..e1d593c 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -53,6 +53,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>  	u32 sprctl;
>  	unsigned long sprsurf_offset, linear_offset;
>  	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
> +	unsigned int rotation = drm_rotation_chain(to_intel_crtc(crtc)->pipe_rotation,
> +						   intel_plane->rotation);
>  
>  	sprctl = I915_READ(SPCNTR(pipe, plane));
>  
> @@ -132,7 +134,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>  							fb->pitches[0]);
>  	linear_offset -= sprsurf_offset;
>  
> -	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
> +	if (rotation == BIT(DRM_ROTATE_180)) {
>  		sprctl |= SP_ROTATE_180;
>  
>  		x += src_w;
> @@ -239,6 +241,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  	u32 sprctl, sprscale = 0;
>  	unsigned long sprsurf_offset, linear_offset;
>  	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
> +	unsigned int rotation = drm_rotation_chain(to_intel_crtc(crtc)->pipe_rotation,
> +						   intel_plane->rotation);
>  
>  	sprctl = I915_READ(SPRCTL(pipe));
>  
> @@ -309,7 +313,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  					       pixel_size, fb->pitches[0]);
>  	linear_offset -= sprsurf_offset;
>  
> -	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
> +	if (rotation == BIT(DRM_ROTATE_180)) {
>  		sprctl |= SPRITE_ROTATE_180;
>  
>  		/* HSW and BDW does this automagically in hardware */
> @@ -435,6 +439,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  	unsigned long dvssurf_offset, linear_offset;
>  	u32 dvscntr, dvsscale;
>  	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
> +	unsigned int rotation = drm_rotation_chain(to_intel_crtc(crtc)->pipe_rotation,
> +						   intel_plane->rotation);
>  
>  	dvscntr = I915_READ(DVSCNTR(pipe));
>  
> @@ -500,7 +506,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  					       pixel_size, fb->pitches[0]);
>  	linear_offset -= dvssurf_offset;
>  
> -	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
> +	if (rotation == BIT(DRM_ROTATE_180)) {
>  		dvscntr |= DVS_ROTATE_180;
>  
>  		x += src_w;
> @@ -738,6 +744,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  		.src_w = src_w,
>  		.src_h = src_h,
>  	};
> +	unsigned int rotation = drm_rotation_chain(intel_crtc->pipe_rotation,
> +						   intel_plane->rotation);
>  
>  	/* Don't modify another pipe's plane */
>  	if (intel_plane->pipe != intel_crtc->pipe) {
> @@ -769,8 +777,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  	max_scale = intel_plane->max_downscale << 16;
>  	min_scale = intel_plane->can_scale ? 1 : (1 << 16);
>  
> +	drm_rect_rotate(&dst, drm_rect_width(&clip), drm_rect_height(&clip),
> +			intel_crtc->pipe_rotation);
> +
>  	drm_rect_rotate(&src, fb->width << 16, fb->height << 16,
> -			intel_plane->rotation);
> +			rotation);
>  
>  	hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale);
>  	BUG_ON(hscale < 0);
> @@ -811,7 +822,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>  				     drm_rect_height(&dst) * vscale - drm_rect_height(&src));
>  
>  		drm_rect_rotate_inv(&src, fb->width << 16, fb->height << 16,
> -				    intel_plane->rotation);
> +				    rotation);
>  
>  		/* sanity check to make sure the src viewport wasn't enlarged */
>  		WARN_ON(src.x1 < (int) src_x ||




More information about the dri-devel mailing list