aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2012-04-17 18:06:33 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-04-18 04:34:49 -0400
commitdf0323c42ac35f81b49e25fe04e8e52b9c6f6467 (patch)
treead651d75626df4bdbd3ddbefa540a4e5649d5b0d
parent446f254566ea8911c9e19c7bc8a162fc0e53cf31 (diff)
drm/i915: IBX+ doesn't have separate vsync/hsync controls on the VGA DAC
When the PCH split occurred, hw dropped support for separate hsync and vsync disable in the VGA DAC. So add a PCH specific DPMS function that just uses the port enable bit for controlling DPMS states. Before this fix, when anything other than a full DPMS off occurred, the VGA port would be left enabled and scanning out while all the other heads would turn off as expected. v2: duplicate encoder helper vtable into pch and gmch versions (Daniel) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48491 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> [danvet: s/intel_crt_dpms/gmch_crt_dpms as suggested by Chris.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 70b0f1abf149..0976137ab79a 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -55,18 +55,36 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
55 struct intel_crt, base); 55 struct intel_crt, base);
56} 56}
57 57
58static void intel_crt_dpms(struct drm_encoder *encoder, int mode) 58static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
59{ 59{
60 struct drm_device *dev = encoder->dev; 60 struct drm_device *dev = encoder->dev;
61 struct drm_i915_private *dev_priv = dev->dev_private; 61 struct drm_i915_private *dev_priv = dev->dev_private;
62 u32 temp, reg; 62 u32 temp;
63 63
64 if (HAS_PCH_SPLIT(dev)) 64 temp = I915_READ(PCH_ADPA);
65 reg = PCH_ADPA; 65 temp &= ~ADPA_DAC_ENABLE;
66 else 66
67 reg = ADPA; 67 switch (mode) {
68 case DRM_MODE_DPMS_ON:
69 temp |= ADPA_DAC_ENABLE;
70 break;
71 case DRM_MODE_DPMS_STANDBY:
72 case DRM_MODE_DPMS_SUSPEND:
73 case DRM_MODE_DPMS_OFF:
74 /* Just leave port enable cleared */
75 break;
76 }
77
78 I915_WRITE(PCH_ADPA, temp);
79}
68 80
69 temp = I915_READ(reg); 81static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
82{
83 struct drm_device *dev = encoder->dev;
84 struct drm_i915_private *dev_priv = dev->dev_private;
85 u32 temp;
86
87 temp = I915_READ(ADPA);
70 temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); 88 temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
71 temp &= ~ADPA_DAC_ENABLE; 89 temp &= ~ADPA_DAC_ENABLE;
72 90
@@ -85,7 +103,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
85 break; 103 break;
86 } 104 }
87 105
88 I915_WRITE(reg, temp); 106 I915_WRITE(ADPA, temp);
89} 107}
90 108
91static int intel_crt_mode_valid(struct drm_connector *connector, 109static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -516,12 +534,20 @@ static void intel_crt_reset(struct drm_connector *connector)
516 * Routines for controlling stuff on the analog port 534 * Routines for controlling stuff on the analog port
517 */ 535 */
518 536
519static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { 537static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
520 .dpms = intel_crt_dpms, 538 .mode_fixup = intel_crt_mode_fixup,
539 .prepare = intel_encoder_prepare,
540 .commit = intel_encoder_commit,
541 .mode_set = intel_crt_mode_set,
542 .dpms = pch_crt_dpms,
543};
544
545static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
521 .mode_fixup = intel_crt_mode_fixup, 546 .mode_fixup = intel_crt_mode_fixup,
522 .prepare = intel_encoder_prepare, 547 .prepare = intel_encoder_prepare,
523 .commit = intel_encoder_commit, 548 .commit = intel_encoder_commit,
524 .mode_set = intel_crt_mode_set, 549 .mode_set = intel_crt_mode_set,
550 .dpms = gmch_crt_dpms,
525}; 551};
526 552
527static const struct drm_connector_funcs intel_crt_connector_funcs = { 553static const struct drm_connector_funcs intel_crt_connector_funcs = {
@@ -567,6 +593,7 @@ void intel_crt_init(struct drm_device *dev)
567 struct intel_crt *crt; 593 struct intel_crt *crt;
568 struct intel_connector *intel_connector; 594 struct intel_connector *intel_connector;
569 struct drm_i915_private *dev_priv = dev->dev_private; 595 struct drm_i915_private *dev_priv = dev->dev_private;
596 const struct drm_encoder_helper_funcs *encoder_helper_funcs;
570 597
571 /* Skip machines without VGA that falsely report hotplug events */ 598 /* Skip machines without VGA that falsely report hotplug events */
572 if (dmi_check_system(intel_no_crt)) 599 if (dmi_check_system(intel_no_crt))
@@ -602,7 +629,12 @@ void intel_crt_init(struct drm_device *dev)
602 connector->interlace_allowed = 1; 629 connector->interlace_allowed = 1;
603 connector->doublescan_allowed = 0; 630 connector->doublescan_allowed = 0;
604 631
605 drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); 632 if (HAS_PCH_SPLIT(dev))
633 encoder_helper_funcs = &pch_encoder_funcs;
634 else
635 encoder_helper_funcs = &gmch_encoder_funcs;
636
637 drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
606 drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); 638 drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
607 639
608 drm_sysfs_connector_add(connector); 640 drm_sysfs_connector_add(connector);