From: Ville Syrjälä <ville.syrj...@linux.intel.com>

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 <ch...@chris-wilson.co.uk>
Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
---
 .../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@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to