aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2016-05-24 08:38:33 -0400
committerImre Deak <imre.deak@intel.com>2016-05-25 08:32:30 -0400
commitd66a21947e2147a0e313825ee461e954e8fe39cb (patch)
treeabc83b2cdd1b76a0a11cfa740970d991937ed3cb
parent1c3f7700b2830cbcc25fda675ad5e997e1454703 (diff)
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: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1464093513-16258-2-git-send-email-imre.deak@intel.com
-rw-r--r--drivers/gpu/drm/i915/intel_display.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d0e4023eaf1a..d6d075c7b8fe 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5491,11 +5491,58 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
5491 intel_update_cdclk(dev_priv->dev); 5491 intel_update_cdclk(dev_priv->dev);
5492} 5492}
5493 5493
5494void broxton_init_cdclk(struct drm_i915_private *dev_priv) 5494static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
5495{ 5495{
5496 u32 cdctl, expected;
5497
5496 intel_update_cdclk(dev_priv->dev); 5498 intel_update_cdclk(dev_priv->dev);
5497 5499
5498 if (dev_priv->cdclk_pll.vco != 0) 5500 if (dev_priv->cdclk_pll.vco == 0 ||
5501 dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
5502 goto sanitize;
5503
5504 /* DPLL okay; verify the cdclock
5505 *
5506 * Some BIOS versions leave an incorrect decimal frequency value and
5507 * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
5508 * so sanitize this register.
5509 */
5510 cdctl = I915_READ(CDCLK_CTL);
5511 /*
5512 * Let's ignore the pipe field, since BIOS could have configured the
5513 * dividers both synching to an active pipe, or asynchronously
5514 * (PIPE_NONE).
5515 */
5516 cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE;
5517
5518 expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) |
5519 skl_cdclk_decimal(dev_priv->cdclk_freq);
5520 /*
5521 * Disable SSA Precharge when CD clock frequency < 500 MHz,
5522 * enable otherwise.
5523 */
5524 if (dev_priv->cdclk_freq >= 500000)
5525 expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
5526
5527 if (cdctl == expected)
5528 /* All well; nothing to sanitize */
5529 return;
5530
5531sanitize:
5532 DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
5533
5534 /* force cdclk programming */
5535 dev_priv->cdclk_freq = 0;
5536
5537 /* force full PLL disable + enable */
5538 dev_priv->cdclk_pll.vco = -1;
5539}
5540
5541void broxton_init_cdclk(struct drm_i915_private *dev_priv)
5542{
5543 bxt_sanitize_cdclk(dev_priv);
5544
5545 if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0)
5499 return; 5546 return;
5500 5547
5501 /* 5548 /*