mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
drm/rockchip: make multi-display independent on synchronous commit
Previous atomic commit force wait for old commit finish, it
would make performance bad, if we have two outputs committing
at the same time, the two commit will block each other, make
things bad.
with this patch, difference output commits can be independent,
they can commit at the same time.
TEST: before this patch: HDMI + MIPI: 40-55fps
after this patch: HDMI + MIPI: 60fps
Change-Id: Ie6c80f908080a40986d0193af5aff52f1bead455
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user