diff options
author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2013-12-05 08:51:39 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-12-17 07:17:57 -0500 |
commit | 8553c18ea696827f26d3ba5652d3a2fa9ce8e874 (patch) | |
tree | 92b5931e1bf354815ddcd38ffbef05ce27087e9e /drivers/gpu/drm/i915/intel_pm.c | |
parent | 96f90c5421aaaba35ffd931728fabeb8f6cd8471 (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.c | 58 |
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 | /* | 2429 | static 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 | */ | ||
2433 | static 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 | */ | ||
2463 | static 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 | ||
2540 | static 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 | |||
2526 | static void haswell_update_wm(struct drm_crtc *crtc) | 2547 | static 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 | ||