brintos

brintos / linux-shallow public Read only

0
0
Text · 26.1 KiB · bb4b07b Raw
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