1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2022 MediaTek Inc.
4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
7 #include <linux/platform_device.h>
8 #include <media/v4l2-ioctl.h>
9 #include <media/v4l2-event.h>
10 #include <media/videobuf2-dma-contig.h>
11 #include "mtk-mdp3-m2m.h"
13 static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh)
15 return container_of(fh, struct mdp_m2m_ctx, fh);
18 static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
20 return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler);
23 static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx,
24 enum v4l2_buf_type type)
26 if (V4L2_TYPE_IS_OUTPUT(type))
27 return &ctx->curr_param.output;
29 return &ctx->curr_param.captures[0];
32 static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state)
34 atomic_or(state, &ctx->curr_param.state);
37 static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask)
39 return ((atomic_read(&ctx->curr_param.state) & mask) == mask);
42 static void mdp_m2m_process_done(void *priv, int vb_state)
44 struct mdp_m2m_ctx *ctx = priv;
45 struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
47 src_vbuf = (struct vb2_v4l2_buffer *)
48 v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
49 dst_vbuf = (struct vb2_v4l2_buffer *)
50 v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
51 ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC];
52 src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++;
53 dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++;
54 v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true);
56 v4l2_m2m_buf_done(src_vbuf, vb_state);
57 v4l2_m2m_buf_done(dst_vbuf, vb_state);
58 v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
61 static void mdp_m2m_device_run(void *priv)
63 struct mdp_m2m_ctx *ctx = priv;
64 struct mdp_frame *frame;
65 struct vb2_v4l2_buffer *src_vb, *dst_vb;
66 struct img_ipi_frameparam param = {};
67 struct mdp_cmdq_param task = {};
68 enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR;
71 if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) {
72 dev_err(&ctx->mdp_dev->pdev->dev,
73 "mdp_m2m_ctx is in error state\n");
77 param.frame_no = ctx->curr_param.frame_no;
78 param.type = ctx->curr_param.type;
80 param.num_outputs = 1;
82 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
83 src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
84 mdp_set_src_config(¶m.inputs[0], frame, &src_vb->vb2_buf);
86 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
87 dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
88 mdp_set_dst_config(¶m.outputs[0], frame, &dst_vb->vb2_buf);
90 ret = mdp_vpu_process(&ctx->mdp_dev->vpu, ¶m);
92 dev_err(&ctx->mdp_dev->pdev->dev,
93 "VPU MDP process failed: %d\n", ret);
97 task.config = ctx->mdp_dev->vpu.config;
99 task.composes[0] = &frame->compose;
104 ret = mdp_cmdq_send(ctx->mdp_dev, &task);
106 dev_err(&ctx->mdp_dev->pdev->dev,
107 "CMDQ sendtask failed: %d\n", ret);
114 mdp_m2m_process_done(ctx, vb_state);
117 static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
119 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
120 struct mdp_frame *capture;
121 struct vb2_queue *vq;
123 bool out_streaming, cap_streaming;
125 if (V4L2_TYPE_IS_OUTPUT(q->type))
126 ctx->frame_count[MDP_M2M_SRC] = 0;
128 if (V4L2_TYPE_IS_CAPTURE(q->type))
129 ctx->frame_count[MDP_M2M_DST] = 0;
131 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
132 vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
133 out_streaming = vb2_is_streaming(vq);
134 vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
135 cap_streaming = vb2_is_streaming(vq);
137 /* Check to see if scaling ratio is within supported range */
138 if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) ||
139 (V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) {
140 ret = mdp_check_scaling_ratio(&capture->crop.c,
143 ctx->curr_param.limit);
145 dev_err(&ctx->mdp_dev->pdev->dev,
146 "Out of scaling range\n");
151 if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
152 ret = mdp_vpu_get_locked(ctx->mdp_dev);
154 dev_err(&ctx->mdp_dev->pdev->dev,
155 "VPU init failed %d\n", ret);
158 mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);
164 static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,
167 if (V4L2_TYPE_IS_OUTPUT(type))
168 return (struct vb2_v4l2_buffer *)
169 v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
171 return (struct vb2_v4l2_buffer *)
172 v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
175 static void mdp_m2m_stop_streaming(struct vb2_queue *q)
177 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
178 struct vb2_v4l2_buffer *vb;
180 vb = mdp_m2m_buf_remove(ctx, q->type);
182 v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
183 vb = mdp_m2m_buf_remove(ctx, q->type);
187 static int mdp_m2m_queue_setup(struct vb2_queue *q,
188 unsigned int *num_buffers,
189 unsigned int *num_planes, unsigned int sizes[],
190 struct device *alloc_devs[])
192 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
193 struct v4l2_pix_format_mplane *pix_mp;
196 pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;
198 /* from VIDIOC_CREATE_BUFS */
200 if (*num_planes != pix_mp->num_planes)
202 for (i = 0; i < pix_mp->num_planes; ++i)
203 if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)
205 } else {/* from VIDIOC_REQBUFS */
206 *num_planes = pix_mp->num_planes;
207 for (i = 0; i < pix_mp->num_planes; ++i)
208 sizes[i] = pix_mp->plane_fmt[i].sizeimage;
214 static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)
216 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
217 struct v4l2_pix_format_mplane *pix_mp;
218 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
221 v4l2_buf->field = V4L2_FIELD_NONE;
223 if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
224 pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp;
225 for (i = 0; i < pix_mp->num_planes; ++i) {
226 vb2_set_plane_payload(vb, i,
227 pix_mp->plane_fmt[i].sizeimage);
233 static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)
235 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
237 v4l2_buf->field = V4L2_FIELD_NONE;
242 static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
244 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
245 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
247 v4l2_buf->field = V4L2_FIELD_NONE;
249 v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
252 static const struct vb2_ops mdp_m2m_qops = {
253 .queue_setup = mdp_m2m_queue_setup,
254 .wait_prepare = vb2_ops_wait_prepare,
255 .wait_finish = vb2_ops_wait_finish,
256 .buf_prepare = mdp_m2m_buf_prepare,
257 .start_streaming = mdp_m2m_start_streaming,
258 .stop_streaming = mdp_m2m_stop_streaming,
259 .buf_queue = mdp_m2m_buf_queue,
260 .buf_out_validate = mdp_m2m_buf_out_validate,
263 static int mdp_m2m_querycap(struct file *file, void *fh,
264 struct v4l2_capability *cap)
266 strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
267 strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));
272 static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
273 struct v4l2_fmtdesc *f)
275 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
277 return mdp_enum_fmt_mplane(ctx->mdp_dev, f);
280 static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
281 struct v4l2_format *f)
283 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
284 struct mdp_frame *frame;
285 struct v4l2_pix_format_mplane *pix_mp;
287 frame = ctx_get_frame(ctx, f->type);
289 pix_mp = &f->fmt.pix_mp;
290 pix_mp->colorspace = ctx->curr_param.colorspace;
291 pix_mp->xfer_func = ctx->curr_param.xfer_func;
292 pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;
293 pix_mp->quantization = ctx->curr_param.quant;
298 static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
299 struct v4l2_format *f)
301 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
302 struct mdp_frame *frame = ctx_get_frame(ctx, f->type);
303 struct mdp_frame *capture;
304 const struct mdp_format *fmt;
305 struct vb2_queue *vq;
307 fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);
311 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
316 frame->mdp_fmt = fmt;
317 frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);
318 frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?
319 MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;
321 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
322 if (V4L2_TYPE_IS_OUTPUT(f->type)) {
323 capture->crop.c.left = 0;
324 capture->crop.c.top = 0;
325 capture->crop.c.width = f->fmt.pix_mp.width;
326 capture->crop.c.height = f->fmt.pix_mp.height;
327 ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;
328 ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
329 ctx->curr_param.quant = f->fmt.pix_mp.quantization;
330 ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;
332 capture->compose.left = 0;
333 capture->compose.top = 0;
334 capture->compose.width = f->fmt.pix_mp.width;
335 capture->compose.height = f->fmt.pix_mp.height;
341 static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
342 struct v4l2_format *f)
344 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
346 if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))
352 static int mdp_m2m_g_selection(struct file *file, void *fh,
353 struct v4l2_selection *s)
355 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
356 struct mdp_frame *frame;
359 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
360 valid = mdp_target_is_crop(s->target);
361 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
362 valid = mdp_target_is_compose(s->target);
368 case V4L2_SEL_TGT_CROP:
369 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
371 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
372 s->r = frame->crop.c;
374 case V4L2_SEL_TGT_COMPOSE:
375 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
377 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
378 s->r = frame->compose;
380 case V4L2_SEL_TGT_CROP_DEFAULT:
381 case V4L2_SEL_TGT_CROP_BOUNDS:
382 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
384 frame = ctx_get_frame(ctx, s->type);
387 s->r.width = frame->format.fmt.pix_mp.width;
388 s->r.height = frame->format.fmt.pix_mp.height;
390 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
391 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
392 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
394 frame = ctx_get_frame(ctx, s->type);
397 s->r.width = frame->format.fmt.pix_mp.width;
398 s->r.height = frame->format.fmt.pix_mp.height;
404 static int mdp_m2m_s_selection(struct file *file, void *fh,
405 struct v4l2_selection *s)
407 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
408 struct mdp_frame *frame = ctx_get_frame(ctx, s->type);
409 struct mdp_frame *capture;
411 struct device *dev = &ctx->mdp_dev->pdev->dev;
415 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
416 valid = (s->target == V4L2_SEL_TGT_CROP);
417 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
418 valid = (s->target == V4L2_SEL_TGT_COMPOSE);
421 dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,
422 ctx->id, s->type, s->target);
426 ret = mdp_try_crop(ctx, &r, s, frame);
429 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
431 if (mdp_target_is_crop(s->target))
434 capture->compose = r;
441 static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {
442 .vidioc_querycap = mdp_m2m_querycap,
443 .vidioc_enum_fmt_vid_cap = mdp_m2m_enum_fmt_mplane,
444 .vidioc_enum_fmt_vid_out = mdp_m2m_enum_fmt_mplane,
445 .vidioc_g_fmt_vid_cap_mplane = mdp_m2m_g_fmt_mplane,
446 .vidioc_g_fmt_vid_out_mplane = mdp_m2m_g_fmt_mplane,
447 .vidioc_s_fmt_vid_cap_mplane = mdp_m2m_s_fmt_mplane,
448 .vidioc_s_fmt_vid_out_mplane = mdp_m2m_s_fmt_mplane,
449 .vidioc_try_fmt_vid_cap_mplane = mdp_m2m_try_fmt_mplane,
450 .vidioc_try_fmt_vid_out_mplane = mdp_m2m_try_fmt_mplane,
451 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
452 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
453 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
454 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
455 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
456 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
457 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
458 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
459 .vidioc_g_selection = mdp_m2m_g_selection,
460 .vidioc_s_selection = mdp_m2m_s_selection,
461 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
462 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
465 static int mdp_m2m_queue_init(void *priv,
466 struct vb2_queue *src_vq,
467 struct vb2_queue *dst_vq)
469 struct mdp_m2m_ctx *ctx = priv;
472 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
473 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
474 src_vq->ops = &mdp_m2m_qops;
475 src_vq->mem_ops = &vb2_dma_contig_memops;
476 src_vq->drv_priv = ctx;
477 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
478 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
479 src_vq->dev = &ctx->mdp_dev->pdev->dev;
480 src_vq->lock = &ctx->ctx_lock;
482 ret = vb2_queue_init(src_vq);
486 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
487 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
488 dst_vq->ops = &mdp_m2m_qops;
489 dst_vq->mem_ops = &vb2_dma_contig_memops;
490 dst_vq->drv_priv = ctx;
491 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
492 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
493 dst_vq->dev = &ctx->mdp_dev->pdev->dev;
494 dst_vq->lock = &ctx->ctx_lock;
496 return vb2_queue_init(dst_vq);
499 static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
501 struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
502 struct mdp_frame *capture;
504 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
507 capture->hflip = ctrl->val;
510 capture->vflip = ctrl->val;
512 case V4L2_CID_ROTATE:
513 capture->rotation = ctrl->val;
520 static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
521 .s_ctrl = mdp_m2m_s_ctrl,
524 static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
526 v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);
527 ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
528 &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,
530 ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
531 &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
533 ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
535 V4L2_CID_ROTATE, 0, 270, 90, 0);
537 if (ctx->ctrl_handler.error) {
538 int err = ctx->ctrl_handler.error;
540 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
541 dev_err(&ctx->mdp_dev->pdev->dev,
542 "Failed to register controls\n");
548 static int mdp_m2m_open(struct file *file)
550 struct video_device *vdev = video_devdata(file);
551 struct mdp_dev *mdp = video_get_drvdata(vdev);
552 struct mdp_m2m_ctx *ctx;
553 struct device *dev = &mdp->pdev->dev;
555 struct v4l2_format default_format = {};
556 const struct mdp_limit *limit = mdp->mdp_data->def_limit;
558 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
562 if (mutex_lock_interruptible(&mdp->m2m_lock)) {
567 ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
569 goto err_unlock_mutex;
574 v4l2_fh_init(&ctx->fh, vdev);
575 file->private_data = &ctx->fh;
576 ret = mdp_m2m_ctrls_create(ctx);
580 /* Use separate control handler per file handle */
581 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
582 v4l2_fh_add(&ctx->fh);
584 mutex_init(&ctx->ctx_lock);
585 ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);
586 if (IS_ERR(ctx->m2m_ctx)) {
587 dev_err(dev, "Failed to initialize m2m context\n");
588 ret = PTR_ERR(ctx->m2m_ctx);
589 goto err_release_handler;
591 ctx->fh.m2m_ctx = ctx->m2m_ctx;
593 ctx->curr_param.ctx = ctx;
594 ret = mdp_frameparam_init(mdp, &ctx->curr_param);
596 dev_err(dev, "Failed to initialize mdp parameter\n");
597 goto err_release_m2m_ctx;
600 mutex_unlock(&mdp->m2m_lock);
603 default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
604 default_format.fmt.pix_mp.width = limit->out_limit.wmin;
605 default_format.fmt.pix_mp.height = limit->out_limit.hmin;
606 default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
607 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
608 default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
609 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
611 dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
616 v4l2_m2m_ctx_release(ctx->m2m_ctx);
618 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
619 v4l2_fh_del(&ctx->fh);
621 v4l2_fh_exit(&ctx->fh);
622 ida_free(&mdp->mdp_ida, ctx->id);
624 mutex_unlock(&mdp->m2m_lock);
631 static int mdp_m2m_release(struct file *file)
633 struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);
634 struct mdp_dev *mdp = video_drvdata(file);
635 struct device *dev = &mdp->pdev->dev;
637 mutex_lock(&mdp->m2m_lock);
638 v4l2_m2m_ctx_release(ctx->m2m_ctx);
639 if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT))
640 mdp_vpu_put_locked(mdp);
642 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
643 v4l2_fh_del(&ctx->fh);
644 v4l2_fh_exit(&ctx->fh);
645 ida_free(&mdp->mdp_ida, ctx->id);
646 mutex_unlock(&mdp->m2m_lock);
648 dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
654 static const struct v4l2_file_operations mdp_m2m_fops = {
655 .owner = THIS_MODULE,
656 .poll = v4l2_m2m_fop_poll,
657 .unlocked_ioctl = video_ioctl2,
658 .mmap = v4l2_m2m_fop_mmap,
659 .open = mdp_m2m_open,
660 .release = mdp_m2m_release,
663 static const struct v4l2_m2m_ops mdp_m2m_ops = {
664 .device_run = mdp_m2m_device_run,
667 int mdp_m2m_device_register(struct mdp_dev *mdp)
669 struct device *dev = &mdp->pdev->dev;
672 mdp->m2m_vdev = video_device_alloc();
673 if (!mdp->m2m_vdev) {
674 dev_err(dev, "Failed to allocate video device\n");
676 goto err_video_alloc;
678 mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
680 mdp->m2m_vdev->fops = &mdp_m2m_fops;
681 mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;
682 mdp->m2m_vdev->release = mdp_video_device_release;
683 mdp->m2m_vdev->lock = &mdp->m2m_lock;
684 mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;
685 mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;
686 snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",
688 video_set_drvdata(mdp->m2m_vdev, mdp);
690 mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);
691 if (IS_ERR(mdp->m2m_dev)) {
692 dev_err(dev, "Failed to initialize v4l2-m2m device\n");
693 ret = PTR_ERR(mdp->m2m_dev);
697 ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);
699 dev_err(dev, "Failed to register video device\n");
700 goto err_video_register;
703 v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
708 v4l2_m2m_release(mdp->m2m_dev);
710 video_device_release(mdp->m2m_vdev);
716 void mdp_m2m_device_unregister(struct mdp_dev *mdp)
718 video_unregister_device(mdp->m2m_vdev);
721 void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
723 enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
725 mdp_m2m_process_done(ctx, vb_state);