Recover from sync lost error flood by resetting the LCDC instead of
turning off the SYNC_LOST error IRQ. When LCDC starves on limited
memory bandwidth it may sometimes result an error situation when the
picture may have shifted couple of pixels to right and SYNC_LOST
interrupt is generated on every frame. LCDC main reset recovers from
this situation and causes a brief blanking on the screen.

Signed-off-by: Jyri Sarha <jsarha at ti.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c 
b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 7a5cc03..6dce763 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -46,6 +46,7 @@ struct tilcdc_crtc {

        int sync_lost_count;
        bool frame_intact;
+       struct work_struct recover_work;
 };
 #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base)

@@ -134,6 +135,28 @@ static void stop(struct drm_crtc *crtc)
        }
 }

+static void tilcdc_crtc_recover_work(struct work_struct *work)
+{
+       struct tilcdc_crtc *tilcdc_crtc =
+               container_of(work, struct tilcdc_crtc, recover_work);
+       struct drm_crtc *crtc = &tilcdc_crtc->base;
+       struct drm_device *dev = crtc->dev;
+
+       dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__);
+
+       drm_modeset_lock_crtc(crtc, NULL);
+
+       if (tilcdc_crtc->dpms == DRM_MODE_DPMS_OFF)
+               goto out;
+
+       tilcdc_crtc->frame_done = false;
+       stop(crtc);
+       tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, LCDC_SYNC_LOST);
+       start(crtc);
+out:
+       drm_modeset_unlock_crtc(crtc);
+}
+
 static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
 {
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
@@ -738,10 +761,12 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
                tilcdc_crtc->frame_intact = false;
                if (tilcdc_crtc->sync_lost_count++ > SYNC_LOST_COUNT_LIMIT) {
                        dev_err(dev->dev,
-                               "%s(0x%08x): Sync lost flood detected, 
disabling the interrupt",
+                               "%s(0x%08x): Sync lost flood detected, 
recovering",
                                __func__, stat);
+                       queue_work(system_wq, &tilcdc_crtc->recover_work);
                        tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
                                     LCDC_SYNC_LOST);
+                       tilcdc_crtc->sync_lost_count = 0;
                }
        }

@@ -775,6 +800,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
                        "unref", unref_worker);

        spin_lock_init(&tilcdc_crtc->irq_lock);
+       INIT_WORK(&tilcdc_crtc->recover_work, tilcdc_crtc_recover_work);

        ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
        if (ret < 0)
-- 
1.9.1

Reply via email to