1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
4  *
5  * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
6  * Sylwester Nawrocki <s.nawrocki@samsung.com>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/errno.h>
13 #include <linux/bug.h>
14 #include <linux/interrupt.h>
15 #include <linux/device.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/list.h>
19 #include <linux/io.h>
20 #include <linux/slab.h>
21 #include <linux/clk.h>
22 #include <media/v4l2-ioctl.h>
23 #include <media/videobuf2-v4l2.h>
24 #include <media/videobuf2-dma-contig.h>
25 
26 #include "common.h"
27 #include "fimc-core.h"
28 #include "fimc-reg.h"
29 #include "media-dev.h"
30 
get_m2m_fmt_flags(unsigned int stream_type)31 static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
32 {
33 	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
34 		return FMT_FLAGS_M2M_IN;
35 	else
36 		return FMT_FLAGS_M2M_OUT;
37 }
38 
fimc_m2m_job_finish(struct fimc_ctx * ctx,int vb_state)39 void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
40 {
41 	struct vb2_v4l2_buffer *src_vb, *dst_vb;
42 
43 	if (!ctx || !ctx->fh.m2m_ctx)
44 		return;
45 
46 	src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
47 	dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
48 
49 	if (src_vb)
50 		v4l2_m2m_buf_done(src_vb, vb_state);
51 	if (dst_vb)
52 		v4l2_m2m_buf_done(dst_vb, vb_state);
53 	if (src_vb && dst_vb)
54 		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
55 				    ctx->fh.m2m_ctx);
56 }
57 
58 /* Complete the transaction which has been scheduled for execution. */
fimc_m2m_shutdown(struct fimc_ctx * ctx)59 static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
60 {
61 	struct fimc_dev *fimc = ctx->fimc_dev;
62 
63 	if (!fimc_m2m_pending(fimc))
64 		return;
65 
66 	fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
67 
68 	wait_event_timeout(fimc->irq_queue,
69 			!fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
70 			FIMC_SHUTDOWN_TIMEOUT);
71 }
72 
start_streaming(struct vb2_queue * q,unsigned int count)73 static int start_streaming(struct vb2_queue *q, unsigned int count)
74 {
75 	struct fimc_ctx *ctx = q->drv_priv;
76 	int ret;
77 
78 	ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
79 	return ret > 0 ? 0 : ret;
80 }
81 
stop_streaming(struct vb2_queue * q)82 static void stop_streaming(struct vb2_queue *q)
83 {
84 	struct fimc_ctx *ctx = q->drv_priv;
85 
86 
87 	fimc_m2m_shutdown(ctx);
88 	fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
89 	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
90 }
91 
fimc_device_run(void * priv)92 static void fimc_device_run(void *priv)
93 {
94 	struct vb2_v4l2_buffer *src_vb, *dst_vb;
95 	struct fimc_ctx *ctx = priv;
96 	struct fimc_frame *sf, *df;
97 	struct fimc_dev *fimc;
98 	unsigned long flags;
99 	int ret;
100 
101 	if (WARN(!ctx, "Null context\n"))
102 		return;
103 
104 	fimc = ctx->fimc_dev;
105 	spin_lock_irqsave(&fimc->slock, flags);
106 
107 	set_bit(ST_M2M_PEND, &fimc->state);
108 	sf = &ctx->s_frame;
109 	df = &ctx->d_frame;
110 
111 	if (ctx->state & FIMC_PARAMS) {
112 		/* Prepare the DMA offsets for scaler */
113 		fimc_prepare_dma_offset(ctx, sf);
114 		fimc_prepare_dma_offset(ctx, df);
115 	}
116 
117 	src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
118 	ret = fimc_prepare_addr(ctx, &src_vb->vb2_buf, sf, &sf->paddr);
119 	if (ret)
120 		goto dma_unlock;
121 
122 	dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
123 	ret = fimc_prepare_addr(ctx, &dst_vb->vb2_buf, df, &df->paddr);
124 	if (ret)
125 		goto dma_unlock;
126 
127 	dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
128 	dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
129 	dst_vb->flags |=
130 		src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
131 
132 	/* Reconfigure hardware if the context has changed. */
133 	if (fimc->m2m.ctx != ctx) {
134 		ctx->state |= FIMC_PARAMS;
135 		fimc->m2m.ctx = ctx;
136 	}
137 
138 	if (ctx->state & FIMC_PARAMS) {
139 		fimc_set_yuv_order(ctx);
140 		fimc_hw_set_input_path(ctx);
141 		fimc_hw_set_in_dma(ctx);
142 		ret = fimc_set_scaler_info(ctx);
143 		if (ret)
144 			goto dma_unlock;
145 		fimc_hw_set_prescaler(ctx);
146 		fimc_hw_set_mainscaler(ctx);
147 		fimc_hw_set_target_format(ctx);
148 		fimc_hw_set_rotation(ctx);
149 		fimc_hw_set_effect(ctx);
150 		fimc_hw_set_out_dma(ctx);
151 		if (fimc->drv_data->alpha_color)
152 			fimc_hw_set_rgb_alpha(ctx);
153 		fimc_hw_set_output_path(ctx);
154 	}
155 	fimc_hw_set_input_addr(fimc, &sf->paddr);
156 	fimc_hw_set_output_addr(fimc, &df->paddr, -1);
157 
158 	fimc_activate_capture(ctx);
159 	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
160 	fimc_hw_activate_input_dma(fimc, true);
161 
162 dma_unlock:
163 	spin_unlock_irqrestore(&fimc->slock, flags);
164 }
165 
fimc_job_abort(void * priv)166 static void fimc_job_abort(void *priv)
167 {
168 	fimc_m2m_shutdown(priv);
169 }
170 
fimc_queue_setup(struct vb2_queue * vq,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])171 static int fimc_queue_setup(struct vb2_queue *vq,
172 			    unsigned int *num_buffers, unsigned int *num_planes,
173 			    unsigned int sizes[], struct device *alloc_devs[])
174 {
175 	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
176 	struct fimc_frame *f;
177 	int i;
178 
179 	f = ctx_get_frame(ctx, vq->type);
180 	if (IS_ERR(f))
181 		return PTR_ERR(f);
182 	/*
183 	 * Return number of non-contiguous planes (plane buffers)
184 	 * depending on the configured color format.
185 	 */
186 	if (!f->fmt)
187 		return -EINVAL;
188 
189 	*num_planes = f->fmt->memplanes;
190 	for (i = 0; i < f->fmt->memplanes; i++)
191 		sizes[i] = f->payload[i];
192 	return 0;
193 }
194 
fimc_buf_prepare(struct vb2_buffer * vb)195 static int fimc_buf_prepare(struct vb2_buffer *vb)
196 {
197 	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
198 	struct fimc_frame *frame;
199 	int i;
200 
201 	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
202 	if (IS_ERR(frame))
203 		return PTR_ERR(frame);
204 
205 	for (i = 0; i < frame->fmt->memplanes; i++)
206 		vb2_set_plane_payload(vb, i, frame->payload[i]);
207 
208 	return 0;
209 }
210 
fimc_buf_queue(struct vb2_buffer * vb)211 static void fimc_buf_queue(struct vb2_buffer *vb)
212 {
213 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
214 	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
215 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
216 }
217 
218 static const struct vb2_ops fimc_qops = {
219 	.queue_setup	 = fimc_queue_setup,
220 	.buf_prepare	 = fimc_buf_prepare,
221 	.buf_queue	 = fimc_buf_queue,
222 	.wait_prepare	 = vb2_ops_wait_prepare,
223 	.wait_finish	 = vb2_ops_wait_finish,
224 	.stop_streaming	 = stop_streaming,
225 	.start_streaming = start_streaming,
226 };
227 
228 /*
229  * V4L2 ioctl handlers
230  */
fimc_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)231 static int fimc_m2m_querycap(struct file *file, void *fh,
232 				     struct v4l2_capability *cap)
233 {
234 	struct fimc_dev *fimc = video_drvdata(file);
235 
236 	__fimc_vidioc_querycap(&fimc->pdev->dev, cap);
237 	return 0;
238 }
239 
fimc_m2m_enum_fmt(struct file * file,void * priv,struct v4l2_fmtdesc * f)240 static int fimc_m2m_enum_fmt(struct file *file, void *priv,
241 			     struct v4l2_fmtdesc *f)
242 {
243 	struct fimc_fmt *fmt;
244 
245 	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
246 			       f->index);
247 	if (!fmt)
248 		return -EINVAL;
249 
250 	f->pixelformat = fmt->fourcc;
251 	return 0;
252 }
253 
fimc_m2m_g_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)254 static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
255 				 struct v4l2_format *f)
256 {
257 	struct fimc_ctx *ctx = fh_to_ctx(fh);
258 	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
259 
260 	if (IS_ERR(frame))
261 		return PTR_ERR(frame);
262 
263 	__fimc_get_format(frame, f);
264 	return 0;
265 }
266 
fimc_try_fmt_mplane(struct fimc_ctx * ctx,struct v4l2_format * f)267 static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
268 {
269 	struct fimc_dev *fimc = ctx->fimc_dev;
270 	const struct fimc_variant *variant = fimc->variant;
271 	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
272 	struct fimc_fmt *fmt;
273 	u32 max_w, mod_x, mod_y;
274 
275 	if (!IS_M2M(f->type))
276 		return -EINVAL;
277 
278 	fmt = fimc_find_format(&pix->pixelformat, NULL,
279 			       get_m2m_fmt_flags(f->type), 0);
280 	if (WARN(fmt == NULL, "Pixel format lookup failed"))
281 		return -EINVAL;
282 
283 	if (pix->field == V4L2_FIELD_ANY)
284 		pix->field = V4L2_FIELD_NONE;
285 	else if (pix->field != V4L2_FIELD_NONE)
286 		return -EINVAL;
287 
288 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
289 		max_w = variant->pix_limit->scaler_dis_w;
290 		mod_x = ffs(variant->min_inp_pixsize) - 1;
291 	} else {
292 		max_w = variant->pix_limit->out_rot_dis_w;
293 		mod_x = ffs(variant->min_out_pixsize) - 1;
294 	}
295 
296 	if (tiled_fmt(fmt)) {
297 		mod_x = 6; /* 64 x 32 pixels tile */
298 		mod_y = 5;
299 	} else {
300 		if (variant->min_vsize_align == 1)
301 			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
302 		else
303 			mod_y = ffs(variant->min_vsize_align) - 1;
304 	}
305 
306 	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
307 		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
308 
309 	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
310 	return 0;
311 }
312 
fimc_m2m_try_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)313 static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
314 				   struct v4l2_format *f)
315 {
316 	struct fimc_ctx *ctx = fh_to_ctx(fh);
317 	return fimc_try_fmt_mplane(ctx, f);
318 }
319 
__set_frame_format(struct fimc_frame * frame,struct fimc_fmt * fmt,struct v4l2_pix_format_mplane * pixm)320 static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
321 			       struct v4l2_pix_format_mplane *pixm)
322 {
323 	int i;
324 
325 	for (i = 0; i < fmt->memplanes; i++) {
326 		frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
327 		frame->payload[i] = pixm->plane_fmt[i].sizeimage;
328 	}
329 
330 	frame->f_width = pixm->width;
331 	frame->f_height	= pixm->height;
332 	frame->o_width = pixm->width;
333 	frame->o_height = pixm->height;
334 	frame->width = pixm->width;
335 	frame->height = pixm->height;
336 	frame->offs_h = 0;
337 	frame->offs_v = 0;
338 	frame->fmt = fmt;
339 }
340 
fimc_m2m_s_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)341 static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
342 				 struct v4l2_format *f)
343 {
344 	struct fimc_ctx *ctx = fh_to_ctx(fh);
345 	struct fimc_dev *fimc = ctx->fimc_dev;
346 	struct fimc_fmt *fmt;
347 	struct vb2_queue *vq;
348 	struct fimc_frame *frame;
349 	int ret;
350 
351 	ret = fimc_try_fmt_mplane(ctx, f);
352 	if (ret)
353 		return ret;
354 
355 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
356 
357 	if (vb2_is_busy(vq)) {
358 		v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
359 		return -EBUSY;
360 	}
361 
362 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
363 		frame = &ctx->s_frame;
364 	else
365 		frame = &ctx->d_frame;
366 
367 	fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
368 			       get_m2m_fmt_flags(f->type), 0);
369 	if (!fmt)
370 		return -EINVAL;
371 
372 	__set_frame_format(frame, fmt, &f->fmt.pix_mp);
373 
374 	/* Update RGB Alpha control state and value range */
375 	fimc_alpha_ctrl_update(ctx);
376 
377 	return 0;
378 }
379 
fimc_m2m_g_selection(struct file * file,void * fh,struct v4l2_selection * s)380 static int fimc_m2m_g_selection(struct file *file, void *fh,
381 				struct v4l2_selection *s)
382 {
383 	struct fimc_ctx *ctx = fh_to_ctx(fh);
384 	struct fimc_frame *frame;
385 
386 	frame = ctx_get_frame(ctx, s->type);
387 	if (IS_ERR(frame))
388 		return PTR_ERR(frame);
389 
390 	switch (s->target) {
391 	case V4L2_SEL_TGT_CROP:
392 	case V4L2_SEL_TGT_CROP_DEFAULT:
393 	case V4L2_SEL_TGT_CROP_BOUNDS:
394 		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
395 			return -EINVAL;
396 		break;
397 	case V4L2_SEL_TGT_COMPOSE:
398 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
399 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
400 		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
401 			return -EINVAL;
402 		break;
403 	default:
404 		return -EINVAL;
405 	}
406 
407 	switch (s->target) {
408 	case V4L2_SEL_TGT_CROP:
409 	case V4L2_SEL_TGT_COMPOSE:
410 		s->r.left = frame->offs_h;
411 		s->r.top = frame->offs_v;
412 		s->r.width = frame->width;
413 		s->r.height = frame->height;
414 		break;
415 	case V4L2_SEL_TGT_CROP_DEFAULT:
416 	case V4L2_SEL_TGT_CROP_BOUNDS:
417 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
418 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
419 		s->r.left = 0;
420 		s->r.top = 0;
421 		s->r.width = frame->o_width;
422 		s->r.height = frame->o_height;
423 		break;
424 	default:
425 		return -EINVAL;
426 	}
427 	return 0;
428 }
429 
fimc_m2m_try_selection(struct fimc_ctx * ctx,struct v4l2_selection * s)430 static int fimc_m2m_try_selection(struct fimc_ctx *ctx,
431 				  struct v4l2_selection *s)
432 {
433 	struct fimc_dev *fimc = ctx->fimc_dev;
434 	struct fimc_frame *f;
435 	u32 min_size, halign, depth = 0;
436 	int i;
437 
438 	if (s->r.top < 0 || s->r.left < 0) {
439 		v4l2_err(&fimc->m2m.vfd,
440 			"doesn't support negative values for top & left\n");
441 		return -EINVAL;
442 	}
443 	if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
444 		f = &ctx->d_frame;
445 		if (s->target != V4L2_SEL_TGT_COMPOSE)
446 			return -EINVAL;
447 	} else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
448 		f = &ctx->s_frame;
449 		if (s->target != V4L2_SEL_TGT_CROP)
450 			return -EINVAL;
451 	} else {
452 		return -EINVAL;
453 	}
454 
455 	min_size = (f == &ctx->s_frame) ?
456 		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
457 
458 	/* Get pixel alignment constraints. */
459 	if (fimc->variant->min_vsize_align == 1)
460 		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
461 	else
462 		halign = ffs(fimc->variant->min_vsize_align) - 1;
463 
464 	for (i = 0; i < f->fmt->memplanes; i++)
465 		depth += f->fmt->depth[i];
466 
467 	v4l_bound_align_image(&s->r.width, min_size, f->o_width,
468 			      ffs(min_size) - 1,
469 			      &s->r.height, min_size, f->o_height,
470 			      halign, 64/(ALIGN(depth, 8)));
471 
472 	/* adjust left/top if cropping rectangle is out of bounds */
473 	if (s->r.left + s->r.width > f->o_width)
474 		s->r.left = f->o_width - s->r.width;
475 	if (s->r.top + s->r.height > f->o_height)
476 		s->r.top = f->o_height - s->r.height;
477 
478 	s->r.left = round_down(s->r.left, min_size);
479 	s->r.top  = round_down(s->r.top, fimc->variant->hor_offs_align);
480 
481 	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
482 	    s->r.left, s->r.top, s->r.width, s->r.height,
483 	    f->f_width, f->f_height);
484 
485 	return 0;
486 }
487 
fimc_m2m_s_selection(struct file * file,void * fh,struct v4l2_selection * s)488 static int fimc_m2m_s_selection(struct file *file, void *fh,
489 				struct v4l2_selection *s)
490 {
491 	struct fimc_ctx *ctx = fh_to_ctx(fh);
492 	struct fimc_dev *fimc = ctx->fimc_dev;
493 	struct fimc_frame *f;
494 	int ret;
495 
496 	ret = fimc_m2m_try_selection(ctx, s);
497 	if (ret)
498 		return ret;
499 
500 	f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
501 		&ctx->s_frame : &ctx->d_frame;
502 
503 	/* Check to see if scaling ratio is within supported range */
504 	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
505 		ret = fimc_check_scaler_ratio(ctx, s->r.width,
506 				s->r.height, ctx->d_frame.width,
507 				ctx->d_frame.height, ctx->rotation);
508 	} else {
509 		ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
510 				ctx->s_frame.height, s->r.width,
511 				s->r.height, ctx->rotation);
512 	}
513 	if (ret) {
514 		v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
515 		return -EINVAL;
516 	}
517 
518 	f->offs_h = s->r.left;
519 	f->offs_v = s->r.top;
520 	f->width  = s->r.width;
521 	f->height = s->r.height;
522 
523 	fimc_ctx_state_set(FIMC_PARAMS, ctx);
524 
525 	return 0;
526 }
527 
528 static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
529 	.vidioc_querycap		= fimc_m2m_querycap,
530 	.vidioc_enum_fmt_vid_cap	= fimc_m2m_enum_fmt,
531 	.vidioc_enum_fmt_vid_out	= fimc_m2m_enum_fmt,
532 	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
533 	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
534 	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
535 	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
536 	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
537 	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
538 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
539 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
540 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
541 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
542 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
543 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
544 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
545 	.vidioc_g_selection		= fimc_m2m_g_selection,
546 	.vidioc_s_selection		= fimc_m2m_s_selection,
547 
548 };
549 
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)550 static int queue_init(void *priv, struct vb2_queue *src_vq,
551 		      struct vb2_queue *dst_vq)
552 {
553 	struct fimc_ctx *ctx = priv;
554 	int ret;
555 
556 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
557 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
558 	src_vq->drv_priv = ctx;
559 	src_vq->ops = &fimc_qops;
560 	src_vq->mem_ops = &vb2_dma_contig_memops;
561 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
562 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
563 	src_vq->lock = &ctx->fimc_dev->lock;
564 	src_vq->dev = &ctx->fimc_dev->pdev->dev;
565 
566 	ret = vb2_queue_init(src_vq);
567 	if (ret)
568 		return ret;
569 
570 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
571 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
572 	dst_vq->drv_priv = ctx;
573 	dst_vq->ops = &fimc_qops;
574 	dst_vq->mem_ops = &vb2_dma_contig_memops;
575 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
576 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
577 	dst_vq->lock = &ctx->fimc_dev->lock;
578 	dst_vq->dev = &ctx->fimc_dev->pdev->dev;
579 
580 	return vb2_queue_init(dst_vq);
581 }
582 
fimc_m2m_set_default_format(struct fimc_ctx * ctx)583 static int fimc_m2m_set_default_format(struct fimc_ctx *ctx)
584 {
585 	struct v4l2_pix_format_mplane pixm = {
586 		.pixelformat	= V4L2_PIX_FMT_RGB32,
587 		.width		= 800,
588 		.height		= 600,
589 		.plane_fmt[0]	= {
590 			.bytesperline = 800 * 4,
591 			.sizeimage = 800 * 4 * 600,
592 		},
593 	};
594 	struct fimc_fmt *fmt;
595 
596 	fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0);
597 	if (!fmt)
598 		return -EINVAL;
599 
600 	__set_frame_format(&ctx->s_frame, fmt, &pixm);
601 	__set_frame_format(&ctx->d_frame, fmt, &pixm);
602 
603 	return 0;
604 }
605 
fimc_m2m_open(struct file * file)606 static int fimc_m2m_open(struct file *file)
607 {
608 	struct fimc_dev *fimc = video_drvdata(file);
609 	struct fimc_ctx *ctx;
610 	int ret = -EBUSY;
611 
612 	pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state);
613 
614 	if (mutex_lock_interruptible(&fimc->lock))
615 		return -ERESTARTSYS;
616 	/*
617 	 * Don't allow simultaneous open() of the mem-to-mem and the
618 	 * capture video node that belong to same FIMC IP instance.
619 	 */
620 	if (test_bit(ST_CAPT_BUSY, &fimc->state))
621 		goto unlock;
622 
623 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
624 	if (!ctx) {
625 		ret = -ENOMEM;
626 		goto unlock;
627 	}
628 	v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd);
629 	ctx->fimc_dev = fimc;
630 
631 	/* Default color format */
632 	ctx->s_frame.fmt = fimc_get_format(0);
633 	ctx->d_frame.fmt = fimc_get_format(0);
634 
635 	ret = fimc_ctrls_create(ctx);
636 	if (ret)
637 		goto error_fh;
638 
639 	/* Use separate control handler per file handle */
640 	ctx->fh.ctrl_handler = &ctx->ctrls.handler;
641 	file->private_data = &ctx->fh;
642 	v4l2_fh_add(&ctx->fh);
643 
644 	/* Setup the device context for memory-to-memory mode */
645 	ctx->state = FIMC_CTX_M2M;
646 	ctx->flags = 0;
647 	ctx->in_path = FIMC_IO_DMA;
648 	ctx->out_path = FIMC_IO_DMA;
649 	ctx->scaler.enabled = 1;
650 
651 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
652 	if (IS_ERR(ctx->fh.m2m_ctx)) {
653 		ret = PTR_ERR(ctx->fh.m2m_ctx);
654 		goto error_c;
655 	}
656 
657 	if (fimc->m2m.refcnt++ == 0)
658 		set_bit(ST_M2M_RUN, &fimc->state);
659 
660 	ret = fimc_m2m_set_default_format(ctx);
661 	if (ret < 0)
662 		goto error_m2m_ctx;
663 
664 	mutex_unlock(&fimc->lock);
665 	return 0;
666 
667 error_m2m_ctx:
668 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
669 error_c:
670 	fimc_ctrls_delete(ctx);
671 	v4l2_fh_del(&ctx->fh);
672 error_fh:
673 	v4l2_fh_exit(&ctx->fh);
674 	kfree(ctx);
675 unlock:
676 	mutex_unlock(&fimc->lock);
677 	return ret;
678 }
679 
fimc_m2m_release(struct file * file)680 static int fimc_m2m_release(struct file *file)
681 {
682 	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
683 	struct fimc_dev *fimc = ctx->fimc_dev;
684 
685 	dbg("pid: %d, state: 0x%lx, refcnt= %d",
686 		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
687 
688 	mutex_lock(&fimc->lock);
689 
690 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
691 	fimc_ctrls_delete(ctx);
692 	v4l2_fh_del(&ctx->fh);
693 	v4l2_fh_exit(&ctx->fh);
694 
695 	if (--fimc->m2m.refcnt <= 0)
696 		clear_bit(ST_M2M_RUN, &fimc->state);
697 	kfree(ctx);
698 
699 	mutex_unlock(&fimc->lock);
700 	return 0;
701 }
702 
703 static const struct v4l2_file_operations fimc_m2m_fops = {
704 	.owner		= THIS_MODULE,
705 	.open		= fimc_m2m_open,
706 	.release	= fimc_m2m_release,
707 	.poll		= v4l2_m2m_fop_poll,
708 	.unlocked_ioctl	= video_ioctl2,
709 	.mmap		= v4l2_m2m_fop_mmap,
710 };
711 
712 static const struct v4l2_m2m_ops m2m_ops = {
713 	.device_run	= fimc_device_run,
714 	.job_abort	= fimc_job_abort,
715 };
716 
fimc_register_m2m_device(struct fimc_dev * fimc,struct v4l2_device * v4l2_dev)717 int fimc_register_m2m_device(struct fimc_dev *fimc,
718 			     struct v4l2_device *v4l2_dev)
719 {
720 	struct video_device *vfd = &fimc->m2m.vfd;
721 	int ret;
722 
723 	fimc->v4l2_dev = v4l2_dev;
724 
725 	memset(vfd, 0, sizeof(*vfd));
726 	vfd->fops = &fimc_m2m_fops;
727 	vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
728 	vfd->v4l2_dev = v4l2_dev;
729 	vfd->minor = -1;
730 	vfd->release = video_device_release_empty;
731 	vfd->lock = &fimc->lock;
732 	vfd->vfl_dir = VFL_DIR_M2M;
733 	vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
734 	set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
735 
736 	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
737 	video_set_drvdata(vfd, fimc);
738 
739 	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
740 	if (IS_ERR(fimc->m2m.m2m_dev)) {
741 		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
742 		return PTR_ERR(fimc->m2m.m2m_dev);
743 	}
744 
745 	ret = media_entity_pads_init(&vfd->entity, 0, NULL);
746 	if (ret)
747 		goto err_me;
748 
749 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
750 	if (ret)
751 		goto err_vd;
752 
753 	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
754 		  vfd->name, video_device_node_name(vfd));
755 	return 0;
756 
757 err_vd:
758 	media_entity_cleanup(&vfd->entity);
759 err_me:
760 	v4l2_m2m_release(fimc->m2m.m2m_dev);
761 	return ret;
762 }
763 
fimc_unregister_m2m_device(struct fimc_dev * fimc)764 void fimc_unregister_m2m_device(struct fimc_dev *fimc)
765 {
766 	if (!fimc)
767 		return;
768 
769 	if (fimc->m2m.m2m_dev)
770 		v4l2_m2m_release(fimc->m2m.m2m_dev);
771 
772 	if (video_is_registered(&fimc->m2m.vfd)) {
773 		video_unregister_device(&fimc->m2m.vfd);
774 		media_entity_cleanup(&fimc->m2m.vfd.entity);
775 	}
776 }
777