diff --git a/drivers/gpu/drm/imx/dpu/dpu-kms.c b/drivers/gpu/drm/imx/dpu/dpu-kms.c index 9371904fdf174783f8b3504ff9578b3796a8cea3..289dc82069c833089fb2a283e552641961248181 100644 --- a/drivers/gpu/drm/imx/dpu/dpu-kms.c +++ b/drivers/gpu/drm/imx/dpu/dpu-kms.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 NXP + * Copyright 2017-2019 NXP * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -772,9 +772,89 @@ static int dpu_drm_atomic_check(struct drm_device *dev, return ret; } +static void dpu_drm_commit_tail(struct drm_atomic_state *old_state) +{ + struct drm_device *dev = old_state->dev; + + drm_atomic_helper_wait_for_fences(dev, old_state, false); + + drm_atomic_helper_wait_for_dependencies(old_state); + + drm_atomic_helper_commit_tail(old_state); + + drm_atomic_helper_commit_cleanup_done(old_state); + + drm_atomic_state_put(old_state); +} + +static void dpu_drm_commit_work(struct work_struct *work) +{ + struct drm_atomic_state *state = container_of(work, + struct drm_atomic_state, + commit_work); + dpu_drm_commit_tail(state); +} + +/* + * This is almost a copy of drm_atomic_helper_commit(). + * For nonblock commits, we queue the work on a freezable and unbound work queue + * of our own instead of system_unbound_wq to make sure work items on the work + * queue are drained in the freeze phase of the system suspend operations. + */ +static int dpu_drm_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool nonblock) +{ + struct imx_drm_device *imxdrm = dev->dev_private; + int ret; + + if (state->async_update) { + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + drm_atomic_helper_async_commit(dev, state); + drm_atomic_helper_cleanup_planes(dev, state); + + return 0; + } + + ret = drm_atomic_helper_setup_commit(state, nonblock); + if (ret) + return ret; + + INIT_WORK(&state->commit_work, dpu_drm_commit_work); + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + if (!nonblock) { + ret = drm_atomic_helper_wait_for_fences(dev, state, true); + if (ret) + goto err; + } + + ret = drm_atomic_helper_swap_state(state, true); + if (ret) + goto err; + + drm_atomic_state_get(state); + if (nonblock) + queue_work(imxdrm->dpu_nonblock_commit_wq, &state->commit_work); + else + dpu_drm_commit_tail(state); + + return 0; + +err: + drm_atomic_helper_cleanup_planes(dev, state); + return ret; +} + const struct drm_mode_config_funcs dpu_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = dpu_drm_output_poll_changed, .atomic_check = dpu_drm_atomic_check, - .atomic_commit = drm_atomic_helper_commit, + .atomic_commit = dpu_drm_atomic_commit, };