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

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Wed Feb 12 13:15:04 PST 2014


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 ||
-- 
1.8.3.2



More information about the dri-devel mailing list