summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorImre Deak2016-05-24 14:38:33 +0200
committerImre Deak2016-05-25 14:32:30 +0200
commitd66a21947e2147a0e313825ee461e954e8fe39cb (patch)
treeabc83b2cdd1b76a0a11cfa740970d991937ed3cb /drivers/gpu/drm/i915/intel_display.c
parentdrm/i915/gen9: Assume CDCLK PLL is off if it's not locked (diff)
downloadkernel-qcow2-linux-d66a21947e2147a0e313825ee461e954e8fe39cb.tar.gz
kernel-qcow2-linux-d66a21947e2147a0e313825ee461e954e8fe39cb.tar.xz
kernel-qcow2-linux-d66a21947e2147a0e313825ee461e954e8fe39cb.zip
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
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-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)
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);
- 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;
/*