DISPC and HDMI have synchronization issues when enabling or disabling
the output. The symptoms are a lot of sync-lost errors and occasionally
dispc gets "stuck" and we never get FRAMEDONE when disabling.

Testing has shown that this is somehow related to the time when DISPC's
output gets enabled:

- If DISPC is disabled when HDMI is in vertical blanking area, DISPC
  often gets stuck.
- If DISPC is disabled after vertical blanking area, no sync lost errors
  are seen.
- If DISPC is enabled right after HDMI VSYNC event, no sync lost errors
  are seen.

This patch is a simple work-around for the above issues:

- Before enabling DISPC output, we wait for HDMI VSYNC.
- Before disabling DISPC output, we wait for HDMI VSYNC and VSW+VBP.

This is not perfect WA, as it relies on the enable/disable of DISPC
happening relatively soon after the wait has ended. In practice I
presume there is at least ~10ms timewindow to accomplish the DISPC
enable/disable, which I hope is enough.

Signed-off-by: Tomi Valkeinen <[email protected]>
---
 drivers/video/fbdev/omap2/dss/hdmi4.c | 50 +++++++++++++++++++++++++++++++++++
 drivers/video/fbdev/omap2/dss/hdmi5.c | 50 +++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c 
b/drivers/video/fbdev/omap2/dss/hdmi4.c
index 916d47978f41..39cdd164d2ae 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -217,6 +217,26 @@ static int hdmi_power_on_full(struct omap_dss_device 
*dssdev)
        if (r)
                goto err_vid_enable;
 
+       /*
+        * XXX Seems that on we easily get a flood of sync-lost errors when
+        * enabling the output. This seems to be related to the time between
+        * HDMI VSYNC and enabling the DISPC output.
+        *
+        * Testing shows that the sync-lost errors do not happen if we enable
+        * the DISPC output very soon after HDMI VBLANK. So wait here for
+        * VBLANK to reduce the chances of sync-losts.
+        */
+       hdmi_write_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_VSYNC);
+
+       while (true) {
+               u32 v = hdmi_read_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS_RAW);
+
+               if (v & HDMI_IRQ_VIDEO_VSYNC)
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
        r = dss_mgr_enable(mgr);
        if (r)
                goto err_mgr_enable;
@@ -242,9 +262,39 @@ err_pll_enable:
 static void hdmi_power_off_full(struct omap_dss_device *dssdev)
 {
        struct omap_overlay_manager *mgr = hdmi.output.manager;
+       const struct omap_video_timings *t;
+       unsigned vblank;
 
        hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
 
+       /*
+        * XXX Seems that on we easily get a flood of sync-lost errors when
+        * disabling the output, and sometimes the DISPC seems to get stuck and
+        * we never get FRAMEDONE. This seems to happen if we disable DISPC
+        * output during HDMI VBLANK.
+        *
+        * To reduce the possibility for sync-lost errors, calculate the time
+        * for the vertical blanking, wait for VBLANK, then wait until VBLANK
+        * ends.
+        */
+       t = &hdmi.cfg.timings;
+       vblank = t->hfp + t->hsw + t->hbp + t->x_res;
+       vblank *= t->vsw + t->vbp;
+       vblank = (vblank * 1000) / (t->pixelclock / 1000);
+
+       hdmi_write_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_VSYNC);
+
+       while (true) {
+               u32 v = hdmi_read_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS_RAW);
+
+               if (v & HDMI_IRQ_VIDEO_VSYNC)
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
+       usleep_range(vblank, vblank + 1000);
+
        dss_mgr_disable(mgr);
 
        hdmi_wp_video_stop(&hdmi.wp);
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c 
b/drivers/video/fbdev/omap2/dss/hdmi5.c
index 3f0b34a7031a..65a91ac87a6a 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -234,6 +234,26 @@ static int hdmi_power_on_full(struct omap_dss_device 
*dssdev)
        if (r)
                goto err_vid_enable;
 
+       /*
+        * XXX Seems that on we easily get a flood of sync-lost errors when
+        * enabling the output. This seems to be related to the time between
+        * HDMI VSYNC and enabling the DISPC output.
+        *
+        * Testing shows that the sync-lost errors do not happen if we enable
+        * the DISPC output very soon after HDMI VBLANK. So wait here for
+        * VBLANK to reduce the chances of sync-losts.
+        */
+       hdmi_write_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_VSYNC);
+
+       while (true) {
+               u32 v = hdmi_read_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS_RAW);
+
+               if (v & HDMI_IRQ_VIDEO_VSYNC)
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
        r = dss_mgr_enable(mgr);
        if (r)
                goto err_mgr_enable;
@@ -259,9 +279,39 @@ err_pll_enable:
 static void hdmi_power_off_full(struct omap_dss_device *dssdev)
 {
        struct omap_overlay_manager *mgr = hdmi.output.manager;
+       const struct omap_video_timings *t;
+       unsigned vblank;
 
        hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
 
+       /*
+        * XXX Seems that on we easily get a flood of sync-lost errors when
+        * disabling the output, and sometimes the DISPC seems to get stuck and
+        * we never get FRAMEDONE. This seems to happen if we disable DISPC
+        * output during HDMI VBLANK.
+        *
+        * To reduce the possibility for sync-lost errors, calculate the time
+        * for the vertical blanking, wait for VBLANK, then wait until VBLANK
+        * ends.
+        */
+       t = &hdmi.cfg.timings;
+       vblank = t->hfp + t->hsw + t->hbp + t->x_res;
+       vblank *= t->vsw + t->vbp;
+       vblank = (vblank * 1000) / (t->pixelclock / 1000);
+
+       hdmi_write_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_VSYNC);
+
+       while (true) {
+               u32 v = hdmi_read_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS_RAW);
+
+               if (v & HDMI_IRQ_VIDEO_VSYNC)
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
+       usleep_range(vblank, vblank + 1000);
+
        dss_mgr_disable(mgr);
 
        hdmi_wp_video_stop(&hdmi.wp);
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to