diff mbox

[RFC] drm/msm/hdmi: spurious hpd disconnect workaround

Message ID 1421872996-28215-1-git-send-email-robdclark@gmail.com (mailing list archive)
State Accepted
Headers show

Commit Message

Rob Clark Jan. 21, 2015, 8:43 p.m. UTC
On some (well, maybe just one) HDMI monitor I get a spurious disconnect
in the process of lighting up the display.  A low-pass filter on HPD
events, in the form of leaving the HPD irq disabled for 100ms after the
previous HPD irq, seems to do a good job of working around the issue.

A somewhat simpler solution is just msleep(100) in the hotplug worker.
But AFAIU that will interfere with the pending HDCP support, if HDCP
requires guarantees about detecting disconnect in a timely fashion.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index bc20e9b..f481f54 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -24,6 +24,7 @@  struct hdmi_connector {
 	struct drm_connector base;
 	struct hdmi *hdmi;
 	struct work_struct hpd_work;
+	struct timer_list hotplug_timer;
 };
 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
 
@@ -228,11 +229,25 @@  static void hdp_disable(struct hdmi_connector *hdmi_connector)
 }
 
 static void
+hotplug_timer(unsigned long data)
+{
+	struct hdmi *hdmi = (struct hdmi *)data;
+	uint32_t hpd_int_ctrl;
+
+	/* re-enable HPD irq: */
+	hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
+	hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_EN;
+	hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
+}
+
+static void
 hotplug_work(struct work_struct *work)
 {
 	struct hdmi_connector *hdmi_connector =
 		container_of(work, struct hdmi_connector, hpd_work);
 	struct drm_connector *connector = &hdmi_connector->base;
+	mod_timer(&hdmi_connector->hotplug_timer,
+			round_jiffies_up(jiffies + msecs_to_jiffies(100)));
 	drm_helper_hpd_irq_event(connector->dev);
 }
 
@@ -258,7 +273,7 @@  void hdmi_connector_irq(struct drm_connector *connector)
 		DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
 
 		/* detect disconnect if we are connected or visa versa: */
-		hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
+		hpd_int_ctrl = 0;
 		if (!detected)
 			hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
 		hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
@@ -416,6 +431,8 @@  struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
 
 	hdmi_connector->hdmi = hdmi;
 	INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
+	setup_timer(&hdmi_connector->hotplug_timer, hotplug_timer,
+			(unsigned long)hdmi);
 
 	connector = &hdmi_connector->base;