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