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


Reply via email to