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(&param.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(&param.outputs[0], frame, &dst_vb->vb2_buf);
89 
90 	ret = mdp_vpu_process(&ctx->mdp_dev->vpu, &param);
91 	if (ret) {
92 		dev_err(&ctx->mdp_dev->pdev->dev,
93 			"VPU MDP process failed: %d\n", ret);
94 		goto worker_end;
95 	}
96 
97 	task.config = ctx->mdp_dev->vpu.config;
98 	task.param = &param;
99 	task.composes[0] = &frame->compose;
100 	task.cmdq_cb = NULL;
101 	task.cb_data = NULL;
102 	task.mdp_ctx = ctx;
103 
104 	ret = mdp_cmdq_send(ctx->mdp_dev, &task);
105 	if (ret) {
106 		dev_err(&ctx->mdp_dev->pdev->dev,
107 			"CMDQ sendtask failed: %d\n", ret);
108 		goto worker_end;
109 	}
110 
111 	return;
112 
113 worker_end:
114 	mdp_m2m_process_done(ctx, vb_state);
115 }
116 
mdp_m2m_start_streaming(struct vb2_queue * q,unsigned int count)117 static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
118 {
119 	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
120 	struct mdp_frame *capture;
121 	struct vb2_queue *vq;
122 	int ret;
123 	bool out_streaming, cap_streaming;
124 
125 	if (V4L2_TYPE_IS_OUTPUT(q->type))
126 		ctx->frame_count[MDP_M2M_SRC] = 0;
127 
128 	if (V4L2_TYPE_IS_CAPTURE(q->type))
129 		ctx->frame_count[MDP_M2M_DST] = 0;
130 
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);
136 
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,
141 					      &capture->compose,
142 					      capture->rotation,
143 					      ctx->curr_param.limit);
144 		if (ret) {
145 			dev_err(&ctx->mdp_dev->pdev->dev,
146 				"Out of scaling range\n");
147 			return ret;
148 		}
149 	}
150 
151 	if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
152 		ret = mdp_vpu_get_locked(ctx->mdp_dev);
153 		if (ret) {
154 			dev_err(&ctx->mdp_dev->pdev->dev,
155 				"VPU init failed %d\n", ret);
156 			return -EINVAL;
157 		}
158 		mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);
159 	}
160 
161 	return 0;
162 }
163 
mdp_m2m_buf_remove(struct mdp_m2m_ctx * ctx,unsigned int type)164 static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,
165 						  unsigned int type)
166 {
167 	if (V4L2_TYPE_IS_OUTPUT(type))
168 		return (struct vb2_v4l2_buffer *)
169 			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
170 	else
171 		return (struct vb2_v4l2_buffer *)
172 			v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
173 }
174 
mdp_m2m_stop_streaming(struct vb2_queue * q)175 static void mdp_m2m_stop_streaming(struct vb2_queue *q)
176 {
177 	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
178 	struct vb2_v4l2_buffer *vb;
179 
180 	vb = mdp_m2m_buf_remove(ctx, q->type);
181 	while (vb) {
182 		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
183 		vb = mdp_m2m_buf_remove(ctx, q->type);
184 	}
185 }
186 
mdp_m2m_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])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[])
191 {
192 	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
193 	struct v4l2_pix_format_mplane *pix_mp;
194 	u32 i;
195 
196 	pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;
197 
198 	/* from VIDIOC_CREATE_BUFS */
199 	if (*num_planes) {
200 		if (*num_planes != pix_mp->num_planes)
201 			return -EINVAL;
202 		for (i = 0; i < pix_mp->num_planes; ++i)
203 			if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)
204 				return -EINVAL;
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;
209 	}
210 
211 	return 0;
212 }
213 
mdp_m2m_buf_prepare(struct vb2_buffer * vb)214 static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)
215 {
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);
219 	u32 i;
220 
221 	v4l2_buf->field = V4L2_FIELD_NONE;
222 
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);
228 		}
229 	}
230 	return 0;
231 }
232 
mdp_m2m_buf_out_validate(struct vb2_buffer * vb)233 static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)
234 {
235 	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
236 
237 	v4l2_buf->field = V4L2_FIELD_NONE;
238 
239 	return 0;
240 }
241 
mdp_m2m_buf_queue(struct vb2_buffer * vb)242 static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
243 {
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);
246 
247 	v4l2_buf->field = V4L2_FIELD_NONE;
248 
249 	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
250 }
251 
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,
261 };
262 
mdp_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)263 static int mdp_m2m_querycap(struct file *file, void *fh,
264 			    struct v4l2_capability *cap)
265 {
266 	strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
267 	strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));
268 
269 	return 0;
270 }
271 
mdp_m2m_enum_fmt_mplane(struct file * file,void * fh,struct v4l2_fmtdesc * f)272 static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
273 				   struct v4l2_fmtdesc *f)
274 {
275 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
276 
277 	return mdp_enum_fmt_mplane(ctx->mdp_dev, f);
278 }
279 
mdp_m2m_g_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)280 static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
281 				struct v4l2_format *f)
282 {
283 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
284 	struct mdp_frame *frame;
285 	struct v4l2_pix_format_mplane *pix_mp;
286 
287 	frame = ctx_get_frame(ctx, f->type);
288 	*f = frame->format;
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;
294 
295 	return 0;
296 }
297 
mdp_m2m_s_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)298 static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
299 				struct v4l2_format *f)
300 {
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;
306 
307 	fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);
308 	if (!fmt)
309 		return -EINVAL;
310 
311 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
312 	if (vb2_is_busy(vq))
313 		return -EBUSY;
314 
315 	frame->format = *f;
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;
320 
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;
331 	} else {
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;
336 	}
337 
338 	return 0;
339 }
340 
mdp_m2m_try_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)341 static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
342 				  struct v4l2_format *f)
343 {
344 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
345 
346 	if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))
347 		return -EINVAL;
348 
349 	return 0;
350 }
351 
mdp_m2m_g_selection(struct file * file,void * fh,struct v4l2_selection * s)352 static int mdp_m2m_g_selection(struct file *file, void *fh,
353 			       struct v4l2_selection *s)
354 {
355 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
356 	struct mdp_frame *frame;
357 	bool valid = false;
358 
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);
363 
364 	if (!valid)
365 		return -EINVAL;
366 
367 	switch (s->target) {
368 	case V4L2_SEL_TGT_CROP:
369 		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
370 			return -EINVAL;
371 		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
372 		s->r = frame->crop.c;
373 		return 0;
374 	case V4L2_SEL_TGT_COMPOSE:
375 		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
376 			return -EINVAL;
377 		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
378 		s->r = frame->compose;
379 		return 0;
380 	case V4L2_SEL_TGT_CROP_DEFAULT:
381 	case V4L2_SEL_TGT_CROP_BOUNDS:
382 		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
383 			return -EINVAL;
384 		frame = ctx_get_frame(ctx, s->type);
385 		s->r.left = 0;
386 		s->r.top = 0;
387 		s->r.width = frame->format.fmt.pix_mp.width;
388 		s->r.height = frame->format.fmt.pix_mp.height;
389 		return 0;
390 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
391 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
392 		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
393 			return -EINVAL;
394 		frame = ctx_get_frame(ctx, s->type);
395 		s->r.left = 0;
396 		s->r.top = 0;
397 		s->r.width = frame->format.fmt.pix_mp.width;
398 		s->r.height = frame->format.fmt.pix_mp.height;
399 		return 0;
400 	}
401 	return -EINVAL;
402 }
403 
mdp_m2m_s_selection(struct file * file,void * fh,struct v4l2_selection * s)404 static int mdp_m2m_s_selection(struct file *file, void *fh,
405 			       struct v4l2_selection *s)
406 {
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;
410 	struct v4l2_rect r;
411 	struct device *dev = &ctx->mdp_dev->pdev->dev;
412 	bool valid = false;
413 	int ret;
414 
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);
419 
420 	if (!valid) {
421 		dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,
422 			ctx->id, s->type, s->target);
423 		return -EINVAL;
424 	}
425 
426 	ret = mdp_try_crop(ctx, &r, s, frame);
427 	if (ret)
428 		return ret;
429 	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
430 
431 	if (mdp_target_is_crop(s->target))
432 		capture->crop.c = r;
433 	else
434 		capture->compose = r;
435 
436 	s->r = r;
437 
438 	return 0;
439 }
440 
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,
463 };
464 
mdp_m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)465 static int mdp_m2m_queue_init(void *priv,
466 			      struct vb2_queue *src_vq,
467 			      struct vb2_queue *dst_vq)
468 {
469 	struct mdp_m2m_ctx *ctx = priv;
470 	int ret;
471 
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;
481 
482 	ret = vb2_queue_init(src_vq);
483 	if (ret)
484 		return ret;
485 
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;
495 
496 	return vb2_queue_init(dst_vq);
497 }
498 
mdp_m2m_s_ctrl(struct v4l2_ctrl * ctrl)499 static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
500 {
501 	struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
502 	struct mdp_frame *capture;
503 
504 	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
505 	switch (ctrl->id) {
506 	case V4L2_CID_HFLIP:
507 		capture->hflip = ctrl->val;
508 		break;
509 	case V4L2_CID_VFLIP:
510 		capture->vflip = ctrl->val;
511 		break;
512 	case V4L2_CID_ROTATE:
513 		capture->rotation = ctrl->val;
514 		break;
515 	}
516 
517 	return 0;
518 }
519 
520 static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
521 	.s_ctrl	= mdp_m2m_s_ctrl,
522 };
523 
mdp_m2m_ctrls_create(struct mdp_m2m_ctx * ctx)524 static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
525 {
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,
529 					     0, 1, 1, 0);
530 	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
531 					     &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
532 					     0, 1, 1, 0);
533 	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
534 					      &mdp_m2m_ctrl_ops,
535 					      V4L2_CID_ROTATE, 0, 270, 90, 0);
536 
537 	if (ctx->ctrl_handler.error) {
538 		int err = ctx->ctrl_handler.error;
539 
540 		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
541 		dev_err(&ctx->mdp_dev->pdev->dev,
542 			"Failed to register controls\n");
543 		return err;
544 	}
545 	return 0;
546 }
547 
mdp_m2m_open(struct file * file)548 static int mdp_m2m_open(struct file *file)
549 {
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;
554 	int ret;
555 	struct v4l2_format default_format = {};
556 	const struct mdp_limit *limit = mdp->mdp_data->def_limit;
557 
558 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
559 	if (!ctx)
560 		return -ENOMEM;
561 
562 	if (mutex_lock_interruptible(&mdp->m2m_lock)) {
563 		ret = -ERESTARTSYS;
564 		goto err_free_ctx;
565 	}
566 
567 	ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
568 	if (ret < 0)
569 		goto err_unlock_mutex;
570 	ctx->id = ret;
571 
572 	ctx->mdp_dev = mdp;
573 
574 	v4l2_fh_init(&ctx->fh, vdev);
575 	file->private_data = &ctx->fh;
576 	ret = mdp_m2m_ctrls_create(ctx);
577 	if (ret)
578 		goto err_exit_fh;
579 
580 	/* Use separate control handler per file handle */
581 	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
582 	v4l2_fh_add(&ctx->fh);
583 
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;
590 	}
591 	ctx->fh.m2m_ctx = ctx->m2m_ctx;
592 
593 	ctx->curr_param.ctx = ctx;
594 	ret = mdp_frameparam_init(mdp, &ctx->curr_param);
595 	if (ret) {
596 		dev_err(dev, "Failed to initialize mdp parameter\n");
597 		goto err_release_m2m_ctx;
598 	}
599 
600 	mutex_unlock(&mdp->m2m_lock);
601 
602 	/* Default format */
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);
610 
611 	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
612 
613 	return 0;
614 
615 err_release_m2m_ctx:
616 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
617 err_release_handler:
618 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
619 	v4l2_fh_del(&ctx->fh);
620 err_exit_fh:
621 	v4l2_fh_exit(&ctx->fh);
622 	ida_free(&mdp->mdp_ida, ctx->id);
623 err_unlock_mutex:
624 	mutex_unlock(&mdp->m2m_lock);
625 err_free_ctx:
626 	kfree(ctx);
627 
628 	return ret;
629 }
630 
mdp_m2m_release(struct file * file)631 static int mdp_m2m_release(struct file *file)
632 {
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;
636 
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);
641 
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);
647 
648 	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
649 	kfree(ctx);
650 
651 	return 0;
652 }
653 
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,
661 };
662 
663 static const struct v4l2_m2m_ops mdp_m2m_ops = {
664 	.device_run	= mdp_m2m_device_run,
665 };
666 
mdp_m2m_device_register(struct mdp_dev * mdp)667 int mdp_m2m_device_register(struct mdp_dev *mdp)
668 {
669 	struct device *dev = &mdp->pdev->dev;
670 	int ret = 0;
671 
672 	mdp->m2m_vdev = video_device_alloc();
673 	if (!mdp->m2m_vdev) {
674 		dev_err(dev, "Failed to allocate video device\n");
675 		ret = -ENOMEM;
676 		goto err_video_alloc;
677 	}
678 	mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
679 		V4L2_CAP_STREAMING;
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",
687 		 MDP_MODULE_NAME);
688 	video_set_drvdata(mdp->m2m_vdev, mdp);
689 
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);
694 		goto err_m2m_init;
695 	}
696 
697 	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);
698 	if (ret) {
699 		dev_err(dev, "Failed to register video device\n");
700 		goto err_video_register;
701 	}
702 
703 	v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
704 		  mdp->m2m_vdev->num);
705 	return 0;
706 
707 err_video_register:
708 	v4l2_m2m_release(mdp->m2m_dev);
709 err_m2m_init:
710 	video_device_release(mdp->m2m_vdev);
711 err_video_alloc:
712 
713 	return ret;
714 }
715 
mdp_m2m_device_unregister(struct mdp_dev * mdp)716 void mdp_m2m_device_unregister(struct mdp_dev *mdp)
717 {
718 	video_unregister_device(mdp->m2m_vdev);
719 }
720 
mdp_m2m_job_finish(struct mdp_m2m_ctx * ctx)721 void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
722 {
723 	enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
724 
725 	mdp_m2m_process_done(ctx, vb_state);
726 }
727