From 13b3d72705817cdcf003226dd9f22f3ecee64ba4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 6 Apr 2016 14:02:38 +0300 Subject: [PATCH] drm/tilcdc: Recover from sync lost error flood by resetting the LCDC 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 Tested-by: Bartosz Golaszewski --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 0d09acce4916..c7873493f506 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -55,6 +55,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) @@ -252,6 +253,25 @@ static bool tilcdc_crtc_is_on(struct drm_crtc *crtc) return crtc->state && crtc->state->enable && crtc->state->active; } +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; + + dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__); + + drm_modeset_lock_crtc(crtc, NULL); + + if (!tilcdc_crtc_is_on(crtc)) + goto out; + + tilcdc_crtc_disable(crtc); + tilcdc_crtc_enable(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); @@ -838,9 +858,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", __func__, stat); + dev_err(dev->dev, "%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; } } @@ -880,6 +903,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_with_planes(dev, crtc, &tilcdc_crtc->primary, -- 2.20.1