xref: /linux/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c (revision 6fd600d742744dc7ef7fc65ca26daa2b1163158a)
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 	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, &param);
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 = &param;
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 	.wait_prepare	= vb2_ops_wait_prepare,
270 	.wait_finish	= vb2_ops_wait_finish,
271 	.buf_prepare	= mdp_m2m_buf_prepare,
272 	.start_streaming = mdp_m2m_start_streaming,
273 	.stop_streaming	= mdp_m2m_stop_streaming,
274 	.buf_queue	= mdp_m2m_buf_queue,
275 	.buf_out_validate = mdp_m2m_buf_out_validate,
276 };
277 
mdp_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)278 static int mdp_m2m_querycap(struct file *file, void *fh,
279 			    struct v4l2_capability *cap)
280 {
281 	strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
282 	strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));
283 
284 	return 0;
285 }
286 
mdp_m2m_enum_fmt_mplane(struct file * file,void * fh,struct v4l2_fmtdesc * f)287 static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
288 				   struct v4l2_fmtdesc *f)
289 {
290 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
291 
292 	return mdp_enum_fmt_mplane(ctx->mdp_dev, f);
293 }
294 
mdp_m2m_g_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)295 static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
296 				struct v4l2_format *f)
297 {
298 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
299 	struct mdp_frame *frame;
300 	struct v4l2_pix_format_mplane *pix_mp;
301 
302 	frame = ctx_get_frame(ctx, f->type);
303 	*f = frame->format;
304 	pix_mp = &f->fmt.pix_mp;
305 	pix_mp->colorspace = ctx->curr_param.colorspace;
306 	pix_mp->xfer_func = ctx->curr_param.xfer_func;
307 	pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;
308 	pix_mp->quantization = ctx->curr_param.quant;
309 
310 	return 0;
311 }
312 
mdp_m2m_s_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)313 static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
314 				struct v4l2_format *f)
315 {
316 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
317 	struct mdp_frame *frame = ctx_get_frame(ctx, f->type);
318 	struct mdp_frame *capture;
319 	const struct mdp_format *fmt;
320 	struct vb2_queue *vq;
321 
322 	fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);
323 	if (!fmt)
324 		return -EINVAL;
325 
326 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
327 	if (vb2_is_busy(vq))
328 		return -EBUSY;
329 
330 	frame->format = *f;
331 	frame->mdp_fmt = fmt;
332 	frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);
333 	frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?
334 		MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;
335 
336 	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
337 	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
338 		capture->crop.c.left = 0;
339 		capture->crop.c.top = 0;
340 		capture->crop.c.width = f->fmt.pix_mp.width;
341 		capture->crop.c.height = f->fmt.pix_mp.height;
342 		ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;
343 		ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
344 		ctx->curr_param.quant = f->fmt.pix_mp.quantization;
345 		ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;
346 	} else {
347 		capture->compose.left = 0;
348 		capture->compose.top = 0;
349 		capture->compose.width = f->fmt.pix_mp.width;
350 		capture->compose.height = f->fmt.pix_mp.height;
351 	}
352 
353 	return 0;
354 }
355 
mdp_m2m_try_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)356 static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
357 				  struct v4l2_format *f)
358 {
359 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
360 
361 	if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))
362 		return -EINVAL;
363 
364 	return 0;
365 }
366 
mdp_m2m_g_selection(struct file * file,void * fh,struct v4l2_selection * s)367 static int mdp_m2m_g_selection(struct file *file, void *fh,
368 			       struct v4l2_selection *s)
369 {
370 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
371 	struct mdp_frame *frame;
372 	bool valid = false;
373 
374 	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
375 		valid = mdp_target_is_crop(s->target);
376 	else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
377 		valid = mdp_target_is_compose(s->target);
378 
379 	if (!valid)
380 		return -EINVAL;
381 
382 	switch (s->target) {
383 	case V4L2_SEL_TGT_CROP:
384 		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
385 			return -EINVAL;
386 		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
387 		s->r = frame->crop.c;
388 		return 0;
389 	case V4L2_SEL_TGT_COMPOSE:
390 		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
391 			return -EINVAL;
392 		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
393 		s->r = frame->compose;
394 		return 0;
395 	case V4L2_SEL_TGT_CROP_DEFAULT:
396 	case V4L2_SEL_TGT_CROP_BOUNDS:
397 		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
398 			return -EINVAL;
399 		frame = ctx_get_frame(ctx, s->type);
400 		s->r.left = 0;
401 		s->r.top = 0;
402 		s->r.width = frame->format.fmt.pix_mp.width;
403 		s->r.height = frame->format.fmt.pix_mp.height;
404 		return 0;
405 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
406 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
407 		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
408 			return -EINVAL;
409 		frame = ctx_get_frame(ctx, s->type);
410 		s->r.left = 0;
411 		s->r.top = 0;
412 		s->r.width = frame->format.fmt.pix_mp.width;
413 		s->r.height = frame->format.fmt.pix_mp.height;
414 		return 0;
415 	}
416 	return -EINVAL;
417 }
418 
mdp_m2m_s_selection(struct file * file,void * fh,struct v4l2_selection * s)419 static int mdp_m2m_s_selection(struct file *file, void *fh,
420 			       struct v4l2_selection *s)
421 {
422 	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
423 	struct mdp_frame *frame = ctx_get_frame(ctx, s->type);
424 	struct mdp_frame *capture;
425 	struct v4l2_rect r;
426 	struct device *dev = &ctx->mdp_dev->pdev->dev;
427 	bool valid = false;
428 	int ret;
429 
430 	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
431 		valid = (s->target == V4L2_SEL_TGT_CROP);
432 	else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
433 		valid = (s->target == V4L2_SEL_TGT_COMPOSE);
434 
435 	if (!valid) {
436 		dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,
437 			ctx->id, s->type, s->target);
438 		return -EINVAL;
439 	}
440 
441 	ret = mdp_try_crop(ctx, &r, s, frame);
442 	if (ret)
443 		return ret;
444 	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
445 
446 	if (mdp_target_is_crop(s->target))
447 		capture->crop.c = r;
448 	else
449 		capture->compose = r;
450 
451 	s->r = r;
452 
453 	return 0;
454 }
455 
456 static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {
457 	.vidioc_querycap		= mdp_m2m_querycap,
458 	.vidioc_enum_fmt_vid_cap	= mdp_m2m_enum_fmt_mplane,
459 	.vidioc_enum_fmt_vid_out	= mdp_m2m_enum_fmt_mplane,
460 	.vidioc_g_fmt_vid_cap_mplane	= mdp_m2m_g_fmt_mplane,
461 	.vidioc_g_fmt_vid_out_mplane	= mdp_m2m_g_fmt_mplane,
462 	.vidioc_s_fmt_vid_cap_mplane	= mdp_m2m_s_fmt_mplane,
463 	.vidioc_s_fmt_vid_out_mplane	= mdp_m2m_s_fmt_mplane,
464 	.vidioc_try_fmt_vid_cap_mplane	= mdp_m2m_try_fmt_mplane,
465 	.vidioc_try_fmt_vid_out_mplane	= mdp_m2m_try_fmt_mplane,
466 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
467 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
468 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
469 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
470 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
471 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
472 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
473 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
474 	.vidioc_g_selection		= mdp_m2m_g_selection,
475 	.vidioc_s_selection		= mdp_m2m_s_selection,
476 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
477 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
478 };
479 
mdp_m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)480 static int mdp_m2m_queue_init(void *priv,
481 			      struct vb2_queue *src_vq,
482 			      struct vb2_queue *dst_vq)
483 {
484 	struct mdp_m2m_ctx *ctx = priv;
485 	int ret;
486 
487 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
488 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
489 	src_vq->ops = &mdp_m2m_qops;
490 	src_vq->mem_ops = &vb2_dma_contig_memops;
491 	src_vq->drv_priv = ctx;
492 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
493 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
494 	src_vq->dev = &ctx->mdp_dev->pdev->dev;
495 	src_vq->lock = &ctx->ctx_lock;
496 
497 	ret = vb2_queue_init(src_vq);
498 	if (ret)
499 		return ret;
500 
501 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
502 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
503 	dst_vq->ops = &mdp_m2m_qops;
504 	dst_vq->mem_ops = &vb2_dma_contig_memops;
505 	dst_vq->drv_priv = ctx;
506 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
507 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
508 	dst_vq->dev = &ctx->mdp_dev->pdev->dev;
509 	dst_vq->lock = &ctx->ctx_lock;
510 
511 	return vb2_queue_init(dst_vq);
512 }
513 
mdp_m2m_s_ctrl(struct v4l2_ctrl * ctrl)514 static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
515 {
516 	struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
517 	struct mdp_frame *capture;
518 
519 	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
520 	switch (ctrl->id) {
521 	case V4L2_CID_HFLIP:
522 		capture->hflip = ctrl->val;
523 		break;
524 	case V4L2_CID_VFLIP:
525 		capture->vflip = ctrl->val;
526 		break;
527 	case V4L2_CID_ROTATE:
528 		capture->rotation = ctrl->val;
529 		break;
530 	}
531 
532 	return 0;
533 }
534 
535 static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
536 	.s_ctrl	= mdp_m2m_s_ctrl,
537 };
538 
mdp_m2m_ctrls_create(struct mdp_m2m_ctx * ctx)539 static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
540 {
541 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);
542 	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
543 					     &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,
544 					     0, 1, 1, 0);
545 	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
546 					     &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
547 					     0, 1, 1, 0);
548 	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
549 					      &mdp_m2m_ctrl_ops,
550 					      V4L2_CID_ROTATE, 0, 270, 90, 0);
551 
552 	if (ctx->ctrl_handler.error) {
553 		int err = ctx->ctrl_handler.error;
554 
555 		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
556 		dev_err(&ctx->mdp_dev->pdev->dev,
557 			"Failed to register controls\n");
558 		return err;
559 	}
560 	return 0;
561 }
562 
mdp_m2m_open(struct file * file)563 static int mdp_m2m_open(struct file *file)
564 {
565 	struct video_device *vdev = video_devdata(file);
566 	struct mdp_dev *mdp = video_get_drvdata(vdev);
567 	struct mdp_m2m_ctx *ctx;
568 	struct device *dev = &mdp->pdev->dev;
569 	int ret;
570 	struct v4l2_format default_format = {};
571 	const struct mdp_limit *limit = mdp->mdp_data->def_limit;
572 
573 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
574 	if (!ctx)
575 		return -ENOMEM;
576 
577 	if (mutex_lock_interruptible(&mdp->m2m_lock)) {
578 		ret = -ERESTARTSYS;
579 		goto err_free_ctx;
580 	}
581 
582 	ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
583 	if (ret < 0)
584 		goto err_unlock_mutex;
585 	ctx->id = ret;
586 
587 	ctx->mdp_dev = mdp;
588 
589 	v4l2_fh_init(&ctx->fh, vdev);
590 	file->private_data = &ctx->fh;
591 	ret = mdp_m2m_ctrls_create(ctx);
592 	if (ret)
593 		goto err_exit_fh;
594 
595 	/* Use separate control handler per file handle */
596 	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
597 	v4l2_fh_add(&ctx->fh);
598 
599 	mutex_init(&ctx->ctx_lock);
600 	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);
601 	if (IS_ERR(ctx->m2m_ctx)) {
602 		dev_err(dev, "Failed to initialize m2m context\n");
603 		ret = PTR_ERR(ctx->m2m_ctx);
604 		goto err_release_handler;
605 	}
606 	ctx->fh.m2m_ctx = ctx->m2m_ctx;
607 
608 	ctx->curr_param.ctx = ctx;
609 	ret = mdp_frameparam_init(mdp, &ctx->curr_param);
610 	if (ret) {
611 		dev_err(dev, "Failed to initialize mdp parameter\n");
612 		goto err_release_m2m_ctx;
613 	}
614 
615 	mutex_unlock(&mdp->m2m_lock);
616 
617 	/* Default format */
618 	default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
619 	default_format.fmt.pix_mp.width = limit->out_limit.wmin;
620 	default_format.fmt.pix_mp.height = limit->out_limit.hmin;
621 	default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
622 	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
623 	default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
624 	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
625 
626 	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
627 
628 	return 0;
629 
630 err_release_m2m_ctx:
631 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
632 err_release_handler:
633 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
634 	v4l2_fh_del(&ctx->fh);
635 err_exit_fh:
636 	v4l2_fh_exit(&ctx->fh);
637 	ida_free(&mdp->mdp_ida, ctx->id);
638 err_unlock_mutex:
639 	mutex_unlock(&mdp->m2m_lock);
640 err_free_ctx:
641 	kfree(ctx);
642 
643 	return ret;
644 }
645 
mdp_m2m_release(struct file * file)646 static int mdp_m2m_release(struct file *file)
647 {
648 	struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);
649 	struct mdp_dev *mdp = video_drvdata(file);
650 	struct device *dev = &mdp->pdev->dev;
651 
652 	mutex_lock(&mdp->m2m_lock);
653 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
654 	if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT))
655 		mdp_vpu_put_locked(mdp);
656 
657 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
658 	v4l2_fh_del(&ctx->fh);
659 	v4l2_fh_exit(&ctx->fh);
660 	ida_free(&mdp->mdp_ida, ctx->id);
661 	mutex_unlock(&mdp->m2m_lock);
662 
663 	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
664 	kfree(ctx);
665 
666 	return 0;
667 }
668 
669 static const struct v4l2_file_operations mdp_m2m_fops = {
670 	.owner		= THIS_MODULE,
671 	.poll		= v4l2_m2m_fop_poll,
672 	.unlocked_ioctl	= video_ioctl2,
673 	.mmap		= v4l2_m2m_fop_mmap,
674 	.open		= mdp_m2m_open,
675 	.release	= mdp_m2m_release,
676 };
677 
678 static const struct v4l2_m2m_ops mdp_m2m_ops = {
679 	.device_run	= mdp_m2m_device_run,
680 };
681 
mdp_m2m_device_register(struct mdp_dev * mdp)682 int mdp_m2m_device_register(struct mdp_dev *mdp)
683 {
684 	struct device *dev = &mdp->pdev->dev;
685 	int ret = 0;
686 
687 	mdp->m2m_vdev = video_device_alloc();
688 	if (!mdp->m2m_vdev) {
689 		dev_err(dev, "Failed to allocate video device\n");
690 		ret = -ENOMEM;
691 		goto err_video_alloc;
692 	}
693 	mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
694 		V4L2_CAP_STREAMING;
695 	mdp->m2m_vdev->fops = &mdp_m2m_fops;
696 	mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;
697 	mdp->m2m_vdev->release = mdp_video_device_release;
698 	mdp->m2m_vdev->lock = &mdp->m2m_lock;
699 	mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;
700 	mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;
701 	snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",
702 		 MDP_MODULE_NAME);
703 	video_set_drvdata(mdp->m2m_vdev, mdp);
704 
705 	mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);
706 	if (IS_ERR(mdp->m2m_dev)) {
707 		dev_err(dev, "Failed to initialize v4l2-m2m device\n");
708 		ret = PTR_ERR(mdp->m2m_dev);
709 		goto err_m2m_init;
710 	}
711 
712 	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);
713 	if (ret) {
714 		dev_err(dev, "Failed to register video device\n");
715 		goto err_video_register;
716 	}
717 
718 	v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
719 		  mdp->m2m_vdev->num);
720 	return 0;
721 
722 err_video_register:
723 	v4l2_m2m_release(mdp->m2m_dev);
724 err_m2m_init:
725 	video_device_release(mdp->m2m_vdev);
726 err_video_alloc:
727 
728 	return ret;
729 }
730 
mdp_m2m_device_unregister(struct mdp_dev * mdp)731 void mdp_m2m_device_unregister(struct mdp_dev *mdp)
732 {
733 	video_unregister_device(mdp->m2m_vdev);
734 }
735 
mdp_m2m_job_finish(struct mdp_m2m_ctx * ctx)736 void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
737 {
738 	enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
739 
740 	mdp_m2m_process_done(ctx, vb_state);
741 }
742