[PATCH 2/4] staging: imx-hdmi: correct connector detect and hotplug

Lucas Stach l.stach at pengutronix.de
Fri Apr 11 14:13:33 UTC 2014


Make sure that we probe for a display on detect regardless
of previous hotplug events. Don't handle connector
hotplug state ourselves, but let DRM do the right thing
for us. This brings our hotplug handling in line with
what other DRM drivers do.

Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
---
 drivers/staging/imx-drm/imx-hdmi.c | 73 +++++++++++++++++---------------------
 1 file changed, 33 insertions(+), 40 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 80b91b1e225c..22cfdfc5ef74 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -32,8 +32,6 @@
 #include "imx-hdmi.h"
 #include "imx-drm.h"
 
-#define HDMI_EDID_LEN		512
-
 #define RGB			0
 #define YCBCR444		1
 #define YCBCR422_16BITS		2
@@ -120,12 +118,10 @@ struct imx_hdmi {
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
 
-	enum drm_connector_status connector_status;
-
 	struct hdmi_data_info hdmi_data;
 	int vic;
 
-	u8 edid[HDMI_EDID_LEN];
+	struct edid *edid;
 	bool cable_plugin;
 
 	bool phy_enabled;
@@ -1386,32 +1382,46 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
 					     connector);
 
-	return hdmi->connector_status;
+	/* free previous EDID block */
+	if (hdmi->edid) {
+		drm_mode_connector_update_edid_property(connector, NULL);
+		kfree(hdmi->edid);
+	}
+
+	if (hdmi->ddc && drm_probe_ddc(hdmi->ddc)) {
+		hdmi->edid = drm_get_edid(connector, hdmi->ddc);
+		if (hdmi->edid) {
+			drm_mode_connector_update_edid_property(connector,
+								hdmi->edid);
+			dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+				hdmi->edid->width_cm, hdmi->edid->height_cm);
+
+			return connector_status_connected;
+		}
+	}
+
+	/* if EDID probing fails, try if we can sense an attached display */
+	if (hdmi_readb(hdmi, HDMI_PHY_STAT0) & 0xf0)
+		return connector_status_connected;
+
+	return connector_status_disconnected;
 }
 
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
 					     connector);
-	struct edid *edid;
-	int ret;
+	int ret = 0;
 
-	if (!hdmi->ddc)
-		return 0;
-
-	edid = drm_get_edid(connector, hdmi->ddc);
-	if (edid) {
-		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
-			edid->width_cm, edid->height_cm);
-
-		drm_mode_connector_update_edid_property(connector, edid);
-		ret = drm_add_edid_modes(connector, edid);
-		kfree(edid);
+	if (hdmi->edid) {
+		ret = drm_add_edid_modes(connector, hdmi->edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, hdmi->edid);
 	} else {
-		dev_dbg(hdmi->dev, "failed to get edid\n");
+		dev_dbg(hdmi->dev, "failed to get edid modes\n");
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
@@ -1519,27 +1529,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	u8 phy_int_pol;
 
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-
 	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
 
 	if (intr_stat & hdmi->sink_detect_status) {
-		int pol_bit = hdmi->sink_detect_polarity;
-
-		if (phy_int_pol & pol_bit) {
-			dev_dbg(hdmi->dev, "EVENT=plugin\n");
-
-			hdmi_modb(hdmi, 0, pol_bit, HDMI_PHY_POL0);
-
-			hdmi->connector_status = connector_status_connected;
-			imx_hdmi_poweron(hdmi);
-		} else {
-			dev_dbg(hdmi->dev, "EVENT=plugout\n");
-
-			hdmi_modb(hdmi, pol_bit, pol_bit, HDMI_PHY_POL0);
-
-			hdmi->connector_status = connector_status_disconnected;
-			imx_hdmi_poweroff(hdmi);
-		}
+		hdmi_modb(hdmi, ~phy_int_pol, ~hdmi->sink_detect_mask, HDMI_PHY_POL0);
 		drm_helper_hpd_irq_event(hdmi->connector.dev);
 	}
 
@@ -1611,7 +1604,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	hdmi->dev = dev;
-	hdmi->connector_status = connector_status_disconnected;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
@@ -1752,6 +1744,7 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
 	i2c_put_adapter(hdmi->ddc);
+	kfree(hdmi->edid);
 }
 
 static const struct component_ops hdmi_ops = {
-- 
1.9.1



More information about the devel mailing list