drm/i915: support page flipping on ValleyView
authorJesse Barnes <jbarnes@virtuousgeek.org>
Wed, 20 Jun 2012 17:53:11 +0000 (10:53 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 20 Jun 2012 20:51:26 +0000 (22:51 +0200)
And restructure the IRQ handling a little.  We can use pipestat for most
things, and make sure we don't affect pipe events when enabling and
disabling vblank interupts.

We can leave vblank interrupts masked but enabled so we're not dependent
on the first client to toggle the disable timer.  We can also mask all
render based interrupts, since the ring code will handle unmasking them
for us.

v2: roll in vblank masking, remove unneeded variable (Daniel)

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_irq.c

index add0aae..84975e1 100644 (file)
@@ -513,15 +513,10 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
        unsigned long irqflags;
        int pipe;
        u32 pipe_stats[I915_MAX_PIPES];
-       u32 vblank_status;
-       int vblank = 0;
        bool blc_event;
 
        atomic_inc(&dev_priv->irq_received);
 
-       vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS |
-               PIPE_VBLANK_INTERRUPT_STATUS;
-
        while (true) {
                iir = I915_READ(VLV_IIR);
                gt_iir = I915_READ(GTIIR);
@@ -551,6 +546,16 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
+               for_each_pipe(pipe) {
+                       if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+                               drm_handle_vblank(dev, pipe);
+
+                       if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
+                               intel_prepare_page_flip(dev, pipe);
+                               intel_finish_page_flip(dev, pipe);
+                       }
+               }
+
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
@@ -565,19 +570,6 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
-
-               if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) {
-                       drm_handle_vblank(dev, 0);
-                       vblank++;
-                       intel_finish_page_flip(dev, 0);
-               }
-
-               if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) {
-                       drm_handle_vblank(dev, 1);
-                       vblank++;
-                       intel_finish_page_flip(dev, 0);
-               }
-
                if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                        blc_event = true;
 
@@ -1479,23 +1471,20 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       u32 dpfl, imr;
+       u32 imr;
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       dpfl = I915_READ(VLV_DPFLIPSTAT);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0) {
-               dpfl |= PIPEA_VBLANK_INT_EN;
+       if (pipe == 0)
                imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       } else {
-               dpfl |= PIPEA_VBLANK_INT_EN;
+       else
                imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       }
-       I915_WRITE(VLV_DPFLIPSTAT, dpfl);
        I915_WRITE(VLV_IMR, imr);
+       i915_enable_pipestat(dev_priv, pipe,
+                            PIPE_START_VBLANK_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -1545,20 +1534,17 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       u32 dpfl, imr;
+       u32 imr;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       dpfl = I915_READ(VLV_DPFLIPSTAT);
+       i915_disable_pipestat(dev_priv, pipe,
+                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0) {
-               dpfl &= ~PIPEA_VBLANK_INT_EN;
+       if (pipe == 0)
                imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       } else {
-               dpfl &= ~PIPEB_VBLANK_INT_EN;
+       else
                imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       }
        I915_WRITE(VLV_IMR, imr);
-       I915_WRITE(VLV_DPFLIPSTAT, dpfl);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -1892,16 +1878,24 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 render_irqs;
        u32 enable_mask;
        u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
        u16 msid;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
-       enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
+       enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
+               I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
                I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
-       dev_priv->irq_mask = ~enable_mask;
+       /*
+        *Leave vblank interrupts masked initially.  enable/disable will
+        * toggle them based on usage.
+        */
+       dev_priv->irq_mask = (~enable_mask) |
+               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
+               I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
        dev_priv->pipestat[0] = 0;
        dev_priv->pipestat[1] = 0;
@@ -1920,26 +1914,27 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        I915_WRITE(PIPESTAT(1), 0xffff);
        POSTING_READ(VLV_IER);
 
+       i915_enable_pipestat(dev_priv, 0, pipestat_enable);
+       i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IIR, 0xffffffff);
 
-       render_irqs = GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT |
-               GT_GEN6_BLT_CS_ERROR_INTERRUPT |
-               GT_GEN6_BLT_USER_INTERRUPT |
-               GT_GEN6_BSD_USER_INTERRUPT |
-               GT_GEN6_BSD_CS_ERROR_INTERRUPT |
-               GT_GEN7_L3_PARITY_ERROR_INTERRUPT |
-               GT_PIPE_NOTIFY |
-               GT_RENDER_CS_ERROR_INTERRUPT |
-               GT_SYNC_STATUS |
-               GT_USER_INTERRUPT;
-
-       dev_priv->gt_irq_mask = ~render_irqs;
+       dev_priv->gt_irq_mask = ~0;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, 0);
-       I915_WRITE(GTIER, render_irqs);
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+       I915_WRITE(GTIER, GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT |
+                  GT_GEN6_BLT_CS_ERROR_INTERRUPT |
+                  GT_GEN6_BLT_USER_INTERRUPT |
+                  GT_GEN6_BSD_USER_INTERRUPT |
+                  GT_GEN6_BSD_CS_ERROR_INTERRUPT |
+                  GT_GEN7_L3_PARITY_ERROR_INTERRUPT |
+                  GT_PIPE_NOTIFY |
+                  GT_RENDER_CS_ERROR_INTERRUPT |
+                  GT_SYNC_STATUS |
+                  GT_USER_INTERRUPT);
        POSTING_READ(GTIER);
 
        /* ack & enable invalid PTE error interrupts */