diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 123 |
1 files changed, 48 insertions, 75 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]; |