diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 64b0a3a..d615710 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2013,6 +2013,7 @@ #define PIPE_DITHER_TYPE_ST01 (1 << 2) /* Pipe A */ #define PIPEADSL 0x70000 +#define PIPEASLC 0x70004 #define PIPEACONF 0x70008 #define PIPEACONF_ENABLE (1<<31) #define PIPEACONF_DISABLE 0 @@ -2265,6 +2266,7 @@ /* Pipe B */ #define PIPEBDSL 0x71000 +#define PIPEBSLC 0x71004 #define PIPEBCONF 0x71008 #define PIPEBSTAT 0x71024 #define PIPEBFRAMEHIGH 0x71040 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a8d65b7..827d022 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1739,6 +1739,28 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } +/* + * When we shut off a pipe, we need to clear any pending scanline wait events + * to avoid hanging the ring, which may be waiting on one. + */ +static void intel_clear_scanline_wait(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe_slc_reg = pipe == PIPE_A ? PIPEASLC : PIPEBSLC; + int vtotal_reg = pipe == PIPE_A ? VTOTAL_A : VTOTAL_B; + + if (IS_GEN6(dev)) { + /* + * SNB needs special treatment as different steppings + * have different scanline wait behaviors + */ + } else { + u32 vtotal = (I915_READ(vtotal_reg) >> 16) & 0xfff; + /* Just match anywhere in the display */ + I915_WRITE(pipe_slc_reg, (1<<31) | vtotal); + } +} + static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; @@ -1979,6 +2001,9 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } + intel_clear_scanline_wait(dev, pipeconf_reg == PIPEACONF ? + PIPE_A : PIPE_B); + i915_disable_vga(dev); /* disable cpu pipe, disable after all planes disabled */ @@ -2238,6 +2263,9 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); + intel_clear_scanline_wait(dev, pipeconf_reg == PIPEACONF ? + PIPE_A : PIPE_B); + /* Disable the VGA plane that we never use */ i915_disable_vga(dev);