diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2015-05-28 00:21:29 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2016-12-19 12:24:56 +0300 |
commit | 728ae8dd696a483355b593487eba73f4c64f1152 (patch) | |
tree | 71f69575be8ded505985561a294b9b3b64908c33 /drivers/gpu/drm/omapdrm/omap_irq.c | |
parent | a078a3ddc7209474e8dd827743390e9ed4bc6881 (diff) | |
download | linux-728ae8dd696a483355b593487eba73f4c64f1152.tar.xz |
drm: omapdrm: Handle FIFO underflow IRQs internally
As the FIFO underflow IRQ handler just prints an error message to the
kernel log, simplify the code by not registering one IRQ handler per
plane but print the messages directly from the main IRQ handler.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_irq.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_irq.c | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 60e1e8016708..57a2de7e0d7b 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -32,7 +32,7 @@ static void omap_irq_update(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_drm_irq *irq; - uint32_t irqmask = priv->vblank_mask; + uint32_t irqmask = priv->irq_mask; assert_spin_locked(&list_lock); @@ -153,7 +153,7 @@ int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe) DBG("dev=%p, crtc=%u", dev, pipe); spin_lock_irqsave(&list_lock, flags); - priv->vblank_mask |= pipe2vbl(crtc); + priv->irq_mask |= pipe2vbl(crtc); omap_irq_update(dev); spin_unlock_irqrestore(&list_lock, flags); @@ -178,11 +178,52 @@ void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe) DBG("dev=%p, crtc=%u", dev, pipe); spin_lock_irqsave(&list_lock, flags); - priv->vblank_mask &= ~pipe2vbl(crtc); + priv->irq_mask &= ~pipe2vbl(crtc); omap_irq_update(dev); spin_unlock_irqrestore(&list_lock, flags); } +static void omap_irq_fifo_underflow(struct omap_drm_private *priv, + u32 irqstatus) +{ + static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + static const struct { + const char *name; + u32 mask; + } sources[] = { + { "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW }, + { "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW }, + { "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW }, + { "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW }, + }; + + const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW + | DISPC_IRQ_VID1_FIFO_UNDERFLOW + | DISPC_IRQ_VID2_FIFO_UNDERFLOW + | DISPC_IRQ_VID3_FIFO_UNDERFLOW; + unsigned int i; + + spin_lock(&list_lock); + irqstatus &= priv->irq_mask & mask; + spin_unlock(&list_lock); + + if (!irqstatus) + return; + + if (!__ratelimit(&_rs)) + return; + + DRM_ERROR("FIFO underflow on "); + + for (i = 0; i < ARRAY_SIZE(sources); ++i) { + if (sources[i].mask & irqstatus) + pr_cont("%s ", sources[i].name); + } + + pr_cont("(0x%08x)\n", irqstatus); +} + static irqreturn_t omap_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -205,6 +246,8 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) drm_handle_vblank(dev, id); } + omap_irq_fifo_underflow(priv, irqstatus); + spin_lock_irqsave(&list_lock, flags); list_for_each_entry_safe(handler, n, &priv->irq_list, node) { if (handler->irqmask & irqstatus) { @@ -218,6 +261,13 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) return IRQ_HANDLED; } +static const u32 omap_underflow_irqs[] = { + [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, + [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, + [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, + [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, +}; + /* * We need a special version, instead of just using drm_irq_install(), * because we need to register the irq via omapdss. Once omapdss and @@ -229,10 +279,21 @@ int omap_drm_irq_install(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_drm_irq *error_handler = &priv->error_handler; + unsigned int max_planes; + unsigned int i; int ret; INIT_LIST_HEAD(&priv->irq_list); + priv->irq_mask = 0; + + max_planes = min(ARRAY_SIZE(priv->planes), + ARRAY_SIZE(omap_underflow_irqs)); + for (i = 0; i < max_planes; ++i) { + if (priv->planes[i]) + priv->irq_mask |= omap_underflow_irqs[i]; + } + dispc_runtime_get(); dispc_clear_irqstatus(0xffffffff); dispc_runtime_put(); |