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. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
b6f3eff713
commit
cdbd2316a0
@ -1427,7 +1427,8 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc)
|
|||||||
/* PCH refclock must be enabled first */
|
/* PCH refclock must be enabled first */
|
||||||
assert_pch_refclk_enabled(dev_priv);
|
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);
|
assert_pch_pll_enabled(dev_priv, pll, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1468,10 +1469,9 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--pll->active) {
|
|
||||||
assert_pch_pll_enabled(dev_priv, pll, NULL);
|
assert_pch_pll_enabled(dev_priv, pll, NULL);
|
||||||
|
if (--pll->active)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg);
|
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;
|
pll = intel_crtc->pch_pll;
|
||||||
if (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);
|
intel_crtc->base.base.id, pll->pll_reg);
|
||||||
goto prepare;
|
intel_put_pch_pll(intel_crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_PCH_IBX(dev_priv->dev)) {
|
if (HAS_PCH_IBX(dev_priv->dev)) {
|
||||||
@ -3128,10 +3128,11 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3
|
|||||||
|
|
||||||
found:
|
found:
|
||||||
intel_crtc->pch_pll = pll;
|
intel_crtc->pch_pll = pll;
|
||||||
pll->refcount++;
|
|
||||||
DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe));
|
DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe));
|
||||||
prepare: /* separate function? */
|
if (pll->active == 0) {
|
||||||
DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg);
|
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 */
|
/* Wait for the clocks to stabilize before rewriting the regs */
|
||||||
I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
|
I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
|
||||||
@ -3140,7 +3141,9 @@ prepare: /* separate function? */
|
|||||||
|
|
||||||
I915_WRITE(pll->fp0_reg, fp);
|
I915_WRITE(pll->fp0_reg, fp);
|
||||||
I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
|
I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
|
||||||
pll->on = false;
|
}
|
||||||
|
pll->refcount++;
|
||||||
|
|
||||||
return pll;
|
return pll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user