On Tue, 11 Dec 2012 12:01:42 +0000 Chris Wilson <chris at chris-wilson.co.uk> wrote: > It operates at twice the declared latency, so adjust the computation to > avoid potential flicker at low power. > > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50248 > Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> > CC: Jesse Barnes <jbarnes at virtuousgeek.org> > --- > drivers/gpu/drm/i915/intel_pm.c | 117 +++++++++++++++++++++++++++++++++++++-- > 1 file changed, 112 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c > index 6e9393c..1e61f5e 100644 > --- a/drivers/gpu/drm/i915/intel_pm.c > +++ b/drivers/gpu/drm/i915/intel_pm.c > @@ -1813,8 +1813,110 @@ static void sandybridge_update_wm(struct drm_device *dev) > enabled |= 2; > } > > - if ((dev_priv->num_pipe == 3) && > - g4x_compute_wm0(dev, 2, > + /* > + * Calculate and update the self-refresh watermark only when one > + * display plane is used. > + * > + * SNB support 3 levels of watermark. > + * > + * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, > + * and disabled in the descending order > + * > + */ > + I915_WRITE(WM3_LP_ILK, 0); > + I915_WRITE(WM2_LP_ILK, 0); > + I915_WRITE(WM1_LP_ILK, 0); > + > + if (!single_plane_enabled(enabled) || > + dev_priv->sprite_scaling_enabled) > + return; > + enabled = ffs(enabled) - 1; > + > + /* WM1 */ > + if (!ironlake_compute_srwm(dev, 1, enabled, > + SNB_READ_WM1_LATENCY() * 500, > + &sandybridge_display_srwm_info, > + &sandybridge_cursor_srwm_info, > + &fbc_wm, &plane_wm, &cursor_wm)) > + return; > + > + I915_WRITE(WM1_LP_ILK, > + WM1_LP_SR_EN | > + (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | > + (fbc_wm << WM1_LP_FBC_SHIFT) | > + (plane_wm << WM1_LP_SR_SHIFT) | > + cursor_wm); > + > + /* WM2 */ > + if (!ironlake_compute_srwm(dev, 2, enabled, > + SNB_READ_WM2_LATENCY() * 500, > + &sandybridge_display_srwm_info, > + &sandybridge_cursor_srwm_info, > + &fbc_wm, &plane_wm, &cursor_wm)) > + return; > + > + I915_WRITE(WM2_LP_ILK, > + WM2_LP_EN | > + (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | > + (fbc_wm << WM1_LP_FBC_SHIFT) | > + (plane_wm << WM1_LP_SR_SHIFT) | > + cursor_wm); > + > + /* WM3 */ > + if (!ironlake_compute_srwm(dev, 3, enabled, > + SNB_READ_WM3_LATENCY() * 500, > + &sandybridge_display_srwm_info, > + &sandybridge_cursor_srwm_info, > + &fbc_wm, &plane_wm, &cursor_wm)) > + return; > + > + I915_WRITE(WM3_LP_ILK, > + WM3_LP_EN | > + (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | > + (fbc_wm << WM1_LP_FBC_SHIFT) | > + (plane_wm << WM1_LP_SR_SHIFT) | > + cursor_wm); > +} > + > +static void ivybridge_update_wm(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ > + u32 val; > + int fbc_wm, plane_wm, cursor_wm; > + int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm; > + unsigned int enabled; > + > + enabled = 0; > + if (g4x_compute_wm0(dev, 0, > + &sandybridge_display_wm_info, latency, > + &sandybridge_cursor_wm_info, latency, > + &plane_wm, &cursor_wm)) { > + val = I915_READ(WM0_PIPEA_ILK); > + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); > + I915_WRITE(WM0_PIPEA_ILK, val | > + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); > + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" > + " plane %d, " "cursor: %d\n", > + plane_wm, cursor_wm); > + enabled |= 1; > + } > + > + if (g4x_compute_wm0(dev, 1, > + &sandybridge_display_wm_info, latency, > + &sandybridge_cursor_wm_info, latency, > + &plane_wm, &cursor_wm)) { > + val = I915_READ(WM0_PIPEB_ILK); > + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); > + I915_WRITE(WM0_PIPEB_ILK, val | > + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); > + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" > + " plane %d, cursor: %d\n", > + plane_wm, cursor_wm); > + enabled |= 2; > + } > + > + if (g4x_compute_wm0(dev, 2, > &sandybridge_display_wm_info, latency, > &sandybridge_cursor_wm_info, latency, > &plane_wm, &cursor_wm)) { > @@ -1877,12 +1979,17 @@ static void sandybridge_update_wm(struct drm_device *dev) > (plane_wm << WM1_LP_SR_SHIFT) | > cursor_wm); > > - /* WM3 */ > + /* WM3, note we have to correct the cursor latency */ > if (!ironlake_compute_srwm(dev, 3, enabled, > SNB_READ_WM3_LATENCY() * 500, > &sandybridge_display_srwm_info, > &sandybridge_cursor_srwm_info, > - &fbc_wm, &plane_wm, &cursor_wm)) > + &fbc_wm, &plane_wm, &ignore_cursor_wm) || > + !ironlake_compute_srwm(dev, 3, enabled, > + 2 * SNB_READ_WM3_LATENCY() * 500, > + &sandybridge_display_srwm_info, > + &sandybridge_cursor_srwm_info, > + &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm)) > return; > > I915_WRITE(WM3_LP_ILK, > @@ -3999,7 +4106,7 @@ void intel_init_pm(struct drm_device *dev) > } else if (IS_IVYBRIDGE(dev)) { > /* FIXME: detect B0+ stepping and use auto training */ > if (SNB_READ_WM0_LATENCY()) { > - dev_priv->display.update_wm = sandybridge_update_wm; > + dev_priv->display.update_wm = ivybridge_update_wm; > dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; > } else { > DRM_DEBUG_KMS("Failed to read display plane latency. " Reviewed-by: Jesse Barnes <jbarnes at virtuousgeek.org> Let's see how this works out... will cost a few more mW, but at least we shouldn't flicker as much. -- Jesse Barnes, Intel Open Source Technology Center