• 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-core.h>
28 #include <media/videobuf2-dma-contig.h>
29 
30 #include "fimc-core.h"
31 #include "fimc-reg.h"
32 #include "media-dev.h"
33 
get_m2m_fmt_flags(unsigned int stream_type)34 static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
35 {
36 	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
37 		return FMT_FLAGS_M2M_IN;
38 	else
39 		return FMT_FLAGS_M2M_OUT;
40 }
41 
fimc_m2m_job_finish(struct fimc_ctx * ctx,int vb_state)42 void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
43 {
44 	struct vb2_buffer *src_vb, *dst_vb;
45 
46 	if (!ctx || !ctx->m2m_ctx)
47 		return;
48 
49 	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
50 	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
51 
52 	if (src_vb && dst_vb) {
53 		v4l2_m2m_buf_done(src_vb, vb_state);
54 		v4l2_m2m_buf_done(dst_vb, vb_state);
55 		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
56 				    ctx->m2m_ctx);
57 	}
58 }
59 
60 /* Complete the transaction which has been scheduled for execution. */
fimc_m2m_shutdown(struct fimc_ctx * ctx)61 static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
62 {
63 	struct fimc_dev *fimc = ctx->fimc_dev;
64 	int ret;
65 
66 	if (!fimc_m2m_pending(fimc))
67 		return 0;
68 
69 	fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
70 
71 	ret = wait_event_timeout(fimc->irq_queue,
72 			   !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
73 			   FIMC_SHUTDOWN_TIMEOUT);
74 
75 	return ret == 0 ? -ETIMEDOUT : ret;
76 }
77 
start_streaming(struct vb2_queue * q,unsigned int count)78 static int start_streaming(struct vb2_queue *q, unsigned int count)
79 {
80 	struct fimc_ctx *ctx = q->drv_priv;
81 	int ret;
82 
83 	ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
84 	return ret > 0 ? 0 : ret;
85 }
86 
stop_streaming(struct vb2_queue * q)87 static int stop_streaming(struct vb2_queue *q)
88 {
89 	struct fimc_ctx *ctx = q->drv_priv;
90 	int ret;
91 
92 	ret = fimc_m2m_shutdown(ctx);
93 	if (ret == -ETIMEDOUT)
94 		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
95 
96 	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
97 	return 0;
98 }
99 
fimc_device_run(void * priv)100 static void fimc_device_run(void *priv)
101 {
102 	struct vb2_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->m2m_ctx);
126 	ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
127 	if (ret)
128 		goto dma_unlock;
129 
130 	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
131 	ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
132 	if (ret)
133 		goto dma_unlock;
134 
135 	dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
136 
137 	/* Reconfigure hardware if the context has changed. */
138 	if (fimc->m2m.ctx != ctx) {
139 		ctx->state |= FIMC_PARAMS;
140 		fimc->m2m.ctx = ctx;
141 	}
142 
143 	if (ctx->state & FIMC_PARAMS) {
144 		fimc_set_yuv_order(ctx);
145 		fimc_hw_set_input_path(ctx);
146 		fimc_hw_set_in_dma(ctx);
147 		ret = fimc_set_scaler_info(ctx);
148 		if (ret)
149 			goto dma_unlock;
150 		fimc_hw_set_prescaler(ctx);
151 		fimc_hw_set_mainscaler(ctx);
152 		fimc_hw_set_target_format(ctx);
153 		fimc_hw_set_rotation(ctx);
154 		fimc_hw_set_effect(ctx);
155 		fimc_hw_set_out_dma(ctx);
156 		if (fimc->drv_data->alpha_color)
157 			fimc_hw_set_rgb_alpha(ctx);
158 		fimc_hw_set_output_path(ctx);
159 	}
160 	fimc_hw_set_input_addr(fimc, &sf->paddr);
161 	fimc_hw_set_output_addr(fimc, &df->paddr, -1);
162 
163 	fimc_activate_capture(ctx);
164 	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
165 	fimc_hw_activate_input_dma(fimc, true);
166 
167 dma_unlock:
168 	spin_unlock_irqrestore(&fimc->slock, flags);
169 }
170 
fimc_job_abort(void * priv)171 static void fimc_job_abort(void *priv)
172 {
173 	fimc_m2m_shutdown(priv);
174 }
175 
fimc_queue_setup(struct vb2_queue * vq,const struct v4l2_format * fmt,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],void * allocators[])176 static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
177 			    unsigned int *num_buffers, unsigned int *num_planes,
178 			    unsigned int sizes[], void *allocators[])
179 {
180 	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
181 	struct fimc_frame *f;
182 	int i;
183 
184 	f = ctx_get_frame(ctx, vq->type);
185 	if (IS_ERR(f))
186 		return PTR_ERR(f);
187 	/*
188 	 * Return number of non-contigous planes (plane buffers)
189 	 * depending on the configured color format.
190 	 */
191 	if (!f->fmt)
192 		return -EINVAL;
193 
194 	*num_planes = f->fmt->memplanes;
195 	for (i = 0; i < f->fmt->memplanes; i++) {
196 		sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
197 		allocators[i] = ctx->fimc_dev->alloc_ctx;
198 	}
199 	return 0;
200 }
201 
fimc_buf_prepare(struct vb2_buffer * vb)202 static int fimc_buf_prepare(struct vb2_buffer *vb)
203 {
204 	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
205 	struct fimc_frame *frame;
206 	int i;
207 
208 	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
209 	if (IS_ERR(frame))
210 		return PTR_ERR(frame);
211 
212 	for (i = 0; i < frame->fmt->memplanes; i++)
213 		vb2_set_plane_payload(vb, i, frame->payload[i]);
214 
215 	return 0;
216 }
217 
fimc_buf_queue(struct vb2_buffer * vb)218 static void fimc_buf_queue(struct vb2_buffer *vb)
219 {
220 	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
221 
222 	dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
223 
224 	if (ctx->m2m_ctx)
225 		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
226 }
227 
fimc_lock(struct vb2_queue * vq)228 static void fimc_lock(struct vb2_queue *vq)
229 {
230 	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
231 	mutex_lock(&ctx->fimc_dev->lock);
232 }
233 
fimc_unlock(struct vb2_queue * vq)234 static void fimc_unlock(struct vb2_queue *vq)
235 {
236 	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
237 	mutex_unlock(&ctx->fimc_dev->lock);
238 }
239 
240 static struct vb2_ops fimc_qops = {
241 	.queue_setup	 = fimc_queue_setup,
242 	.buf_prepare	 = fimc_buf_prepare,
243 	.buf_queue	 = fimc_buf_queue,
244 	.wait_prepare	 = fimc_unlock,
245 	.wait_finish	 = fimc_lock,
246 	.stop_streaming	 = stop_streaming,
247 	.start_streaming = start_streaming,
248 };
249 
250 /*
251  * V4L2 ioctl handlers
252  */
fimc_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)253 static int fimc_m2m_querycap(struct file *file, void *fh,
254 				     struct v4l2_capability *cap)
255 {
256 	struct fimc_dev *fimc = video_drvdata(file);
257 	unsigned int caps;
258 
259 	/*
260 	 * This is only a mem-to-mem video device. The capture and output
261 	 * device capability flags are left only for backward compatibility
262 	 * and are scheduled for removal.
263 	 */
264 	caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
265 		V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
266 
267 	__fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps);
268 	return 0;
269 }
270 
fimc_m2m_enum_fmt_mplane(struct file * file,void * priv,struct v4l2_fmtdesc * f)271 static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
272 				    struct v4l2_fmtdesc *f)
273 {
274 	struct fimc_fmt *fmt;
275 
276 	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
277 			       f->index);
278 	if (!fmt)
279 		return -EINVAL;
280 
281 	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
282 	f->pixelformat = fmt->fourcc;
283 	return 0;
284 }
285 
fimc_m2m_g_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)286 static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
287 				 struct v4l2_format *f)
288 {
289 	struct fimc_ctx *ctx = fh_to_ctx(fh);
290 	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
291 
292 	if (IS_ERR(frame))
293 		return PTR_ERR(frame);
294 
295 	__fimc_get_format(frame, f);
296 	return 0;
297 }
298 
fimc_try_fmt_mplane(struct fimc_ctx * ctx,struct v4l2_format * f)299 static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
300 {
301 	struct fimc_dev *fimc = ctx->fimc_dev;
302 	const struct fimc_variant *variant = fimc->variant;
303 	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
304 	struct fimc_fmt *fmt;
305 	u32 max_w, mod_x, mod_y;
306 
307 	if (!IS_M2M(f->type))
308 		return -EINVAL;
309 
310 	fmt = fimc_find_format(&pix->pixelformat, NULL,
311 			       get_m2m_fmt_flags(f->type), 0);
312 	if (WARN(fmt == NULL, "Pixel format lookup failed"))
313 		return -EINVAL;
314 
315 	if (pix->field == V4L2_FIELD_ANY)
316 		pix->field = V4L2_FIELD_NONE;
317 	else if (pix->field != V4L2_FIELD_NONE)
318 		return -EINVAL;
319 
320 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
321 		max_w = variant->pix_limit->scaler_dis_w;
322 		mod_x = ffs(variant->min_inp_pixsize) - 1;
323 	} else {
324 		max_w = variant->pix_limit->out_rot_dis_w;
325 		mod_x = ffs(variant->min_out_pixsize) - 1;
326 	}
327 
328 	if (tiled_fmt(fmt)) {
329 		mod_x = 6; /* 64 x 32 pixels tile */
330 		mod_y = 5;
331 	} else {
332 		if (variant->min_vsize_align == 1)
333 			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
334 		else
335 			mod_y = ffs(variant->min_vsize_align) - 1;
336 	}
337 
338 	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
339 		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
340 
341 	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
342 	return 0;
343 }
344 
fimc_m2m_try_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)345 static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
346 				   struct v4l2_format *f)
347 {
348 	struct fimc_ctx *ctx = fh_to_ctx(fh);
349 	return fimc_try_fmt_mplane(ctx, f);
350 }
351 
__set_frame_format(struct fimc_frame * frame,struct fimc_fmt * fmt,struct v4l2_pix_format_mplane * pixm)352 static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
353 			       struct v4l2_pix_format_mplane *pixm)
354 {
355 	int i;
356 
357 	for (i = 0; i < fmt->colplanes; i++) {
358 		frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
359 		frame->payload[i] = pixm->plane_fmt[i].sizeimage;
360 	}
361 
362 	frame->f_width = pixm->width;
363 	frame->f_height	= pixm->height;
364 	frame->o_width = pixm->width;
365 	frame->o_height = pixm->height;
366 	frame->width = pixm->width;
367 	frame->height = pixm->height;
368 	frame->offs_h = 0;
369 	frame->offs_v = 0;
370 	frame->fmt = fmt;
371 }
372 
fimc_m2m_s_fmt_mplane(struct file * file,void * fh,struct v4l2_format * f)373 static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
374 				 struct v4l2_format *f)
375 {
376 	struct fimc_ctx *ctx = fh_to_ctx(fh);
377 	struct fimc_dev *fimc = ctx->fimc_dev;
378 	struct fimc_fmt *fmt;
379 	struct vb2_queue *vq;
380 	struct fimc_frame *frame;
381 	int ret;
382 
383 	ret = fimc_try_fmt_mplane(ctx, f);
384 	if (ret)
385 		return ret;
386 
387 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
388 
389 	if (vb2_is_busy(vq)) {
390 		v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
391 		return -EBUSY;
392 	}
393 
394 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
395 		frame = &ctx->s_frame;
396 	else
397 		frame = &ctx->d_frame;
398 
399 	fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
400 			       get_m2m_fmt_flags(f->type), 0);
401 	if (!fmt)
402 		return -EINVAL;
403 
404 	__set_frame_format(frame, fmt, &f->fmt.pix_mp);
405 
406 	/* Update RGB Alpha control state and value range */
407 	fimc_alpha_ctrl_update(ctx);
408 
409 	return 0;
410 }
411 
fimc_m2m_reqbufs(struct file * file,void * fh,struct v4l2_requestbuffers * reqbufs)412 static int fimc_m2m_reqbufs(struct file *file, void *fh,
413 			    struct v4l2_requestbuffers *reqbufs)
414 {
415 	struct fimc_ctx *ctx = fh_to_ctx(fh);
416 	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
417 }
418 
fimc_m2m_querybuf(struct file * file,void * fh,struct v4l2_buffer * buf)419 static int fimc_m2m_querybuf(struct file *file, void *fh,
420 			     struct v4l2_buffer *buf)
421 {
422 	struct fimc_ctx *ctx = fh_to_ctx(fh);
423 	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
424 }
425 
fimc_m2m_qbuf(struct file * file,void * fh,struct v4l2_buffer * buf)426 static int fimc_m2m_qbuf(struct file *file, void *fh,
427 			 struct v4l2_buffer *buf)
428 {
429 	struct fimc_ctx *ctx = fh_to_ctx(fh);
430 	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
431 }
432 
fimc_m2m_dqbuf(struct file * file,void * fh,struct v4l2_buffer * buf)433 static int fimc_m2m_dqbuf(struct file *file, void *fh,
434 			  struct v4l2_buffer *buf)
435 {
436 	struct fimc_ctx *ctx = fh_to_ctx(fh);
437 	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
438 }
439 
fimc_m2m_expbuf(struct file * file,void * fh,struct v4l2_exportbuffer * eb)440 static int fimc_m2m_expbuf(struct file *file, void *fh,
441 			    struct v4l2_exportbuffer *eb)
442 {
443 	struct fimc_ctx *ctx = fh_to_ctx(fh);
444 	return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
445 }
446 
447 
fimc_m2m_streamon(struct file * file,void * fh,enum v4l2_buf_type type)448 static int fimc_m2m_streamon(struct file *file, void *fh,
449 			     enum v4l2_buf_type type)
450 {
451 	struct fimc_ctx *ctx = fh_to_ctx(fh);
452 	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
453 }
454 
fimc_m2m_streamoff(struct file * file,void * fh,enum v4l2_buf_type type)455 static int fimc_m2m_streamoff(struct file *file, void *fh,
456 			    enum v4l2_buf_type type)
457 {
458 	struct fimc_ctx *ctx = fh_to_ctx(fh);
459 	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
460 }
461 
fimc_m2m_cropcap(struct file * file,void * fh,struct v4l2_cropcap * cr)462 static int fimc_m2m_cropcap(struct file *file, void *fh,
463 			    struct v4l2_cropcap *cr)
464 {
465 	struct fimc_ctx *ctx = fh_to_ctx(fh);
466 	struct fimc_frame *frame;
467 
468 	frame = ctx_get_frame(ctx, cr->type);
469 	if (IS_ERR(frame))
470 		return PTR_ERR(frame);
471 
472 	cr->bounds.left = 0;
473 	cr->bounds.top = 0;
474 	cr->bounds.width = frame->o_width;
475 	cr->bounds.height = frame->o_height;
476 	cr->defrect = cr->bounds;
477 
478 	return 0;
479 }
480 
fimc_m2m_g_crop(struct file * file,void * fh,struct v4l2_crop * cr)481 static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
482 {
483 	struct fimc_ctx *ctx = fh_to_ctx(fh);
484 	struct fimc_frame *frame;
485 
486 	frame = ctx_get_frame(ctx, cr->type);
487 	if (IS_ERR(frame))
488 		return PTR_ERR(frame);
489 
490 	cr->c.left = frame->offs_h;
491 	cr->c.top = frame->offs_v;
492 	cr->c.width = frame->width;
493 	cr->c.height = frame->height;
494 
495 	return 0;
496 }
497 
fimc_m2m_try_crop(struct fimc_ctx * ctx,struct v4l2_crop * cr)498 static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
499 {
500 	struct fimc_dev *fimc = ctx->fimc_dev;
501 	struct fimc_frame *f;
502 	u32 min_size, halign, depth = 0;
503 	int i;
504 
505 	if (cr->c.top < 0 || cr->c.left < 0) {
506 		v4l2_err(&fimc->m2m.vfd,
507 			"doesn't support negative values for top & left\n");
508 		return -EINVAL;
509 	}
510 	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
511 		f = &ctx->d_frame;
512 	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
513 		f = &ctx->s_frame;
514 	else
515 		return -EINVAL;
516 
517 	min_size = (f == &ctx->s_frame) ?
518 		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
519 
520 	/* Get pixel alignment constraints. */
521 	if (fimc->variant->min_vsize_align == 1)
522 		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
523 	else
524 		halign = ffs(fimc->variant->min_vsize_align) - 1;
525 
526 	for (i = 0; i < f->fmt->colplanes; i++)
527 		depth += f->fmt->depth[i];
528 
529 	v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
530 			      ffs(min_size) - 1,
531 			      &cr->c.height, min_size, f->o_height,
532 			      halign, 64/(ALIGN(depth, 8)));
533 
534 	/* adjust left/top if cropping rectangle is out of bounds */
535 	if (cr->c.left + cr->c.width > f->o_width)
536 		cr->c.left = f->o_width - cr->c.width;
537 	if (cr->c.top + cr->c.height > f->o_height)
538 		cr->c.top = f->o_height - cr->c.height;
539 
540 	cr->c.left = round_down(cr->c.left, min_size);
541 	cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
542 
543 	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
544 	    cr->c.left, cr->c.top, cr->c.width, cr->c.height,
545 	    f->f_width, f->f_height);
546 
547 	return 0;
548 }
549 
fimc_m2m_s_crop(struct file * file,void * fh,const struct v4l2_crop * crop)550 static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
551 {
552 	struct fimc_ctx *ctx = fh_to_ctx(fh);
553 	struct fimc_dev *fimc = ctx->fimc_dev;
554 	struct v4l2_crop cr = *crop;
555 	struct fimc_frame *f;
556 	int ret;
557 
558 	ret = fimc_m2m_try_crop(ctx, &cr);
559 	if (ret)
560 		return ret;
561 
562 	f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
563 		&ctx->s_frame : &ctx->d_frame;
564 
565 	/* Check to see if scaling ratio is within supported range */
566 	if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
567 		ret = fimc_check_scaler_ratio(ctx, cr.c.width,
568 				cr.c.height, ctx->d_frame.width,
569 				ctx->d_frame.height, ctx->rotation);
570 	} else {
571 		ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
572 				ctx->s_frame.height, cr.c.width,
573 				cr.c.height, ctx->rotation);
574 	}
575 	if (ret) {
576 		v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
577 		return -EINVAL;
578 	}
579 
580 	f->offs_h = cr.c.left;
581 	f->offs_v = cr.c.top;
582 	f->width  = cr.c.width;
583 	f->height = cr.c.height;
584 
585 	fimc_ctx_state_set(FIMC_PARAMS, ctx);
586 
587 	return 0;
588 }
589 
590 static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
591 	.vidioc_querycap		= fimc_m2m_querycap,
592 	.vidioc_enum_fmt_vid_cap_mplane	= fimc_m2m_enum_fmt_mplane,
593 	.vidioc_enum_fmt_vid_out_mplane	= fimc_m2m_enum_fmt_mplane,
594 	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
595 	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
596 	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
597 	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
598 	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
599 	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
600 	.vidioc_reqbufs			= fimc_m2m_reqbufs,
601 	.vidioc_querybuf		= fimc_m2m_querybuf,
602 	.vidioc_qbuf			= fimc_m2m_qbuf,
603 	.vidioc_dqbuf			= fimc_m2m_dqbuf,
604 	.vidioc_expbuf			= fimc_m2m_expbuf,
605 	.vidioc_streamon		= fimc_m2m_streamon,
606 	.vidioc_streamoff		= fimc_m2m_streamoff,
607 	.vidioc_g_crop			= fimc_m2m_g_crop,
608 	.vidioc_s_crop			= fimc_m2m_s_crop,
609 	.vidioc_cropcap			= fimc_m2m_cropcap
610 
611 };
612 
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)613 static int queue_init(void *priv, struct vb2_queue *src_vq,
614 		      struct vb2_queue *dst_vq)
615 {
616 	struct fimc_ctx *ctx = priv;
617 	int ret;
618 
619 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
620 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
621 	src_vq->drv_priv = ctx;
622 	src_vq->ops = &fimc_qops;
623 	src_vq->mem_ops = &vb2_dma_contig_memops;
624 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
625 	src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
626 
627 	ret = vb2_queue_init(src_vq);
628 	if (ret)
629 		return ret;
630 
631 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
632 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
633 	dst_vq->drv_priv = ctx;
634 	dst_vq->ops = &fimc_qops;
635 	dst_vq->mem_ops = &vb2_dma_contig_memops;
636 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
637 	dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
638 
639 	return vb2_queue_init(dst_vq);
640 }
641 
fimc_m2m_set_default_format(struct fimc_ctx * ctx)642 static int fimc_m2m_set_default_format(struct fimc_ctx *ctx)
643 {
644 	struct v4l2_pix_format_mplane pixm = {
645 		.pixelformat	= V4L2_PIX_FMT_RGB32,
646 		.width		= 800,
647 		.height		= 600,
648 		.plane_fmt[0]	= {
649 			.bytesperline = 800 * 4,
650 			.sizeimage = 800 * 4 * 600,
651 		},
652 	};
653 	struct fimc_fmt *fmt;
654 
655 	fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0);
656 	if (!fmt)
657 		return -EINVAL;
658 
659 	__set_frame_format(&ctx->s_frame, fmt, &pixm);
660 	__set_frame_format(&ctx->d_frame, fmt, &pixm);
661 
662 	return 0;
663 }
664 
fimc_m2m_open(struct file * file)665 static int fimc_m2m_open(struct file *file)
666 {
667 	struct fimc_dev *fimc = video_drvdata(file);
668 	struct fimc_ctx *ctx;
669 	int ret = -EBUSY;
670 
671 	pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state);
672 
673 	if (mutex_lock_interruptible(&fimc->lock))
674 		return -ERESTARTSYS;
675 	/*
676 	 * Don't allow simultaneous open() of the mem-to-mem and the
677 	 * capture video node that belong to same FIMC IP instance.
678 	 */
679 	if (test_bit(ST_CAPT_BUSY, &fimc->state))
680 		goto unlock;
681 
682 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
683 	if (!ctx) {
684 		ret = -ENOMEM;
685 		goto unlock;
686 	}
687 	v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd);
688 	ctx->fimc_dev = fimc;
689 
690 	/* Default color format */
691 	ctx->s_frame.fmt = fimc_get_format(0);
692 	ctx->d_frame.fmt = fimc_get_format(0);
693 
694 	ret = fimc_ctrls_create(ctx);
695 	if (ret)
696 		goto error_fh;
697 
698 	/* Use separate control handler per file handle */
699 	ctx->fh.ctrl_handler = &ctx->ctrls.handler;
700 	file->private_data = &ctx->fh;
701 	v4l2_fh_add(&ctx->fh);
702 
703 	/* Setup the device context for memory-to-memory mode */
704 	ctx->state = FIMC_CTX_M2M;
705 	ctx->flags = 0;
706 	ctx->in_path = FIMC_IO_DMA;
707 	ctx->out_path = FIMC_IO_DMA;
708 	ctx->scaler.enabled = 1;
709 
710 	ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
711 	if (IS_ERR(ctx->m2m_ctx)) {
712 		ret = PTR_ERR(ctx->m2m_ctx);
713 		goto error_c;
714 	}
715 
716 	if (fimc->m2m.refcnt++ == 0)
717 		set_bit(ST_M2M_RUN, &fimc->state);
718 
719 	ret = fimc_m2m_set_default_format(ctx);
720 	if (ret < 0)
721 		goto error_m2m_ctx;
722 
723 	mutex_unlock(&fimc->lock);
724 	return 0;
725 
726 error_m2m_ctx:
727 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
728 error_c:
729 	fimc_ctrls_delete(ctx);
730 error_fh:
731 	v4l2_fh_del(&ctx->fh);
732 	v4l2_fh_exit(&ctx->fh);
733 	kfree(ctx);
734 unlock:
735 	mutex_unlock(&fimc->lock);
736 	return ret;
737 }
738 
fimc_m2m_release(struct file * file)739 static int fimc_m2m_release(struct file *file)
740 {
741 	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
742 	struct fimc_dev *fimc = ctx->fimc_dev;
743 
744 	dbg("pid: %d, state: 0x%lx, refcnt= %d",
745 		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
746 
747 	mutex_lock(&fimc->lock);
748 
749 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
750 	fimc_ctrls_delete(ctx);
751 	v4l2_fh_del(&ctx->fh);
752 	v4l2_fh_exit(&ctx->fh);
753 
754 	if (--fimc->m2m.refcnt <= 0)
755 		clear_bit(ST_M2M_RUN, &fimc->state);
756 	kfree(ctx);
757 
758 	mutex_unlock(&fimc->lock);
759 	return 0;
760 }
761 
fimc_m2m_poll(struct file * file,struct poll_table_struct * wait)762 static unsigned int fimc_m2m_poll(struct file *file,
763 				  struct poll_table_struct *wait)
764 {
765 	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
766 	struct fimc_dev *fimc = ctx->fimc_dev;
767 	int ret;
768 
769 	if (mutex_lock_interruptible(&fimc->lock))
770 		return -ERESTARTSYS;
771 
772 	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
773 	mutex_unlock(&fimc->lock);
774 
775 	return ret;
776 }
777 
778 
fimc_m2m_mmap(struct file * file,struct vm_area_struct * vma)779 static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
780 {
781 	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
782 	struct fimc_dev *fimc = ctx->fimc_dev;
783 	int ret;
784 
785 	if (mutex_lock_interruptible(&fimc->lock))
786 		return -ERESTARTSYS;
787 
788 	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
789 	mutex_unlock(&fimc->lock);
790 
791 	return ret;
792 }
793 
794 static const struct v4l2_file_operations fimc_m2m_fops = {
795 	.owner		= THIS_MODULE,
796 	.open		= fimc_m2m_open,
797 	.release	= fimc_m2m_release,
798 	.poll		= fimc_m2m_poll,
799 	.unlocked_ioctl	= video_ioctl2,
800 	.mmap		= fimc_m2m_mmap,
801 };
802 
803 static struct v4l2_m2m_ops m2m_ops = {
804 	.device_run	= fimc_device_run,
805 	.job_abort	= fimc_job_abort,
806 };
807 
fimc_register_m2m_device(struct fimc_dev * fimc,struct v4l2_device * v4l2_dev)808 int fimc_register_m2m_device(struct fimc_dev *fimc,
809 			     struct v4l2_device *v4l2_dev)
810 {
811 	struct video_device *vfd = &fimc->m2m.vfd;
812 	int ret;
813 
814 	fimc->v4l2_dev = v4l2_dev;
815 
816 	memset(vfd, 0, sizeof(*vfd));
817 	vfd->fops = &fimc_m2m_fops;
818 	vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
819 	vfd->v4l2_dev = v4l2_dev;
820 	vfd->minor = -1;
821 	vfd->release = video_device_release_empty;
822 	vfd->lock = &fimc->lock;
823 	vfd->vfl_dir = VFL_DIR_M2M;
824 
825 	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
826 	video_set_drvdata(vfd, fimc);
827 
828 	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
829 	if (IS_ERR(fimc->m2m.m2m_dev)) {
830 		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
831 		return PTR_ERR(fimc->m2m.m2m_dev);
832 	}
833 
834 	ret = media_entity_init(&vfd->entity, 0, NULL, 0);
835 	if (ret)
836 		goto err_me;
837 
838 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
839 	if (ret)
840 		goto err_vd;
841 
842 	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
843 		  vfd->name, video_device_node_name(vfd));
844 	return 0;
845 
846 err_vd:
847 	media_entity_cleanup(&vfd->entity);
848 err_me:
849 	v4l2_m2m_release(fimc->m2m.m2m_dev);
850 	return ret;
851 }
852 
fimc_unregister_m2m_device(struct fimc_dev * fimc)853 void fimc_unregister_m2m_device(struct fimc_dev *fimc)
854 {
855 	if (!fimc)
856 		return;
857 
858 	if (fimc->m2m.m2m_dev)
859 		v4l2_m2m_release(fimc->m2m.m2m_dev);
860 
861 	if (video_is_registered(&fimc->m2m.vfd)) {
862 		video_unregister_device(&fimc->m2m.vfd);
863 		media_entity_cleanup(&fimc->m2m.vfd.entity);
864 	}
865 }
866