This change is to comply with the BUN - Vblank interrupt on disabled pipe. BUN states - Do not unmask and enable a vertical blank interrupt on a pipe that is not enabled. Do not leave this interrupt enabled and unmasked after the associated pipe is disabled. If the vblank interrupt is unmasked and enabled on a disabled pipe it will block package C3, wasting power. Issue: HSD link - https://hsdhsw.intel.com/hsd/haswell_platform/default.aspx#sighting/default.aspx?sighting_id=4391617 Change Details: drmP.h Add two new functions to enable and disable the IER bit for Vblank interrupt. i915_irq.c Set these functions to interrupt_enable and interrupt_disable. intel_display.c Call interrupt_enable(), from intel_enable_pipe(), after pipe is enabled. Call interrupt_disable(), from intel_disable_pipe(), after pipe is disabled. Change-Id: I982654f6ca9a5d48b3d7bc569069a1b0b38f4280 Signed-off-by: Sandeep Ramankutty <sandeepx.ramakutty@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_irq.c | 51 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_display.c | 6 +++- include/drm/drmP.h | 20 +++++++++++++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bc14d30..89a5793 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -27,7 +27,6 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/sysrq.h> #include <linux/slab.h> #include <drm/drmP.h> @@ -2216,6 +2215,35 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe) return 0; } +/* Enable Vblank interrupt for the pipe. set IER bit. Bit - 0(A),5(B),10(c) */ +static void hsw_enable_interrupt(struct drm_device *dev, int pipe) +{ + u32 de_ier; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + /* Enable Vblank interrupt only if pipe is enabled */ + if (IS_HASWELL(dev) && i915_pipe_enabled(dev, pipe)) { + de_ier = I915_READ(DEIER); + de_ier |= (DE_PIPEA_VBLANK_IVB << (5 * pipe)); + I915_WRITE(DEIER, de_ier); + POSTING_READ(DEIMR); + } else + DRM_ERROR("Vblank Interrupt enable not allowed\n"); +} + +/* Disable Vblank interrupt for the pipe. set IER bit to 0. */ +static void hsw_disable_interrupt(struct drm_device *dev, int pipe) +{ + u32 de_ier; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (IS_HASWELL(dev)) { + de_ier = I915_READ(DEIER); + de_ier &= (~(DE_PIPEA_VBLANK_IVB << (5 * pipe))); + I915_WRITE(DEIER, de_ier); + POSTING_READ(DEIMR); + } else + DRM_ERROR("Vblank Interrupt disable failed\n"); +} + static int ivybridge_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2768,11 +2796,17 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); - I915_WRITE(DEIER, - display_mask | - DE_PIPEC_VBLANK_IVB | - DE_PIPEB_VBLANK_IVB | - DE_PIPEA_VBLANK_IVB); + + /* For Haswell, do not enable the Vblank interrupt by default. + Enable the interrupt when pipe is enabled */ + if (IS_HASWELL(dev)) { + I915_WRITE(DEIER, display_mask); + } else + I915_WRITE(DEIER, + display_mask | + DE_PIPEC_VBLANK_IVB | + DE_PIPEB_VBLANK_IVB | + DE_PIPEA_VBLANK_IVB); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; @@ -3623,6 +3657,11 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; + /* handlers to enable and disable vblank interrupt */ + if (IS_HASWELL(dev)) { + dev->driver->enable_interrupt = hsw_enable_interrupt; + dev->driver->disable_interrupt = hsw_disable_interrupt; + } dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24fa298..3efc25a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1646,6 +1646,9 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, return; I915_WRITE(reg, val | PIPECONF_ENABLE); + /* Enable Vblank interrupt for the pipe */ + dev_priv->dev->driver->enable_interrupt(dev_priv->dev, pipe); + intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1684,7 +1687,8 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, val = I915_READ(reg); if ((val & PIPECONF_ENABLE) == 0) return; - + /* Disable Vblank interrupt for the pipe */ + dev_priv->dev->driver->disable_interrupt(dev_priv->dev, pipe); I915_WRITE(reg, val & ~PIPECONF_ENABLE); intel_wait_for_pipe_off(dev_priv->dev, pipe); } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 4ccc955..78ad5dc 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -805,6 +805,26 @@ struct drm_driver { void (*disable_vblank) (struct drm_device *dev, int crtc); /** + * enable_interrupt - enable Vblank interrupt + * @dev: DRM device + * @crtc: which pipe to enable + * + * Enable Vblank interrupt for @crtc. If the device is connected + * i.e. the pipe is enabled, the Vblank interrupt is enabled. + */ + void (*enable_interrupt) (struct drm_device *dev, int crtc); + + /** + * disable_interrupt - disable interrupt + * @dev: DRM device + * @crtc: which pipe to enable + * + * Disable vblank interrupts for @crtc. If the device is disconnected + * or pipe is disabled the interrupt is disabled. + */ + void (*disable_interrupt) (struct drm_device *dev, int crtc); + + /** * Called by \c drm_device_is_agp. Typically used to determine if a * card is really attached to AGP or not. * -- 1.7.9.5 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx