diff options
author | Jyri Sarha <jsarha@ti.com> | 2016-04-06 14:02:38 +0300 |
---|---|---|
committer | Jyri Sarha <jsarha@ti.com> | 2016-11-30 14:14:40 +0200 |
commit | 13b3d72705817cdcf003226dd9f22f3ecee64ba4 (patch) | |
tree | 6ea4f220a76be5661e7d485c97736c93aecacbea /drivers/gpu/drm/tilcdc | |
parent | 2d53a18098e5a03a30b1b1419ab4103357b69f0d (diff) | |
download | linux-stable-13b3d72705817cdcf003226dd9f22f3ecee64ba4.tar.gz linux-stable-13b3d72705817cdcf003226dd9f22f3ecee64ba4.tar.bz2 linux-stable-13b3d72705817cdcf003226dd9f22f3ecee64ba4.zip |
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 <jsarha@ti.com>
Tested-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Diffstat (limited to 'drivers/gpu/drm/tilcdc')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 26 |
1 files changed, 25 insertions, 1 deletions
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, |