diff options
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) | |||
32 | { | 32 | { |
33 | struct omap_drm_private *priv = dev->dev_private; | 33 | struct omap_drm_private *priv = dev->dev_private; |
34 | struct omap_drm_irq *irq; | 34 | struct omap_drm_irq *irq; |
35 | uint32_t irqmask = priv->vblank_mask; | 35 | uint32_t irqmask = priv->irq_mask; |
36 | 36 | ||
37 | assert_spin_locked(&list_lock); | 37 | assert_spin_locked(&list_lock); |
38 | 38 | ||
@@ -153,7 +153,7 @@ int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe) | |||
153 | DBG("dev=%p, crtc=%u", dev, pipe); | 153 | DBG("dev=%p, crtc=%u", dev, pipe); |
154 | 154 | ||
155 | spin_lock_irqsave(&list_lock, flags); | 155 | spin_lock_irqsave(&list_lock, flags); |
156 | priv->vblank_mask |= pipe2vbl(crtc); | 156 | priv->irq_mask |= pipe2vbl(crtc); |
157 | omap_irq_update(dev); | 157 | omap_irq_update(dev); |
158 | spin_unlock_irqrestore(&list_lock, flags); | 158 | spin_unlock_irqrestore(&list_lock, flags); |
159 | 159 | ||
@@ -178,11 +178,52 @@ void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe) | |||
178 | DBG("dev=%p, crtc=%u", dev, pipe); | 178 | DBG("dev=%p, crtc=%u", dev, pipe); |
179 | 179 | ||
180 | spin_lock_irqsave(&list_lock, flags); | 180 | spin_lock_irqsave(&list_lock, flags); |
181 | priv->vblank_mask &= ~pipe2vbl(crtc); | 181 | priv->irq_mask &= ~pipe2vbl(crtc); |
182 | omap_irq_update(dev); | 182 | omap_irq_update(dev); |
183 | spin_unlock_irqrestore(&list_lock, flags); | 183 | spin_unlock_irqrestore(&list_lock, flags); |
184 | } | 184 | } |
185 | 185 | ||
186 | static void omap_irq_fifo_underflow(struct omap_drm_private *priv, | ||
187 | u32 irqstatus) | ||
188 | { | ||
189 | static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, | ||
190 | DEFAULT_RATELIMIT_BURST); | ||
191 | static const struct { | ||
192 | const char *name; | ||
193 | u32 mask; | ||
194 | } sources[] = { | ||
195 | { "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW }, | ||
196 | { "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW }, | ||
197 | { "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW }, | ||
198 | { "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW }, | ||
199 | }; | ||
200 | |||
201 | const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW | ||
202 | | DISPC_IRQ_VID1_FIFO_UNDERFLOW | ||
203 | | DISPC_IRQ_VID2_FIFO_UNDERFLOW | ||
204 | | DISPC_IRQ_VID3_FIFO_UNDERFLOW; | ||
205 | unsigned int i; | ||
206 | |||
207 | spin_lock(&list_lock); | ||
208 | irqstatus &= priv->irq_mask & mask; | ||
209 | spin_unlock(&list_lock); | ||
210 | |||
211 | if (!irqstatus) | ||
212 | return; | ||
213 | |||
214 | if (!__ratelimit(&_rs)) | ||
215 | return; | ||
216 | |||
217 | DRM_ERROR("FIFO underflow on "); | ||
218 | |||
219 | for (i = 0; i < ARRAY_SIZE(sources); ++i) { | ||
220 | if (sources[i].mask & irqstatus) | ||
221 | pr_cont("%s ", sources[i].name); | ||
222 | } | ||
223 | |||
224 | pr_cont("(0x%08x)\n", irqstatus); | ||
225 | } | ||
226 | |||
186 | static irqreturn_t omap_irq_handler(int irq, void *arg) | 227 | static irqreturn_t omap_irq_handler(int irq, void *arg) |
187 | { | 228 | { |
188 | struct drm_device *dev = (struct drm_device *) arg; | 229 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -205,6 +246,8 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) | |||
205 | drm_handle_vblank(dev, id); | 246 | drm_handle_vblank(dev, id); |
206 | } | 247 | } |
207 | 248 | ||
249 | omap_irq_fifo_underflow(priv, irqstatus); | ||
250 | |||
208 | spin_lock_irqsave(&list_lock, flags); | 251 | spin_lock_irqsave(&list_lock, flags); |
209 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { | 252 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { |
210 | if (handler->irqmask & irqstatus) { | 253 | if (handler->irqmask & irqstatus) { |
@@ -218,6 +261,13 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) | |||
218 | return IRQ_HANDLED; | 261 | return IRQ_HANDLED; |
219 | } | 262 | } |
220 | 263 | ||
264 | static const u32 omap_underflow_irqs[] = { | ||
265 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
266 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
267 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
268 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
269 | }; | ||
270 | |||
221 | /* | 271 | /* |
222 | * We need a special version, instead of just using drm_irq_install(), | 272 | * We need a special version, instead of just using drm_irq_install(), |
223 | * because we need to register the irq via omapdss. Once omapdss and | 273 | * 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) | |||
229 | { | 279 | { |
230 | struct omap_drm_private *priv = dev->dev_private; | 280 | struct omap_drm_private *priv = dev->dev_private; |
231 | struct omap_drm_irq *error_handler = &priv->error_handler; | 281 | struct omap_drm_irq *error_handler = &priv->error_handler; |
282 | unsigned int max_planes; | ||
283 | unsigned int i; | ||
232 | int ret; | 284 | int ret; |
233 | 285 | ||
234 | INIT_LIST_HEAD(&priv->irq_list); | 286 | INIT_LIST_HEAD(&priv->irq_list); |
235 | 287 | ||
288 | priv->irq_mask = 0; | ||
289 | |||
290 | max_planes = min(ARRAY_SIZE(priv->planes), | ||
291 | ARRAY_SIZE(omap_underflow_irqs)); | ||
292 | for (i = 0; i < max_planes; ++i) { | ||
293 | if (priv->planes[i]) | ||
294 | priv->irq_mask |= omap_underflow_irqs[i]; | ||
295 | } | ||
296 | |||
236 | dispc_runtime_get(); | 297 | dispc_runtime_get(); |
237 | dispc_clear_irqstatus(0xffffffff); | 298 | dispc_clear_irqstatus(0xffffffff); |
238 | dispc_runtime_put(); | 299 | dispc_runtime_put(); |