| From 35cb46d950d8e9a098f6b2cb5eb24c5d7c1e3f46 Mon Sep 17 00:00:00 2001 |
| From: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Date: Wed, 5 Jun 2013 13:34:03 +0200 |
| Subject: drm/i915: fix up pch pll handling in ->mode_set |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| 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. |
| |
| Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit cdbd2316a03f68b25a135a34d1d24f01ddef0c53) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| 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 8927b3fb1982..89722233ad8b 100644 |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -1427,7 +1427,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; |
| } |
| @@ -1468,10 +1469,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); |
| |
| @@ -3081,9 +3081,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)) { |
| @@ -3128,19 +3128,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.8.5.rc3 |
| |