#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
#include <drm/drm_plane_helper.h>
#include <linux/devfreq.h>
int zpos;
};
+enum vop_pending {
+ VOP_PENDING_FB_UNREF,
+};
+
struct vop_plane_state {
struct drm_plane_state base;
int format;
struct completion wait_update_complete;
struct drm_pending_vblank_event *event;
+ struct drm_flip_work fb_unref_work;
+ unsigned long pending;
+
struct completion line_flag_completion;
const struct vop_data *data;
static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
+ struct drm_atomic_state *old_state = old_crtc_state->state;
+ struct drm_plane_state *old_plane_state;
struct vop *vop = to_vop(crtc);
+ struct drm_plane *plane;
+ int i;
vop_cfg_update(crtc, old_crtc_state);
* signalling flip completion we need to wait for it to finish.
*/
vop_wait_for_irq_handler(vop);
+
+ for_each_plane_in_state(old_state, plane, old_plane_state, i) {
+ if (!old_plane_state->fb)
+ continue;
+
+ if (old_plane_state->fb == plane->state->fb)
+ continue;
+
+ drm_framebuffer_reference(old_plane_state->fb);
+ drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
+ set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+ }
}
static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
.atomic_destroy_state = vop_crtc_destroy_state,
};
+static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
+{
+ struct vop *vop = container_of(work, struct vop, fb_unref_work);
+ struct drm_framebuffer *fb = val;
+
+ drm_crtc_vblank_put(&vop->crtc);
+ drm_framebuffer_unreference(fb);
+}
+
static void vop_handle_vblank(struct vop *vop)
{
struct drm_device *drm = vop->drm_dev;
}
if (!completion_done(&vop->wait_update_complete))
complete(&vop->wait_update_complete);
+
+ if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending))
+ drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);
}
static irqreturn_t vop_isr(int irq, void *data)
goto err_cleanup_crtc;
}
+ drm_flip_work_init(&vop->fb_unref_work, "fb_unref",
+ vop_fb_unref_worker);
+
init_completion(&vop->dsp_hold_completion);
init_completion(&vop->wait_update_complete);
init_completion(&vop->line_flag_completion);
* references the CRTC.
*/
drm_crtc_cleanup(crtc);
+ drm_flip_work_cleanup(&vop->fb_unref_work);
}
/*