diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 8d2901a0b982..8459eccc3033 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1235,8 +1235,8 @@ static int rockchip_drm_bind(struct device *dev) goto err_free; } - mutex_init(&private->commit.lock); - INIT_WORK(&private->commit.work, rockchip_drm_atomic_work); + mutex_init(&private->commit_lock); + INIT_WORK(&private->commit_work, rockchip_drm_atomic_work); drm_dev->dev_private = private; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index d7171a764531..7f01c908b441 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -66,10 +66,8 @@ struct drm_rockchip_subdrv { }; struct rockchip_atomic_commit { - struct work_struct work; struct drm_atomic_state *state; struct drm_device *dev; - struct mutex lock; size_t bandwidth; }; @@ -150,7 +148,10 @@ struct rockchip_drm_private { const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; - struct rockchip_atomic_commit commit; + struct rockchip_atomic_commit *commit; + /* protect async commit */ + struct mutex commit_lock; + struct work_struct commit_work; struct iommu_domain *domain; struct gen_pool *secure_buffer_pool; #ifdef CONFIG_DRM_DMA_SYNC diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20e30443ae87..6efb861410ad 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -264,6 +264,8 @@ rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit) * * See the kerneldoc entries for these three functions for more details. */ + drm_atomic_helper_wait_for_dependencies(state); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_modeset_enables(dev, state); @@ -274,19 +276,26 @@ rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit) drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); + drm_atomic_helper_commit_cleanup_done(state); + drm_atomic_state_free(state); + + kfree(commit); } void rockchip_drm_atomic_work(struct work_struct *work) { - struct rockchip_atomic_commit *commit = container_of(work, - struct rockchip_atomic_commit, work); + struct rockchip_drm_private *private = container_of(work, + struct rockchip_drm_private, commit_work); - rockchip_atomic_commit_complete(commit); + rockchip_atomic_commit_complete(private->commit); + private->commit = NULL; } int rockchip_drm_atomic_commit(struct drm_device *dev, @@ -294,10 +303,14 @@ int rockchip_drm_atomic_commit(struct drm_device *dev, bool async) { struct rockchip_drm_private *private = dev->dev_private; - struct rockchip_atomic_commit *commit = &private->commit; + struct rockchip_atomic_commit *commit; size_t bandwidth; int ret; + ret = drm_atomic_helper_setup_commit(state, false); + if (ret) + return ret; + ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; @@ -311,22 +324,28 @@ int rockchip_drm_atomic_commit(struct drm_device *dev, DRM_ERROR("vop bandwidth too large %zd\n", bandwidth); } - /* serialize outstanding asynchronous commits */ - mutex_lock(&commit->lock); - flush_work(&commit->work); - drm_atomic_helper_swap_state(dev, state); + commit = kmalloc(sizeof(*commit), GFP_KERNEL); + if (!commit) + return -ENOMEM; + commit->dev = dev; commit->state = state; commit->bandwidth = bandwidth; - if (async) - schedule_work(&commit->work); - else - rockchip_atomic_commit_complete(commit); + if (async) { + mutex_lock(&private->commit_lock); - mutex_unlock(&commit->lock); + flush_work(&private->commit_work); + WARN_ON(private->commit); + private->commit = commit; + schedule_work(&private->commit_work); + + mutex_unlock(&private->commit_lock); + } else { + rockchip_atomic_commit_complete(commit); + } return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9371bea21ba1..17abc34b77f3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1038,6 +1038,14 @@ static void vop_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&vop->vop_lock); rockchip_clear_system_status(sys_status); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + + crtc->state->event = NULL; + } } static void vop_plane_destroy(struct drm_plane *plane) @@ -2859,15 +2867,13 @@ static void vop_handle_vblank(struct vop *vop) struct drm_crtc *crtc = &vop->crtc; unsigned long flags; + spin_lock_irqsave(&drm->event_lock, flags); if (vop->event) { - spin_lock_irqsave(&drm->event_lock, flags); - drm_crtc_send_vblank_event(crtc, vop->event); drm_crtc_vblank_put(crtc); vop->event = NULL; - - spin_unlock_irqrestore(&drm->event_lock, flags); } + spin_unlock_irqrestore(&drm->event_lock, flags); if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);