drm/i915: IBX+ doesn't have separate vsync/hsync controls on the VGA DAC
authorJesse Barnes <jbarnes@virtuousgeek.org>
Tue, 17 Apr 2012 22:06:33 +0000 (15:06 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 18 Apr 2012 08:34:49 +0000 (10:34 +0200)
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>
drivers/gpu/drm/i915/intel_crt.c

index 70b0f1a..0976137 100644 (file)
@@ -55,18 +55,36 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
                            struct intel_crt, base);
 }
 
-static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
+static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 temp, reg;
+       u32 temp;
 
-       if (HAS_PCH_SPLIT(dev))
-               reg = PCH_ADPA;
-       else
-               reg = ADPA;
+       temp = I915_READ(PCH_ADPA);
+       temp &= ~ADPA_DAC_ENABLE;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               temp |= ADPA_DAC_ENABLE;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               /* Just leave port enable cleared */
+               break;
+       }
+
+       I915_WRITE(PCH_ADPA, temp);
+}
 
-       temp = I915_READ(reg);
+static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 temp;
+
+       temp = I915_READ(ADPA);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
        temp &= ~ADPA_DAC_ENABLE;
 
@@ -85,7 +103,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
                break;
        }
 
-       I915_WRITE(reg, temp);
+       I915_WRITE(ADPA, temp);
 }
 
 static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -516,12 +534,20 @@ static void intel_crt_reset(struct drm_connector *connector)
  * Routines for controlling stuff on the analog port
  */
 
-static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
-       .dpms = intel_crt_dpms,
+static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
+       .mode_fixup = intel_crt_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .commit = intel_encoder_commit,
+       .mode_set = intel_crt_mode_set,
+       .dpms = pch_crt_dpms,
+};
+
+static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
        .mode_fixup = intel_crt_mode_fixup,
        .prepare = intel_encoder_prepare,
        .commit = intel_encoder_commit,
        .mode_set = intel_crt_mode_set,
+       .dpms = gmch_crt_dpms,
 };
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
@@ -567,6 +593,7 @@ void intel_crt_init(struct drm_device *dev)
        struct intel_crt *crt;
        struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct drm_encoder_helper_funcs *encoder_helper_funcs;
 
        /* Skip machines without VGA that falsely report hotplug events */
        if (dmi_check_system(intel_no_crt))
@@ -602,7 +629,12 @@ void intel_crt_init(struct drm_device *dev)
                connector->interlace_allowed = 1;
        connector->doublescan_allowed = 0;
 
-       drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
+       if (HAS_PCH_SPLIT(dev))
+               encoder_helper_funcs = &pch_encoder_funcs;
+       else
+               encoder_helper_funcs = &gmch_encoder_funcs;
+
+       drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);