Recover from sync lost error flood by resetting the LCDC in stead 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@xxxxxx> --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 051e5e1..5aa86e9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -46,6 +46,8 @@ struct tilcdc_crtc { int sync_lost_count; bool frame_intact; + struct workqueue_struct *wq; + struct work_struct recover_work; }; #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) @@ -60,6 +62,25 @@ static void unref_worker(struct drm_flip_work *work, void *val) mutex_unlock(&dev->mode_config.mutex); } +static void stop(struct drm_crtc *crtc); +static void start(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; + + dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__); + + if (tilcdc_crtc->dpms == DRM_MODE_DPMS_OFF) + return; + + drm_modeset_lock_crtc(crtc, NULL); + stop(crtc); + start(crtc); + drm_modeset_unlock_crtc(crtc); +} + static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); @@ -125,6 +146,7 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); of_node_put(crtc->port); + destroy_workqueue(tilcdc_crtc->wq); drm_crtc_cleanup(crtc); drm_flip_work_cleanup(&tilcdc_crtc->unref_work); } @@ -732,10 +754,10 @@ 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); - tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, - LCDC_SYNC_LOST); + queue_work(tilcdc_crtc->wq, &tilcdc_crtc->recover_work); + tilcdc_crtc->sync_lost_count = 0; } } @@ -768,6 +790,12 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) "unref", unref_worker); spin_lock_init(&tilcdc_crtc->irq_lock); + tilcdc_crtc->wq = create_singlethread_workqueue("tilcdc/crtc"); + if (!tilcdc_crtc->wq) { + kfree(tilcdc_crtc); + return NULL; + } + 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel