• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for Renesas R-Car VIN
4  *
5  * Copyright (C) 2016 Renesas Electronics Corp.
6  * Copyright (C) 2011-2013 Renesas Solutions Corp.
7  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
8  * Copyright (C) 2008 Magnus Damm
9  *
10  * Based on the soc-camera rcar_vin driver
11  */
12 
13 #include <linux/pm_runtime.h>
14 
15 #include <media/v4l2-event.h>
16 #include <media/v4l2-ioctl.h>
17 #include <media/v4l2-mc.h>
18 #include <media/v4l2-rect.h>
19 
20 #include "rcar-vin.h"
21 
22 #define RVIN_DEFAULT_FORMAT	V4L2_PIX_FMT_YUYV
23 #define RVIN_DEFAULT_WIDTH	800
24 #define RVIN_DEFAULT_HEIGHT	600
25 #define RVIN_DEFAULT_FIELD	V4L2_FIELD_NONE
26 #define RVIN_DEFAULT_COLORSPACE	V4L2_COLORSPACE_SRGB
27 
28 /* -----------------------------------------------------------------------------
29  * Format Conversions
30  */
31 
32 static const struct rvin_video_format rvin_formats[] = {
33 	{
34 		.fourcc			= V4L2_PIX_FMT_NV16,
35 		.bpp			= 1,
36 	},
37 	{
38 		.fourcc			= V4L2_PIX_FMT_YUYV,
39 		.bpp			= 2,
40 	},
41 	{
42 		.fourcc			= V4L2_PIX_FMT_UYVY,
43 		.bpp			= 2,
44 	},
45 	{
46 		.fourcc			= V4L2_PIX_FMT_RGB565,
47 		.bpp			= 2,
48 	},
49 	{
50 		.fourcc			= V4L2_PIX_FMT_XRGB555,
51 		.bpp			= 2,
52 	},
53 	{
54 		.fourcc			= V4L2_PIX_FMT_XBGR32,
55 		.bpp			= 4,
56 	},
57 };
58 
rvin_format_from_pixel(u32 pixelformat)59 const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat)
60 {
61 	int i;
62 
63 	for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
64 		if (rvin_formats[i].fourcc == pixelformat)
65 			return rvin_formats + i;
66 
67 	return NULL;
68 }
69 
rvin_format_bytesperline(struct v4l2_pix_format * pix)70 static u32 rvin_format_bytesperline(struct v4l2_pix_format *pix)
71 {
72 	const struct rvin_video_format *fmt;
73 
74 	fmt = rvin_format_from_pixel(pix->pixelformat);
75 
76 	if (WARN_ON(!fmt))
77 		return -EINVAL;
78 
79 	return pix->width * fmt->bpp;
80 }
81 
rvin_format_sizeimage(struct v4l2_pix_format * pix)82 static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
83 {
84 	if (pix->pixelformat == V4L2_PIX_FMT_NV16)
85 		return pix->bytesperline * pix->height * 2;
86 
87 	return pix->bytesperline * pix->height;
88 }
89 
rvin_format_align(struct rvin_dev * vin,struct v4l2_pix_format * pix)90 static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
91 {
92 	u32 walign;
93 
94 	if (!rvin_format_from_pixel(pix->pixelformat) ||
95 	    (vin->info->model == RCAR_M1 &&
96 	     pix->pixelformat == V4L2_PIX_FMT_XBGR32))
97 		pix->pixelformat = RVIN_DEFAULT_FORMAT;
98 
99 	switch (pix->field) {
100 	case V4L2_FIELD_TOP:
101 	case V4L2_FIELD_BOTTOM:
102 	case V4L2_FIELD_NONE:
103 	case V4L2_FIELD_INTERLACED_TB:
104 	case V4L2_FIELD_INTERLACED_BT:
105 	case V4L2_FIELD_INTERLACED:
106 		break;
107 	case V4L2_FIELD_ALTERNATE:
108 		/*
109 		 * Driver does not (yet) support outputting ALTERNATE to a
110 		 * userspace. It does support outputting INTERLACED so use
111 		 * the VIN hardware to combine the two fields.
112 		 */
113 		pix->field = V4L2_FIELD_INTERLACED;
114 		pix->height *= 2;
115 		break;
116 	default:
117 		pix->field = RVIN_DEFAULT_FIELD;
118 		break;
119 	}
120 
121 	/* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
122 	walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
123 
124 	/* Limit to VIN capabilities */
125 	v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
126 			      &pix->height, 4, vin->info->max_height, 2, 0);
127 
128 	pix->bytesperline = rvin_format_bytesperline(pix);
129 	pix->sizeimage = rvin_format_sizeimage(pix);
130 
131 	vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
132 		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
133 }
134 
135 /* -----------------------------------------------------------------------------
136  * V4L2
137  */
138 
rvin_reset_format(struct rvin_dev * vin)139 static int rvin_reset_format(struct rvin_dev *vin)
140 {
141 	struct v4l2_subdev_format fmt = {
142 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
143 		.pad = vin->parallel->source_pad,
144 	};
145 	int ret;
146 
147 	ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
148 	if (ret)
149 		return ret;
150 
151 	v4l2_fill_pix_format(&vin->format, &fmt.format);
152 
153 	rvin_format_align(vin, &vin->format);
154 
155 	vin->source.top = 0;
156 	vin->source.left = 0;
157 	vin->source.width = vin->format.width;
158 	vin->source.height = vin->format.height;
159 
160 	vin->crop = vin->source;
161 	vin->compose = vin->source;
162 
163 	return 0;
164 }
165 
rvin_try_format(struct rvin_dev * vin,u32 which,struct v4l2_pix_format * pix,struct v4l2_rect * crop,struct v4l2_rect * compose)166 static int rvin_try_format(struct rvin_dev *vin, u32 which,
167 			   struct v4l2_pix_format *pix,
168 			   struct v4l2_rect *crop, struct v4l2_rect *compose)
169 {
170 	struct v4l2_subdev *sd = vin_to_source(vin);
171 	struct v4l2_subdev_pad_config *pad_cfg;
172 	struct v4l2_subdev_format format = {
173 		.which = which,
174 		.pad = vin->parallel->source_pad,
175 	};
176 	enum v4l2_field field;
177 	u32 width, height;
178 	int ret;
179 
180 	pad_cfg = v4l2_subdev_alloc_pad_config(sd);
181 	if (pad_cfg == NULL)
182 		return -ENOMEM;
183 
184 	if (!rvin_format_from_pixel(pix->pixelformat) ||
185 	    (vin->info->model == RCAR_M1 &&
186 	     pix->pixelformat == V4L2_PIX_FMT_XBGR32))
187 		pix->pixelformat = RVIN_DEFAULT_FORMAT;
188 
189 	v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
190 
191 	/* Allow the video device to override field and to scale */
192 	field = pix->field;
193 	width = pix->width;
194 	height = pix->height;
195 
196 	ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
197 	if (ret < 0 && ret != -ENOIOCTLCMD)
198 		goto done;
199 	ret = 0;
200 
201 	v4l2_fill_pix_format(pix, &format.format);
202 
203 	if (crop) {
204 		crop->top = 0;
205 		crop->left = 0;
206 		crop->width = pix->width;
207 		crop->height = pix->height;
208 
209 		/*
210 		 * If source is ALTERNATE the driver will use the VIN hardware
211 		 * to INTERLACE it. The crop height then needs to be doubled.
212 		 */
213 		if (pix->field == V4L2_FIELD_ALTERNATE)
214 			crop->height *= 2;
215 	}
216 
217 	if (field != V4L2_FIELD_ANY)
218 		pix->field = field;
219 
220 	pix->width = width;
221 	pix->height = height;
222 
223 	rvin_format_align(vin, pix);
224 
225 	if (compose) {
226 		compose->top = 0;
227 		compose->left = 0;
228 		compose->width = pix->width;
229 		compose->height = pix->height;
230 	}
231 done:
232 	v4l2_subdev_free_pad_config(pad_cfg);
233 
234 	return ret;
235 }
236 
rvin_querycap(struct file * file,void * priv,struct v4l2_capability * cap)237 static int rvin_querycap(struct file *file, void *priv,
238 			 struct v4l2_capability *cap)
239 {
240 	struct rvin_dev *vin = video_drvdata(file);
241 
242 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
243 	strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card));
244 	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
245 		 dev_name(vin->dev));
246 	return 0;
247 }
248 
rvin_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)249 static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
250 				struct v4l2_format *f)
251 {
252 	struct rvin_dev *vin = video_drvdata(file);
253 
254 	return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
255 			       NULL);
256 }
257 
rvin_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)258 static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
259 			      struct v4l2_format *f)
260 {
261 	struct rvin_dev *vin = video_drvdata(file);
262 	struct v4l2_rect crop, compose;
263 	int ret;
264 
265 	if (vb2_is_busy(&vin->queue))
266 		return -EBUSY;
267 
268 	ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
269 			      &crop, &compose);
270 	if (ret)
271 		return ret;
272 
273 	vin->format = f->fmt.pix;
274 	vin->crop = crop;
275 	vin->compose = compose;
276 	vin->source = crop;
277 
278 	return 0;
279 }
280 
rvin_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)281 static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
282 			      struct v4l2_format *f)
283 {
284 	struct rvin_dev *vin = video_drvdata(file);
285 
286 	f->fmt.pix = vin->format;
287 
288 	return 0;
289 }
290 
rvin_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)291 static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
292 				 struct v4l2_fmtdesc *f)
293 {
294 	if (f->index >= ARRAY_SIZE(rvin_formats))
295 		return -EINVAL;
296 
297 	f->pixelformat = rvin_formats[f->index].fourcc;
298 
299 	return 0;
300 }
301 
rvin_g_selection(struct file * file,void * fh,struct v4l2_selection * s)302 static int rvin_g_selection(struct file *file, void *fh,
303 			    struct v4l2_selection *s)
304 {
305 	struct rvin_dev *vin = video_drvdata(file);
306 
307 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
308 		return -EINVAL;
309 
310 	switch (s->target) {
311 	case V4L2_SEL_TGT_CROP_BOUNDS:
312 	case V4L2_SEL_TGT_CROP_DEFAULT:
313 		s->r.left = s->r.top = 0;
314 		s->r.width = vin->source.width;
315 		s->r.height = vin->source.height;
316 		break;
317 	case V4L2_SEL_TGT_CROP:
318 		s->r = vin->crop;
319 		break;
320 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
321 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
322 		s->r.left = s->r.top = 0;
323 		s->r.width = vin->format.width;
324 		s->r.height = vin->format.height;
325 		break;
326 	case V4L2_SEL_TGT_COMPOSE:
327 		s->r = vin->compose;
328 		break;
329 	default:
330 		return -EINVAL;
331 	}
332 
333 	return 0;
334 }
335 
rvin_s_selection(struct file * file,void * fh,struct v4l2_selection * s)336 static int rvin_s_selection(struct file *file, void *fh,
337 			    struct v4l2_selection *s)
338 {
339 	struct rvin_dev *vin = video_drvdata(file);
340 	const struct rvin_video_format *fmt;
341 	struct v4l2_rect r = s->r;
342 	struct v4l2_rect max_rect;
343 	struct v4l2_rect min_rect = {
344 		.width = 6,
345 		.height = 2,
346 	};
347 
348 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
349 		return -EINVAL;
350 
351 	v4l2_rect_set_min_size(&r, &min_rect);
352 
353 	switch (s->target) {
354 	case V4L2_SEL_TGT_CROP:
355 		/* Can't crop outside of source input */
356 		max_rect.top = max_rect.left = 0;
357 		max_rect.width = vin->source.width;
358 		max_rect.height = vin->source.height;
359 		v4l2_rect_map_inside(&r, &max_rect);
360 
361 		v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
362 				      &r.height, 2, vin->source.height, 0, 0);
363 
364 		r.top  = clamp_t(s32, r.top, 0, vin->source.height - r.height);
365 		r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
366 
367 		vin->crop = s->r = r;
368 
369 		vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
370 			r.width, r.height, r.left, r.top,
371 			vin->source.width, vin->source.height);
372 		break;
373 	case V4L2_SEL_TGT_COMPOSE:
374 		/* Make sure compose rect fits inside output format */
375 		max_rect.top = max_rect.left = 0;
376 		max_rect.width = vin->format.width;
377 		max_rect.height = vin->format.height;
378 		v4l2_rect_map_inside(&r, &max_rect);
379 
380 		/*
381 		 * Composing is done by adding a offset to the buffer address,
382 		 * the HW wants this address to be aligned to HW_BUFFER_MASK.
383 		 * Make sure the top and left values meets this requirement.
384 		 */
385 		while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
386 			r.top--;
387 
388 		fmt = rvin_format_from_pixel(vin->format.pixelformat);
389 		while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
390 			r.left--;
391 
392 		vin->compose = s->r = r;
393 
394 		vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
395 			r.width, r.height, r.left, r.top,
396 			vin->format.width, vin->format.height);
397 		break;
398 	default:
399 		return -EINVAL;
400 	}
401 
402 	/* HW supports modifying configuration while running */
403 	rvin_crop_scale_comp(vin);
404 
405 	return 0;
406 }
407 
rvin_cropcap(struct file * file,void * priv,struct v4l2_cropcap * crop)408 static int rvin_cropcap(struct file *file, void *priv,
409 			struct v4l2_cropcap *crop)
410 {
411 	struct rvin_dev *vin = video_drvdata(file);
412 	struct v4l2_subdev *sd = vin_to_source(vin);
413 
414 	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
415 		return -EINVAL;
416 
417 	return v4l2_subdev_call(sd, video, g_pixelaspect, &crop->pixelaspect);
418 }
419 
rvin_enum_input(struct file * file,void * priv,struct v4l2_input * i)420 static int rvin_enum_input(struct file *file, void *priv,
421 			   struct v4l2_input *i)
422 {
423 	struct rvin_dev *vin = video_drvdata(file);
424 	struct v4l2_subdev *sd = vin_to_source(vin);
425 	int ret;
426 
427 	if (i->index != 0)
428 		return -EINVAL;
429 
430 	ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
431 	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
432 		return ret;
433 
434 	i->type = V4L2_INPUT_TYPE_CAMERA;
435 
436 	if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
437 		i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
438 		i->std = 0;
439 	} else {
440 		i->capabilities = V4L2_IN_CAP_STD;
441 		i->std = vin->vdev.tvnorms;
442 	}
443 
444 	strlcpy(i->name, "Camera", sizeof(i->name));
445 
446 	return 0;
447 }
448 
rvin_g_input(struct file * file,void * priv,unsigned int * i)449 static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
450 {
451 	*i = 0;
452 	return 0;
453 }
454 
rvin_s_input(struct file * file,void * priv,unsigned int i)455 static int rvin_s_input(struct file *file, void *priv, unsigned int i)
456 {
457 	if (i > 0)
458 		return -EINVAL;
459 	return 0;
460 }
461 
rvin_querystd(struct file * file,void * priv,v4l2_std_id * a)462 static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
463 {
464 	struct rvin_dev *vin = video_drvdata(file);
465 	struct v4l2_subdev *sd = vin_to_source(vin);
466 
467 	return v4l2_subdev_call(sd, video, querystd, a);
468 }
469 
rvin_s_std(struct file * file,void * priv,v4l2_std_id a)470 static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
471 {
472 	struct rvin_dev *vin = video_drvdata(file);
473 	int ret;
474 
475 	ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
476 	if (ret < 0)
477 		return ret;
478 
479 	vin->std = a;
480 
481 	/* Changing the standard will change the width/height */
482 	return rvin_reset_format(vin);
483 }
484 
rvin_g_std(struct file * file,void * priv,v4l2_std_id * a)485 static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
486 {
487 	struct rvin_dev *vin = video_drvdata(file);
488 
489 	if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
490 		return -ENOIOCTLCMD;
491 
492 	*a = vin->std;
493 
494 	return 0;
495 }
496 
rvin_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)497 static int rvin_subscribe_event(struct v4l2_fh *fh,
498 				const struct v4l2_event_subscription *sub)
499 {
500 	switch (sub->type) {
501 	case V4L2_EVENT_SOURCE_CHANGE:
502 		return v4l2_event_subscribe(fh, sub, 4, NULL);
503 	}
504 	return v4l2_ctrl_subscribe_event(fh, sub);
505 }
506 
rvin_enum_dv_timings(struct file * file,void * priv_fh,struct v4l2_enum_dv_timings * timings)507 static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
508 				struct v4l2_enum_dv_timings *timings)
509 {
510 	struct rvin_dev *vin = video_drvdata(file);
511 	struct v4l2_subdev *sd = vin_to_source(vin);
512 	int ret;
513 
514 	if (timings->pad)
515 		return -EINVAL;
516 
517 	timings->pad = vin->parallel->sink_pad;
518 
519 	ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
520 
521 	timings->pad = 0;
522 
523 	return ret;
524 }
525 
rvin_s_dv_timings(struct file * file,void * priv_fh,struct v4l2_dv_timings * timings)526 static int rvin_s_dv_timings(struct file *file, void *priv_fh,
527 			     struct v4l2_dv_timings *timings)
528 {
529 	struct rvin_dev *vin = video_drvdata(file);
530 	struct v4l2_subdev *sd = vin_to_source(vin);
531 	int ret;
532 
533 	ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
534 	if (ret)
535 		return ret;
536 
537 	/* Changing the timings will change the width/height */
538 	return rvin_reset_format(vin);
539 }
540 
rvin_g_dv_timings(struct file * file,void * priv_fh,struct v4l2_dv_timings * timings)541 static int rvin_g_dv_timings(struct file *file, void *priv_fh,
542 			     struct v4l2_dv_timings *timings)
543 {
544 	struct rvin_dev *vin = video_drvdata(file);
545 	struct v4l2_subdev *sd = vin_to_source(vin);
546 
547 	return v4l2_subdev_call(sd, video, g_dv_timings, timings);
548 }
549 
rvin_query_dv_timings(struct file * file,void * priv_fh,struct v4l2_dv_timings * timings)550 static int rvin_query_dv_timings(struct file *file, void *priv_fh,
551 				 struct v4l2_dv_timings *timings)
552 {
553 	struct rvin_dev *vin = video_drvdata(file);
554 	struct v4l2_subdev *sd = vin_to_source(vin);
555 
556 	return v4l2_subdev_call(sd, video, query_dv_timings, timings);
557 }
558 
rvin_dv_timings_cap(struct file * file,void * priv_fh,struct v4l2_dv_timings_cap * cap)559 static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
560 			       struct v4l2_dv_timings_cap *cap)
561 {
562 	struct rvin_dev *vin = video_drvdata(file);
563 	struct v4l2_subdev *sd = vin_to_source(vin);
564 	int ret;
565 
566 	if (cap->pad)
567 		return -EINVAL;
568 
569 	cap->pad = vin->parallel->sink_pad;
570 
571 	ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
572 
573 	cap->pad = 0;
574 
575 	return ret;
576 }
577 
rvin_g_edid(struct file * file,void * fh,struct v4l2_edid * edid)578 static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
579 {
580 	struct rvin_dev *vin = video_drvdata(file);
581 	struct v4l2_subdev *sd = vin_to_source(vin);
582 	int ret;
583 
584 	if (edid->pad)
585 		return -EINVAL;
586 
587 	edid->pad = vin->parallel->sink_pad;
588 
589 	ret = v4l2_subdev_call(sd, pad, get_edid, edid);
590 
591 	edid->pad = 0;
592 
593 	return ret;
594 }
595 
rvin_s_edid(struct file * file,void * fh,struct v4l2_edid * edid)596 static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
597 {
598 	struct rvin_dev *vin = video_drvdata(file);
599 	struct v4l2_subdev *sd = vin_to_source(vin);
600 	int ret;
601 
602 	if (edid->pad)
603 		return -EINVAL;
604 
605 	edid->pad = vin->parallel->sink_pad;
606 
607 	ret = v4l2_subdev_call(sd, pad, set_edid, edid);
608 
609 	edid->pad = 0;
610 
611 	return ret;
612 }
613 
614 static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
615 	.vidioc_querycap		= rvin_querycap,
616 	.vidioc_try_fmt_vid_cap		= rvin_try_fmt_vid_cap,
617 	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
618 	.vidioc_s_fmt_vid_cap		= rvin_s_fmt_vid_cap,
619 	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,
620 
621 	.vidioc_g_selection		= rvin_g_selection,
622 	.vidioc_s_selection		= rvin_s_selection,
623 
624 	.vidioc_cropcap			= rvin_cropcap,
625 
626 	.vidioc_enum_input		= rvin_enum_input,
627 	.vidioc_g_input			= rvin_g_input,
628 	.vidioc_s_input			= rvin_s_input,
629 
630 	.vidioc_dv_timings_cap		= rvin_dv_timings_cap,
631 	.vidioc_enum_dv_timings		= rvin_enum_dv_timings,
632 	.vidioc_g_dv_timings		= rvin_g_dv_timings,
633 	.vidioc_s_dv_timings		= rvin_s_dv_timings,
634 	.vidioc_query_dv_timings	= rvin_query_dv_timings,
635 
636 	.vidioc_g_edid			= rvin_g_edid,
637 	.vidioc_s_edid			= rvin_s_edid,
638 
639 	.vidioc_querystd		= rvin_querystd,
640 	.vidioc_g_std			= rvin_g_std,
641 	.vidioc_s_std			= rvin_s_std,
642 
643 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
644 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
645 	.vidioc_querybuf		= vb2_ioctl_querybuf,
646 	.vidioc_qbuf			= vb2_ioctl_qbuf,
647 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
648 	.vidioc_expbuf			= vb2_ioctl_expbuf,
649 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
650 	.vidioc_streamon		= vb2_ioctl_streamon,
651 	.vidioc_streamoff		= vb2_ioctl_streamoff,
652 
653 	.vidioc_log_status		= v4l2_ctrl_log_status,
654 	.vidioc_subscribe_event		= rvin_subscribe_event,
655 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
656 };
657 
658 /* -----------------------------------------------------------------------------
659  * V4L2 Media Controller
660  */
661 
rvin_mc_try_format(struct rvin_dev * vin,struct v4l2_pix_format * pix)662 static void rvin_mc_try_format(struct rvin_dev *vin,
663 			       struct v4l2_pix_format *pix)
664 {
665 	/*
666 	 * The V4L2 specification clearly documents the colorspace fields
667 	 * as being set by drivers for capture devices. Using the values
668 	 * supplied by userspace thus wouldn't comply with the API. Until
669 	 * the API is updated force fixed vaules.
670 	 */
671 	pix->colorspace = RVIN_DEFAULT_COLORSPACE;
672 	pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
673 	pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
674 	pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
675 							  pix->ycbcr_enc);
676 
677 	rvin_format_align(vin, pix);
678 }
679 
rvin_mc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)680 static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
681 				   struct v4l2_format *f)
682 {
683 	struct rvin_dev *vin = video_drvdata(file);
684 
685 	rvin_mc_try_format(vin, &f->fmt.pix);
686 
687 	return 0;
688 }
689 
rvin_mc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)690 static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
691 				 struct v4l2_format *f)
692 {
693 	struct rvin_dev *vin = video_drvdata(file);
694 
695 	if (vb2_is_busy(&vin->queue))
696 		return -EBUSY;
697 
698 	rvin_mc_try_format(vin, &f->fmt.pix);
699 
700 	vin->format = f->fmt.pix;
701 
702 	vin->crop.top = 0;
703 	vin->crop.left = 0;
704 	vin->crop.width = vin->format.width;
705 	vin->crop.height = vin->format.height;
706 	vin->compose = vin->crop;
707 
708 	return 0;
709 }
710 
rvin_mc_enum_input(struct file * file,void * priv,struct v4l2_input * i)711 static int rvin_mc_enum_input(struct file *file, void *priv,
712 			      struct v4l2_input *i)
713 {
714 	if (i->index != 0)
715 		return -EINVAL;
716 
717 	i->type = V4L2_INPUT_TYPE_CAMERA;
718 	strlcpy(i->name, "Camera", sizeof(i->name));
719 
720 	return 0;
721 }
722 
723 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
724 	.vidioc_querycap		= rvin_querycap,
725 	.vidioc_try_fmt_vid_cap		= rvin_mc_try_fmt_vid_cap,
726 	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
727 	.vidioc_s_fmt_vid_cap		= rvin_mc_s_fmt_vid_cap,
728 	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,
729 
730 	.vidioc_enum_input		= rvin_mc_enum_input,
731 	.vidioc_g_input			= rvin_g_input,
732 	.vidioc_s_input			= rvin_s_input,
733 
734 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
735 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
736 	.vidioc_querybuf		= vb2_ioctl_querybuf,
737 	.vidioc_qbuf			= vb2_ioctl_qbuf,
738 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
739 	.vidioc_expbuf			= vb2_ioctl_expbuf,
740 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
741 	.vidioc_streamon		= vb2_ioctl_streamon,
742 	.vidioc_streamoff		= vb2_ioctl_streamoff,
743 
744 	.vidioc_log_status		= v4l2_ctrl_log_status,
745 	.vidioc_subscribe_event		= rvin_subscribe_event,
746 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
747 };
748 
749 /* -----------------------------------------------------------------------------
750  * File Operations
751  */
752 
rvin_power_on(struct rvin_dev * vin)753 static int rvin_power_on(struct rvin_dev *vin)
754 {
755 	int ret;
756 	struct v4l2_subdev *sd = vin_to_source(vin);
757 
758 	pm_runtime_get_sync(vin->v4l2_dev.dev);
759 
760 	ret = v4l2_subdev_call(sd, core, s_power, 1);
761 	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
762 		return ret;
763 	return 0;
764 }
765 
rvin_power_off(struct rvin_dev * vin)766 static int rvin_power_off(struct rvin_dev *vin)
767 {
768 	int ret;
769 	struct v4l2_subdev *sd = vin_to_source(vin);
770 
771 	ret = v4l2_subdev_call(sd, core, s_power, 0);
772 
773 	pm_runtime_put(vin->v4l2_dev.dev);
774 
775 	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
776 		return ret;
777 
778 	return 0;
779 }
780 
rvin_initialize_device(struct file * file)781 static int rvin_initialize_device(struct file *file)
782 {
783 	struct rvin_dev *vin = video_drvdata(file);
784 	int ret;
785 
786 	struct v4l2_format f = {
787 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
788 		.fmt.pix = {
789 			.width		= vin->format.width,
790 			.height		= vin->format.height,
791 			.field		= vin->format.field,
792 			.colorspace	= vin->format.colorspace,
793 			.pixelformat	= vin->format.pixelformat,
794 		},
795 	};
796 
797 	ret = rvin_power_on(vin);
798 	if (ret < 0)
799 		return ret;
800 
801 	pm_runtime_enable(&vin->vdev.dev);
802 	ret = pm_runtime_resume(&vin->vdev.dev);
803 	if (ret < 0 && ret != -ENOSYS)
804 		goto eresume;
805 
806 	/*
807 	 * Try to configure with default parameters. Notice: this is the
808 	 * very first open, so, we cannot race against other calls,
809 	 * apart from someone else calling open() simultaneously, but
810 	 * .host_lock is protecting us against it.
811 	 */
812 	ret = rvin_s_fmt_vid_cap(file, NULL, &f);
813 	if (ret < 0)
814 		goto esfmt;
815 
816 	v4l2_ctrl_handler_setup(&vin->ctrl_handler);
817 
818 	return 0;
819 esfmt:
820 	pm_runtime_disable(&vin->vdev.dev);
821 eresume:
822 	rvin_power_off(vin);
823 
824 	return ret;
825 }
826 
rvin_open(struct file * file)827 static int rvin_open(struct file *file)
828 {
829 	struct rvin_dev *vin = video_drvdata(file);
830 	int ret;
831 
832 	mutex_lock(&vin->lock);
833 
834 	file->private_data = vin;
835 
836 	ret = v4l2_fh_open(file);
837 	if (ret)
838 		goto unlock;
839 
840 	if (!v4l2_fh_is_singular_file(file))
841 		goto unlock;
842 
843 	if (rvin_initialize_device(file)) {
844 		v4l2_fh_release(file);
845 		ret = -ENODEV;
846 	}
847 
848 unlock:
849 	mutex_unlock(&vin->lock);
850 	return ret;
851 }
852 
rvin_release(struct file * file)853 static int rvin_release(struct file *file)
854 {
855 	struct rvin_dev *vin = video_drvdata(file);
856 	bool fh_singular;
857 	int ret;
858 
859 	mutex_lock(&vin->lock);
860 
861 	/* Save the singular status before we call the clean-up helper */
862 	fh_singular = v4l2_fh_is_singular_file(file);
863 
864 	/* the release helper will cleanup any on-going streaming */
865 	ret = _vb2_fop_release(file, NULL);
866 
867 	/*
868 	 * If this was the last open file.
869 	 * Then de-initialize hw module.
870 	 */
871 	if (fh_singular) {
872 		pm_runtime_suspend(&vin->vdev.dev);
873 		pm_runtime_disable(&vin->vdev.dev);
874 		rvin_power_off(vin);
875 	}
876 
877 	mutex_unlock(&vin->lock);
878 
879 	return ret;
880 }
881 
882 static const struct v4l2_file_operations rvin_fops = {
883 	.owner		= THIS_MODULE,
884 	.unlocked_ioctl	= video_ioctl2,
885 	.open		= rvin_open,
886 	.release	= rvin_release,
887 	.poll		= vb2_fop_poll,
888 	.mmap		= vb2_fop_mmap,
889 	.read		= vb2_fop_read,
890 };
891 
892 /* -----------------------------------------------------------------------------
893  * Media controller file operations
894  */
895 
rvin_mc_open(struct file * file)896 static int rvin_mc_open(struct file *file)
897 {
898 	struct rvin_dev *vin = video_drvdata(file);
899 	int ret;
900 
901 	ret = mutex_lock_interruptible(&vin->lock);
902 	if (ret)
903 		return ret;
904 
905 	ret = pm_runtime_get_sync(vin->dev);
906 	if (ret < 0)
907 		goto err_unlock;
908 
909 	ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
910 	if (ret < 0)
911 		goto err_pm;
912 
913 	file->private_data = vin;
914 
915 	ret = v4l2_fh_open(file);
916 	if (ret)
917 		goto err_v4l2pm;
918 
919 	mutex_unlock(&vin->lock);
920 
921 	return 0;
922 err_v4l2pm:
923 	v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
924 err_pm:
925 	pm_runtime_put(vin->dev);
926 err_unlock:
927 	mutex_unlock(&vin->lock);
928 
929 	return ret;
930 }
931 
rvin_mc_release(struct file * file)932 static int rvin_mc_release(struct file *file)
933 {
934 	struct rvin_dev *vin = video_drvdata(file);
935 	int ret;
936 
937 	mutex_lock(&vin->lock);
938 
939 	/* the release helper will cleanup any on-going streaming. */
940 	ret = _vb2_fop_release(file, NULL);
941 
942 	v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
943 	pm_runtime_put(vin->dev);
944 
945 	mutex_unlock(&vin->lock);
946 
947 	return ret;
948 }
949 
950 static const struct v4l2_file_operations rvin_mc_fops = {
951 	.owner		= THIS_MODULE,
952 	.unlocked_ioctl	= video_ioctl2,
953 	.open		= rvin_mc_open,
954 	.release	= rvin_mc_release,
955 	.poll		= vb2_fop_poll,
956 	.mmap		= vb2_fop_mmap,
957 	.read		= vb2_fop_read,
958 };
959 
rvin_v4l2_unregister(struct rvin_dev * vin)960 void rvin_v4l2_unregister(struct rvin_dev *vin)
961 {
962 	if (!video_is_registered(&vin->vdev))
963 		return;
964 
965 	v4l2_info(&vin->v4l2_dev, "Removing %s\n",
966 		  video_device_node_name(&vin->vdev));
967 
968 	/* Checks internaly if vdev have been init or not */
969 	video_unregister_device(&vin->vdev);
970 }
971 
rvin_notify(struct v4l2_subdev * sd,unsigned int notification,void * arg)972 static void rvin_notify(struct v4l2_subdev *sd,
973 			unsigned int notification, void *arg)
974 {
975 	struct rvin_dev *vin =
976 		container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
977 
978 	switch (notification) {
979 	case V4L2_DEVICE_NOTIFY_EVENT:
980 		v4l2_event_queue(&vin->vdev, arg);
981 		break;
982 	default:
983 		break;
984 	}
985 }
986 
rvin_v4l2_register(struct rvin_dev * vin)987 int rvin_v4l2_register(struct rvin_dev *vin)
988 {
989 	struct video_device *vdev = &vin->vdev;
990 	int ret;
991 
992 	vin->v4l2_dev.notify = rvin_notify;
993 
994 	/* video node */
995 	vdev->v4l2_dev = &vin->v4l2_dev;
996 	vdev->queue = &vin->queue;
997 	snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
998 	vdev->release = video_device_release_empty;
999 	vdev->lock = &vin->lock;
1000 	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
1001 		V4L2_CAP_READWRITE;
1002 
1003 	/* Set a default format */
1004 	vin->format.pixelformat	= RVIN_DEFAULT_FORMAT;
1005 	vin->format.width = RVIN_DEFAULT_WIDTH;
1006 	vin->format.height = RVIN_DEFAULT_HEIGHT;
1007 	vin->format.field = RVIN_DEFAULT_FIELD;
1008 	vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
1009 
1010 	if (vin->info->use_mc) {
1011 		vdev->fops = &rvin_mc_fops;
1012 		vdev->ioctl_ops = &rvin_mc_ioctl_ops;
1013 	} else {
1014 		vdev->fops = &rvin_fops;
1015 		vdev->ioctl_ops = &rvin_ioctl_ops;
1016 		rvin_reset_format(vin);
1017 	}
1018 
1019 	rvin_format_align(vin, &vin->format);
1020 
1021 	ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
1022 	if (ret) {
1023 		vin_err(vin, "Failed to register video device\n");
1024 		return ret;
1025 	}
1026 
1027 	video_set_drvdata(&vin->vdev, vin);
1028 
1029 	v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
1030 		  video_device_node_name(&vin->vdev));
1031 
1032 	return ret;
1033 }
1034