aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-02-04 16:57:30 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2011-02-07 07:06:14 -0500
commitdcbe6f2b3d136995915e2f9ecc7d4f3b28f47b6c (patch)
treec127bdd87bdcb712d11d12cd44c97f343cafc8dc /drivers/gpu/drm/i915
parent291906f11c90467ce552089ea9f7b393f41a87bb (diff)
drm/i915: the PCH reference clocks are global, so don't clobber unconditionally
The PCH can drive several reference clocks simultaneously, and needs to with multiple display configurations. So we can't just clobber the existing state everytime we set a mode, we need to take into account what the other CRTCs are doing at the time. Doing so fixes an issue where you'd lose the LVDS display at boot if you had an LVDS+DP config. [updated: init bools and check CRTC status correctly] Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c123
1 files changed, 77 insertions, 46 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 84f3054a066f..cc431f4581c3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4463,6 +4463,81 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
4463 return dev_priv->lvds_use_ssc && i915_panel_use_ssc; 4463 return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
4464} 4464}
4465 4465
4466static void intel_update_dref(struct drm_i915_private *dev_priv)
4467{
4468 struct drm_device *dev = dev_priv->dev;
4469 struct drm_mode_config *mode_config = &dev->mode_config;
4470 struct intel_encoder *encoder;
4471 struct drm_crtc *crtc;
4472 u32 temp;
4473 bool lvds_on = false, edp_on = false, pch_edp_on = false, other_on = false;
4474
4475 list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
4476 crtc = encoder->base.crtc;
4477
4478 if (!crtc || !crtc->enabled)
4479 continue;
4480
4481 switch (encoder->type) {
4482 case INTEL_OUTPUT_LVDS:
4483 lvds_on = true;
4484 break;
4485 case INTEL_OUTPUT_EDP:
4486 edp_on = true;
4487 if (!pch_edp_on)
4488 pch_edp_on = intel_encoder_is_pch_edp(&encoder->base);
4489 break;
4490 default:
4491 other_on = true;
4492 break;
4493 }
4494 }
4495
4496 /*XXX BIOS treats 16:31 as a mask for 0:15 */
4497
4498 temp = I915_READ(PCH_DREF_CONTROL);
4499
4500 /* First clear the current state for output switching */
4501 temp &= ~DREF_SSC1_ENABLE;
4502 temp &= ~DREF_SSC4_ENABLE;
4503 temp &= ~DREF_SUPERSPREAD_SOURCE_MASK;
4504 temp &= ~DREF_NONSPREAD_SOURCE_MASK;
4505 temp &= ~DREF_SSC_SOURCE_MASK;
4506 temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
4507 I915_WRITE(PCH_DREF_CONTROL, temp);
4508
4509 POSTING_READ(PCH_DREF_CONTROL);
4510 udelay(200);
4511
4512 if ((lvds_on || edp_on) && intel_panel_use_ssc(dev_priv)) {
4513 temp |= DREF_SSC_SOURCE_ENABLE;
4514 if (edp_on) {
4515 if (!pch_edp_on) {
4516 /* Enable CPU source on CPU attached eDP */
4517 temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
4518 } else {
4519 /* Enable SSC on PCH eDP if needed */
4520 temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
4521 }
4522 I915_WRITE(PCH_DREF_CONTROL, temp);
4523 }
4524 if (!dev_priv->display_clock_mode)
4525 temp |= DREF_SSC1_ENABLE;
4526 }
4527
4528 if (other_on && dev_priv->display_clock_mode)
4529 temp |= DREF_NONSPREAD_CK505_ENABLE;
4530 else if (other_on) {
4531 temp |= DREF_NONSPREAD_SOURCE_ENABLE;
4532 if (edp_on && !pch_edp_on)
4533 temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
4534 }
4535
4536 I915_WRITE(PCH_DREF_CONTROL, temp);
4537 POSTING_READ(PCH_DREF_CONTROL);
4538 udelay(200);
4539}
4540
4466static int intel_crtc_mode_set(struct drm_crtc *crtc, 4541static int intel_crtc_mode_set(struct drm_crtc *crtc,
4467 struct drm_display_mode *mode, 4542 struct drm_display_mode *mode,
4468 struct drm_display_mode *adjusted_mode, 4543 struct drm_display_mode *adjusted_mode,
@@ -4688,52 +4763,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
4688 * PCH B stepping, previous chipset stepping should be 4763 * PCH B stepping, previous chipset stepping should be
4689 * ignoring this setting. 4764 * ignoring this setting.
4690 */ 4765 */
4691 if (HAS_PCH_SPLIT(dev)) { 4766 if (HAS_PCH_SPLIT(dev))
4692 /*XXX BIOS treats 16:31 as a mask for 0:15 */ 4767 intel_update_dref(dev_priv);
4693
4694 temp = I915_READ(PCH_DREF_CONTROL);
4695
4696 /* First clear the current state for output switching */
4697 temp &= ~DREF_SSC1_ENABLE;
4698 temp &= ~DREF_SSC4_ENABLE;
4699 temp &= ~DREF_SUPERSPREAD_SOURCE_MASK;
4700 temp &= ~DREF_NONSPREAD_SOURCE_MASK;
4701 temp &= ~DREF_SSC_SOURCE_MASK;
4702 temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
4703 I915_WRITE(PCH_DREF_CONTROL, temp);
4704
4705 POSTING_READ(PCH_DREF_CONTROL);
4706 udelay(200);
4707
4708 if ((is_lvds || has_edp_encoder) &&
4709 intel_panel_use_ssc(dev_priv)) {
4710 temp |= DREF_SSC_SOURCE_ENABLE;
4711 if (has_edp_encoder) {
4712 if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
4713 /* Enable CPU source on CPU attached eDP */
4714 temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
4715 } else {
4716 /* Enable SSC on PCH eDP if needed */
4717 temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
4718 }
4719 I915_WRITE(PCH_DREF_CONTROL, temp);
4720 }
4721 if (!dev_priv->display_clock_mode)
4722 temp |= DREF_SSC1_ENABLE;
4723 } else {
4724 if (dev_priv->display_clock_mode)
4725 temp |= DREF_NONSPREAD_CK505_ENABLE;
4726 else
4727 temp |= DREF_NONSPREAD_SOURCE_ENABLE;
4728 if (has_edp_encoder &&
4729 !intel_encoder_is_pch_edp(&has_edp_encoder->base))
4730 temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
4731 }
4732
4733 I915_WRITE(PCH_DREF_CONTROL, temp);
4734 POSTING_READ(PCH_DREF_CONTROL);
4735 udelay(200);
4736 }
4737 4768
4738 if (IS_PINEVIEW(dev)) { 4769 if (IS_PINEVIEW(dev)) {
4739 fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; 4770 fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;