From: Sagar Kamble <sagar.a.kam...@intel.com>

This patch enables 180 degree rotation for primary and sprite planes
through sysfs interface.

Signed-off-by: Uma Shankar <uma.shan...@intel.com>
Signed-off-by: Sagar Kamble <sagar.a.kam...@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h      |   1 +
 drivers/gpu/drm/i915/i915_sysfs.c    | 124 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |  28 +++++++-
 drivers/gpu/drm/i915/intel_drv.h     |   8 +++
 drivers/gpu/drm/i915/intel_sprite.c  |  38 +++++++++--
 5 files changed, 191 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 5d06ad6..92fa3d2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3555,6 +3555,7 @@
 #define   DISPPLANE_STEREO_POLARITY_SECOND     (1<<18)
 #define   DISPPLANE_TRICKLE_FEED_DISABLE       (1<<14) /* Ironlake */
 #define   DISPPLANE_TILED                      (1<<10)
+#define   DISPPLANE_180_ROTATION_ENABLE                (1<<15)
 #define _DSPAADDR              (dev_priv->info->display_mmio_offset + 0x70184)
 #define _DSPASTRIDE            (dev_priv->info->display_mmio_offset + 0x70188)
 #define _DSPAPOS               (dev_priv->info->display_mmio_offset + 0x7018C) 
/* reserved */
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c 
b/drivers/gpu/drm/i915/i915_sysfs.c
index 33bcae3..12a214c 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -127,6 +127,122 @@ static struct attribute_group rc6_attr_group = {
 };
 #endif
 
+int i915_set_180_rotation(struct drm_device *dev,
+                               struct i915_180_rotation *rotation)
+{
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       struct drm_plane *plane;
+       struct intel_plane *intel_plane;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       if (rotation->obj_type == DRM_MODE_OBJECT_PLANE) {
+               obj = drm_mode_object_find(dev, rotation->obj_id,
+                                               DRM_MODE_OBJECT_PLANE);
+               if (!obj) {
+                       DRM_DEBUG_DRIVER("Unknown PLANE ID %d\n",
+                                       rotation->obj_id);
+                       return -EINVAL;
+               }
+
+               plane = obj_to_plane(obj);
+               intel_plane = to_intel_plane(plane);
+               DRM_DEBUG_DRIVER("[SPRITE:%d] rotation set\n",
+                                               intel_plane->base.base.id);
+               intel_plane->rotate180 = (rotation->rotate & 0x1) ?
+                                                       true : false;
+               ret = 1;
+       } else if (rotation->obj_type == DRM_MODE_OBJECT_CRTC) {
+               obj = drm_mode_object_find(dev, rotation->obj_id,
+                                               DRM_MODE_OBJECT_CRTC);
+               if (!obj) {
+                       DRM_DEBUG_DRIVER("Unknown CRTC ID %d\n",
+                                               rotation->obj_id);
+                       return -EINVAL;
+               }
+
+               crtc = obj_to_crtc(obj);
+               if (!crtc->enabled) {
+                       DRM_DEBUG_DRIVER("[CRTC:%d] not active\n", 
crtc->base.id);
+                       return ret;
+               }
+               DRM_DEBUG_DRIVER("[CRTC:%d] rotation set\n", crtc->base.id);
+               intel_crtc = to_intel_crtc(crtc);
+               intel_crtc->rotate180 = (rotation->rotate & 0x1) ?
+                                                       true : false;
+               dev_priv->display.update_plane(crtc, crtc->fb, 0, 0);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static ssize_t
+i915_180_rotation_store(struct device *kdev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct drm_minor *minor = dev_to_drm_minor(kdev);
+       struct drm_device *dev = minor->dev;
+       struct i915_180_rotation rotation;
+       char buf1[30], id[11], type[11], val[2], format[18];
+       int len = 0, ret, no_of_tokens;
+       u32 rotate;
+
+       if (count == 0)
+               return -EINVAL;
+
+       /* Reset the string */
+       memset(buf1, 0, 30);
+       if (count > 0) {
+               if (count > sizeof(buf1) - 1)
+                       return -EINVAL;
+               memcpy(buf1, buf, count);
+       }
+
+       scnprintf(format, sizeof(format), "%%%zus %%%zus %%%zus",
+                       sizeof(id), sizeof(type), sizeof(val));
+
+       no_of_tokens = sscanf(buf1, format, id, type, val);
+       if (no_of_tokens < 3)
+               return len;
+
+       ret = kstrtou32(id, 0, &(rotation.obj_id));
+       if (ret)
+               return ret;
+
+       ret = kstrtou32(type, 0, &(rotation.obj_type));
+       if (ret)
+               return ret;
+
+       ret = kstrtou32(val, 0, &rotate);
+       if (ret)
+               return ret;
+
+       rotation.rotate = rotate ? true : false;
+
+       if (!i915_set_180_rotation(dev, &rotation))
+               return -EINVAL;
+
+       return count;
+}
+
+static DEVICE_ATTR(i915_180_rotation, S_IWUSR,
+                               NULL,
+                               i915_180_rotation_store);
+
+static struct attribute *display_attrs[] = {
+       &dev_attr_i915_180_rotation.attr,
+       NULL
+};
+
+static struct attribute_group display_attr_group = {
+       .name = "display",
+       .attrs =  display_attrs
+};
+
 static int l3_access_valid(struct drm_device *dev, loff_t offset)
 {
        if (!HAS_L3_DPF(dev))
@@ -568,6 +684,13 @@ void i915_setup_sysfs(struct drm_device *dev)
                        DRM_ERROR("RC6 residency sysfs setup failed\n");
        }
 #endif
+       if (INTEL_INFO(dev)->gen >= 6) {
+               ret = sysfs_create_group(&dev->primary->kdev->kobj,
+                                       &display_attr_group);
+               if (ret)
+                       DRM_ERROR("Display sysfs setup failed\n");
+       }
+
        if (HAS_L3_DPF(dev)) {
                ret = device_create_bin_file(dev->primary->kdev, &dpf_attrs);
                if (ret)
@@ -607,4 +730,5 @@ void i915_teardown_sysfs(struct drm_device *dev)
 #ifdef CONFIG_PM
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group);
 #endif
+       sysfs_unmerge_group(&dev->primary->kdev->kobj, &display_attr_group);
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index ec96002..5a1dc0b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -52,7 +52,6 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
                          int x, int y, struct drm_framebuffer *old_fb);
 
-
 typedef struct {
        int     min, max;
 } intel_range_t;
@@ -2034,7 +2033,10 @@ static int i9xx_update_plane(struct drm_crtc *crtc, 
struct drm_framebuffer *fb,
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj;
        int plane = intel_crtc->plane;
+       int pipe = intel_crtc->pipe;
        unsigned long linear_offset;
+       bool rotate = false;
+       int pixel_size = 0;
        u32 dspcntr;
        u32 reg;
 
@@ -2047,6 +2049,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, 
struct drm_framebuffer *fb,
                return -EINVAL;
        }
 
+       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
@@ -2085,6 +2088,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, 
struct drm_framebuffer *fb,
                BUG();
        }
 
+       if (intel_crtc->rotate180 && (pipe == 0))
+               rotate = true;
+
        if (INTEL_INFO(dev)->gen >= 4) {
                if (obj->tiling_mode != I915_TILING_NONE)
                        dspcntr |= DISPPLANE_TILED;
@@ -2095,6 +2101,11 @@ static int i9xx_update_plane(struct drm_crtc *crtc, 
struct drm_framebuffer *fb,
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
+       if (rotate)
+               dspcntr |= DISPPLANE_180_ROTATION_ENABLE;
+       else
+               dspcntr &= ~DISPPLANE_180_ROTATION_ENABLE;
+
        I915_WRITE(reg, dspcntr);
 
        linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -2116,8 +2127,18 @@ static int i9xx_update_plane(struct drm_crtc *crtc, 
struct drm_framebuffer *fb,
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_MODIFY_DISPBASE(DSPSURF(plane),
                                     i915_gem_obj_ggtt_offset(obj) + 
intel_crtc->dspaddr_offset);
-               I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
-               I915_WRITE(DSPLINOFF(plane), linear_offset);
+               if (rotate) {
+                       I915_WRITE(DSPTILEOFF(plane),
+                                  (((y + fb->height - 1) << 16) |
+                                   (x + fb->width - 1)));
+                       I915_WRITE(DSPLINOFF(plane),
+                                  linear_offset +
+                                  (fb->height - 1) * fb->pitches[0] +
+                                  fb->width * pixel_size);
+               } else {
+                       I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+                       I915_WRITE(DSPLINOFF(plane), linear_offset);
+               }
        } else
                I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + 
linear_offset);
        POSTING_READ(reg);
@@ -10317,6 +10338,7 @@ static void intel_crtc_init(struct drm_device *dev, int 
pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
+       intel_crtc->rotate180 = false;
        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 7b3c209..1c199fd 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -327,10 +327,17 @@ struct intel_pipe_wm {
        bool fbc_wm_enabled;
 };
 
+struct i915_180_rotation {
+       u32 obj_id;
+       u32 obj_type;
+       bool rotate;
+};
+
 struct intel_crtc {
        struct drm_crtc base;
        enum pipe pipe;
        enum plane plane;
+       bool rotate180;
        u8 lut_r[256], lut_g[256], lut_b[256];
        /*
         * Whether the crtc and the connected output pipeline is active. Implies
@@ -392,6 +399,7 @@ struct intel_plane {
        struct drm_i915_gem_object *obj;
        bool can_scale;
        int max_downscale;
+       bool rotate180;
        u32 lut_r[1024], lut_g[1024], lut_b[1024];
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
b/drivers/gpu/drm/i915/intel_sprite.c
index ed9fa7c..f3224fa 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -51,6 +51,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc 
*crtc,
        int pipe = intel_plane->pipe;
        int plane = intel_plane->plane;
        u32 sprctl;
+       bool rotate = false;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
@@ -118,6 +119,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc 
*crtc,
        intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
                                       src_w != crtc_w || src_h != crtc_h);
 
+       if (intel_plane->rotate180  && (pipe == 0))
+               rotate = true;
+
        /* Sizes are 0 based */
        src_w--;
        src_h--;
@@ -132,14 +136,37 @@ vlv_update_plane(struct drm_plane *dplane, struct 
drm_crtc *crtc,
        linear_offset -= sprsurf_offset;
 
        I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
-       I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
-
-       if (obj->tiling_mode != I915_TILING_NONE)
-               I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
+       if (rotate)
+               I915_WRITE(SPPOS(pipe, plane),
+                       ((crtc->hwmode.vdisplay - (crtc_y + crtc_h + 1))
+                       << 16) |
+                       (crtc->hwmode.hdisplay - (crtc_x + crtc_w + 1)));
        else
-               I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
+               I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
 
+       if (obj->tiling_mode != I915_TILING_NONE) {
+               if (rotate)
+                       I915_WRITE(SPTILEOFF(pipe, plane),
+                               ((y + crtc_h) << 16) | (x + crtc_w));
+               else
+                       I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
+       } else {
+               if (rotate) {
+                       int rot_linoff = linear_offset +
+                                        crtc_h * fb->pitches[0] +
+                                        (crtc_w + 1) * pixel_size;
+                       I915_WRITE(SPLINOFF(pipe, plane), rot_linoff);
+
+               } else
+                       I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
+       }
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
+
+       if (rotate)
+               sprctl |= DISPPLANE_180_ROTATION_ENABLE;
+       else
+               sprctl &= ~DISPPLANE_180_ROTATION_ENABLE;
+
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
        I915_MODIFY_DISPBASE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) 
+
                             sprsurf_offset);
@@ -1141,6 +1168,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, 
int plane)
 
        intel_plane->pipe = pipe;
        intel_plane->plane = plane;
+       intel_plane->rotate180 = false;
        possible_crtcs = (1 << pipe);
        ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
                             &intel_plane_funcs,
-- 
1.8.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to