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
13static 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
18static 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
23static 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
32static 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
37static 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
42static 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
61static 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 (atomic_read(&ctx->mdp_dev->job_count)) {
108		ret = wait_event_timeout(ctx->mdp_dev->callback_wq,
109					 !atomic_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				atomic_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
128worker_end:
129	mdp_m2m_process_done(ctx, vb_state);
130}
131
132static 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
179static 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
190static 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
202static 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
229static 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
248static 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
257static 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
267static 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
278static 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
287static 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
295static 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
313static 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
356static 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
367static 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
419static 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
456static 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
480static 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
514static 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
535static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
536	.s_ctrl	= mdp_m2m_s_ctrl,
537};
538
539static 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
563static 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
630err_release_m2m_ctx:
631	v4l2_m2m_ctx_release(ctx->m2m_ctx);
632err_release_handler:
633	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
634	v4l2_fh_del(&ctx->fh);
635err_exit_fh:
636	v4l2_fh_exit(&ctx->fh);
637	ida_free(&mdp->mdp_ida, ctx->id);
638err_unlock_mutex:
639	mutex_unlock(&mdp->m2m_lock);
640err_free_ctx:
641	kfree(ctx);
642
643	return ret;
644}
645
646static 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
669static 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
678static const struct v4l2_m2m_ops mdp_m2m_ops = {
679	.device_run	= mdp_m2m_device_run,
680};
681
682int 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
722err_video_register:
723	v4l2_m2m_release(mdp->m2m_dev);
724err_m2m_init:
725	video_device_release(mdp->m2m_vdev);
726err_video_alloc:
727
728	return ret;
729}
730
731void mdp_m2m_device_unregister(struct mdp_dev *mdp)
732{
733	video_unregister_device(mdp->m2m_vdev);
734}
735
736void 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