Commit f5afcd3d authored by David Müller's avatar David Müller Committed by Chris Wilson

drm/i915/crt: Check for a analog monitor in case of DVI-I

Since Linux 2.6.36 the digital output on my system (855GME + DVI-I) is
not working any longer. The analog output is always activated
regardless of the type of monitor attached.

The culprit seems to be intel_crt_detect_ddc(), which returns true as
soon as an ACK from the EDID device is received. Obviously this
approach does not work with DVI-I where the analog and digital outputs
share a common DDC bus.

In a similar manner to the shared DDC wire, ala the "Mac Mini Hack", we
need an additional check to make sure that there really is an analog
device attached to the DDC.
Signed-off-by: default avatarDavid Müller <d.mueller@elsoft.ch>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: stable@kernel.org
parent 37f80975
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "drm.h" #include "drm.h"
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
#include "drm_edid.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
...@@ -287,8 +288,9 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) ...@@ -287,8 +288,9 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
} }
static bool intel_crt_detect_ddc(struct intel_crt *crt) static bool intel_crt_detect_ddc(struct drm_connector *connector)
{ {
struct intel_crt *crt = intel_attached_crt(connector);
struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
/* CRT should always be at 0, but check anyway */ /* CRT should always be at 0, but check anyway */
...@@ -301,9 +303,27 @@ static bool intel_crt_detect_ddc(struct intel_crt *crt) ...@@ -301,9 +303,27 @@ static bool intel_crt_detect_ddc(struct intel_crt *crt)
} }
if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
struct edid *edid;
bool is_digital = false;
edid = drm_get_edid(connector,
&dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
/*
* This may be a DVI-I connector with a shared DDC
* link between analog and digital outputs, so we
* have to check the EDID input spec of the attached device.
*/
if (edid != NULL) {
is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
connector->display_info.raw_edid = NULL;
kfree(edid);
}
if (!is_digital) {
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
return true; return true;
} }
}
return false; return false;
} }
...@@ -458,7 +478,7 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -458,7 +478,7 @@ intel_crt_detect(struct drm_connector *connector, bool force)
} }
} }
if (intel_crt_detect_ddc(crt)) if (intel_crt_detect_ddc(connector))
return connector_status_connected; return connector_status_connected;
if (!force) if (!force)
...@@ -472,7 +492,7 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -472,7 +492,7 @@ intel_crt_detect(struct drm_connector *connector, bool force)
crtc = intel_get_load_detect_pipe(&crt->base, connector, crtc = intel_get_load_detect_pipe(&crt->base, connector,
NULL, &dpms_mode); NULL, &dpms_mode);
if (crtc) { if (crtc) {
if (intel_crt_detect_ddc(crt)) if (intel_crt_detect_ddc(connector))
status = connector_status_connected; status = connector_status_connected;
else else
status = intel_crt_load_detect(crtc, crt); status = intel_crt_load_detect(crtc, crt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment