aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-10-10 02:22:09 -0400
committerBoris Brezillon <boris.brezillon@free-electrons.com>2016-04-14 03:17:25 -0400
commit9b190610dcb9ed541539bc59d8877e941cf3a809 (patch)
tree480b72aec9771c36a302cb0087a1cf08c0a34b4a /drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
parent1a7b37ca349bbdeb2f208a6a71a9925a716141f4 (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.c94
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
430struct atmel_hlcdc_dc_commit {
431 struct work_struct work;
432 struct drm_device *dev;
433 struct drm_atomic_state *state;
434};
435
436static void
437atmel_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
463static 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
471static 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
516error:
517 drm_atomic_helper_cleanup_planes(dev, state);
518 return ret;
519}
520
430static const struct drm_mode_config_funcs mode_config_funcs = { 521static 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
437static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) 528static 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;