drm/rockchip: convert to helper nonblocking atomic commit
With the various bits fixed rockchip now has an atomic compliant handling/signalling of crtc_state->event, which means we can just switch over to the new nonblocking helpers and remove some code. v2: Fixes from Tomeu. v3: Send out vblank events correctly when shutting down a crtc for good. This is part of the atomic interface contract. v4: Properly protect vop->event. v5: Add more WARN_ON to check vop->event isn't clobbered. Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com> Cc: Mark yao <mark.yao@rock-chips.com> Tested-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
This commit is contained in:
@ -157,9 +157,6 @@ static int rockchip_drm_bind(struct device *dev)
|
|||||||
goto err_unregister;
|
goto err_unregister;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&private->commit.lock);
|
|
||||||
INIT_WORK(&private->commit.work, rockchip_drm_atomic_work);
|
|
||||||
|
|
||||||
drm_dev->dev_private = private;
|
drm_dev->dev_private = private;
|
||||||
|
|
||||||
drm_mode_config_init(drm_dev);
|
drm_mode_config_init(drm_dev);
|
||||||
|
@ -43,13 +43,6 @@ struct rockchip_crtc_funcs {
|
|||||||
void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv);
|
void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rockchip_atomic_commit {
|
|
||||||
struct work_struct work;
|
|
||||||
struct drm_atomic_state *state;
|
|
||||||
struct drm_device *dev;
|
|
||||||
struct mutex lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rockchip_crtc_state {
|
struct rockchip_crtc_state {
|
||||||
struct drm_crtc_state base;
|
struct drm_crtc_state base;
|
||||||
int output_type;
|
int output_type;
|
||||||
@ -68,11 +61,8 @@ struct rockchip_drm_private {
|
|||||||
struct drm_fb_helper fbdev_helper;
|
struct drm_fb_helper fbdev_helper;
|
||||||
struct drm_gem_object *fbdev_bo;
|
struct drm_gem_object *fbdev_bo;
|
||||||
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
|
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
|
||||||
|
|
||||||
struct rockchip_atomic_commit commit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void rockchip_drm_atomic_work(struct work_struct *work);
|
|
||||||
int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
|
int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
|
||||||
const struct rockchip_crtc_funcs *crtc_funcs);
|
const struct rockchip_crtc_funcs *crtc_funcs);
|
||||||
void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
|
void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
|
||||||
|
@ -228,87 +228,32 @@ rockchip_atomic_wait_for_complete(struct drm_device *dev, struct drm_atomic_stat
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
|
rockchip_atomic_commit_tail(struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
struct drm_atomic_state *state = commit->state;
|
struct drm_device *dev = state->dev;
|
||||||
struct drm_device *dev = commit->dev;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: do fence wait here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Rockchip crtc support runtime PM, can't update display planes
|
|
||||||
* when crtc is disabled.
|
|
||||||
*
|
|
||||||
* drm_atomic_helper_commit comments detail that:
|
|
||||||
* For drivers supporting runtime PM the recommended sequence is
|
|
||||||
*
|
|
||||||
* drm_atomic_helper_commit_modeset_disables(dev, state);
|
|
||||||
*
|
|
||||||
* drm_atomic_helper_commit_modeset_enables(dev, state);
|
|
||||||
*
|
|
||||||
* drm_atomic_helper_commit_planes(dev, state, true);
|
|
||||||
*
|
|
||||||
* See the kerneldoc entries for these three functions for more details.
|
|
||||||
*/
|
|
||||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||||
|
|
||||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||||
|
|
||||||
drm_atomic_helper_commit_planes(dev, state, true);
|
drm_atomic_helper_commit_planes(dev, state, true);
|
||||||
|
|
||||||
|
drm_atomic_helper_commit_hw_done(state);
|
||||||
|
|
||||||
rockchip_atomic_wait_for_complete(dev, state);
|
rockchip_atomic_wait_for_complete(dev, state);
|
||||||
|
|
||||||
drm_atomic_helper_cleanup_planes(dev, state);
|
drm_atomic_helper_cleanup_planes(dev, state);
|
||||||
|
|
||||||
drm_atomic_state_free(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rockchip_drm_atomic_work(struct work_struct *work)
|
struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
|
||||||
{
|
.atomic_commit_tail = rockchip_atomic_commit_tail,
|
||||||
struct rockchip_atomic_commit *commit = container_of(work,
|
};
|
||||||
struct rockchip_atomic_commit, work);
|
|
||||||
|
|
||||||
rockchip_atomic_commit_complete(commit);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rockchip_drm_atomic_commit(struct drm_device *dev,
|
|
||||||
struct drm_atomic_state *state,
|
|
||||||
bool nonblock)
|
|
||||||
{
|
|
||||||
struct rockchip_drm_private *private = dev->dev_private;
|
|
||||||
struct rockchip_atomic_commit *commit = &private->commit;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* serialize outstanding nonblocking commits */
|
|
||||||
mutex_lock(&commit->lock);
|
|
||||||
flush_work(&commit->work);
|
|
||||||
|
|
||||||
drm_atomic_helper_swap_state(state, true);
|
|
||||||
|
|
||||||
commit->dev = dev;
|
|
||||||
commit->state = state;
|
|
||||||
|
|
||||||
if (nonblock)
|
|
||||||
schedule_work(&commit->work);
|
|
||||||
else
|
|
||||||
rockchip_atomic_commit_complete(commit);
|
|
||||||
|
|
||||||
mutex_unlock(&commit->lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
|
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
|
||||||
.fb_create = rockchip_user_fb_create,
|
.fb_create = rockchip_user_fb_create,
|
||||||
.output_poll_changed = rockchip_drm_output_poll_changed,
|
.output_poll_changed = rockchip_drm_output_poll_changed,
|
||||||
.atomic_check = drm_atomic_helper_check,
|
.atomic_check = drm_atomic_helper_check,
|
||||||
.atomic_commit = rockchip_drm_atomic_commit,
|
.atomic_commit = drm_atomic_helper_commit,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drm_framebuffer *
|
struct drm_framebuffer *
|
||||||
@ -339,4 +284,5 @@ void rockchip_drm_mode_config_init(struct drm_device *dev)
|
|||||||
dev->mode_config.max_height = 4096;
|
dev->mode_config.max_height = 4096;
|
||||||
|
|
||||||
dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
|
dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
|
||||||
|
dev->mode_config.helper_private = &rockchip_mode_config_helpers;
|
||||||
}
|
}
|
||||||
|
@ -502,6 +502,8 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
|
|||||||
struct vop *vop = to_vop(crtc);
|
struct vop *vop = to_vop(crtc);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
WARN_ON(vop->event);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to make sure that all windows are disabled before we
|
* We need to make sure that all windows are disabled before we
|
||||||
* disable that crtc. Otherwise we might try to scan from a destroyed
|
* disable that crtc. Otherwise we might try to scan from a destroyed
|
||||||
@ -551,6 +553,14 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
|
|||||||
clk_disable(vop->aclk);
|
clk_disable(vop->aclk);
|
||||||
clk_disable(vop->hclk);
|
clk_disable(vop->hclk);
|
||||||
pm_runtime_put(vop->dev);
|
pm_runtime_put(vop->dev);
|
||||||
|
|
||||||
|
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)
|
static void vop_plane_destroy(struct drm_plane *plane)
|
||||||
@ -939,6 +949,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
|
|||||||
u16 vact_end = vact_st + vdisplay;
|
u16 vact_end = vact_st + vdisplay;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
|
WARN_ON(vop->event);
|
||||||
|
|
||||||
vop_enable(crtc);
|
vop_enable(crtc);
|
||||||
/*
|
/*
|
||||||
* If dclk rate is zero, mean that scanout is stop,
|
* If dclk rate is zero, mean that scanout is stop,
|
||||||
@ -1035,12 +1047,15 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
|
|||||||
{
|
{
|
||||||
struct vop *vop = to_vop(crtc);
|
struct vop *vop = to_vop(crtc);
|
||||||
|
|
||||||
|
spin_lock_irq(&crtc->dev->event_lock);
|
||||||
if (crtc->state->event) {
|
if (crtc->state->event) {
|
||||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||||
|
WARN_ON(vop->event);
|
||||||
|
|
||||||
vop->event = crtc->state->event;
|
vop->event = crtc->state->event;
|
||||||
crtc->state->event = NULL;
|
crtc->state->event = NULL;
|
||||||
}
|
}
|
||||||
|
spin_unlock_irq(&crtc->dev->event_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
|
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
|
||||||
@ -1110,15 +1125,16 @@ static void vop_handle_vblank(struct vop *vop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&drm->event_lock, flags);
|
||||||
if (vop->event) {
|
if (vop->event) {
|
||||||
spin_lock_irqsave(&drm->event_lock, flags);
|
|
||||||
|
|
||||||
drm_crtc_send_vblank_event(crtc, vop->event);
|
drm_crtc_send_vblank_event(crtc, vop->event);
|
||||||
drm_crtc_vblank_put(crtc);
|
drm_crtc_vblank_put(crtc);
|
||||||
vop->event = NULL;
|
vop->event = NULL;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&drm->event_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&drm->event_lock, flags);
|
||||||
|
|
||||||
if (!completion_done(&vop->wait_update_complete))
|
if (!completion_done(&vop->wait_update_complete))
|
||||||
complete(&vop->wait_update_complete);
|
complete(&vop->wait_update_complete);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user