]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_crt.c
drm/i915/crt: Do not rely upon the HPD presence pin
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_crt.c
index 4d3d736a4f56a9c65b315162dac4dc1b2b372c28..5978490dac9265719e886219f65f3d021eab3e58 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,
@@ -278,9 +296,10 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
        if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
                struct edid *edid;
                bool is_digital = false;
+               struct i2c_adapter *i2c;
 
-               edid = drm_get_edid(connector,
-                       &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+               i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+               edid = drm_get_edid(connector, i2c);
                /*
                 * This may be a DVI-I connector with a shared DDC
                 * link between analog and digital outputs, so we
@@ -430,43 +449,45 @@ intel_crt_detect(struct drm_connector *connector, bool force)
 {
        struct drm_device *dev = connector->dev;
        struct intel_crt *crt = intel_attached_crt(connector);
-       struct drm_crtc *crtc;
        enum drm_connector_status status;
+       struct intel_load_detect_pipe tmp;
 
        if (I915_HAS_HOTPLUG(dev)) {
+               /* We can not rely on the HPD pin always being correctly wired
+                * up, for example many KVM do not pass it through, and so
+                * only trust an assertion that the monitor is connected.
+                */
                if (intel_crt_detect_hotplug(connector)) {
                        DRM_DEBUG_KMS("CRT detected via hotplug\n");
                        return connector_status_connected;
-               } else {
+               } else
                        DRM_DEBUG_KMS("CRT not detected via hotplug\n");
-                       return connector_status_disconnected;
-               }
        }
 
        if (intel_crt_detect_ddc(connector))
                return connector_status_connected;
 
+       /* Load detection is broken on HPD capable machines. Whoever wants a
+        * broken monitor (without edid) to work behind a broken kvm (that fails
+        * to have the right resistors for HP detection) needs to fix this up.
+        * For now just bail out. */
+       if (I915_HAS_HOTPLUG(dev))
+               return connector_status_disconnected;
+
        if (!force)
                return connector->status;
 
        /* for pre-945g platforms use load detect */
-       crtc = crt->base.base.crtc;
-       if (crtc && crtc->enabled) {
-               status = intel_crt_load_detect(crt);
-       } else {
-               struct intel_load_detect_pipe tmp;
-
-               if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
-                                              &tmp)) {
-                       if (intel_crt_detect_ddc(connector))
-                               status = connector_status_connected;
-                       else
-                               status = intel_crt_load_detect(crt);
-                       intel_release_load_detect_pipe(&crt->base, connector,
-                                                      &tmp);
-               } else
-                       status = connector_status_unknown;
-       }
+       if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
+                                      &tmp)) {
+               if (intel_crt_detect_ddc(connector))
+                       status = connector_status_connected;
+               else
+                       status = intel_crt_load_detect(crt);
+               intel_release_load_detect_pipe(&crt->base, connector,
+                                              &tmp);
+       } else
+               status = connector_status_unknown;
 
        return status;
 }
@@ -483,15 +504,16 @@ static int intel_crt_get_modes(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
+       struct i2c_adapter *i2c;
 
-       ret = intel_ddc_get_modes(connector,
-                                &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+       i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+       ret = intel_ddc_get_modes(connector, i2c);
        if (ret || !IS_G4X(dev))
                return ret;
 
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
-       return intel_ddc_get_modes(connector,
-                                  &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
+       i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
+       return intel_ddc_get_modes(connector, i2c);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -514,12 +536,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 = {
@@ -543,7 +573,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
 
 static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id)
 {
-       DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
+       DRM_INFO("Skipping CRT initialization for %s\n", id->ident);
        return 1;
 }
 
@@ -565,6 +595,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))
@@ -593,14 +624,23 @@ void intel_crt_init(struct drm_device *dev)
        crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
                                1 << INTEL_ANALOG_CLONE_BIT |
                                1 << INTEL_SDVO_LVDS_CLONE_BIT);
-       crt->base.crtc_mask = (1 << 0) | (1 << 1);
+       if (IS_HASWELL(dev))
+               crt->base.crtc_mask = (1 << 0);
+       else
+               crt->base.crtc_mask = (1 << 0) | (1 << 1);
+
        if (IS_GEN2(dev))
                connector->interlace_allowed = 0;
        else
                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);