summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c120
1 files changed, 98 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index fc2b2a7..caaf1e2 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -136,12 +136,6 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
POSTING_READ(type##IIR); \
} while (0)
-static void
-intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, unsigned pipe)
-{
- DRM_DEBUG_KMS("Finished page flip\n");
-}
-
/*
* We should clear IMR at preinstall/uninstall, and just check at postinstall.
*/
@@ -1637,11 +1631,16 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
}
}
-static void intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
+static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- if (drm_handle_vblank(dev_priv->dev, pipe))
+ bool ret;
+
+ ret = drm_handle_vblank(dev_priv->dev, pipe);
+ if (ret)
intel_finish_page_flip_mmio(dev_priv, pipe);
+
+ return ret;
}
static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
@@ -1708,8 +1707,9 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe;
for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
- intel_pipe_handle_vblank(dev_priv, pipe);
+ if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
+ intel_pipe_handle_vblank(dev_priv, pipe))
+ intel_check_page_flip(dev_priv, pipe);
if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
intel_finish_page_flip_cs(dev_priv, pipe);
@@ -2155,8 +2155,9 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
DRM_ERROR("Poison interrupt\n");
for_each_pipe(dev_priv, pipe) {
- if (de_iir & DE_PIPE_VBLANK(pipe))
- intel_pipe_handle_vblank(dev_priv, pipe);
+ if (de_iir & DE_PIPE_VBLANK(pipe) &&
+ intel_pipe_handle_vblank(dev_priv, pipe))
+ intel_check_page_flip(dev_priv, pipe);
if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
@@ -2205,8 +2206,9 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
intel_opregion_asle_intr(dev_priv);
for_each_pipe(dev_priv, pipe) {
- if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
- intel_pipe_handle_vblank(dev_priv, pipe);
+ if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
+ intel_pipe_handle_vblank(dev_priv, pipe))
+ intel_check_page_flip(dev_priv, pipe);
/* plane/pipes map 1:1 on ilk+ */
if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
@@ -2405,8 +2407,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
ret = IRQ_HANDLED;
I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
- if (iir & GEN8_PIPE_VBLANK)
- intel_pipe_handle_vblank(dev_priv, pipe);
+ if (iir & GEN8_PIPE_VBLANK &&
+ intel_pipe_handle_vblank(dev_priv, pipe))
+ intel_check_page_flip(dev_priv, pipe);
flip_done = iir;
if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -3972,6 +3975,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
return 0;
}
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
+ int plane, int pipe, u32 iir)
+{
+ u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
+
+ if (!intel_pipe_handle_vblank(dev_priv, pipe))
+ return false;
+
+ if ((iir & flip_pending) == 0)
+ goto check_page_flip;
+
+ /* We detect FlipDone by looking for the change in PendingFlip from '1'
+ * to '0' on the following vblank, i.e. IIR has the Pendingflip
+ * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+ * the flip is completed (no longer pending). Since this doesn't raise
+ * an interrupt per se, we watch for the change at vblank.
+ */
+ if (I915_READ16(ISR) & flip_pending)
+ goto check_page_flip;
+
+ intel_finish_page_flip_cs(dev_priv, pipe);
+ return true;
+
+check_page_flip:
+ intel_check_page_flip(dev_priv, pipe);
+ return false;
+}
+
static irqreturn_t i8xx_irq_handler(int irq, void *arg)
{
struct drm_device *dev = arg;
@@ -4024,8 +4058,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
notify_ring(&dev_priv->engine[RCS]);
for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
- intel_pipe_handle_vblank(dev_priv, pipe);
+ int plane = pipe;
+ if (HAS_FBC(dev_priv))
+ plane = !plane;
+
+ if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ i8xx_handle_vblank(dev_priv, plane, pipe, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev_priv, pipe);
@@ -4125,6 +4164,37 @@ static int i915_irq_postinstall(struct drm_device *dev)
return 0;
}
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
+ int plane, int pipe, u32 iir)
+{
+ u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
+
+ if (!intel_pipe_handle_vblank(dev_priv, pipe))
+ return false;
+
+ if ((iir & flip_pending) == 0)
+ goto check_page_flip;
+
+ /* We detect FlipDone by looking for the change in PendingFlip from '1'
+ * to '0' on the following vblank, i.e. IIR has the Pendingflip
+ * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+ * the flip is completed (no longer pending). Since this doesn't raise
+ * an interrupt per se, we watch for the change at vblank.
+ */
+ if (I915_READ(ISR) & flip_pending)
+ goto check_page_flip;
+
+ intel_finish_page_flip_cs(dev_priv, pipe);
+ return true;
+
+check_page_flip:
+ intel_check_page_flip(dev_priv, pipe);
+ return false;
+}
+
static irqreturn_t i915_irq_handler(int irq, void *arg)
{
struct drm_device *dev = arg;
@@ -4185,8 +4255,13 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
notify_ring(&dev_priv->engine[RCS]);
for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
- intel_pipe_handle_vblank(dev_priv, pipe);
+ int plane = pipe;
+ if (HAS_FBC(dev_priv))
+ plane = !plane;
+
+ if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ i915_handle_vblank(dev_priv, plane, pipe, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
@@ -4414,8 +4489,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
notify_ring(&dev_priv->engine[VCS]);
for_each_pipe(dev_priv, pipe) {
- if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
- intel_pipe_handle_vblank(dev_priv, pipe);
+ if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
+ i915_handle_vblank(dev_priv, pipe, pipe, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
OpenPOWER on IntegriCloud