void (*fn)(struct armada_crtc *, struct armada_plane_work *))
{
struct armada_plane *dplane = drm_to_armada_plane(work->plane);
- struct drm_pending_vblank_event *event = work->event;
- struct drm_framebuffer *fb = work->old_fb;
+ struct drm_pending_vblank_event *event;
+ struct drm_framebuffer *fb;
if (fn)
fn(dcrtc, work);
drm_crtc_vblank_put(&dcrtc->crtc);
+ event = work->event;
+ fb = work->old_fb;
if (event || fb) {
struct drm_device *dev = dcrtc->crtc.dev;
unsigned long flags;
spin_unlock_irqrestore(&dev->event_lock, flags);
}
+ if (work->need_kfree)
+ kfree(work);
+
wake_up(&dplane->frame_wait);
}
armada_drm_plane_work_call(dcrtc, work, work->cancel);
}
-static void armada_drm_crtc_finish_frame_work(struct armada_crtc *dcrtc,
- struct armada_plane_work *work)
-{
- kfree(work);
-}
-
static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
struct armada_plane_work *work)
{
spin_lock_irqsave(&dcrtc->irq_lock, flags);
armada_drm_crtc_update_regs(dcrtc, work->regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
-
- armada_drm_crtc_finish_frame_work(dcrtc, work);
}
static struct armada_plane_work *
work->plane = plane;
work->fn = armada_drm_crtc_complete_frame_work;
- work->cancel = armada_drm_crtc_finish_frame_work;
+ work->need_kfree = true;
armada_reg_queue_end(work->regs, i);
return work;
int armada_drm_plane_init(struct armada_plane *plane)
{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(plane->works); i++)
+ plane->works[i].plane = &plane->base;
+
init_waitqueue_head(&plane->frame_wait);
return 0;
struct armada_plane_work {
void (*fn)(struct armada_crtc *, struct armada_plane_work *);
void (*cancel)(struct armada_crtc *, struct armada_plane_work *);
+ bool need_kfree;
struct drm_plane *plane;
struct drm_framebuffer *old_fb;
struct drm_pending_vblank_event *event;
struct armada_plane {
struct drm_plane base;
wait_queue_head_t frame_wait;
+ bool next_work;
+ struct armada_plane_work works[2];
struct armada_plane_work *work;
struct armada_plane_state state;
};
struct armada_ovl_plane {
struct armada_plane base;
- struct armada_plane_work work;
struct armada_ovl_plane_properties prop;
};
#define drm_to_armada_ovl_plane(p) \
{
struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
- struct armada_plane_work *work = &dplane->work;
+ struct armada_plane_work *work;
const struct drm_format_info *format;
struct drm_plane_state state = {
.plane = plane,
if (ret)
return ret;
+ work = &dplane->base.works[dplane->base.next_work];
+
ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) |
CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) |
CFG_CBSH_ENA;
ret = armada_drm_plane_work_queue(dcrtc, work);
if (ret)
DRM_ERROR("failed to queue plane work: %d\n", ret);
+
+ dplane->base.next_work = !dplane->base.next_work;
}
return 0;
}
return ret;
}
- dplane->work.plane = &dplane->base.base;
- dplane->work.fn = armada_ovl_plane_work;
+ dplane->base.works[0].fn = armada_ovl_plane_work;
+ dplane->base.works[1].fn = armada_ovl_plane_work;
ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs,
&armada_ovl_plane_funcs,