1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022 MediaTek Inc.
4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
5 */
6
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"
12
fh_to_ctx(struct v4l2_fh * fh)13 static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh)
14 {
15 return container_of(fh, struct mdp_m2m_ctx, fh);
16 }
17
ctrl_to_ctx(struct v4l2_ctrl * ctrl)18 static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
19 {
20 return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler);
21 }
22
ctx_get_frame(struct mdp_m2m_ctx * ctx,enum v4l2_buf_type type)23 static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx,
24 enum v4l2_buf_type type)
25 {
26 if (V4L2_TYPE_IS_OUTPUT(type))
27 return &ctx->curr_param.output;
28 else
29 return &ctx->curr_param.captures[0];
30 }
31
mdp_m2m_ctx_set_state(struct mdp_m2m_ctx * ctx,u32 state)32 static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state)
33 {
34 atomic_or(state, &ctx->curr_param.state);
35 }
36
mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx * ctx,u32 mask)37 static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask)
38 {
39 return ((atomic_read(&ctx->curr_param.state) & mask) == mask);
40 }
41
mdp_m2m_process_done(void * priv,int vb_state)42 static void mdp_m2m_process_done(void *priv, int vb_state)
43 {
44 struct mdp_m2m_ctx *ctx = priv;
45 struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
46
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);
55
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);
59 }
60
mdp_m2m_device_run(void * priv)61 static void mdp_m2m_device_run(void *priv)
62 {
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;
69 int ret;
70
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");
74 goto worker_end;
75 }
76
77 param.frame_no = ctx->curr_param.frame_no;
78 param.type = ctx->curr_param.type;
79 param.num_inputs = 1;
80 param.num_outputs = 1;
81
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);
85
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);
89
90 if (mdp_check_pp_enable(ctx->mdp_dev, frame))
91 param.type = MDP_STREAM_TYPE_DUAL_BITBLT;
92
93 ret = mdp_vpu_process(&ctx->mdp_dev->vpu, ¶m);
94 if (ret) {
95 dev_err(&ctx->mdp_dev->pdev->dev,
96 "VPU MDP process failed: %d\n", ret);
97 goto worker_end;
98 }
99
100 task.config = ctx->mdp_dev->vpu.config;
101 task.param = ¶m;
102 task.composes[0] = &frame->compose;
103 task.cmdq_cb = NULL;
104 task.cb_data = NULL;
105 task.mdp_ctx = ctx;
106
107 if (refcount_read(&ctx->mdp_dev->job_count)) {
108 ret = wait_event_timeout(ctx->mdp_dev->callback_wq,
109 !refcount_read(&ctx->mdp_dev->job_count),
110 2 * HZ);
111 if (ret == 0) {
112 dev_err(&ctx->mdp_dev->pdev->dev,
113 "%d jobs not yet done\n",
114 refcount_read(&ctx->mdp_dev->job_count));
115 goto worker_end;
116 }
117 }
118
119 ret = mdp_cmdq_send(ctx->mdp_dev, &task);
120 if (ret) {
121 dev_err(&ctx->mdp_dev->pdev->dev,
122 "CMDQ sendtask failed: %d\n", ret);
123 goto worker_end;
124 }
125
126 return;
127
128 worker_end:
129 mdp_m2m_process_done(ctx, vb_state);
130 }
131
mdp_m2m_start_streaming(struct vb2_queue * q,unsigned int count)132 static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
133 {
134 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
135 struct mdp_frame *capture;
136 struct vb2_queue *vq;
137 int ret;
138 bool out_streaming, cap_streaming;
139
140 if (V4L2_TYPE_IS_OUTPUT(q->type))
141 ctx->frame_count[MDP_M2M_SRC] = 0;
142
143 if (V4L2_TYPE_IS_CAPTURE(q->type))
144 ctx->frame_count[MDP_M2M_DST] = 0;
145
146 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
147 vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
148 out_streaming = vb2_is_streaming(vq);
149 vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
150 cap_streaming = vb2_is_streaming(vq);
151
152 /* Check to see if scaling ratio is within supported range */
153 if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) ||
154 (V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) {
155 ret = mdp_check_scaling_ratio(&capture->crop.c,
156 &capture->compose,
157 capture->rotation,
158 ctx->curr_param.limit);
159 if (ret) {
160 dev_err(&ctx->mdp_dev->pdev->dev,
161 "Out of scaling range\n");
162 return ret;
163 }
164 }
165
166 if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
167 ret = mdp_vpu_get_locked(ctx->mdp_dev);
168 if (ret) {
169 dev_err(&ctx->mdp_dev->pdev->dev,
170 "VPU init failed %d\n", ret);
171 return -EINVAL;
172 }
173 mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);
174 }
175
176 return 0;
177 }
178
mdp_m2m_buf_remove(struct mdp_m2m_ctx * ctx,unsigned int type)179 static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,
180 unsigned int type)
181 {
182 if (V4L2_TYPE_IS_OUTPUT(type))
183 return (struct vb2_v4l2_buffer *)
184 v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
185 else
186 return (struct vb2_v4l2_buffer *)
187 v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
188 }
189
mdp_m2m_stop_streaming(struct vb2_queue * q)190 static void mdp_m2m_stop_streaming(struct vb2_queue *q)
191 {
192 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
193 struct vb2_v4l2_buffer *vb;
194
195 vb = mdp_m2m_buf_remove(ctx, q->type);
196 while (vb) {
197 v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
198 vb = mdp_m2m_buf_remove(ctx, q->type);
199 }
200 }
201
mdp_m2m_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])202 static int mdp_m2m_queue_setup(struct vb2_queue *q,
203 unsigned int *num_buffers,
204 unsigned int *num_planes, unsigned int sizes[],
205 struct device *alloc_devs[])
206 {
207 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
208 struct v4l2_pix_format_mplane *pix_mp;
209 u32 i;
210
211 pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;
212
213 /* from VIDIOC_CREATE_BUFS */
214 if (*num_planes) {
215 if (*num_planes != pix_mp->num_planes)
216 return -EINVAL;
217 for (i = 0; i < pix_mp->num_planes; ++i)
218 if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)
219 return -EINVAL;
220 } else {/* from VIDIOC_REQBUFS */
221 *num_planes = pix_mp->num_planes;
222 for (i = 0; i < pix_mp->num_planes; ++i)
223 sizes[i] = pix_mp->plane_fmt[i].sizeimage;
224 }
225
226 return 0;
227 }
228
mdp_m2m_buf_prepare(struct vb2_buffer * vb)229 static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)
230 {
231 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
232 struct v4l2_pix_format_mplane *pix_mp;
233 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
234 u32 i;
235
236 v4l2_buf->field = V4L2_FIELD_NONE;
237
238 if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
239 pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp;
240 for (i = 0; i < pix_mp->num_planes; ++i) {
241 vb2_set_plane_payload(vb, i,
242 pix_mp->plane_fmt[i].sizeimage);
243 }
244 }
245 return 0;
246 }
247
mdp_m2m_buf_out_validate(struct vb2_buffer * vb)248 static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)
249 {
250 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
251
252 v4l2_buf->field = V4L2_FIELD_NONE;
253
254 return 0;
255 }
256
mdp_m2m_buf_queue(struct vb2_buffer * vb)257 static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
258 {
259 struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
260 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
261
262 v4l2_buf->field = V4L2_FIELD_NONE;
263
264 v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
265 }
266
267 static const struct vb2_ops mdp_m2m_qops = {
268 .queue_setup = mdp_m2m_queue_setup,
269 .buf_prepare = mdp_m2m_buf_prepare,
270 .start_streaming = mdp_m2m_start_streaming,
271 .stop_streaming = mdp_m2m_stop_streaming,
272 .buf_queue = mdp_m2m_buf_queue,
273 .buf_out_validate = mdp_m2m_buf_out_validate,
274 };
275
mdp_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)276 static int mdp_m2m_querycap(struct file *file, void *fh,
277 struct v4l2_capability *cap)
278 {
279 strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
280 strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));
281
282 return 0;
283 }
284
mdp_m2m_enum_fmt_mplane(struct file * file,void * fh,struct v4l2_fmtdesc * f)285 static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
286 struct v4l2_fmtdesc *f)
287 {
288 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
289
290 return mdp_enum_fmt_mplane(ctx->mdp_dev, f);
291 }
292
mdp_m2m_g_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)293 static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
294 struct v4l2_format *f)
295 {
296 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
297 struct mdp_frame *frame;
298 struct v4l2_pix_format_mplane *pix_mp;
299
300 frame = ctx_get_frame(ctx, f->type);
301 *f = frame->format;
302 pix_mp = &f->fmt.pix_mp;
303 pix_mp->colorspace = ctx->curr_param.colorspace;
304 pix_mp->xfer_func = ctx->curr_param.xfer_func;
305 pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;
306 pix_mp->quantization = ctx->curr_param.quant;
307
308 return 0;
309 }
310
mdp_m2m_s_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)311 static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
312 struct v4l2_format *f)
313 {
314 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
315 struct mdp_frame *frame = ctx_get_frame(ctx, f->type);
316 struct mdp_frame *capture;
317 const struct mdp_format *fmt;
318 struct vb2_queue *vq;
319
320 fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);
321 if (!fmt)
322 return -EINVAL;
323
324 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
325 if (vb2_is_busy(vq))
326 return -EBUSY;
327
328 frame->format = *f;
329 frame->mdp_fmt = fmt;
330 frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);
331 frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?
332 MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;
333
334 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
335 if (V4L2_TYPE_IS_OUTPUT(f->type)) {
336 capture->crop.c.left = 0;
337 capture->crop.c.top = 0;
338 capture->crop.c.width = f->fmt.pix_mp.width;
339 capture->crop.c.height = f->fmt.pix_mp.height;
340 ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;
341 ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
342 ctx->curr_param.quant = f->fmt.pix_mp.quantization;
343 ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;
344 } else {
345 capture->compose.left = 0;
346 capture->compose.top = 0;
347 capture->compose.width = f->fmt.pix_mp.width;
348 capture->compose.height = f->fmt.pix_mp.height;
349 }
350
351 return 0;
352 }
353
mdp_m2m_try_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)354 static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
355 struct v4l2_format *f)
356 {
357 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
358
359 if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))
360 return -EINVAL;
361
362 return 0;
363 }
364
mdp_m2m_g_selection(struct file * file,void * fh,struct v4l2_selection * s)365 static int mdp_m2m_g_selection(struct file *file, void *fh,
366 struct v4l2_selection *s)
367 {
368 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
369 struct mdp_frame *frame;
370 bool valid = false;
371
372 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
373 valid = mdp_target_is_crop(s->target);
374 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
375 valid = mdp_target_is_compose(s->target);
376
377 if (!valid)
378 return -EINVAL;
379
380 switch (s->target) {
381 case V4L2_SEL_TGT_CROP:
382 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
383 return -EINVAL;
384 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
385 s->r = frame->crop.c;
386 return 0;
387 case V4L2_SEL_TGT_COMPOSE:
388 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
389 return -EINVAL;
390 frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
391 s->r = frame->compose;
392 return 0;
393 case V4L2_SEL_TGT_CROP_DEFAULT:
394 case V4L2_SEL_TGT_CROP_BOUNDS:
395 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
396 return -EINVAL;
397 frame = ctx_get_frame(ctx, s->type);
398 s->r.left = 0;
399 s->r.top = 0;
400 s->r.width = frame->format.fmt.pix_mp.width;
401 s->r.height = frame->format.fmt.pix_mp.height;
402 return 0;
403 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
404 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
405 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
406 return -EINVAL;
407 frame = ctx_get_frame(ctx, s->type);
408 s->r.left = 0;
409 s->r.top = 0;
410 s->r.width = frame->format.fmt.pix_mp.width;
411 s->r.height = frame->format.fmt.pix_mp.height;
412 return 0;
413 }
414 return -EINVAL;
415 }
416
mdp_m2m_s_selection(struct file * file,void * fh,struct v4l2_selection * s)417 static int mdp_m2m_s_selection(struct file *file, void *fh,
418 struct v4l2_selection *s)
419 {
420 struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
421 struct mdp_frame *frame = ctx_get_frame(ctx, s->type);
422 struct mdp_frame *capture;
423 struct v4l2_rect r;
424 struct device *dev = &ctx->mdp_dev->pdev->dev;
425 bool valid = false;
426 int ret;
427
428 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
429 valid = (s->target == V4L2_SEL_TGT_CROP);
430 else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
431 valid = (s->target == V4L2_SEL_TGT_COMPOSE);
432
433 if (!valid) {
434 dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,
435 ctx->id, s->type, s->target);
436 return -EINVAL;
437 }
438
439 ret = mdp_try_crop(ctx, &r, s, frame);
440 if (ret)
441 return ret;
442 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
443
444 if (mdp_target_is_crop(s->target))
445 capture->crop.c = r;
446 else
447 capture->compose = r;
448
449 s->r = r;
450
451 return 0;
452 }
453
454 static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {
455 .vidioc_querycap = mdp_m2m_querycap,
456 .vidioc_enum_fmt_vid_cap = mdp_m2m_enum_fmt_mplane,
457 .vidioc_enum_fmt_vid_out = mdp_m2m_enum_fmt_mplane,
458 .vidioc_g_fmt_vid_cap_mplane = mdp_m2m_g_fmt_mplane,
459 .vidioc_g_fmt_vid_out_mplane = mdp_m2m_g_fmt_mplane,
460 .vidioc_s_fmt_vid_cap_mplane = mdp_m2m_s_fmt_mplane,
461 .vidioc_s_fmt_vid_out_mplane = mdp_m2m_s_fmt_mplane,
462 .vidioc_try_fmt_vid_cap_mplane = mdp_m2m_try_fmt_mplane,
463 .vidioc_try_fmt_vid_out_mplane = mdp_m2m_try_fmt_mplane,
464 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
465 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
466 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
467 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
468 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
469 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
470 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
471 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
472 .vidioc_g_selection = mdp_m2m_g_selection,
473 .vidioc_s_selection = mdp_m2m_s_selection,
474 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
475 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
476 };
477
mdp_m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)478 static int mdp_m2m_queue_init(void *priv,
479 struct vb2_queue *src_vq,
480 struct vb2_queue *dst_vq)
481 {
482 struct mdp_m2m_ctx *ctx = priv;
483 int ret;
484
485 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
486 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
487 src_vq->ops = &mdp_m2m_qops;
488 src_vq->mem_ops = &vb2_dma_contig_memops;
489 src_vq->drv_priv = ctx;
490 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
491 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
492 src_vq->dev = &ctx->mdp_dev->pdev->dev;
493 src_vq->lock = &ctx->ctx_lock;
494
495 ret = vb2_queue_init(src_vq);
496 if (ret)
497 return ret;
498
499 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
500 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
501 dst_vq->ops = &mdp_m2m_qops;
502 dst_vq->mem_ops = &vb2_dma_contig_memops;
503 dst_vq->drv_priv = ctx;
504 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
505 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
506 dst_vq->dev = &ctx->mdp_dev->pdev->dev;
507 dst_vq->lock = &ctx->ctx_lock;
508
509 return vb2_queue_init(dst_vq);
510 }
511
mdp_m2m_s_ctrl(struct v4l2_ctrl * ctrl)512 static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
513 {
514 struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
515 struct mdp_frame *capture;
516
517 capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
518 switch (ctrl->id) {
519 case V4L2_CID_HFLIP:
520 capture->hflip = ctrl->val;
521 break;
522 case V4L2_CID_VFLIP:
523 capture->vflip = ctrl->val;
524 break;
525 case V4L2_CID_ROTATE:
526 capture->rotation = ctrl->val;
527 break;
528 }
529
530 return 0;
531 }
532
533 static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
534 .s_ctrl = mdp_m2m_s_ctrl,
535 };
536
mdp_m2m_ctrls_create(struct mdp_m2m_ctx * ctx)537 static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
538 {
539 v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);
540 ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
541 &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,
542 0, 1, 1, 0);
543 ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
544 &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
545 0, 1, 1, 0);
546 ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
547 &mdp_m2m_ctrl_ops,
548 V4L2_CID_ROTATE, 0, 270, 90, 0);
549
550 if (ctx->ctrl_handler.error) {
551 int err = ctx->ctrl_handler.error;
552
553 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
554 dev_err(&ctx->mdp_dev->pdev->dev,
555 "Failed to register controls\n");
556 return err;
557 }
558 return 0;
559 }
560
mdp_m2m_open(struct file * file)561 static int mdp_m2m_open(struct file *file)
562 {
563 struct video_device *vdev = video_devdata(file);
564 struct mdp_dev *mdp = video_get_drvdata(vdev);
565 struct mdp_m2m_ctx *ctx;
566 struct device *dev = &mdp->pdev->dev;
567 int ret;
568 struct v4l2_format default_format = {};
569 const struct mdp_limit *limit = mdp->mdp_data->def_limit;
570
571 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
572 if (!ctx)
573 return -ENOMEM;
574
575 if (mutex_lock_interruptible(&mdp->m2m_lock)) {
576 ret = -ERESTARTSYS;
577 goto err_free_ctx;
578 }
579
580 ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
581 if (ret < 0)
582 goto err_unlock_mutex;
583 ctx->id = ret;
584
585 ctx->mdp_dev = mdp;
586
587 v4l2_fh_init(&ctx->fh, vdev);
588 file->private_data = &ctx->fh;
589 ret = mdp_m2m_ctrls_create(ctx);
590 if (ret)
591 goto err_exit_fh;
592
593 /* Use separate control handler per file handle */
594 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
595 v4l2_fh_add(&ctx->fh);
596
597 mutex_init(&ctx->ctx_lock);
598 ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);
599 if (IS_ERR(ctx->m2m_ctx)) {
600 dev_err(dev, "Failed to initialize m2m context\n");
601 ret = PTR_ERR(ctx->m2m_ctx);
602 goto err_release_handler;
603 }
604 ctx->fh.m2m_ctx = ctx->m2m_ctx;
605
606 ctx->curr_param.ctx = ctx;
607 ret = mdp_frameparam_init(mdp, &ctx->curr_param);
608 if (ret) {
609 dev_err(dev, "Failed to initialize mdp parameter\n");
610 goto err_release_m2m_ctx;
611 }
612
613 mutex_unlock(&mdp->m2m_lock);
614
615 /* Default format */
616 default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
617 default_format.fmt.pix_mp.width = limit->out_limit.wmin;
618 default_format.fmt.pix_mp.height = limit->out_limit.hmin;
619 default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
620 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
621 default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
622 mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
623
624 dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
625
626 return 0;
627
628 err_release_m2m_ctx:
629 v4l2_m2m_ctx_release(ctx->m2m_ctx);
630 err_release_handler:
631 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
632 v4l2_fh_del(&ctx->fh);
633 err_exit_fh:
634 v4l2_fh_exit(&ctx->fh);
635 ida_free(&mdp->mdp_ida, ctx->id);
636 err_unlock_mutex:
637 mutex_unlock(&mdp->m2m_lock);
638 err_free_ctx:
639 kfree(ctx);
640
641 return ret;
642 }
643
mdp_m2m_release(struct file * file)644 static int mdp_m2m_release(struct file *file)
645 {
646 struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);
647 struct mdp_dev *mdp = video_drvdata(file);
648 struct device *dev = &mdp->pdev->dev;
649
650 mutex_lock(&mdp->m2m_lock);
651 v4l2_m2m_ctx_release(ctx->m2m_ctx);
652 if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT))
653 mdp_vpu_put_locked(mdp);
654
655 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
656 v4l2_fh_del(&ctx->fh);
657 v4l2_fh_exit(&ctx->fh);
658 ida_free(&mdp->mdp_ida, ctx->id);
659 mutex_unlock(&mdp->m2m_lock);
660
661 dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
662 kfree(ctx);
663
664 return 0;
665 }
666
667 static const struct v4l2_file_operations mdp_m2m_fops = {
668 .owner = THIS_MODULE,
669 .poll = v4l2_m2m_fop_poll,
670 .unlocked_ioctl = video_ioctl2,
671 .mmap = v4l2_m2m_fop_mmap,
672 .open = mdp_m2m_open,
673 .release = mdp_m2m_release,
674 };
675
676 static const struct v4l2_m2m_ops mdp_m2m_ops = {
677 .device_run = mdp_m2m_device_run,
678 };
679
mdp_m2m_device_register(struct mdp_dev * mdp)680 int mdp_m2m_device_register(struct mdp_dev *mdp)
681 {
682 struct device *dev = &mdp->pdev->dev;
683 int ret = 0;
684
685 mdp->m2m_vdev = video_device_alloc();
686 if (!mdp->m2m_vdev) {
687 dev_err(dev, "Failed to allocate video device\n");
688 ret = -ENOMEM;
689 goto err_video_alloc;
690 }
691 mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
692 V4L2_CAP_STREAMING;
693 mdp->m2m_vdev->fops = &mdp_m2m_fops;
694 mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;
695 mdp->m2m_vdev->release = mdp_video_device_release;
696 mdp->m2m_vdev->lock = &mdp->m2m_lock;
697 mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;
698 mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;
699 snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",
700 MDP_MODULE_NAME);
701 video_set_drvdata(mdp->m2m_vdev, mdp);
702
703 mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);
704 if (IS_ERR(mdp->m2m_dev)) {
705 dev_err(dev, "Failed to initialize v4l2-m2m device\n");
706 ret = PTR_ERR(mdp->m2m_dev);
707 goto err_m2m_init;
708 }
709
710 ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);
711 if (ret) {
712 dev_err(dev, "Failed to register video device\n");
713 goto err_video_register;
714 }
715
716 v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
717 mdp->m2m_vdev->num);
718 return 0;
719
720 err_video_register:
721 v4l2_m2m_release(mdp->m2m_dev);
722 err_m2m_init:
723 video_device_release(mdp->m2m_vdev);
724 err_video_alloc:
725
726 return ret;
727 }
728
mdp_m2m_device_unregister(struct mdp_dev * mdp)729 void mdp_m2m_device_unregister(struct mdp_dev *mdp)
730 {
731 video_unregister_device(mdp->m2m_vdev);
732 }
733
mdp_m2m_job_finish(struct mdp_m2m_ctx * ctx)734 void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
735 {
736 enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
737
738 mdp_m2m_process_done(ctx, vb_state);
739 }
740