aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2013-12-05 15:51:33 +0200
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-12-17 13:17:53 +0100
commitfacd619b8869b308e02104a200abf6f9d7cddcab (patch)
treed0dabad6f3bbdadfb893eb6a900761d5058c9641 /drivers/gpu/drm/i915
parent6cef2b8a5671dc6abbc0414a94be843590f93ede (diff)
drm/i915: Fix LP1+ watermark disabling ILK
On ILK disabling LP1+ watermarks must be done carefully to avoid underruns. If we just write 0 to the register in the middle of the scan cycle we often get an underrun. So instead we have to leave the actual watermark levels in the register intact, and just toggle the enable bit. Presumably the hardware takes a while to get out of low power mode, and so the watermark level need to stay valid until that time. We also have to be careful with the WM1S_LP_EN bit. It seems the hardware more or less treats it like the actual watermarks numbers, and so we must not toggle it too soon. Just leave it alone when disabling the LP1+ watermarks. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 232d8c3b1f1..c43cf138c87 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2896,16 +2896,23 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
if (!dirty)
return;
- if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != 0)
- I915_WRITE(WM3_LP_ILK, 0);
- if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != 0)
- I915_WRITE(WM2_LP_ILK, 0);
- if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0)
- I915_WRITE(WM1_LP_ILK, 0);
+ if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) {
+ previous->wm_lp[2] &= ~WM1_LP_SR_EN;
+ I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]);
+ }
+ if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) {
+ previous->wm_lp[1] &= ~WM1_LP_SR_EN;
+ I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]);
+ }
+ if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) {
+ previous->wm_lp[0] &= ~WM1_LP_SR_EN;
+ I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]);
+ }
- if (INTEL_INFO(dev)->gen <= 6 &&
- dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != 0)
- I915_WRITE(WM1S_LP_ILK, 0);
+ /*
+ * Don't touch WM1S_LP_EN here.
+ * Doing so could cause underruns.
+ */
if (dirty & WM_DIRTY_PIPE(PIPE_A))
I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
@@ -2949,7 +2956,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
}
if (INTEL_INFO(dev)->gen <= 6) {
- if (dirty & WM_DIRTY_LP(1) && results->wm_lp_spr[0] != 0)
+ if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0])
I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
} else {
if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0])
@@ -2960,11 +2967,11 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
}
- if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0)
+ if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0])
I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
- if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0)
+ if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1])
I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
- if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0)
+ if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2])
I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
dev_priv->wm.hw = *results;