[Intel-gfx] [PATCH] drm/i915/crt: Keep the EDID for the whole detect cycle
Chris Wilson
chris at chris-wilson.co.uk
Fri Jan 20 14:51:49 UTC 2017
Other than reducing the number of EDID reads required for probing the
modes on a connector, this refactor has the importance of centralising
the logic for deciding when we need to probe for an analogue output via
DVI-I and then consistently using that information between detection and
mode computation.
References: https://bugs.freedesktop.org/show_bug.cgi?id=97971
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Imre Deak <imre.deak at intel.com>
Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
drivers/gpu/drm/i915/intel_crt.c | 108 +++++++++++++++------------------------
1 file changed, 41 insertions(+), 67 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 385e29af8baa..a94b6c981fea 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -459,8 +459,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
return ret;
}
-static struct edid *intel_crt_get_edid(struct drm_connector *connector,
- struct i2c_adapter *i2c)
+static struct edid *__intel_crt_get_edid(struct drm_connector *connector,
+ struct i2c_adapter *i2c)
{
struct edid *edid;
@@ -473,59 +473,50 @@ static struct edid *intel_crt_get_edid(struct drm_connector *connector,
intel_gmbus_force_bit(i2c, false);
}
- return edid;
-}
-
-/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */
-static int intel_crt_ddc_get_modes(struct drm_connector *connector,
- struct i2c_adapter *adapter)
-{
- struct edid *edid;
- int ret;
-
- edid = intel_crt_get_edid(connector, adapter);
- if (!edid)
- return 0;
-
- ret = intel_connector_update_modes(connector, edid);
- kfree(edid);
+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+ DRM_DEBUG_KMS("EDID reports a digital output, ignoring for this VGA connector\n");
+ kfree(edid);
+ edid = NULL;
+ }
- return ret;
+ return edid;
}
-static bool intel_crt_detect_ddc(struct drm_connector *connector)
+static struct edid *intel_crt_get_edid(struct drm_connector *connector)
{
- struct intel_crt *crt = intel_attached_crt(connector);
- struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev);
- struct edid *edid;
+#define HAS_DVI_I(p) 1 /* XXX anything with HDMI, i.e. g33+ */
+ struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct i2c_adapter *i2c;
-
- BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
+ struct edid *edid;
i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
- edid = intel_crt_get_edid(connector, i2c);
-
- if (edid) {
- bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
-
+ edid = __intel_crt_get_edid(connector, i2c);
+ if (!edid && HAS_DVI_I(dev_priv)) {
/*
* 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 (!is_digital) {
- DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
- return true;
- }
-
- DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
- } else {
- DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
+ i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB);
+ edid = __intel_crt_get_edid(connector, i2c);
}
- kfree(edid);
+ return edid;
+}
+
+static bool intel_crt_detect_ddc(struct drm_connector *connector)
+{
+ struct edid *edid;
+
+ kfree(to_intel_connector(connector)->detect_edid);
+ to_intel_connector(connector)->detect_edid = NULL;
- return false;
+ edid = intel_crt_get_edid(connector);
+ if (!edid)
+ return false;
+
+ to_intel_connector(connector)->detect_edid = edid;
+ return true;
}
static enum drm_connector_status
@@ -691,6 +682,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
power_domain = intel_display_port_power_domain(intel_encoder);
intel_display_power_get(dev_priv, power_domain);
+ if (intel_crt_detect_ddc(connector)) {
+ status = connector_status_connected;
+ goto out;
+ }
+
if (I915_HAS_HOTPLUG(dev_priv)) {
/* We can not rely on the HPD pin always being correctly wired
* up, for example many KVM do not pass it through, and so
@@ -704,11 +700,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_KMS("CRT not detected via hotplug\n");
}
- if (intel_crt_detect_ddc(connector)) {
- status = connector_status_connected;
- goto out;
- }
-
/* 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.
@@ -756,30 +747,13 @@ static void intel_crt_destroy(struct drm_connector *connector)
static int intel_crt_get_modes(struct drm_connector *connector)
{
- struct drm_device *dev = connector->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_crt *crt = intel_attached_crt(connector);
- struct intel_encoder *intel_encoder = &crt->base;
- enum intel_display_power_domain power_domain;
- int ret;
- struct i2c_adapter *i2c;
-
- power_domain = intel_display_port_power_domain(intel_encoder);
- intel_display_power_get(dev_priv, power_domain);
-
- i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
- ret = intel_crt_ddc_get_modes(connector, i2c);
- if (ret || !IS_G4X(dev_priv))
- goto out;
-
- /* Try to probe digital port for output in DVI-I -> VGA mode. */
- i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB);
- ret = intel_crt_ddc_get_modes(connector, i2c);
+ struct edid *edid;
-out:
- intel_display_power_put(dev_priv, power_domain);
+ edid = to_intel_connector(connector)->detect_edid;
+ if (!edid)
+ return 0;
- return ret;
+ return intel_connector_update_modes(connector, edid);
}
static int intel_crt_set_property(struct drm_connector *connector,
--
2.11.0
More information about the Intel-gfx
mailing list