aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-10-12 12:51:31 -0400
committerKeith Packard <keithp@keithp.com>2011-10-21 02:13:23 -0400
commit4b645f14021871e06ce96c359bbdf0b48248c26e (patch)
treea5d1522a25c1d4279981e68ee0d7f281d62947aa /drivers/gpu
parentd3ccbe8670520fc61cbe974c97761b0dfc57f6df (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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c98
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
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 63f81416033e..c9bbf5e8fbe8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2893,7 +2893,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
2893 struct drm_i915_private *dev_priv = dev->dev_private; 2893 struct drm_i915_private *dev_priv = dev->dev_private;
2894 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2894 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
2895 int pipe = intel_crtc->pipe; 2895 int pipe = intel_crtc->pipe;
2896 u32 reg, temp; 2896 u32 reg, temp, transc_sel;
2897 2897
2898 /* For PCH output, training FDI link */ 2898 /* For PCH output, training FDI link */
2899 dev_priv->display.fdi_link_train(crtc); 2899 dev_priv->display.fdi_link_train(crtc);
@@ -2901,6 +2901,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
2901 intel_enable_pch_pll(dev_priv, pipe); 2901 intel_enable_pch_pll(dev_priv, pipe);
2902 2902
2903 if (HAS_PCH_CPT(dev)) { 2903 if (HAS_PCH_CPT(dev)) {
2904 transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
2905 TRANSC_DPLLB_SEL;
2906
2904 /* Be sure PCH DPLL SEL is set */ 2907 /* Be sure PCH DPLL SEL is set */
2905 temp = I915_READ(PCH_DPLL_SEL); 2908 temp = I915_READ(PCH_DPLL_SEL);
2906 if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0) 2909 if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
@@ -2908,7 +2911,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
2908 else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0) 2911 else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
2909 temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); 2912 temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
2910 else if (pipe == 2 && (temp & TRANSC_DPLL_ENABLE) == 0) 2913 else if (pipe == 2 && (temp & TRANSC_DPLL_ENABLE) == 0)
2911 temp |= (TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); 2914 temp |= (TRANSC_DPLL_ENABLE | transc_sel);
2912 I915_WRITE(PCH_DPLL_SEL, temp); 2915 I915_WRITE(PCH_DPLL_SEL, temp);
2913 } 2916 }
2914 2917
@@ -3080,8 +3083,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
3080 temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); 3083 temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
3081 break; 3084 break;
3082 case 2: 3085 case 2:
3083 /* FIXME: manage transcoder PLLs? */ 3086 /* C shares PLL A or B */
3084 temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); 3087 temp &= ~(TRANSC_DPLL_ENABLE | TRANSB_DPLLB_SEL);
3085 break; 3088 break;
3086 default: 3089 default:
3087 BUG(); /* wtf */ 3090 BUG(); /* wtf */
@@ -3090,7 +3093,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
3090 } 3093 }
3091 3094
3092 /* disable PCH DPLL */ 3095 /* disable PCH DPLL */
3093 intel_disable_pch_pll(dev_priv, pipe); 3096 if (!intel_crtc->no_pll)
3097 intel_disable_pch_pll(dev_priv, pipe);
3094 3098
3095 /* Switch from PCDclk to Rawclk */ 3099 /* Switch from PCDclk to Rawclk */
3096 reg = FDI_RX_CTL(pipe); 3100 reg = FDI_RX_CTL(pipe);
@@ -5549,16 +5553,34 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
5549 drm_mode_debug_printmodeline(mode); 5553 drm_mode_debug_printmodeline(mode);
5550 5554
5551 /* PCH eDP needs FDI, but CPU eDP does not */ 5555 /* PCH eDP needs FDI, but CPU eDP does not */
5552 if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { 5556 if (!intel_crtc->no_pll) {
5553 I915_WRITE(PCH_FP0(pipe), fp); 5557 if (!has_edp_encoder ||
5554 I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); 5558 intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
5555 5559 I915_WRITE(PCH_FP0(pipe), fp);
5556 POSTING_READ(PCH_DPLL(pipe)); 5560 I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
5557 udelay(150); 5561
5562 POSTING_READ(PCH_DPLL(pipe));
5563 udelay(150);
5564 }
5565 } else {
5566 if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) &&
5567 fp == I915_READ(PCH_FP0(0))) {
5568 intel_crtc->use_pll_a = true;
5569 DRM_DEBUG_KMS("using pipe a dpll\n");
5570 } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) &&
5571 fp == I915_READ(PCH_FP0(1))) {
5572 intel_crtc->use_pll_a = false;
5573 DRM_DEBUG_KMS("using pipe b dpll\n");
5574 } else {
5575 DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n");
5576 return -EINVAL;
5577 }
5558 } 5578 }
5559 5579
5560 /* enable transcoder DPLL */ 5580 /* enable transcoder DPLL */
5561 if (HAS_PCH_CPT(dev)) { 5581 if (HAS_PCH_CPT(dev)) {
5582 u32 transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
5583 TRANSC_DPLLB_SEL;
5562 temp = I915_READ(PCH_DPLL_SEL); 5584 temp = I915_READ(PCH_DPLL_SEL);
5563 switch (pipe) { 5585 switch (pipe) {
5564 case 0: 5586 case 0:
@@ -5568,8 +5590,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
5568 temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL; 5590 temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
5569 break; 5591 break;
5570 case 2: 5592 case 2:
5571 /* FIXME: manage transcoder PLLs? */ 5593 temp |= TRANSC_DPLL_ENABLE | transc_sel;
5572 temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
5573 break; 5594 break;
5574 default: 5595 default:
5575 BUG(); 5596 BUG();
@@ -5587,17 +5608,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
5587 if (is_lvds) { 5608 if (is_lvds) {
5588 temp = I915_READ(PCH_LVDS); 5609 temp = I915_READ(PCH_LVDS);
5589 temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; 5610 temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
5590 if (pipe == 1) { 5611 if (HAS_PCH_CPT(dev))
5591 if (HAS_PCH_CPT(dev)) 5612 temp |= PORT_TRANS_SEL_CPT(pipe);
5592 temp |= PORT_TRANS_B_SEL_CPT; 5613 else if (pipe == 1)
5593 else 5614 temp |= LVDS_PIPEB_SELECT;
5594 temp |= LVDS_PIPEB_SELECT; 5615 else
5595 } else { 5616 temp &= ~LVDS_PIPEB_SELECT;
5596 if (HAS_PCH_CPT(dev)) 5617
5597 temp &= ~PORT_TRANS_SEL_MASK;
5598 else
5599 temp &= ~LVDS_PIPEB_SELECT;
5600 }
5601 /* set the corresponsding LVDS_BORDER bit */ 5618 /* set the corresponsding LVDS_BORDER bit */
5602 temp |= dev_priv->lvds_border_bits; 5619 temp |= dev_priv->lvds_border_bits;
5603 /* Set the B0-B3 data pairs corresponding to whether we're going to 5620 /* Set the B0-B3 data pairs corresponding to whether we're going to
@@ -5647,8 +5664,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
5647 I915_WRITE(TRANSDPLINK_N1(pipe), 0); 5664 I915_WRITE(TRANSDPLINK_N1(pipe), 0);
5648 } 5665 }
5649 5666
5650 if (!has_edp_encoder || 5667 if (!intel_crtc->no_pll &&
5651 intel_encoder_is_pch_edp(&has_edp_encoder->base)) { 5668 (!has_edp_encoder ||
5669 intel_encoder_is_pch_edp(&has_edp_encoder->base))) {
5652 I915_WRITE(PCH_DPLL(pipe), dpll); 5670 I915_WRITE(PCH_DPLL(pipe), dpll);
5653 5671
5654 /* Wait for the clocks to stabilize. */ 5672 /* Wait for the clocks to stabilize. */
@@ -5664,18 +5682,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
5664 } 5682 }
5665 5683
5666 intel_crtc->lowfreq_avail = false; 5684 intel_crtc->lowfreq_avail = false;
5667 if (is_lvds && has_reduced_clock && i915_powersave) { 5685 if (!intel_crtc->no_pll) {
5668 I915_WRITE(PCH_FP1(pipe), fp2); 5686 if (is_lvds && has_reduced_clock && i915_powersave) {
5669 intel_crtc->lowfreq_avail = true; 5687 I915_WRITE(PCH_FP1(pipe), fp2);
5670 if (HAS_PIPE_CXSR(dev)) { 5688 intel_crtc->lowfreq_avail = true;
5671 DRM_DEBUG_KMS("enabling CxSR downclocking\n"); 5689 if (HAS_PIPE_CXSR(dev)) {
5672 pipeconf |= PIPECONF_CXSR_DOWNCLOCK; 5690 DRM_DEBUG_KMS("enabling CxSR downclocking\n");
5673 } 5691 pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
5674 } else { 5692 }
5675 I915_WRITE(PCH_FP1(pipe), fp); 5693 } else {
5676 if (HAS_PIPE_CXSR(dev)) { 5694 I915_WRITE(PCH_FP1(pipe), fp);
5677 DRM_DEBUG_KMS("disabling CxSR downclocking\n"); 5695 if (HAS_PIPE_CXSR(dev)) {
5678 pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; 5696 DRM_DEBUG_KMS("disabling CxSR downclocking\n");
5697 pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
5698 }
5679 } 5699 }
5680 } 5700 }
5681 5701
@@ -7291,6 +7311,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
7291 intel_crtc->bpp = 24; /* default for pre-Ironlake */ 7311 intel_crtc->bpp = 24; /* default for pre-Ironlake */
7292 7312
7293 if (HAS_PCH_SPLIT(dev)) { 7313 if (HAS_PCH_SPLIT(dev)) {
7314 if (pipe == 2 && IS_IVYBRIDGE(dev))
7315 intel_crtc->no_pll = true;
7294 intel_helper_funcs.prepare = ironlake_crtc_prepare; 7316 intel_helper_funcs.prepare = ironlake_crtc_prepare;
7295 intel_helper_funcs.commit = ironlake_crtc_commit; 7317 intel_helper_funcs.commit = ironlake_crtc_commit;
7296 } else { 7318 } else {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 98044d626a8d..5829854ecbf6 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -171,6 +171,9 @@ struct intel_crtc {
171 int16_t cursor_width, cursor_height; 171 int16_t cursor_width, cursor_height;
172 bool cursor_visible; 172 bool cursor_visible;
173 unsigned int bpp; 173 unsigned int bpp;
174
175 bool no_pll; /* tertiary pipe for IVB */
176 bool use_pll_a;
174}; 177};
175 178
176#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) 179#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)