From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> There are some rare BDW machines where the BIOS apparently does not enable LCPLL/CDLCK. Let's try to do that ourselves. Or maybe we should treat this case as "don't use the display engine!" kind of knob? Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- .../drm/i915/display/intel_display_power.c | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 246e406bb385..e7641e57cebd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -4538,24 +4538,14 @@ static void icl_mbus_init(struct drm_i915_private *dev_priv) } } -static void hsw_assert_cdclk(struct drm_i915_private *dev_priv) +static bool hsw_lcpll_ok(u32 lcpll_ctl) { - u32 val = intel_de_read(dev_priv, LCPLL_CTL); - - /* - * The LCPLL register should be turned on by the BIOS. For now - * let's just check its state and print errors in case - * something is wrong. Don't even try to turn it on. - */ - - if (val & LCPLL_CD_SOURCE_FCLK) - drm_err(&dev_priv->drm, "CDCLK source is not LCPLL\n"); - - if (val & LCPLL_PLL_DISABLE) - drm_err(&dev_priv->drm, "LCPLL is disabled\n"); - - if ((val & LCPLL_REF_MASK) != LCPLL_REF_NON_SSC) - drm_err(&dev_priv->drm, "LCPLL not using non-SSC reference\n"); + return (lcpll_ctl & (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK | + LCPLL_CD_CLOCK_DISABLE | + LCPLL_ROOT_CD_CLOCK_DISABLE | + LCPLL_CD2X_CLOCK_DISABLE | + LCPLL_POWER_DOWN_ALLOW | + LCPLL_CD_SOURCE_FCLK)) == LCPLL_PLL_LOCK; } static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) @@ -4632,8 +4622,6 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv, { u32 val; - assert_can_disable_lcpll(dev_priv); - val = intel_de_read(dev_priv, LCPLL_CTL); if (switch_to_fclk) { @@ -4681,8 +4669,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) val = intel_de_read(dev_priv, LCPLL_CTL); - if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK | - LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK) + if (hsw_lcpll_ok(val)) return; /* @@ -4720,6 +4707,11 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) "Switching back to LCPLL failed\n"); } + val &= ~(LCPLL_CD_CLOCK_DISABLE | + LCPLL_ROOT_CD_CLOCK_DISABLE | + LCPLL_CD2X_CLOCK_DISABLE); + intel_de_write(dev_priv, LCPLL_CTL, val); + intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL); intel_update_cdclk(dev_priv); @@ -4762,6 +4754,7 @@ static void hsw_enable_pc8(struct drm_i915_private *dev_priv) } lpt_disable_clkout_dp(dev_priv); + assert_can_disable_lcpll(dev_priv); hsw_disable_lcpll(dev_priv, true, true); } @@ -4781,6 +4774,27 @@ static void hsw_disable_pc8(struct drm_i915_private *dev_priv) } } +static void hsw_lcpll_init(struct drm_i915_private *dev_priv) +{ + u32 val; + + /* + * The LCPLL register should be turned on by the BIOS. + * Some machines apparently don't, so we're going to + * try to fix it if somehting is not correct. + */ + val = intel_de_read(dev_priv, LCPLL_CTL); + if (hsw_lcpll_ok(val)) + return; + + drm_dbg(&dev_priv->drm, + "Reinitializing misconfigured LCPLL/CDCLK (LCPLL_CTL=0x%08x)\n", + val); + + hsw_disable_lcpll(dev_priv, true, true); + hsw_restore_lcpll(dev_priv); +} + static void intel_pch_reset_handshake(struct drm_i915_private *dev_priv, bool enable) { @@ -5307,8 +5321,8 @@ void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume) assert_ved_power_gated(i915); assert_isp_power_gated(i915); } else if (IS_BROADWELL(i915) || IS_HASWELL(i915)) { - hsw_assert_cdclk(i915); intel_pch_reset_handshake(i915, !HAS_PCH_NOP(i915)); + hsw_lcpll_init(i915); } else if (IS_IVYBRIDGE(i915)) { intel_pch_reset_handshake(i915, !HAS_PCH_NOP(i915)); } -- 2.24.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx