drm/i915: Fix offset page-flips on i965+
authorChris Wilson <chris@chris-wilson.co.uk>
Sun, 8 Aug 2010 09:15:59 +0000 (10:15 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 7 Sep 2010 10:13:00 +0000 (11:13 +0100)
i965 uses the Display Registers to compute the offset from the display
base so the new base does not need adjusting when flipping. The older
chipsets use a fence to access the display and so do perceive the
surface as linear and have a single base register which is reprogrammed
using the flip.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Reported-by: Marty Jack <martyj19@comcast.net>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/gpu/drm/i915/intel_display.c

index 3fc767b..334665c 100644 (file)
@@ -5042,9 +5042,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        unsigned long flags, offset;
-       int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
-       int ret, pipesrc;
-       u32 flip_mask;
+       int pipe = intel_crtc->pipe;
+       u32 pf, pipesrc;
+       int ret;
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (work == NULL)
@@ -5093,12 +5093,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        atomic_inc(&obj_priv->pending_flip);
        work->pending_flip_obj = obj;
 
-       if (intel_crtc->plane)
-               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
-       else
-               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
        if (IS_GEN3(dev) || IS_GEN2(dev)) {
+               u32 flip_mask;
+
+               if (intel_crtc->plane)
+                       flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+               else
+                       flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
                BEGIN_LP_RING(2);
                OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
                OUT_RING(0);
@@ -5106,29 +5108,56 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        }
 
        /* Offset into the new buffer for cases of shared fbs between CRTCs */
-       offset = obj_priv->gtt_offset;
-       offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8);
+       offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;
 
        BEGIN_LP_RING(4);
-       if (IS_I965G(dev)) {
+       switch(INTEL_INFO(dev)->gen) {
+       case 2:
                OUT_RING(MI_DISPLAY_FLIP |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch);
-               OUT_RING(offset | obj_priv->tiling_mode);
-               pipesrc = I915_READ(pipesrc_reg); 
-               OUT_RING(pipesrc & 0x0fff0fff);
-       } else if (IS_GEN3(dev)) {
+               OUT_RING(obj_priv->gtt_offset + offset);
+               OUT_RING(MI_NOOP);
+               break;
+
+       case 3:
                OUT_RING(MI_DISPLAY_FLIP_I915 |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch);
-               OUT_RING(offset);
+               OUT_RING(obj_priv->gtt_offset + offset);
                OUT_RING(MI_NOOP);
-       } else {
+               break;
+
+       case 4:
+       case 5:
+               /* i965+ uses the linear or tiled offsets from the
+                * Display Registers (which do not change across a page-flip)
+                * so we need only reprogram the base address.
+                */
                OUT_RING(MI_DISPLAY_FLIP |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch);
-               OUT_RING(offset);
-               OUT_RING(MI_NOOP);
+               OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
+
+               /* XXX Enabling the panel-fitter across page-flip is so far
+                * untested on non-native modes, so ignore it for now.
+                * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
+                */
+               pf = 0;
+               pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
+               OUT_RING(pf | pipesrc);
+               break;
+
+       case 6:
+               OUT_RING(MI_DISPLAY_FLIP |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch | obj_priv->tiling_mode);
+               OUT_RING(obj_priv->gtt_offset);
+
+               pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
+               pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
+               OUT_RING(pf | pipesrc);
+               break;
        }
        ADVANCE_LP_RING();