diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-10-10 02:22:09 -0400 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-04-14 03:17:25 -0400 |
commit | 9b190610dcb9ed541539bc59d8877e941cf3a809 (patch) | |
tree | 480b72aec9771c36a302cb0087a1cf08c0a34b4a /drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |
parent | 1a7b37ca349bbdeb2f208a6a71a9925a716141f4 (diff) |
drm: atmel-hlcdc: support asynchronous atomic commit operations
drm_atomic_helper_commit() does not support asynchronous commits.
Replace it by a specific commit function supporting these kind of requests.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c')
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8ab4318e57a1..67b139174e7b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
@@ -427,11 +427,102 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) | |||
427 | } | 427 | } |
428 | } | 428 | } |
429 | 429 | ||
430 | struct atmel_hlcdc_dc_commit { | ||
431 | struct work_struct work; | ||
432 | struct drm_device *dev; | ||
433 | struct drm_atomic_state *state; | ||
434 | }; | ||
435 | |||
436 | static void | ||
437 | atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit) | ||
438 | { | ||
439 | struct drm_device *dev = commit->dev; | ||
440 | struct atmel_hlcdc_dc *dc = dev->dev_private; | ||
441 | struct drm_atomic_state *old_state = commit->state; | ||
442 | |||
443 | /* Apply the atomic update. */ | ||
444 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | ||
445 | drm_atomic_helper_commit_planes(dev, old_state, false); | ||
446 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | ||
447 | |||
448 | drm_atomic_helper_wait_for_vblanks(dev, old_state); | ||
449 | |||
450 | drm_atomic_helper_cleanup_planes(dev, old_state); | ||
451 | |||
452 | drm_atomic_state_free(old_state); | ||
453 | |||
454 | /* Complete the commit, wake up any waiter. */ | ||
455 | spin_lock(&dc->commit.wait.lock); | ||
456 | dc->commit.pending = false; | ||
457 | wake_up_all_locked(&dc->commit.wait); | ||
458 | spin_unlock(&dc->commit.wait.lock); | ||
459 | |||
460 | kfree(commit); | ||
461 | } | ||
462 | |||
463 | static void atmel_hlcdc_dc_atomic_work(struct work_struct *work) | ||
464 | { | ||
465 | struct atmel_hlcdc_dc_commit *commit = | ||
466 | container_of(work, struct atmel_hlcdc_dc_commit, work); | ||
467 | |||
468 | atmel_hlcdc_dc_atomic_complete(commit); | ||
469 | } | ||
470 | |||
471 | static int atmel_hlcdc_dc_atomic_commit(struct drm_device *dev, | ||
472 | struct drm_atomic_state *state, | ||
473 | bool async) | ||
474 | { | ||
475 | struct atmel_hlcdc_dc *dc = dev->dev_private; | ||
476 | struct atmel_hlcdc_dc_commit *commit; | ||
477 | int ret; | ||
478 | |||
479 | ret = drm_atomic_helper_prepare_planes(dev, state); | ||
480 | if (ret) | ||
481 | return ret; | ||
482 | |||
483 | /* Allocate the commit object. */ | ||
484 | commit = kzalloc(sizeof(*commit), GFP_KERNEL); | ||
485 | if (!commit) { | ||
486 | ret = -ENOMEM; | ||
487 | goto error; | ||
488 | } | ||
489 | |||
490 | INIT_WORK(&commit->work, atmel_hlcdc_dc_atomic_work); | ||
491 | commit->dev = dev; | ||
492 | commit->state = state; | ||
493 | |||
494 | spin_lock(&dc->commit.wait.lock); | ||
495 | ret = wait_event_interruptible_locked(dc->commit.wait, | ||
496 | !dc->commit.pending); | ||
497 | if (ret == 0) | ||
498 | dc->commit.pending = true; | ||
499 | spin_unlock(&dc->commit.wait.lock); | ||
500 | |||
501 | if (ret) { | ||
502 | kfree(commit); | ||
503 | goto error; | ||
504 | } | ||
505 | |||
506 | /* Swap the state, this is the point of no return. */ | ||
507 | drm_atomic_helper_swap_state(dev, state); | ||
508 | |||
509 | if (async) | ||
510 | queue_work(dc->wq, &commit->work); | ||
511 | else | ||
512 | atmel_hlcdc_dc_atomic_complete(commit); | ||
513 | |||
514 | return 0; | ||
515 | |||
516 | error: | ||
517 | drm_atomic_helper_cleanup_planes(dev, state); | ||
518 | return ret; | ||
519 | } | ||
520 | |||
430 | static const struct drm_mode_config_funcs mode_config_funcs = { | 521 | static const struct drm_mode_config_funcs mode_config_funcs = { |
431 | .fb_create = atmel_hlcdc_fb_create, | 522 | .fb_create = atmel_hlcdc_fb_create, |
432 | .output_poll_changed = atmel_hlcdc_fb_output_poll_changed, | 523 | .output_poll_changed = atmel_hlcdc_fb_output_poll_changed, |
433 | .atomic_check = drm_atomic_helper_check, | 524 | .atomic_check = drm_atomic_helper_check, |
434 | .atomic_commit = drm_atomic_helper_commit, | 525 | .atomic_commit = atmel_hlcdc_dc_atomic_commit, |
435 | }; | 526 | }; |
436 | 527 | ||
437 | static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) | 528 | static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) |
@@ -509,6 +600,7 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) | |||
509 | if (!dc->wq) | 600 | if (!dc->wq) |
510 | return -ENOMEM; | 601 | return -ENOMEM; |
511 | 602 | ||
603 | init_waitqueue_head(&dc->commit.wait); | ||
512 | dc->desc = match->data; | 604 | dc->desc = match->data; |
513 | dc->hlcdc = dev_get_drvdata(dev->dev->parent); | 605 | dc->hlcdc = dev_get_drvdata(dev->dev->parent); |
514 | dev->dev_private = dc; | 606 | dev->dev_private = dc; |