diff options
author | Imre Deak <imre.deak@intel.com> | 2016-05-24 08:38:33 -0400 |
---|---|---|
committer | Imre Deak <imre.deak@intel.com> | 2016-05-25 08:32:30 -0400 |
commit | d66a21947e2147a0e313825ee461e954e8fe39cb (patch) | |
tree | abc83b2cdd1b76a0a11cfa740970d991937ed3cb | |
parent | 1c3f7700b2830cbcc25fda675ad5e997e1454703 (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.c | 51 |
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 | ||
5494 | void broxton_init_cdclk(struct drm_i915_private *dev_priv) | 5494 | static 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 | |||
5531 | sanitize: | ||
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 | |||
5541 | void 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 | /* |