summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c67
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c24
4 files changed, 67 insertions, 30 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index fdc83cbcde61..6faba13c8e41 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -315,8 +315,6 @@ static int omap_modeset_init(struct drm_device *dev)
drm_mode_config_init(dev);
- omap_drm_irq_install(dev);
-
ret = omap_modeset_init_properties(dev);
if (ret < 0)
return ret;
@@ -489,6 +487,8 @@ static int omap_modeset_init(struct drm_device *dev)
drm_mode_config_reset(dev);
+ omap_drm_irq_install(dev);
+
return 0;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 919c14d3503c..a3594fa10ef3 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -102,7 +102,7 @@ struct omap_drm_private {
/* irq handling: */
struct list_head irq_list; /* list of omap_drm_irq */
- uint32_t vblank_mask; /* irq bits set for userspace vblank */
+ uint32_t irq_mask; /* enabled irqs in addition to irq_list */
struct omap_drm_irq error_handler;
/* atomic commit */
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();
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 82b2c23d6769..386d90af70f7 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -43,8 +43,6 @@ struct omap_plane {
uint32_t nformats;
uint32_t formats[32];
-
- struct omap_drm_irq error_irq;
};
struct omap_plane_state {
@@ -204,8 +202,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
DBG("%s", omap_plane->name);
- omap_irq_unregister(plane->dev, &omap_plane->error_irq);
-
drm_plane_cleanup(plane);
kfree(omap_plane);
@@ -332,14 +328,6 @@ static const struct drm_plane_funcs omap_plane_funcs = {
.atomic_get_property = omap_plane_atomic_get_property,
};
-static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
- struct omap_plane *omap_plane =
- container_of(irq, struct omap_plane, error_irq);
- DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
- irqstatus);
-}
-
static const char *plane_names[] = {
[OMAP_DSS_GFX] = "gfx",
[OMAP_DSS_VIDEO1] = "vid1",
@@ -347,13 +335,6 @@ static const char *plane_names[] = {
[OMAP_DSS_VIDEO3] = "vid3",
};
-static const uint32_t error_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,
-};
-
/* initialize plane */
struct drm_plane *omap_plane_init(struct drm_device *dev,
int id, enum drm_plane_type type,
@@ -377,10 +358,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
plane = &omap_plane->base;
- omap_plane->error_irq.irqmask = error_irqs[id];
- omap_plane->error_irq.irq = omap_plane_error_irq;
- omap_irq_register(dev, &omap_plane->error_irq);
-
ret = drm_universal_plane_init(dev, plane, possible_crtcs,
&omap_plane_funcs, omap_plane->formats,
omap_plane->nformats, type, NULL);
@@ -394,7 +371,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
return plane;
error:
- omap_irq_unregister(plane->dev, &omap_plane->error_irq);
kfree(omap_plane);
return NULL;
}
OpenPOWER on IntegriCloud