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