[Intel-gfx] [PATCH V2] drm/i915: read edid-extensions when sdvo device is connected with hdmi monitor

Ma Ling ling.ma at intel.com
Thu Apr 16 11:03:22 CEST 2009


Currently drm_get_edid function will fetch basic edid, then determine to continue edid extensions
by edid->extensions field. However for sdvo output, after first i2c_stop of drm_get_edid function
we have to do switch ddc bus for following edid extensions, or i2c will fail to work.
The patch intends to fetch basic edid, then switch ddc bus to get edid extension
by drm_do_probe_ddc_edid, instead of drm_get_edid.

It has fixed bug #21042

Signed-off-by: Ma Ling <ling.ma at intel.com>
---
In this version, it is based on our latest version, and do corresponding modification
to intel_sdvo_hdmi_sink_detect function.

 drivers/gpu/drm/i915/intel_sdvo.c |   79 +++++++++++++++++++++++++++++++++++--
 1 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 9913651..3677cbf 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -30,6 +30,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
+#include "drm_edid.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
@@ -100,6 +101,8 @@ struct intel_sdvo_priv {
 	u32 save_SDVOX;
 };
 
+static struct edid *intel_sdvo_get_ddc_edid(struct intel_output *intel_output);
+
 /**
  * Writes the SDVOB or SDVOC with the given value, but always writes both
  * SDVOB and SDVOC to work around apparent hardware issues (according to
@@ -1365,8 +1368,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 	struct edid *edid = NULL;
 
 	intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
-	edid = drm_get_edid(&intel_output->base,
-			    &intel_output->ddc_bus->adapter);
+	edid = intel_sdvo_get_ddc_edid(intel_output);
+
 	if (edid != NULL) {
 		sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
 		kfree(edid);
@@ -1395,14 +1398,82 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 		return connector_status_disconnected;
 }
 
+#define MAX_EDID_EXT_NUM 4
+/**
+ * This function will fetch EDID by switch ddc bus, instead of drm_get_edid
+ * function.
+ */
+static struct edid *intel_sdvo_get_ddc_edid(struct intel_output *intel_output)
+{
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	struct edid *edid;
+	int ret = 0;
+
+	edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
+		       GFP_KERNEL);
+
+	if (edid == NULL) {
+		DRM_DEBUG("Failed to allocated EDID for SDVO HDMI\n");
+		goto end;
+	}
+
+	/* Read first EDID block */
+	ret = drm_do_probe_ddc_edid(&intel_output->ddc_bus->adapter,
+				    (unsigned char *)edid, EDID_LENGTH);
+	if (ret != 0) {
+		DRM_DEBUG("Failed to read basic EDID for SDVO HDMI\n");
+		goto clean_up;
+	}
+
+	/* There are EDID extensions to be read */
+	if (edid->extensions != 0) {
+		int edid_ext_num = edid->extensions;
+
+		if (edid_ext_num > MAX_EDID_EXT_NUM) {
+			DRM_DEBUG("The number of extension(%d) is "
+				  "over max (%d), actually read number (%d)\n",
+				  edid_ext_num, MAX_EDID_EXT_NUM,
+				  MAX_EDID_EXT_NUM);
+			/* Reset EDID extension number to be read */
+			edid_ext_num = MAX_EDID_EXT_NUM;
+		}
+		/* Must set the bus switch and get the edid again */
+		intel_sdvo_set_control_bus_switch(intel_output,
+						  sdvo_priv->ddc_bus);
+		/* Read EDID including extensions too */
+		ret = drm_do_probe_ddc_edid(&intel_output->ddc_bus->adapter,
+					    (unsigned char *)edid,
+					    EDID_LENGTH * (edid_ext_num + 1));
+		if (ret != 0) {
+			DRM_DEBUG("Failed to read EDID EXT for SDVO HDMI\n");
+			goto clean_up;
+		}
+	}
+	goto end;
+
+clean_up:
+	kfree(edid);
+	edid = NULL;
+end:
+	return edid;
+}
+
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
+	struct edid *edid;
 	struct intel_output *intel_output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
 	/* set the bus switch and get the modes */
-	intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
-	intel_ddc_get_modes(intel_output);
+	intel_sdvo_set_control_bus_switch(intel_output,
+					  sdvo_priv->ddc_bus);
+	edid = intel_sdvo_get_ddc_edid(intel_output);
+	if (edid != NULL) {
+		drm_mode_connector_update_edid_property(&intel_output->base,
+							edid);
+		drm_add_edid_modes(&intel_output->base, edid);
+		kfree(edid);
+	}
 
 #if 0
 	struct drm_device *dev = encoder->dev;
-- 
1.5.4.4






More information about the Intel-gfx mailing list