diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2015-05-29 09:01:18 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2015-06-12 16:30:47 -0400 |
commit | 5f741b39dde47c054af78727cce7202fff9f781b (patch) | |
tree | e0ba2b0b2f0b4a301b7c23c1439ee80fc0e33237 /drivers | |
parent | 6646dfd02985eb67d8dcc00d0d345c8dc40f9925 (diff) |
drm: omapdrm: new vblank and event handling
Rework the crtc event/flip_wait system as follows:
- If we enable a crtc (full modeset), we set omap_crtc->pending and
register vblank irq.
- If we need to set GO bit (page flip), we do the same but also set the
GO bit.
- On vblank we unregister the irq, clear the 'pending' flag, send vblank
event to userspace if crtc->state->event != NULL, and wake up
'pending_wait' wq.
- In omap_atomic_complete() we wait for the 'pending' flag to get reset
for all enabled crtcs using 'pending_wait' wq.
The above ensures that we send the events to userspace in vblank, and
that after the wait in omap_atomic_complete() everything for the
affected crtcs has been completed.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 123 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.h | 1 |
3 files changed, 70 insertions, 76 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 8d2bf8565ddd..23d9c928cdc9 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c | |||
@@ -17,8 +17,6 @@ | |||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/completion.h> | ||
21 | |||
22 | #include <drm/drm_atomic.h> | 20 | #include <drm/drm_atomic.h> |
23 | #include <drm/drm_atomic_helper.h> | 21 | #include <drm/drm_atomic_helper.h> |
24 | #include <drm/drm_crtc.h> | 22 | #include <drm/drm_crtc.h> |
@@ -49,13 +47,10 @@ struct omap_crtc { | |||
49 | struct omap_drm_irq vblank_irq; | 47 | struct omap_drm_irq vblank_irq; |
50 | struct omap_drm_irq error_irq; | 48 | struct omap_drm_irq error_irq; |
51 | 49 | ||
52 | /* pending event */ | ||
53 | struct drm_pending_vblank_event *event; | ||
54 | wait_queue_head_t flip_wait; | ||
55 | |||
56 | struct completion completion; | ||
57 | |||
58 | bool ignore_digit_sync_lost; | 50 | bool ignore_digit_sync_lost; |
51 | |||
52 | bool pending; | ||
53 | wait_queue_head_t pending_wait; | ||
59 | }; | 54 | }; |
60 | 55 | ||
61 | /* ----------------------------------------------------------------------------- | 56 | /* ----------------------------------------------------------------------------- |
@@ -81,6 +76,15 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) | |||
81 | return omap_crtc->channel; | 76 | return omap_crtc->channel; |
82 | } | 77 | } |
83 | 78 | ||
79 | int omap_crtc_wait_pending(struct drm_crtc *crtc) | ||
80 | { | ||
81 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
82 | |||
83 | return wait_event_timeout(omap_crtc->pending_wait, | ||
84 | !omap_crtc->pending, | ||
85 | msecs_to_jiffies(50)); | ||
86 | } | ||
87 | |||
84 | /* ----------------------------------------------------------------------------- | 88 | /* ----------------------------------------------------------------------------- |
85 | * DSS Manager Functions | 89 | * DSS Manager Functions |
86 | */ | 90 | */ |
@@ -255,61 +259,29 @@ static const struct dss_mgr_ops mgr_ops = { | |||
255 | 259 | ||
256 | static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) | 260 | static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) |
257 | { | 261 | { |
258 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
259 | struct drm_pending_vblank_event *event; | 262 | struct drm_pending_vblank_event *event; |
260 | struct drm_device *dev = crtc->dev; | 263 | struct drm_device *dev = crtc->dev; |
261 | unsigned long flags; | 264 | unsigned long flags; |
262 | 265 | ||
263 | spin_lock_irqsave(&dev->event_lock, flags); | 266 | event = crtc->state->event; |
264 | |||
265 | event = omap_crtc->event; | ||
266 | omap_crtc->event = NULL; | ||
267 | 267 | ||
268 | if (event) { | 268 | if (!event) |
269 | list_del(&event->base.link); | 269 | return; |
270 | |||
271 | /* | ||
272 | * Queue the event for delivery if it's still linked to a file | ||
273 | * handle, otherwise just destroy it. | ||
274 | */ | ||
275 | if (event->base.file_priv) | ||
276 | drm_crtc_send_vblank_event(crtc, event); | ||
277 | else | ||
278 | event->base.destroy(&event->base); | ||
279 | |||
280 | wake_up(&omap_crtc->flip_wait); | ||
281 | drm_crtc_vblank_put(crtc); | ||
282 | } | ||
283 | |||
284 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
285 | } | ||
286 | |||
287 | static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc) | ||
288 | { | ||
289 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
290 | struct drm_device *dev = crtc->dev; | ||
291 | unsigned long flags; | ||
292 | bool pending; | ||
293 | 270 | ||
294 | spin_lock_irqsave(&dev->event_lock, flags); | 271 | spin_lock_irqsave(&dev->event_lock, flags); |
295 | pending = omap_crtc->event != NULL; | ||
296 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
297 | 272 | ||
298 | return pending; | 273 | list_del(&event->base.link); |
299 | } | ||
300 | 274 | ||
301 | static void omap_crtc_wait_page_flip(struct drm_crtc *crtc) | 275 | /* |
302 | { | 276 | * Queue the event for delivery if it's still linked to a file |
303 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 277 | * handle, otherwise just destroy it. |
304 | 278 | */ | |
305 | if (wait_event_timeout(omap_crtc->flip_wait, | 279 | if (event->base.file_priv) |
306 | !omap_crtc_page_flip_pending(crtc), | 280 | drm_crtc_send_vblank_event(crtc, event); |
307 | msecs_to_jiffies(50))) | 281 | else |
308 | return; | 282 | event->base.destroy(&event->base); |
309 | |||
310 | dev_warn(crtc->dev->dev, "page flip timeout!\n"); | ||
311 | 283 | ||
312 | omap_crtc_complete_page_flip(crtc); | 284 | spin_unlock_irqrestore(&dev->event_lock, flags); |
313 | } | 285 | } |
314 | 286 | ||
315 | static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | 287 | static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) |
@@ -336,12 +308,19 @@ static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | |||
336 | return; | 308 | return; |
337 | 309 | ||
338 | DBG("%s: apply done", omap_crtc->name); | 310 | DBG("%s: apply done", omap_crtc->name); |
311 | |||
339 | __omap_irq_unregister(dev, &omap_crtc->vblank_irq); | 312 | __omap_irq_unregister(dev, &omap_crtc->vblank_irq); |
340 | 313 | ||
341 | /* wakeup userspace */ | 314 | rmb(); |
315 | WARN_ON(!omap_crtc->pending); | ||
316 | omap_crtc->pending = false; | ||
317 | wmb(); | ||
318 | |||
319 | /* wake up userspace */ | ||
342 | omap_crtc_complete_page_flip(&omap_crtc->base); | 320 | omap_crtc_complete_page_flip(&omap_crtc->base); |
343 | 321 | ||
344 | complete(&omap_crtc->completion); | 322 | /* wake up omap_atomic_complete */ |
323 | wake_up(&omap_crtc->pending_wait); | ||
345 | } | 324 | } |
346 | 325 | ||
347 | /* ----------------------------------------------------------------------------- | 326 | /* ----------------------------------------------------------------------------- |
@@ -375,6 +354,13 @@ static void omap_crtc_enable(struct drm_crtc *crtc) | |||
375 | 354 | ||
376 | DBG("%s", omap_crtc->name); | 355 | DBG("%s", omap_crtc->name); |
377 | 356 | ||
357 | rmb(); | ||
358 | WARN_ON(omap_crtc->pending); | ||
359 | omap_crtc->pending = true; | ||
360 | wmb(); | ||
361 | |||
362 | omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); | ||
363 | |||
378 | drm_crtc_vblank_on(crtc); | 364 | drm_crtc_vblank_on(crtc); |
379 | } | 365 | } |
380 | 366 | ||
@@ -384,7 +370,6 @@ static void omap_crtc_disable(struct drm_crtc *crtc) | |||
384 | 370 | ||
385 | DBG("%s", omap_crtc->name); | 371 | DBG("%s", omap_crtc->name); |
386 | 372 | ||
387 | omap_crtc_wait_page_flip(crtc); | ||
388 | drm_crtc_vblank_off(crtc); | 373 | drm_crtc_vblank_off(crtc); |
389 | } | 374 | } |
390 | 375 | ||
@@ -405,19 +390,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
405 | 390 | ||
406 | static void omap_crtc_atomic_begin(struct drm_crtc *crtc) | 391 | static void omap_crtc_atomic_begin(struct drm_crtc *crtc) |
407 | { | 392 | { |
408 | struct drm_pending_vblank_event *event = crtc->state->event; | ||
409 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
410 | struct drm_device *dev = crtc->dev; | ||
411 | unsigned long flags; | ||
412 | |||
413 | if (event) { | ||
414 | WARN_ON(omap_crtc->event); | ||
415 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | ||
416 | |||
417 | spin_lock_irqsave(&dev->event_lock, flags); | ||
418 | omap_crtc->event = event; | ||
419 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
420 | } | ||
421 | } | 393 | } |
422 | 394 | ||
423 | static void omap_crtc_atomic_flush(struct drm_crtc *crtc) | 395 | static void omap_crtc_atomic_flush(struct drm_crtc *crtc) |
@@ -427,14 +399,16 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc) | |||
427 | WARN_ON(omap_crtc->vblank_irq.registered); | 399 | WARN_ON(omap_crtc->vblank_irq.registered); |
428 | 400 | ||
429 | if (dispc_mgr_is_enabled(omap_crtc->channel)) { | 401 | if (dispc_mgr_is_enabled(omap_crtc->channel)) { |
402 | |||
430 | DBG("%s: GO", omap_crtc->name); | 403 | DBG("%s: GO", omap_crtc->name); |
431 | 404 | ||
405 | rmb(); | ||
406 | WARN_ON(omap_crtc->pending); | ||
407 | omap_crtc->pending = true; | ||
408 | wmb(); | ||
409 | |||
432 | dispc_mgr_go(omap_crtc->channel); | 410 | dispc_mgr_go(omap_crtc->channel); |
433 | omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); | 411 | omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); |
434 | |||
435 | WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion, | ||
436 | msecs_to_jiffies(100))); | ||
437 | reinit_completion(&omap_crtc->completion); | ||
438 | } | 412 | } |
439 | 413 | ||
440 | crtc->invert_dimensions = !!(crtc->primary->state->rotation & | 414 | crtc->invert_dimensions = !!(crtc->primary->state->rotation & |
@@ -534,8 +508,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
534 | 508 | ||
535 | crtc = &omap_crtc->base; | 509 | crtc = &omap_crtc->base; |
536 | 510 | ||
537 | init_waitqueue_head(&omap_crtc->flip_wait); | 511 | init_waitqueue_head(&omap_crtc->pending_wait); |
538 | init_completion(&omap_crtc->completion); | ||
539 | 512 | ||
540 | omap_crtc->channel = channel; | 513 | omap_crtc->channel = channel; |
541 | omap_crtc->name = channel_names[channel]; | 514 | omap_crtc->name = channel_names[channel]; |
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 50f555530e55..419c2e49adf5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
@@ -66,6 +66,26 @@ struct omap_atomic_state_commit { | |||
66 | u32 crtcs; | 66 | u32 crtcs; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static void omap_atomic_wait_for_completion(struct drm_device *dev, | ||
70 | struct drm_atomic_state *old_state) | ||
71 | { | ||
72 | struct drm_crtc_state *old_crtc_state; | ||
73 | struct drm_crtc *crtc; | ||
74 | unsigned int i; | ||
75 | int ret; | ||
76 | |||
77 | for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { | ||
78 | if (!crtc->state->enable) | ||
79 | continue; | ||
80 | |||
81 | ret = omap_crtc_wait_pending(crtc); | ||
82 | |||
83 | if (!ret) | ||
84 | dev_warn(dev->dev, | ||
85 | "atomic complete timeout (pipe %u)!\n", i); | ||
86 | } | ||
87 | } | ||
88 | |||
69 | static void omap_atomic_complete(struct omap_atomic_state_commit *commit) | 89 | static void omap_atomic_complete(struct omap_atomic_state_commit *commit) |
70 | { | 90 | { |
71 | struct drm_device *dev = commit->dev; | 91 | struct drm_device *dev = commit->dev; |
@@ -79,7 +99,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) | |||
79 | drm_atomic_helper_commit_planes(dev, old_state); | 99 | drm_atomic_helper_commit_planes(dev, old_state); |
80 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 100 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
81 | 101 | ||
82 | drm_atomic_helper_wait_for_vblanks(dev, old_state); | 102 | omap_atomic_wait_for_completion(dev, old_state); |
83 | 103 | ||
84 | drm_atomic_helper_cleanup_planes(dev, old_state); | 104 | drm_atomic_helper_cleanup_planes(dev, old_state); |
85 | 105 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 0b7a055bf007..ae2df41f216f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h | |||
@@ -147,6 +147,7 @@ void omap_crtc_pre_init(void); | |||
147 | void omap_crtc_pre_uninit(void); | 147 | void omap_crtc_pre_uninit(void); |
148 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 148 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
149 | struct drm_plane *plane, enum omap_channel channel, int id); | 149 | struct drm_plane *plane, enum omap_channel channel, int id); |
150 | int omap_crtc_wait_pending(struct drm_crtc *crtc); | ||
150 | 151 | ||
151 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 152 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
152 | int id, enum drm_plane_type type); | 153 | int id, enum drm_plane_type type); |