diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-10-12 09:51:31 -0700 |
---|---|---|
committer | Eugeni Dodonov <eugeni.dodonov@intel.com> | 2012-02-08 18:23:18 -0200 |
commit | 58369a28978713e4afc5387dd0acf10858efd077 (patch) | |
tree | a7923a70719aeca8a876431f84e49474729a354c | |
parent | d3b649cb69ca60aba1b6e88a8be713c52e06383f (diff) |
drm/i915: add PLL sharing support to handle 3 pipes
Add two new fields to the intel_crtc struct for 3 pipe support: no_pll
and use_pll_a. The no_pll field is only set on the 3rd pipe to indicate
that it doesn't have a PLL of its own and so shouldn't try to write the
main PLL regs. The use_pll_a field controls which PLL pipe 3 will
share, A or B. The core code will try to share PLLs with whichever pipe
has the same timings, rejecting the mode set if none is found. This
means that pipe 3 must always be set after one of the other pipes has
been configured with real PLL settings.
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Tested-By: Eugeni Dodonov <eugeni.dodonov@intel.com>
Reviewed-By: Eugeni Dodonov <eugeni.dodonov@intel.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 98 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 3 |
2 files changed, 63 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 49f4eb45a04..74076996419 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2896,7 +2896,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp; + u32 reg, temp, transc_sel; /* For PCH output, training FDI link */ dev_priv->display.fdi_link_train(crtc); @@ -2904,6 +2904,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) intel_enable_pch_pll(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { + transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL : + TRANSC_DPLLB_SEL; + /* Be sure PCH DPLL SEL is set */ temp = I915_READ(PCH_DPLL_SEL); if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0) @@ -2911,7 +2914,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0) temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); else if (pipe == 2 && (temp & TRANSC_DPLL_ENABLE) == 0) - temp |= (TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); + temp |= (TRANSC_DPLL_ENABLE | transc_sel); I915_WRITE(PCH_DPLL_SEL, temp); } @@ -3083,8 +3086,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); break; case 2: - /* FIXME: manage transcoder PLLs? */ - temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); + /* C shares PLL A or B */ + temp &= ~(TRANSC_DPLL_ENABLE | TRANSB_DPLLB_SEL); break; default: BUG(); /* wtf */ @@ -3093,7 +3096,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) } /* disable PCH DPLL */ - intel_disable_pch_pll(dev_priv, pipe); + if (!intel_crtc->no_pll) + intel_disable_pch_pll(dev_priv, pipe); /* Switch from PCDclk to Rawclk */ reg = FDI_RX_CTL(pipe); @@ -5552,16 +5556,34 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, drm_mode_debug_printmodeline(mode); /* PCH eDP needs FDI, but CPU eDP does not */ - if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - I915_WRITE(PCH_FP0(pipe), fp); - I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); - - POSTING_READ(PCH_DPLL(pipe)); - udelay(150); + if (!intel_crtc->no_pll) { + if (!has_edp_encoder || + intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + I915_WRITE(PCH_FP0(pipe), fp); + I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); + + POSTING_READ(PCH_DPLL(pipe)); + udelay(150); + } + } else { + if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) && + fp == I915_READ(PCH_FP0(0))) { + intel_crtc->use_pll_a = true; + DRM_DEBUG_KMS("using pipe a dpll\n"); + } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) && + fp == I915_READ(PCH_FP0(1))) { + intel_crtc->use_pll_a = false; + DRM_DEBUG_KMS("using pipe b dpll\n"); + } else { + DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n"); + return -EINVAL; + } } /* enable transcoder DPLL */ if (HAS_PCH_CPT(dev)) { + u32 transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL : + TRANSC_DPLLB_SEL; temp = I915_READ(PCH_DPLL_SEL); switch (pipe) { case 0: @@ -5571,8 +5593,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL; break; case 2: - /* FIXME: manage transcoder PLLs? */ - temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL; + temp |= TRANSC_DPLL_ENABLE | transc_sel; break; default: BUG(); @@ -5590,17 +5611,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds) { temp = I915_READ(PCH_LVDS); temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (pipe == 1) { - if (HAS_PCH_CPT(dev)) - temp |= PORT_TRANS_B_SEL_CPT; - else - temp |= LVDS_PIPEB_SELECT; - } else { - if (HAS_PCH_CPT(dev)) - temp &= ~PORT_TRANS_SEL_MASK; - else - temp &= ~LVDS_PIPEB_SELECT; - } + if (HAS_PCH_CPT(dev)) + temp |= PORT_TRANS_SEL_CPT(pipe); + else if (pipe == 1) + temp |= LVDS_PIPEB_SELECT; + else + temp &= ~LVDS_PIPEB_SELECT; + /* set the corresponsding LVDS_BORDER bit */ temp |= dev_priv->lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to @@ -5650,8 +5667,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(TRANSDPLINK_N1(pipe), 0); } - if (!has_edp_encoder || - intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (!intel_crtc->no_pll && + (!has_edp_encoder || + intel_encoder_is_pch_edp(&has_edp_encoder->base))) { I915_WRITE(PCH_DPLL(pipe), dpll); /* Wait for the clocks to stabilize. */ @@ -5667,18 +5685,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } intel_crtc->lowfreq_avail = false; - if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(PCH_FP1(pipe), fp2); - intel_crtc->lowfreq_avail = true; - if (HAS_PIPE_CXSR(dev)) { - DRM_DEBUG_KMS("enabling CxSR downclocking\n"); - pipeconf |= PIPECONF_CXSR_DOWNCLOCK; - } - } else { - I915_WRITE(PCH_FP1(pipe), fp); - if (HAS_PIPE_CXSR(dev)) { - DRM_DEBUG_KMS("disabling CxSR downclocking\n"); - pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; + if (!intel_crtc->no_pll) { + if (is_lvds && has_reduced_clock && i915_powersave) { + I915_WRITE(PCH_FP1(pipe), fp2); + intel_crtc->lowfreq_avail = true; + if (HAS_PIPE_CXSR(dev)) { + DRM_DEBUG_KMS("enabling CxSR downclocking\n"); + pipeconf |= PIPECONF_CXSR_DOWNCLOCK; + } + } else { + I915_WRITE(PCH_FP1(pipe), fp); + if (HAS_PIPE_CXSR(dev)) { + DRM_DEBUG_KMS("disabling CxSR downclocking\n"); + pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; + } } } @@ -7324,6 +7344,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->bpp = 24; /* default for pre-Ironlake */ if (HAS_PCH_SPLIT(dev)) { + if (pipe == 2 && IS_IVYBRIDGE(dev)) + intel_crtc->no_pll = true; intel_helper_funcs.prepare = ironlake_crtc_prepare; intel_helper_funcs.commit = ironlake_crtc_commit; } else { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cee98a20ef0..b9a15a8f40c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -171,6 +171,9 @@ struct intel_crtc { int16_t cursor_width, cursor_height; bool cursor_visible; unsigned int bpp; + + bool no_pll; /* tertiary pipe for IVB */ + bool use_pll_a; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) |