Skip to content

Commit

Permalink
drm/i915: Increase WM memory latency values on SNB
Browse files Browse the repository at this point in the history
On SNB the BIOS provided WM memory latency values seem insufficient to
handle high resolution displays.

In this particular case the display mode was a 2560x1440@60Hz, which
makes the pixel clock 241.5 MHz. It was empirically found that a memory
latency value if 1.2 usec is enough to avoid underruns, whereas the BIOS
provided value of 0.7 usec was clearly too low. Incidentally 1.2 usec
is what the typical BIOS provided values are on IVB systems.

Increase the WM memory latency values to at least 1.2 usec on SNB.
Hopefully this won't have a significant effect on power consumption.

v2: Increase the latency values regardless of the pixel clock

Cc: Robert N <crshman@gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70254
Tested-by: Robert Navarro <crshman@gmail.com>
Tested-by: Vitaly Minko <vitaly.minko@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
  • Loading branch information
vsyrjala authored and jnikula committed May 15, 2014
1 parent 721e82c commit e95a2f7
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions drivers/gpu/drm/i915/intel_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,43 @@ static void intel_print_wm_latency(struct drm_device *dev,
}
}

static bool ilk_increase_wm_latency(struct drm_i915_private *dev_priv,
uint16_t wm[5], uint16_t min)
{
int level, max_level = ilk_wm_max_level(dev_priv->dev);

if (wm[0] >= min)
return false;

wm[0] = max(wm[0], min);
for (level = 1; level <= max_level; level++)
wm[level] = max_t(uint16_t, wm[level], DIV_ROUND_UP(min, 5));

return true;
}

static void snb_wm_latency_quirk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
bool changed;

/*
* The BIOS provided WM memory latency values are often
* inadequate for high resolution displays. Adjust them.
*/
changed = ilk_increase_wm_latency(dev_priv, dev_priv->wm.pri_latency, 12) |
ilk_increase_wm_latency(dev_priv, dev_priv->wm.spr_latency, 12) |
ilk_increase_wm_latency(dev_priv, dev_priv->wm.cur_latency, 12);

if (!changed)
return;

DRM_DEBUG_KMS("WM latency values increased to avoid potential underruns\n");
intel_print_wm_latency(dev, "Primary", dev_priv->wm.pri_latency);
intel_print_wm_latency(dev, "Sprite", dev_priv->wm.spr_latency);
intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);
}

static void ilk_setup_wm_latency(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
Expand All @@ -2112,6 +2149,9 @@ static void ilk_setup_wm_latency(struct drm_device *dev)
intel_print_wm_latency(dev, "Primary", dev_priv->wm.pri_latency);
intel_print_wm_latency(dev, "Sprite", dev_priv->wm.spr_latency);
intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);

if (IS_GEN6(dev))
snb_wm_latency_quirk(dev);
}

static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
Expand Down

0 comments on commit e95a2f7

Please sign in to comment.