[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