aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_pm.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2013-12-05 08:51:39 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-12-17 07:17:57 -0500
commit8553c18ea696827f26d3ba5652d3a2fa9ce8e874 (patch)
tree92b5931e1bf354815ddcd38ffbef05ce27087e9e /drivers/gpu/drm/i915/intel_pm.c
parent96f90c5421aaaba35ffd931728fabeb8f6cd8471 (diff)
drm/i915: Try to fix the messy IVB sprite scaling workaround
We now have a very clear method of disabling LP1+ wartermarks, and we can actually detect if we actually did disable them, or if they were already disabled. Use that to clean up the WaCxSRDisabledForSpriteScaling:ivb handling. I was hoping to apply the workaround in a way that wouldn't require a blocking wait, but sadly IVB really does appear to require LP1+ watermarks to be off for an entire frame before enabling sprite scaling. Simply disabling LP1+ watermarks during the previous frame is not enough, no matter how early in the frame we do it :( 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/intel_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c58
1 files changed, 45 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 7e028341b2f5..ecdb64e44e2a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2426,33 +2426,26 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
2426 return dirty; 2426 return dirty;
2427} 2427}
2428 2428
2429/* 2429static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
2430 * The spec says we shouldn't write when we don't need, because every write 2430 unsigned int dirty)
2431 * causes WMs to be re-evaluated, expending some power.
2432 */
2433static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
2434 struct hsw_wm_values *results)
2435{ 2431{
2436 struct drm_device *dev = dev_priv->dev;
2437 struct hsw_wm_values *previous = &dev_priv->wm.hw; 2432 struct hsw_wm_values *previous = &dev_priv->wm.hw;
2438 unsigned int dirty; 2433 bool changed = false;
2439 uint32_t val;
2440
2441 dirty = ilk_compute_wm_dirty(dev_priv->dev, previous, results);
2442 if (!dirty)
2443 return;
2444 2434
2445 if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) { 2435 if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) {
2446 previous->wm_lp[2] &= ~WM1_LP_SR_EN; 2436 previous->wm_lp[2] &= ~WM1_LP_SR_EN;
2447 I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]); 2437 I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]);
2438 changed = true;
2448 } 2439 }
2449 if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) { 2440 if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) {
2450 previous->wm_lp[1] &= ~WM1_LP_SR_EN; 2441 previous->wm_lp[1] &= ~WM1_LP_SR_EN;
2451 I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]); 2442 I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]);
2443 changed = true;
2452 } 2444 }
2453 if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) { 2445 if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) {
2454 previous->wm_lp[0] &= ~WM1_LP_SR_EN; 2446 previous->wm_lp[0] &= ~WM1_LP_SR_EN;
2455 I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]); 2447 I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]);
2448 changed = true;
2456 } 2449 }
2457 2450
2458 /* 2451 /*
@@ -2460,6 +2453,27 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
2460 * Doing so could cause underruns. 2453 * Doing so could cause underruns.
2461 */ 2454 */
2462 2455
2456 return changed;
2457}
2458
2459/*
2460 * The spec says we shouldn't write when we don't need, because every write
2461 * causes WMs to be re-evaluated, expending some power.
2462 */
2463static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
2464 struct hsw_wm_values *results)
2465{
2466 struct drm_device *dev = dev_priv->dev;
2467 struct hsw_wm_values *previous = &dev_priv->wm.hw;
2468 unsigned int dirty;
2469 uint32_t val;
2470
2471 dirty = ilk_compute_wm_dirty(dev, previous, results);
2472 if (!dirty)
2473 return;
2474
2475 _ilk_disable_lp_wm(dev_priv, dirty);
2476
2463 if (dirty & WM_DIRTY_PIPE(PIPE_A)) 2477 if (dirty & WM_DIRTY_PIPE(PIPE_A))
2464 I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); 2478 I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
2465 if (dirty & WM_DIRTY_PIPE(PIPE_B)) 2479 if (dirty & WM_DIRTY_PIPE(PIPE_B))
@@ -2523,6 +2537,13 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
2523 dev_priv->wm.hw = *results; 2537 dev_priv->wm.hw = *results;
2524} 2538}
2525 2539
2540static bool ilk_disable_lp_wm(struct drm_device *dev)
2541{
2542 struct drm_i915_private *dev_priv = dev->dev_private;
2543
2544 return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
2545}
2546
2526static void haswell_update_wm(struct drm_crtc *crtc) 2547static void haswell_update_wm(struct drm_crtc *crtc)
2527{ 2548{
2528 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2549 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -2572,6 +2593,7 @@ static void haswell_update_sprite_wm(struct drm_plane *plane,
2572 uint32_t sprite_width, int pixel_size, 2593 uint32_t sprite_width, int pixel_size,
2573 bool enabled, bool scaled) 2594 bool enabled, bool scaled)
2574{ 2595{
2596 struct drm_device *dev = plane->dev;
2575 struct intel_plane *intel_plane = to_intel_plane(plane); 2597 struct intel_plane *intel_plane = to_intel_plane(plane);
2576 2598
2577 intel_plane->wm.enabled = enabled; 2599 intel_plane->wm.enabled = enabled;
@@ -2579,6 +2601,16 @@ static void haswell_update_sprite_wm(struct drm_plane *plane,
2579 intel_plane->wm.horiz_pixels = sprite_width; 2601 intel_plane->wm.horiz_pixels = sprite_width;
2580 intel_plane->wm.bytes_per_pixel = pixel_size; 2602 intel_plane->wm.bytes_per_pixel = pixel_size;
2581 2603
2604 /*
2605 * IVB workaround: must disable low power watermarks for at least
2606 * one frame before enabling scaling. LP watermarks can be re-enabled
2607 * when scaling is disabled.
2608 *
2609 * WaCxSRDisabledForSpriteScaling:ivb
2610 */
2611 if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
2612 intel_wait_for_vblank(dev, intel_plane->pipe);
2613
2582 haswell_update_wm(crtc); 2614 haswell_update_wm(crtc);
2583} 2615}
2584 2616