drm/i915: gen3 page flipping fixes
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 26 Mar 2010 17:35:20 +0000 (10:35 -0700)
committerEric Anholt <eric@anholt.net>
Sat, 19 Jun 2010 00:59:53 +0000 (17:59 -0700)
Gen3 chips have slightly different flip commands, and also contain a bit
that indicates whether a "flip pending" interrupt means the flip has
been queued or has been completed.

So implement support for the gen3 flip command, and make sure we use the
flip pending interrupt correctly depending on the value of ECOSKPD bit
0.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index 84ce95602f00b478f5fe1ab90bdc6f7fa01276bc..4d59710c717e195d955e7849cba4132f72c0adbb 100644 (file)
@@ -1408,6 +1408,10 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                goto destroy_ringbuffer;
 
+       /* IIR "flip pending" bit means done if this bit is set */
+       if (IS_GEN3(dev) && (I915_READ(ECOSKPD) & ECO_FLIP_DONE))
+               dev_priv->flip_pending_is_done = true;
+
        intel_modeset_init(dev);
 
        ret = drm_irq_install(dev);
index f3f681fca76a7e69e2e1d8c4cac91944f96a83cf..21e217dd48efdc0af6c2ec136dbd2b3ac7763780 100644 (file)
@@ -595,6 +595,7 @@ typedef struct drm_i915_private {
        struct drm_crtc *plane_to_crtc_mapping[2];
        struct drm_crtc *pipe_to_crtc_mapping[2];
        wait_queue_head_t pending_flip_queue;
+       bool flip_pending_is_done;
 
        /* Reclocking support */
        bool render_reclock_avail;
index e9710a7005d4f80853504b6bbd2f61be505ee66a..70e1e4b6674467c69ae1fd8b0e69c68c8688f314 100644 (file)
@@ -940,22 +940,30 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
                        DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
 
-               if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
+               if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
                        intel_prepare_page_flip(dev, 0);
+                       if (dev_priv->flip_pending_is_done)
+                               intel_finish_page_flip_plane(dev, 0);
+               }
 
-               if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
+               if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
+                       if (dev_priv->flip_pending_is_done)
+                               intel_finish_page_flip_plane(dev, 1);
                        intel_prepare_page_flip(dev, 1);
+               }
 
                if (pipea_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 0);
-                       intel_finish_page_flip(dev, 0);
+                       if (!dev_priv->flip_pending_is_done)
+                               intel_finish_page_flip(dev, 0);
                }
 
                if (pipeb_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 1);
-                       intel_finish_page_flip(dev, 1);
+                       if (!dev_priv->flip_pending_is_done)
+                               intel_finish_page_flip(dev, 1);
                }
 
                if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
index 64b0a3afd92bcd8cdb11c71ba455edbad156396e..2cae38a572477229d7f0872b9f4c6187dcb2a7ac 100644 (file)
 #define   MI_OVERLAY_OFF       (0x2<<21)
 #define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
 #define MI_DISPLAY_FLIP                MI_INSTR(0x14, 2)
+#define MI_DISPLAY_FLIP_I915   MI_INSTR(0x14, 1)
 #define   MI_DISPLAY_FLIP_PLANE(n) ((n) << 20)
 #define MI_STORE_DWORD_IMM     MI_INSTR(0x20, 1)
 #define   MI_MEM_VIRTUAL       (1 << 22) /* 965+ only */
 #define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
 #define BB_ADDR                0x02140 /* 8 bytes */
 #define GFX_FLSH_CNTL  0x02170 /* 915+ only */
+#define ECOSKPD                0x021d0
+#define   ECO_GATING_CX_ONLY   (1<<3)
+#define   ECO_FLIP_DONE                (1<<0)
 
 /* GEN6 interrupt control */
 #define GEN6_RENDER_HWSTAM     0x2098
index dc65a1de5f0206daf29f992077d44fd48af057ce..6db778a75e42db23af382dcd71e2358018fb7c77 100644 (file)
@@ -4603,10 +4603,10 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        kfree(work);
 }
 
-void intel_finish_page_flip(struct drm_device *dev, int pipe)
+static void do_intel_finish_page_flip(struct drm_device *dev,
+                                     struct drm_crtc *crtc)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        struct drm_i915_gem_object *obj_priv;
@@ -4650,6 +4650,22 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
        schedule_work(&work->work);
 }
 
+void intel_finish_page_flip(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+       do_intel_finish_page_flip(dev, crtc);
+}
+
+void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
+
+       do_intel_finish_page_flip(dev, crtc);
+}
+
 void intel_prepare_page_flip(struct drm_device *dev, int plane)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4745,14 +4761,17 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                        ;
 
        BEGIN_LP_RING(4);
-       OUT_RING(MI_DISPLAY_FLIP |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitch);
        if (IS_I965G(dev)) {
+               OUT_RING(MI_DISPLAY_FLIP |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch);
                OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
                pipesrc = I915_READ(pipesrc_reg); 
                OUT_RING(pipesrc & 0x0fff0fff);
        } else {
+               OUT_RING(MI_DISPLAY_FLIP_I915 |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch);
                OUT_RING(obj_priv->gtt_offset);
                OUT_RING(MI_NOOP);
        }
index df931f7876652e7af0b8f6f480fdbd05ce3596ae..72206f37c4fb847c8d32d80c5c893fd3a68a5faa 100644 (file)
@@ -224,6 +224,7 @@ extern void intel_fbdev_fini(struct drm_device *dev);
 
 extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
 extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
+extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 
 extern void intel_setup_overlay(struct drm_device *dev);
 extern void intel_cleanup_overlay(struct drm_device *dev);