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 at gmail.com>
---
 drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

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;

-- 
2.1.0

Reply via email to