Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+25 -1
+25 -1
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
··· 55 55 56 56 int sync_lost_count; 57 57 bool frame_intact; 58 + struct work_struct recover_work; 58 59 }; 59 60 #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) 60 61 ··· 251 250 static bool tilcdc_crtc_is_on(struct drm_crtc *crtc) 252 251 { 253 252 return crtc->state && crtc->state->enable && crtc->state->active; 253 + } 254 + 255 + static void tilcdc_crtc_recover_work(struct work_struct *work) 256 + { 257 + struct tilcdc_crtc *tilcdc_crtc = 258 + container_of(work, struct tilcdc_crtc, recover_work); 259 + struct drm_crtc *crtc = &tilcdc_crtc->base; 260 + 261 + dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__); 262 + 263 + drm_modeset_lock_crtc(crtc, NULL); 264 + 265 + if (!tilcdc_crtc_is_on(crtc)) 266 + goto out; 267 + 268 + tilcdc_crtc_disable(crtc); 269 + tilcdc_crtc_enable(crtc); 270 + out: 271 + drm_modeset_unlock_crtc(crtc); 254 272 } 255 273 256 274 static void tilcdc_crtc_destroy(struct drm_crtc *crtc) ··· 858 838 tilcdc_crtc->frame_intact = false; 859 839 if (tilcdc_crtc->sync_lost_count++ > 860 840 SYNC_LOST_COUNT_LIMIT) { 861 - dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, disabling the interrupt", __func__, stat); 841 + dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat); 842 + queue_work(system_wq, 843 + &tilcdc_crtc->recover_work); 862 844 tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, 863 845 LCDC_SYNC_LOST); 846 + tilcdc_crtc->sync_lost_count = 0; 864 847 } 865 848 } 866 849 ··· 903 880 "unref", unref_worker); 904 881 905 882 spin_lock_init(&tilcdc_crtc->irq_lock); 883 + INIT_WORK(&tilcdc_crtc->recover_work, tilcdc_crtc_recover_work); 906 884 907 885 ret = drm_crtc_init_with_planes(dev, crtc, 908 886 &tilcdc_crtc->primary,