From 81e9957de804c91429c136d5266fbd1009871901 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 26 May 2013 18:56:26 +0200 Subject: [PATCH] drm/i915: fix up pch pll handling in ->mode_set We ->mode_set is called we can't just blindly reuse an existing pll since that might be shared with a different, still active pch output. v2: Only update the pll settings when the pch pll is know to be unused, otherwise we can wreak havoc with a running pipe. Which in the case of DP will likely result in a black screen due to loss of link lock. v3: Tighten up the asserts a bit more, especially make sure that the pch pll is still enabled when we try to disable it. This would have caught the bug fixed in this patch. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5fadcf7..e4a24e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1401,7 +1401,8 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) /* PCH refclock must be enabled first */ assert_pch_refclk_enabled(dev_priv); - if (pll->active++ && pll->on) { + if (pll->active++) { + WARN_ON(!pll->on); assert_pch_pll_enabled(dev_priv, pll, NULL); return; } @@ -1442,10 +1443,9 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) return; } - if (--pll->active) { - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_pch_pll_enabled(dev_priv, pll, NULL); + if (--pll->active) return; - } DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); @@ -3056,9 +3056,9 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 pll = intel_crtc->pch_pll; if (pll) { - DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n", + DRM_DEBUG_KMS("CRTC:%d dropping existing PCH PLL %x\n", intel_crtc->base.base.id, pll->pll_reg); - goto prepare; + intel_put_pch_pll(intel_crtc); } if (HAS_PCH_IBX(dev_priv->dev)) { @@ -3103,19 +3103,22 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 found: intel_crtc->pch_pll = pll; - pll->refcount++; DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe)); -prepare: /* separate function? */ - DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg); + if (pll->active == 0) { + DRM_DEBUG_DRIVER("setting up pll %d\n", i); + WARN_ON(pll->on); + assert_pch_pll_disabled(dev_priv, pll, NULL); - /* Wait for the clocks to stabilize before rewriting the regs */ - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(pll->pll_reg); - udelay(150); + /* Wait for the clocks to stabilize before rewriting the regs */ + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(pll->pll_reg); + udelay(150); + + I915_WRITE(pll->fp0_reg, fp); + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + } + pll->refcount++; - I915_WRITE(pll->fp0_reg, fp); - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); - pll->on = false; return pll; } -- 1.7.11.7