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
32static const struct rvin_video_format rvin_formats[] = {
33 {
34 .fourcc = V4L2_PIX_FMT_NV12,
35 .bpp = 1,
36 },
37 {
38 .fourcc = V4L2_PIX_FMT_NV16,
39 .bpp = 1,
40 },
41 {
42 .fourcc = V4L2_PIX_FMT_YUYV,
43 .bpp = 2,
44 },
45 {
46 .fourcc = V4L2_PIX_FMT_UYVY,
47 .bpp = 2,
48 },
49 {
50 .fourcc = V4L2_PIX_FMT_RGB565,
51 .bpp = 2,
52 },
53 {
54 .fourcc = V4L2_PIX_FMT_XRGB555,
55 .bpp = 2,
56 },
57 {
58 .fourcc = V4L2_PIX_FMT_XBGR32,
59 .bpp = 4,
60 },
61 {
62 .fourcc = V4L2_PIX_FMT_ARGB555,
63 .bpp = 2,
64 },
65 {
66 .fourcc = V4L2_PIX_FMT_ABGR32,
67 .bpp = 4,
68 },
69 {
70 .fourcc = V4L2_PIX_FMT_SBGGR8,
71 .bpp = 1,
72 },
73 {
74 .fourcc = V4L2_PIX_FMT_SGBRG8,
75 .bpp = 1,
76 },
77 {
78 .fourcc = V4L2_PIX_FMT_SGRBG8,
79 .bpp = 1,
80 },
81 {
82 .fourcc = V4L2_PIX_FMT_SRGGB8,
83 .bpp = 1,
84 },
85 {
86 .fourcc = V4L2_PIX_FMT_GREY,
87 .bpp = 1,
88 },
89 {
90 .fourcc = V4L2_PIX_FMT_SBGGR10,
91 .bpp = 2,
92 },
93 {
94 .fourcc = V4L2_PIX_FMT_SGBRG10,
95 .bpp = 2,
96 },
97 {
98 .fourcc = V4L2_PIX_FMT_SGRBG10,
99 .bpp = 2,
100 },
101 {
102 .fourcc = V4L2_PIX_FMT_SRGGB10,
103 .bpp = 2,
104 },
105};
106
107const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
108 u32 pixelformat)
109{
110 int i;
111
112 switch (pixelformat) {
113 case V4L2_PIX_FMT_XBGR32:
114 if (vin->info->model == RCAR_M1)
115 return NULL;
116 break;
117 case V4L2_PIX_FMT_NV12:
118 /*
119 * If NV12 is supported it's only supported on channels 0, 1, 4,
120 * 5, 8, 9, 12 and 13.
121 */
122 if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
123 return NULL;
124 break;
125 case V4L2_PIX_FMT_SBGGR10:
126 case V4L2_PIX_FMT_SGBRG10:
127 case V4L2_PIX_FMT_SGRBG10:
128 case V4L2_PIX_FMT_SRGGB10:
129 if (!vin->info->raw10)
130 return NULL;
131 break;
132 default:
133 break;
134 }
135
136 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
137 if (rvin_formats[i].fourcc == pixelformat)
138 return rvin_formats + i;
139
140 return NULL;
141}
142
143static u32 rvin_format_bytesperline(struct rvin_dev *vin,
144 struct v4l2_pix_format *pix)
145{
146 const struct rvin_video_format *fmt;
147 u32 align;
148
149 fmt = rvin_format_from_pixel(vin, pixelformat: pix->pixelformat);
150
151 if (WARN_ON(!fmt))
152 return -EINVAL;
153
154 switch (pix->pixelformat) {
155 case V4L2_PIX_FMT_NV12:
156 case V4L2_PIX_FMT_NV16:
157 align = 0x20;
158 break;
159 default:
160 align = 0x10;
161 break;
162 }
163
164 return ALIGN(pix->width, align) * fmt->bpp;
165}
166
167static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
168{
169 switch (pix->pixelformat) {
170 case V4L2_PIX_FMT_NV12:
171 return pix->bytesperline * pix->height * 3 / 2;
172 case V4L2_PIX_FMT_NV16:
173 return pix->bytesperline * pix->height * 2;
174 default:
175 return pix->bytesperline * pix->height;
176 }
177}
178
179static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
180{
181 u32 walign;
182
183 if (!rvin_format_from_pixel(vin, pixelformat: pix->pixelformat))
184 pix->pixelformat = RVIN_DEFAULT_FORMAT;
185
186 switch (pix->field) {
187 case V4L2_FIELD_TOP:
188 case V4L2_FIELD_BOTTOM:
189 case V4L2_FIELD_NONE:
190 case V4L2_FIELD_INTERLACED_TB:
191 case V4L2_FIELD_INTERLACED_BT:
192 case V4L2_FIELD_INTERLACED:
193 case V4L2_FIELD_ALTERNATE:
194 break;
195 default:
196 pix->field = RVIN_DEFAULT_FIELD;
197 break;
198 }
199
200 /* Hardware limits width alignment based on format. */
201 switch (pix->pixelformat) {
202 /* Multiple of 32 (2^5) for NV12/16. */
203 case V4L2_PIX_FMT_NV12:
204 case V4L2_PIX_FMT_NV16:
205 walign = 5;
206 break;
207 /* Multiple of 2 (2^1) for YUV. */
208 case V4L2_PIX_FMT_YUYV:
209 case V4L2_PIX_FMT_UYVY:
210 walign = 1;
211 break;
212 /* No multiple for RGB. */
213 default:
214 walign = 0;
215 break;
216 }
217
218 /* Limit to VIN capabilities */
219 v4l_bound_align_image(width: &pix->width, wmin: 5, wmax: vin->info->max_width, walign,
220 height: &pix->height, hmin: 2, hmax: vin->info->max_height, halign: 0, salign: 0);
221
222 pix->bytesperline = rvin_format_bytesperline(vin, pix);
223 pix->sizeimage = rvin_format_sizeimage(pix);
224
225 vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
226 pix->width, pix->height, pix->bytesperline, pix->sizeimage);
227}
228
229/* -----------------------------------------------------------------------------
230 * V4L2
231 */
232
233static int rvin_reset_format(struct rvin_dev *vin)
234{
235 struct v4l2_subdev_format fmt = {
236 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
237 .pad = vin->parallel.source_pad,
238 };
239 int ret;
240
241 ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
242 if (ret)
243 return ret;
244
245 v4l2_fill_pix_format(pix_fmt: &vin->format, mbus_fmt: &fmt.format);
246
247 vin->crop.top = 0;
248 vin->crop.left = 0;
249 vin->crop.width = vin->format.width;
250 vin->crop.height = vin->format.height;
251
252 /* Make use of the hardware interlacer by default. */
253 if (vin->format.field == V4L2_FIELD_ALTERNATE) {
254 vin->format.field = V4L2_FIELD_INTERLACED;
255 vin->format.height *= 2;
256 }
257
258 rvin_format_align(vin, pix: &vin->format);
259
260 vin->compose.top = 0;
261 vin->compose.left = 0;
262 vin->compose.width = vin->format.width;
263 vin->compose.height = vin->format.height;
264
265 return 0;
266}
267
268static int rvin_try_format(struct rvin_dev *vin, u32 which,
269 struct v4l2_pix_format *pix,
270 struct v4l2_rect *src_rect)
271{
272 struct v4l2_subdev *sd = vin_to_source(vin);
273 struct v4l2_subdev_state *sd_state;
274 static struct lock_class_key key;
275 struct v4l2_subdev_format format = {
276 .which = which,
277 .pad = vin->parallel.source_pad,
278 };
279 enum v4l2_field field;
280 u32 width, height;
281 int ret;
282
283 /*
284 * FIXME: Drop this call, drivers are not supposed to use
285 * __v4l2_subdev_state_alloc().
286 */
287 sd_state = __v4l2_subdev_state_alloc(sd, lock_name: "rvin:state->lock", key: &key);
288 if (IS_ERR(ptr: sd_state))
289 return PTR_ERR(ptr: sd_state);
290
291 if (!rvin_format_from_pixel(vin, pixelformat: pix->pixelformat))
292 pix->pixelformat = RVIN_DEFAULT_FORMAT;
293
294 v4l2_fill_mbus_format(mbus_fmt: &format.format, pix_fmt: pix, code: vin->mbus_code);
295
296 /* Allow the video device to override field and to scale */
297 field = pix->field;
298 width = pix->width;
299 height = pix->height;
300
301 ret = v4l2_subdev_call(sd, pad, set_fmt, sd_state, &format);
302 if (ret < 0 && ret != -ENOIOCTLCMD)
303 goto done;
304 ret = 0;
305
306 v4l2_fill_pix_format(pix_fmt: pix, mbus_fmt: &format.format);
307
308 if (src_rect) {
309 src_rect->top = 0;
310 src_rect->left = 0;
311 src_rect->width = pix->width;
312 src_rect->height = pix->height;
313 }
314
315 if (field != V4L2_FIELD_ANY)
316 pix->field = field;
317
318 pix->width = width;
319 pix->height = height;
320
321 rvin_format_align(vin, pix);
322done:
323 __v4l2_subdev_state_free(state: sd_state);
324
325 return ret;
326}
327
328static int rvin_querycap(struct file *file, void *priv,
329 struct v4l2_capability *cap)
330{
331 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
332 strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
333 return 0;
334}
335
336static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
337 struct v4l2_format *f)
338{
339 struct rvin_dev *vin = video_drvdata(file);
340
341 return rvin_try_format(vin, which: V4L2_SUBDEV_FORMAT_TRY, pix: &f->fmt.pix, NULL);
342}
343
344static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
345 struct v4l2_format *f)
346{
347 struct rvin_dev *vin = video_drvdata(file);
348 struct v4l2_rect fmt_rect, src_rect;
349 int ret;
350
351 if (vb2_is_busy(q: &vin->queue))
352 return -EBUSY;
353
354 ret = rvin_try_format(vin, which: V4L2_SUBDEV_FORMAT_ACTIVE, pix: &f->fmt.pix,
355 src_rect: &src_rect);
356 if (ret)
357 return ret;
358
359 vin->format = f->fmt.pix;
360
361 fmt_rect.top = 0;
362 fmt_rect.left = 0;
363 fmt_rect.width = vin->format.width;
364 fmt_rect.height = vin->format.height;
365
366 v4l2_rect_map_inside(r: &vin->crop, boundary: &src_rect);
367 v4l2_rect_map_inside(r: &vin->compose, boundary: &fmt_rect);
368
369 return 0;
370}
371
372static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
373 struct v4l2_format *f)
374{
375 struct rvin_dev *vin = video_drvdata(file);
376
377 f->fmt.pix = vin->format;
378
379 return 0;
380}
381
382static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
383 struct v4l2_fmtdesc *f)
384{
385 struct rvin_dev *vin = video_drvdata(file);
386 unsigned int i;
387 int matched;
388
389 /*
390 * If mbus_code is set only enumerate supported pixel formats for that
391 * bus code. Converting from YCbCr to RGB and RGB to YCbCr is possible
392 * with VIN, so all supported YCbCr and RGB media bus codes can produce
393 * all of the related pixel formats. If mbus_code is not set enumerate
394 * all possible pixelformats.
395 *
396 * TODO: Once raw MEDIA_BUS_FMT_SRGGB12_1X12 format is added to the
397 * driver this needs to be extended so raw media bus code only result in
398 * raw pixel format.
399 */
400 switch (f->mbus_code) {
401 case 0:
402 case MEDIA_BUS_FMT_YUYV8_1X16:
403 case MEDIA_BUS_FMT_UYVY8_1X16:
404 case MEDIA_BUS_FMT_UYVY8_2X8:
405 case MEDIA_BUS_FMT_UYVY10_2X10:
406 case MEDIA_BUS_FMT_RGB888_1X24:
407 break;
408 case MEDIA_BUS_FMT_SBGGR8_1X8:
409 if (f->index)
410 return -EINVAL;
411 f->pixelformat = V4L2_PIX_FMT_SBGGR8;
412 return 0;
413 case MEDIA_BUS_FMT_SGBRG8_1X8:
414 if (f->index)
415 return -EINVAL;
416 f->pixelformat = V4L2_PIX_FMT_SGBRG8;
417 return 0;
418 case MEDIA_BUS_FMT_SGRBG8_1X8:
419 if (f->index)
420 return -EINVAL;
421 f->pixelformat = V4L2_PIX_FMT_SGRBG8;
422 return 0;
423 case MEDIA_BUS_FMT_SRGGB8_1X8:
424 if (f->index)
425 return -EINVAL;
426 f->pixelformat = V4L2_PIX_FMT_SRGGB8;
427 return 0;
428 case MEDIA_BUS_FMT_SBGGR10_1X10:
429 if (f->index)
430 return -EINVAL;
431 f->pixelformat = V4L2_PIX_FMT_SBGGR10;
432 return 0;
433 case MEDIA_BUS_FMT_SGBRG10_1X10:
434 if (f->index)
435 return -EINVAL;
436 f->pixelformat = V4L2_PIX_FMT_SGBRG10;
437 return 0;
438 case MEDIA_BUS_FMT_SGRBG10_1X10:
439 if (f->index)
440 return -EINVAL;
441 f->pixelformat = V4L2_PIX_FMT_SGRBG10;
442 return 0;
443 case MEDIA_BUS_FMT_SRGGB10_1X10:
444 if (f->index)
445 return -EINVAL;
446 f->pixelformat = V4L2_PIX_FMT_SRGGB10;
447 return 0;
448 default:
449 return -EINVAL;
450 }
451
452 matched = -1;
453 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) {
454 if (rvin_format_from_pixel(vin, pixelformat: rvin_formats[i].fourcc))
455 matched++;
456
457 if (matched == f->index) {
458 f->pixelformat = rvin_formats[i].fourcc;
459 return 0;
460 }
461 }
462
463 return -EINVAL;
464}
465
466static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect)
467{
468 struct v4l2_subdev_format fmt = {
469 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
470 };
471 struct v4l2_subdev *sd;
472 unsigned int index;
473 int ret;
474
475 if (vin->info->use_mc) {
476 struct media_pad *pad = media_pad_remote_pad_first(pad: &vin->pad);
477
478 if (!pad)
479 return -EINVAL;
480
481 sd = media_entity_to_v4l2_subdev(pad->entity);
482 index = pad->index;
483 } else {
484 sd = vin_to_source(vin);
485 index = vin->parallel.source_pad;
486 }
487
488 fmt.pad = index;
489 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
490 if (ret)
491 return ret;
492
493 rect->left = rect->top = 0;
494 rect->width = fmt.format.width;
495 rect->height = fmt.format.height;
496
497 if (fmt.format.field == V4L2_FIELD_ALTERNATE) {
498 switch (vin->format.field) {
499 case V4L2_FIELD_INTERLACED_TB:
500 case V4L2_FIELD_INTERLACED_BT:
501 case V4L2_FIELD_INTERLACED:
502 rect->height *= 2;
503 break;
504 }
505 }
506
507 return 0;
508}
509
510static int rvin_g_selection(struct file *file, void *fh,
511 struct v4l2_selection *s)
512{
513 struct rvin_dev *vin = video_drvdata(file);
514 int ret;
515
516 if (!vin->scaler)
517 return -ENOIOCTLCMD;
518
519 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
520 return -EINVAL;
521
522 switch (s->target) {
523 case V4L2_SEL_TGT_CROP_BOUNDS:
524 case V4L2_SEL_TGT_CROP_DEFAULT:
525 ret = rvin_remote_rectangle(vin, rect: &s->r);
526 if (ret)
527 return ret;
528
529 break;
530 case V4L2_SEL_TGT_CROP:
531 s->r = vin->crop;
532 break;
533 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
534 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
535 s->r.left = s->r.top = 0;
536 s->r.width = vin->format.width;
537 s->r.height = vin->format.height;
538 break;
539 case V4L2_SEL_TGT_COMPOSE:
540 s->r = vin->compose;
541 break;
542 default:
543 return -EINVAL;
544 }
545
546 return 0;
547}
548
549static int rvin_s_selection(struct file *file, void *fh,
550 struct v4l2_selection *s)
551{
552 struct rvin_dev *vin = video_drvdata(file);
553 const struct rvin_video_format *fmt;
554 struct v4l2_rect r = s->r;
555 struct v4l2_rect max_rect;
556 struct v4l2_rect min_rect = {
557 .width = 6,
558 .height = 2,
559 };
560 int ret;
561
562 if (!vin->scaler)
563 return -ENOIOCTLCMD;
564
565 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
566 return -EINVAL;
567
568 v4l2_rect_set_min_size(r: &r, min_size: &min_rect);
569
570 switch (s->target) {
571 case V4L2_SEL_TGT_CROP:
572 /* Can't crop outside of source input */
573 ret = rvin_remote_rectangle(vin, rect: &max_rect);
574 if (ret)
575 return ret;
576
577 v4l2_rect_map_inside(r: &r, boundary: &max_rect);
578
579 v4l_bound_align_image(width: &r.width, wmin: 6, wmax: max_rect.width, walign: 0,
580 height: &r.height, hmin: 2, hmax: max_rect.height, halign: 0, salign: 0);
581
582 r.top = clamp_t(s32, r.top, 0, max_rect.height - r.height);
583 r.left = clamp_t(s32, r.left, 0, max_rect.width - r.width);
584
585 vin->crop = s->r = r;
586
587 vin_dbg(vin, "Cropped (%d,%d)/%ux%u of %dx%d\n",
588 r.left, r.top, r.width, r.height,
589 max_rect.width, max_rect.height);
590 break;
591 case V4L2_SEL_TGT_COMPOSE:
592 /* Make sure compose rect fits inside output format */
593 max_rect.top = max_rect.left = 0;
594 max_rect.width = vin->format.width;
595 max_rect.height = vin->format.height;
596 v4l2_rect_map_inside(r: &r, boundary: &max_rect);
597
598 /*
599 * Composing is done by adding a offset to the buffer address,
600 * the HW wants this address to be aligned to HW_BUFFER_MASK.
601 * Make sure the top and left values meets this requirement.
602 */
603 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
604 r.top--;
605
606 fmt = rvin_format_from_pixel(vin, pixelformat: vin->format.pixelformat);
607 while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
608 r.left--;
609
610 vin->compose = s->r = r;
611
612 vin_dbg(vin, "Compose (%d,%d)/%ux%u in %dx%d\n",
613 r.left, r.top, r.width, r.height,
614 vin->format.width, vin->format.height);
615 break;
616 default:
617 return -EINVAL;
618 }
619
620 /* HW supports modifying configuration while running */
621 rvin_crop_scale_comp(vin);
622
623 return 0;
624}
625
626static int rvin_g_parm(struct file *file, void *priv,
627 struct v4l2_streamparm *parm)
628{
629 struct rvin_dev *vin = video_drvdata(file);
630 struct v4l2_subdev *sd = vin_to_source(vin);
631
632 return v4l2_g_parm_cap(vdev: &vin->vdev, sd, a: parm);
633}
634
635static int rvin_s_parm(struct file *file, void *priv,
636 struct v4l2_streamparm *parm)
637{
638 struct rvin_dev *vin = video_drvdata(file);
639 struct v4l2_subdev *sd = vin_to_source(vin);
640
641 return v4l2_s_parm_cap(vdev: &vin->vdev, sd, a: parm);
642}
643
644static int rvin_g_pixelaspect(struct file *file, void *priv,
645 int type, struct v4l2_fract *f)
646{
647 struct rvin_dev *vin = video_drvdata(file);
648 struct v4l2_subdev *sd = vin_to_source(vin);
649
650 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
651 return -EINVAL;
652
653 return v4l2_subdev_call(sd, video, g_pixelaspect, f);
654}
655
656static int rvin_enum_input(struct file *file, void *priv,
657 struct v4l2_input *i)
658{
659 struct rvin_dev *vin = video_drvdata(file);
660 struct v4l2_subdev *sd = vin_to_source(vin);
661 int ret;
662
663 if (i->index != 0)
664 return -EINVAL;
665
666 ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
667 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
668 return ret;
669
670 i->type = V4L2_INPUT_TYPE_CAMERA;
671
672 if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
673 i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
674 i->std = 0;
675 } else {
676 i->capabilities = V4L2_IN_CAP_STD;
677 i->std = vin->vdev.tvnorms;
678 }
679
680 strscpy(i->name, "Camera", sizeof(i->name));
681
682 return 0;
683}
684
685static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
686{
687 *i = 0;
688 return 0;
689}
690
691static int rvin_s_input(struct file *file, void *priv, unsigned int i)
692{
693 if (i > 0)
694 return -EINVAL;
695 return 0;
696}
697
698static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
699{
700 struct rvin_dev *vin = video_drvdata(file);
701 struct v4l2_subdev *sd = vin_to_source(vin);
702
703 return v4l2_subdev_call(sd, video, querystd, a);
704}
705
706static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
707{
708 struct rvin_dev *vin = video_drvdata(file);
709 int ret;
710
711 ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
712 if (ret < 0)
713 return ret;
714
715 vin->std = a;
716
717 /* Changing the standard will change the width/height */
718 return rvin_reset_format(vin);
719}
720
721static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
722{
723 struct rvin_dev *vin = video_drvdata(file);
724
725 if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
726 return -ENOIOCTLCMD;
727
728 *a = vin->std;
729
730 return 0;
731}
732
733static int rvin_subscribe_event(struct v4l2_fh *fh,
734 const struct v4l2_event_subscription *sub)
735{
736 switch (sub->type) {
737 case V4L2_EVENT_SOURCE_CHANGE:
738 return v4l2_event_subscribe(fh, sub, elems: 4, NULL);
739 }
740 return v4l2_ctrl_subscribe_event(fh, sub);
741}
742
743static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
744 struct v4l2_enum_dv_timings *timings)
745{
746 struct rvin_dev *vin = video_drvdata(file);
747 struct v4l2_subdev *sd = vin_to_source(vin);
748 int ret;
749
750 if (timings->pad)
751 return -EINVAL;
752
753 timings->pad = vin->parallel.sink_pad;
754
755 ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
756
757 timings->pad = 0;
758
759 return ret;
760}
761
762static int rvin_s_dv_timings(struct file *file, void *priv_fh,
763 struct v4l2_dv_timings *timings)
764{
765 struct rvin_dev *vin = video_drvdata(file);
766 struct v4l2_subdev *sd = vin_to_source(vin);
767 int ret;
768
769 ret = v4l2_subdev_call(sd, pad, s_dv_timings,
770 vin->parallel.sink_pad, timings);
771 if (ret)
772 return ret;
773
774 /* Changing the timings will change the width/height */
775 return rvin_reset_format(vin);
776}
777
778static int rvin_g_dv_timings(struct file *file, void *priv_fh,
779 struct v4l2_dv_timings *timings)
780{
781 struct rvin_dev *vin = video_drvdata(file);
782 struct v4l2_subdev *sd = vin_to_source(vin);
783
784 return v4l2_subdev_call(sd, pad, g_dv_timings,
785 vin->parallel.sink_pad, timings);
786}
787
788static int rvin_query_dv_timings(struct file *file, void *priv_fh,
789 struct v4l2_dv_timings *timings)
790{
791 struct rvin_dev *vin = video_drvdata(file);
792 struct v4l2_subdev *sd = vin_to_source(vin);
793
794 return v4l2_subdev_call(sd, pad, query_dv_timings,
795 vin->parallel.sink_pad, timings);
796}
797
798static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
799 struct v4l2_dv_timings_cap *cap)
800{
801 struct rvin_dev *vin = video_drvdata(file);
802 struct v4l2_subdev *sd = vin_to_source(vin);
803 int ret;
804
805 if (cap->pad)
806 return -EINVAL;
807
808 cap->pad = vin->parallel.sink_pad;
809
810 ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
811
812 cap->pad = 0;
813
814 return ret;
815}
816
817static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
818{
819 struct rvin_dev *vin = video_drvdata(file);
820 struct v4l2_subdev *sd = vin_to_source(vin);
821 int ret;
822
823 if (edid->pad)
824 return -EINVAL;
825
826 edid->pad = vin->parallel.sink_pad;
827
828 ret = v4l2_subdev_call(sd, pad, get_edid, edid);
829
830 edid->pad = 0;
831
832 return ret;
833}
834
835static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
836{
837 struct rvin_dev *vin = video_drvdata(file);
838 struct v4l2_subdev *sd = vin_to_source(vin);
839 int ret;
840
841 if (edid->pad)
842 return -EINVAL;
843
844 edid->pad = vin->parallel.sink_pad;
845
846 ret = v4l2_subdev_call(sd, pad, set_edid, edid);
847
848 edid->pad = 0;
849
850 return ret;
851}
852
853static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
854 .vidioc_querycap = rvin_querycap,
855 .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap,
856 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
857 .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap,
858 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
859
860 .vidioc_g_selection = rvin_g_selection,
861 .vidioc_s_selection = rvin_s_selection,
862
863 .vidioc_g_parm = rvin_g_parm,
864 .vidioc_s_parm = rvin_s_parm,
865
866 .vidioc_g_pixelaspect = rvin_g_pixelaspect,
867
868 .vidioc_enum_input = rvin_enum_input,
869 .vidioc_g_input = rvin_g_input,
870 .vidioc_s_input = rvin_s_input,
871
872 .vidioc_dv_timings_cap = rvin_dv_timings_cap,
873 .vidioc_enum_dv_timings = rvin_enum_dv_timings,
874 .vidioc_g_dv_timings = rvin_g_dv_timings,
875 .vidioc_s_dv_timings = rvin_s_dv_timings,
876 .vidioc_query_dv_timings = rvin_query_dv_timings,
877
878 .vidioc_g_edid = rvin_g_edid,
879 .vidioc_s_edid = rvin_s_edid,
880
881 .vidioc_querystd = rvin_querystd,
882 .vidioc_g_std = rvin_g_std,
883 .vidioc_s_std = rvin_s_std,
884
885 .vidioc_reqbufs = vb2_ioctl_reqbufs,
886 .vidioc_create_bufs = vb2_ioctl_create_bufs,
887 .vidioc_querybuf = vb2_ioctl_querybuf,
888 .vidioc_qbuf = vb2_ioctl_qbuf,
889 .vidioc_dqbuf = vb2_ioctl_dqbuf,
890 .vidioc_expbuf = vb2_ioctl_expbuf,
891 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
892 .vidioc_streamon = vb2_ioctl_streamon,
893 .vidioc_streamoff = vb2_ioctl_streamoff,
894
895 .vidioc_log_status = v4l2_ctrl_log_status,
896 .vidioc_subscribe_event = rvin_subscribe_event,
897 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
898};
899
900/* -----------------------------------------------------------------------------
901 * V4L2 Media Controller
902 */
903
904static void rvin_mc_try_format(struct rvin_dev *vin,
905 struct v4l2_pix_format *pix)
906{
907 /*
908 * The V4L2 specification clearly documents the colorspace fields
909 * as being set by drivers for capture devices. Using the values
910 * supplied by userspace thus wouldn't comply with the API. Until
911 * the API is updated force fixed values.
912 */
913 pix->colorspace = RVIN_DEFAULT_COLORSPACE;
914 pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
915 pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
916 pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
917 pix->ycbcr_enc);
918
919 rvin_format_align(vin, pix);
920}
921
922static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
923 struct v4l2_format *f)
924{
925 struct rvin_dev *vin = video_drvdata(file);
926
927 rvin_mc_try_format(vin, pix: &f->fmt.pix);
928
929 return 0;
930}
931
932static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
933 struct v4l2_format *f)
934{
935 struct rvin_dev *vin = video_drvdata(file);
936
937 if (vb2_is_busy(q: &vin->queue))
938 return -EBUSY;
939
940 rvin_mc_try_format(vin, pix: &f->fmt.pix);
941
942 vin->format = f->fmt.pix;
943
944 vin->crop.top = 0;
945 vin->crop.left = 0;
946 vin->crop.width = vin->format.width;
947 vin->crop.height = vin->format.height;
948 vin->compose = vin->crop;
949
950 return 0;
951}
952
953static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
954 .vidioc_querycap = rvin_querycap,
955 .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap,
956 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap,
957 .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap,
958 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap,
959
960 .vidioc_g_selection = rvin_g_selection,
961 .vidioc_s_selection = rvin_s_selection,
962
963 .vidioc_reqbufs = vb2_ioctl_reqbufs,
964 .vidioc_create_bufs = vb2_ioctl_create_bufs,
965 .vidioc_querybuf = vb2_ioctl_querybuf,
966 .vidioc_qbuf = vb2_ioctl_qbuf,
967 .vidioc_dqbuf = vb2_ioctl_dqbuf,
968 .vidioc_expbuf = vb2_ioctl_expbuf,
969 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
970 .vidioc_streamon = vb2_ioctl_streamon,
971 .vidioc_streamoff = vb2_ioctl_streamoff,
972
973 .vidioc_log_status = v4l2_ctrl_log_status,
974 .vidioc_subscribe_event = rvin_subscribe_event,
975 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
976};
977
978/* -----------------------------------------------------------------------------
979 * File Operations
980 */
981
982static int rvin_power_parallel(struct rvin_dev *vin, bool on)
983{
984 struct v4l2_subdev *sd = vin_to_source(vin);
985 int power = on ? 1 : 0;
986 int ret;
987
988 ret = v4l2_subdev_call(sd, core, s_power, power);
989 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
990 return ret;
991
992 return 0;
993}
994
995static int rvin_open(struct file *file)
996{
997 struct rvin_dev *vin = video_drvdata(file);
998 int ret;
999
1000 ret = pm_runtime_resume_and_get(dev: vin->dev);
1001 if (ret < 0)
1002 return ret;
1003
1004 ret = mutex_lock_interruptible(&vin->lock);
1005 if (ret)
1006 goto err_pm;
1007
1008 file->private_data = vin;
1009
1010 ret = v4l2_fh_open(filp: file);
1011 if (ret)
1012 goto err_unlock;
1013
1014 if (vin->info->use_mc)
1015 ret = v4l2_pipeline_pm_get(entity: &vin->vdev.entity);
1016 else if (v4l2_fh_is_singular_file(filp: file))
1017 ret = rvin_power_parallel(vin, on: true);
1018
1019 if (ret < 0)
1020 goto err_open;
1021
1022 ret = v4l2_ctrl_handler_setup(hdl: &vin->ctrl_handler);
1023 if (ret)
1024 goto err_power;
1025
1026 mutex_unlock(lock: &vin->lock);
1027
1028 return 0;
1029err_power:
1030 if (vin->info->use_mc)
1031 v4l2_pipeline_pm_put(entity: &vin->vdev.entity);
1032 else if (v4l2_fh_is_singular_file(filp: file))
1033 rvin_power_parallel(vin, on: false);
1034err_open:
1035 v4l2_fh_release(filp: file);
1036err_unlock:
1037 mutex_unlock(lock: &vin->lock);
1038err_pm:
1039 pm_runtime_put(dev: vin->dev);
1040
1041 return ret;
1042}
1043
1044static int rvin_release(struct file *file)
1045{
1046 struct rvin_dev *vin = video_drvdata(file);
1047 bool fh_singular;
1048 int ret;
1049
1050 mutex_lock(&vin->lock);
1051
1052 /* Save the singular status before we call the clean-up helper */
1053 fh_singular = v4l2_fh_is_singular_file(filp: file);
1054
1055 /* the release helper will cleanup any on-going streaming */
1056 ret = _vb2_fop_release(file, NULL);
1057
1058 if (vin->info->use_mc) {
1059 v4l2_pipeline_pm_put(entity: &vin->vdev.entity);
1060 } else {
1061 if (fh_singular)
1062 rvin_power_parallel(vin, on: false);
1063 }
1064
1065 mutex_unlock(lock: &vin->lock);
1066
1067 pm_runtime_put(dev: vin->dev);
1068
1069 return ret;
1070}
1071
1072static const struct v4l2_file_operations rvin_fops = {
1073 .owner = THIS_MODULE,
1074 .unlocked_ioctl = video_ioctl2,
1075 .open = rvin_open,
1076 .release = rvin_release,
1077 .poll = vb2_fop_poll,
1078 .mmap = vb2_fop_mmap,
1079 .read = vb2_fop_read,
1080};
1081
1082void rvin_v4l2_unregister(struct rvin_dev *vin)
1083{
1084 if (!video_is_registered(vdev: &vin->vdev))
1085 return;
1086
1087 v4l2_info(&vin->v4l2_dev, "Removing %s\n",
1088 video_device_node_name(&vin->vdev));
1089
1090 /* Checks internally if vdev have been init or not */
1091 video_unregister_device(vdev: &vin->vdev);
1092}
1093
1094static void rvin_notify_video_device(struct rvin_dev *vin,
1095 unsigned int notification, void *arg)
1096{
1097 switch (notification) {
1098 case V4L2_DEVICE_NOTIFY_EVENT:
1099 v4l2_event_queue(vdev: &vin->vdev, ev: arg);
1100 break;
1101 default:
1102 break;
1103 }
1104}
1105
1106static void rvin_notify(struct v4l2_subdev *sd,
1107 unsigned int notification, void *arg)
1108{
1109 struct v4l2_subdev *remote;
1110 struct rvin_group *group;
1111 struct media_pad *pad;
1112 struct rvin_dev *vin =
1113 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
1114 unsigned int i;
1115
1116 /* If no media controller, no need to route the event. */
1117 if (!vin->info->use_mc) {
1118 rvin_notify_video_device(vin, notification, arg);
1119 return;
1120 }
1121
1122 group = vin->group;
1123
1124 for (i = 0; i < RCAR_VIN_NUM; i++) {
1125 vin = group->vin[i];
1126 if (!vin)
1127 continue;
1128
1129 pad = media_pad_remote_pad_first(pad: &vin->pad);
1130 if (!pad)
1131 continue;
1132
1133 remote = media_entity_to_v4l2_subdev(pad->entity);
1134 if (remote != sd)
1135 continue;
1136
1137 rvin_notify_video_device(vin, notification, arg);
1138 }
1139}
1140
1141int rvin_v4l2_register(struct rvin_dev *vin)
1142{
1143 struct video_device *vdev = &vin->vdev;
1144 int ret;
1145
1146 vin->v4l2_dev.notify = rvin_notify;
1147
1148 /* video node */
1149 vdev->v4l2_dev = &vin->v4l2_dev;
1150 vdev->queue = &vin->queue;
1151 snprintf(buf: vdev->name, size: sizeof(vdev->name), fmt: "VIN%u output", vin->id);
1152 vdev->release = video_device_release_empty;
1153 vdev->lock = &vin->lock;
1154 vdev->fops = &rvin_fops;
1155 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
1156 V4L2_CAP_READWRITE;
1157
1158 /* Set a default format */
1159 vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
1160 vin->format.width = RVIN_DEFAULT_WIDTH;
1161 vin->format.height = RVIN_DEFAULT_HEIGHT;
1162 vin->format.field = RVIN_DEFAULT_FIELD;
1163 vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
1164
1165 if (vin->info->use_mc) {
1166 vdev->device_caps |= V4L2_CAP_IO_MC;
1167 vdev->ioctl_ops = &rvin_mc_ioctl_ops;
1168 } else {
1169 vdev->ioctl_ops = &rvin_ioctl_ops;
1170 rvin_reset_format(vin);
1171 }
1172
1173 rvin_format_align(vin, pix: &vin->format);
1174
1175 ret = video_register_device(vdev: &vin->vdev, type: VFL_TYPE_VIDEO, nr: -1);
1176 if (ret) {
1177 vin_err(vin, "Failed to register video device\n");
1178 return ret;
1179 }
1180
1181 video_set_drvdata(vdev: &vin->vdev, data: vin);
1182
1183 v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
1184 video_device_node_name(&vin->vdev));
1185
1186 return ret;
1187}
1188

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c