drm/i915: Always apply cursor width changes
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 30 May 2014 13:35:26 +0000 (16:35 +0300)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 5 Jun 2014 06:52:45 +0000 (08:52 +0200)
It is possible for userspace to create a big object large enough for a
256x256, and then switch over to using it as a 64x64 cursor. This
requires the cursor update routines to check for a change in width on
every update, rather than just when the cursor is originally enabled.

This also fixes an issue with 845g/865g which cannot change the base
address of the cursor whilst it is active.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
[Antti:rebased, adjusted macro names and moved some lines, no functional
changes]
Reviewed-by: Antti Koskipaa <antti.koskipaa@linux.intel.com>
Tested-by: Antti Koskipaa <antti.koskipaa@linux.intel.com>
Cc: stable@vger.kernel.org
Testcase: igt/kms_cursor_crc/cursor-size-change
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index 98ab492..601caa8 100644 (file)
@@ -2353,7 +2353,7 @@ static int i915_display_info(struct seq_file *m, void *unused)
 
                        active = cursor_position(dev, crtc->pipe, &x, &y);
                        seq_printf(m, "\tcursor visible? %s, position (%d, %d), addr 0x%08x, active? %s\n",
-                                  yesno(crtc->cursor_visible),
+                                  yesno(crtc->cursor_base),
                                   x, y, crtc->cursor_addr,
                                   yesno(active));
                }
index ea0b5df..5abef04 100644 (file)
@@ -7866,29 +7866,33 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       bool visible = base != 0;
-       u32 cntl;
+       uint32_t cntl;
 
-       if (intel_crtc->cursor_visible == visible)
-               return;
-
-       cntl = I915_READ(_CURACNTR);
-       if (visible) {
+       if (base != intel_crtc->cursor_base) {
                /* On these chipsets we can only modify the base whilst
                 * the cursor is disabled.
                 */
+               if (intel_crtc->cursor_cntl) {
+                       I915_WRITE(_CURACNTR, 0);
+                       POSTING_READ(_CURACNTR);
+                       intel_crtc->cursor_cntl = 0;
+               }
+
                I915_WRITE(_CURABASE, base);
+               POSTING_READ(_CURABASE);
+       }
 
-               cntl &= ~(CURSOR_FORMAT_MASK);
-               /* XXX width must be 64, stride 256 => 0x00 << 28 */
-               cntl |= CURSOR_ENABLE |
+       /* XXX width must be 64, stride 256 => 0x00 << 28 */
+       cntl = 0;
+       if (base)
+               cntl = (CURSOR_ENABLE |
                        CURSOR_GAMMA_ENABLE |
-                       CURSOR_FORMAT_ARGB;
-       } else
-               cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
-       I915_WRITE(_CURACNTR, cntl);
-
-       intel_crtc->cursor_visible = visible;
+                       CURSOR_FORMAT_ARGB);
+       if (intel_crtc->cursor_cntl != cntl) {
+               I915_WRITE(_CURACNTR, cntl);
+               POSTING_READ(_CURACNTR);
+               intel_crtc->cursor_cntl = cntl;
+       }
 }
 
 static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
@@ -7897,16 +7901,12 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       bool visible = base != 0;
-
-       if (intel_crtc->cursor_visible != visible) {
-               int16_t width = intel_crtc->cursor_width;
-               uint32_t cntl = I915_READ(CURCNTR(pipe));
-               if (base) {
-                       cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
-                       cntl |= MCURSOR_GAMMA_ENABLE;
+       uint32_t cntl;
 
-                       switch (width) {
+       cntl = 0;
+       if (base) {
+               cntl = MCURSOR_GAMMA_ENABLE;
+               switch (intel_crtc->cursor_width) {
                        case 64:
                                cntl |= CURSOR_MODE_64_ARGB_AX;
                                break;
@@ -7919,18 +7919,16 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
                        default:
                                WARN_ON(1);
                                return;
-                       }
-                       cntl |= pipe << 28; /* Connect to correct pipe */
-               } else {
-                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
-                       cntl |= CURSOR_MODE_DISABLE;
                }
+               cntl |= pipe << 28; /* Connect to correct pipe */
+       }
+       if (intel_crtc->cursor_cntl != cntl) {
                I915_WRITE(CURCNTR(pipe), cntl);
-
-               intel_crtc->cursor_visible = visible;
+               POSTING_READ(CURCNTR(pipe));
+               intel_crtc->cursor_cntl = cntl;
        }
+
        /* and commit changes on next vblank */
-       POSTING_READ(CURCNTR(pipe));
        I915_WRITE(CURBASE(pipe), base);
        POSTING_READ(CURBASE(pipe));
 }
@@ -7941,15 +7939,12 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       bool visible = base != 0;
-
-       if (intel_crtc->cursor_visible != visible) {
-               int16_t width = intel_crtc->cursor_width;
-               uint32_t cntl = I915_READ(CURCNTR(pipe));
-               if (base) {
-                       cntl &= ~CURSOR_MODE;
-                       cntl |= MCURSOR_GAMMA_ENABLE;
-                       switch (width) {
+       uint32_t cntl;
+
+       cntl = 0;
+       if (base) {
+               cntl = MCURSOR_GAMMA_ENABLE;
+               switch (intel_crtc->cursor_width) {
                        case 64:
                                cntl |= CURSOR_MODE_64_ARGB_AX;
                                break;
@@ -7962,21 +7957,18 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
                        default:
                                WARN_ON(1);
                                return;
-                       }
-               } else {
-                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
-                       cntl |= CURSOR_MODE_DISABLE;
-               }
-               if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-                       cntl |= CURSOR_PIPE_CSC_ENABLE;
-                       cntl &= ~CURSOR_TRICKLE_FEED_DISABLE;
                }
-               I915_WRITE(CURCNTR(pipe), cntl);
+       }
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               cntl |= CURSOR_PIPE_CSC_ENABLE;
 
-               intel_crtc->cursor_visible = visible;
+       if (intel_crtc->cursor_cntl != cntl) {
+               I915_WRITE(CURCNTR(pipe), cntl);
+               POSTING_READ(CURCNTR(pipe));
+               intel_crtc->cursor_cntl = cntl;
        }
+
        /* and commit changes on next vblank */
-       POSTING_READ(CURCNTR(pipe));
        I915_WRITE(CURBASE(pipe), base);
        POSTING_READ(CURBASE(pipe));
 }
@@ -7992,7 +7984,6 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        int x = intel_crtc->cursor_x;
        int y = intel_crtc->cursor_y;
        u32 base = 0, pos = 0;
-       bool visible;
 
        if (on)
                base = intel_crtc->cursor_addr;
@@ -8021,8 +8012,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        }
        pos |= y << CURSOR_Y_SHIFT;
 
-       visible = base != 0;
-       if (!visible && !intel_crtc->cursor_visible)
+       if (base == 0 && intel_crtc->cursor_base == 0)
                return;
 
        I915_WRITE(CURPOS(pipe), pos);
@@ -8033,6 +8023,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
                i845_update_cursor(crtc, base);
        else
                i9xx_update_cursor(crtc, base);
+       intel_crtc->cursor_base = base;
 }
 
 static int intel_crtc_cursor_set(struct drm_crtc *crtc,
@@ -10993,6 +10984,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
                intel_crtc->plane = !pipe;
        }
 
+       intel_crtc->cursor_base = ~0;
+       intel_crtc->cursor_cntl = ~0;
+
        init_waitqueue_head(&intel_crtc->vbl_wait);
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
index 8ce90d6..bda0ae3 100644 (file)
@@ -386,7 +386,8 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_x, cursor_y;
        int16_t cursor_width, cursor_height;
-       bool cursor_visible;
+       uint32_t cursor_cntl;
+       uint32_t cursor_base;
 
        struct intel_plane_config plane_config;
        struct intel_crtc_config config;