Commit d66a2194 authored by Imre Deak's avatar Imre Deak

drm/i915/bxt: Sanitize CDCLK to fix breakage during S4 resume

I noticed that during S4 resume BIOS incorrectly sets bits 18, 19 which
are reserved/MBZ and sets the decimal frequency fields to all 0xff in
the CDCLK register. The result is a hard lockup as display register
accesses are attempted later. Work around this by sanitizing the CDCLK
PLL/dividers the same way it's done on SKL.

While this is clearly a BIOS bug which should be fixed separately, it
doesn't hurt to check/sanitize this regardless.

v2:
- Use the same condition for VCO and CDCLK in broxton_init_cdclk as is
  used in skl_init_cdclk for the same purpose.

CC: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1464093513-16258-2-git-send-email-imre.deak@intel.com
parent 1c3f7700
...@@ -5491,11 +5491,58 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) ...@@ -5491,11 +5491,58 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
intel_update_cdclk(dev_priv->dev); intel_update_cdclk(dev_priv->dev);
} }
void broxton_init_cdclk(struct drm_i915_private *dev_priv) static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
{ {
u32 cdctl, expected;
intel_update_cdclk(dev_priv->dev); intel_update_cdclk(dev_priv->dev);
if (dev_priv->cdclk_pll.vco != 0) if (dev_priv->cdclk_pll.vco == 0 ||
dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
goto sanitize;
/* DPLL okay; verify the cdclock
*
* Some BIOS versions leave an incorrect decimal frequency value and
* set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
* so sanitize this register.
*/
cdctl = I915_READ(CDCLK_CTL);
/*
* Let's ignore the pipe field, since BIOS could have configured the
* dividers both synching to an active pipe, or asynchronously
* (PIPE_NONE).
*/
cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE;
expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) |
skl_cdclk_decimal(dev_priv->cdclk_freq);
/*
* Disable SSA Precharge when CD clock frequency < 500 MHz,
* enable otherwise.
*/
if (dev_priv->cdclk_freq >= 500000)
expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
if (cdctl == expected)
/* All well; nothing to sanitize */
return;
sanitize:
DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
/* force cdclk programming */
dev_priv->cdclk_freq = 0;
/* force full PLL disable + enable */
dev_priv->cdclk_pll.vco = -1;
}
void broxton_init_cdclk(struct drm_i915_private *dev_priv)
{
bxt_sanitize_cdclk(dev_priv);
if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0)
return; return;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment