diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-10-12 12:51:31 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-10-21 02:13:23 -0400 |
commit | 4b645f14021871e06ce96c359bbdf0b48248c26e (patch) | |
tree | a5d1522a25c1d4279981e68ee0d7f281d62947aa /drivers | |
parent | d3ccbe8670520fc61cbe974c97761b0dfc57f6df (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')
-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 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) |