diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-06-08 15:19:11 +0300 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-06-10 18:11:18 +0300 |
commit | 4f9d39a78e1d3100b990ec30da5a14a059e0a304 (patch) | |
tree | b4a6b4db5035812f64fe7978879dfe0e9b87ec48 /drivers/gpu/drm | |
parent | 05c960e79dbcd751bbcae148a01121dddf997465 (diff) | |
download | linux-4f9d39a78e1d3100b990ec30da5a14a059e0a304.tar.xz |
drm/rockchip: Fix crtc_state->event signalling
It's not permissible to look at plane->state from interrupt context,
since doing that would need the irq handler to acquire the
plane->mutex lock.
The other problem is that if we pipeline updates using the new
nonblocking atomic helpers new state gets commit before the irq
handler fires, resulting in a lost event.
Fix both issues by caching the necessary values in vop_win, protected
by dev->event_lock.
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>
Link: http://patchwork.freedesktop.org/patch/msgid/1465388359-8070-19-git-send-email-daniel.vetter@ffwll.ch
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 957a6b4917c8..94eaeec29b6b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -98,7 +98,9 @@ struct vop_win { const struct vop_win_data *data; struct vop *vop; - struct vop_plane_state state; + /* protected by dev->event_lock */ + bool enable; + dma_addr_t yrgb_mst; }; struct vop { @@ -112,6 +114,8 @@ struct vop { bool vsync_work_pending; struct completion dsp_hold_completion; struct completion wait_update_complete; + + /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; const struct vop_data *data; @@ -652,6 +656,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, if (!old_state->crtc) return; + spin_lock_irq(&plane->dev->event_lock); + vop_win->enable = false; + vop_win->yrgb_mst = 0; + spin_unlock_irq(&plane->dev->event_lock); + spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, enable, 0); @@ -686,7 +695,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, /* * can't update plane when vop is disabled. */ - if (!crtc) + if (WARN_ON(!crtc)) return; if (WARN_ON(!vop->is_enabled)) @@ -715,6 +724,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, offset += (src->y1 >> 16) * fb->pitches[0]; vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; + spin_lock_irq(&plane->dev->event_lock); + vop_win->enable = true; + vop_win->yrgb_mst = vop_plane_state->yrgb_mst; + spin_unlock_irq(&plane->dev->event_lock); + spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, format, vop_plane_state->format); @@ -1074,16 +1088,14 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { static bool vop_win_pending_is_complete(struct vop_win *vop_win) { - struct drm_plane *plane = &vop_win->base; - struct vop_plane_state *state = to_vop_plane_state(plane->state); dma_addr_t yrgb_mst; - if (!state->enable) + if (!vop_win->enable) return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0; yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data); - return yrgb_mst == state->yrgb_mst; + return yrgb_mst == vop_win->yrgb_mst; } static void vop_handle_vblank(struct vop *vop) |