1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * TI Camera Access Layer (CAL) - Video Device
4 *
5 * Copyright (c) 2015-2020 Texas Instruments Inc.
6 *
7 * Authors:
8 *	Benoit Parrot <bparrot@ti.com>
9 *	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 */
11
12#include <linux/ioctl.h>
13#include <linux/pm_runtime.h>
14#include <linux/videodev2.h>
15
16#include <media/media-device.h>
17#include <media/v4l2-common.h>
18#include <media/v4l2-ctrls.h>
19#include <media/v4l2-device.h>
20#include <media/v4l2-event.h>
21#include <media/v4l2-fh.h>
22#include <media/v4l2-ioctl.h>
23#include <media/videobuf2-core.h>
24#include <media/videobuf2-dma-contig.h>
25
26#include "cal.h"
27
28/*  Print Four-character-code (FOURCC) */
29static char *fourcc_to_str(u32 fmt)
30{
31	static char code[5];
32
33	code[0] = (unsigned char)(fmt & 0xff);
34	code[1] = (unsigned char)((fmt >> 8) & 0xff);
35	code[2] = (unsigned char)((fmt >> 16) & 0xff);
36	code[3] = (unsigned char)((fmt >> 24) & 0xff);
37	code[4] = '\0';
38
39	return code;
40}
41
42/* ------------------------------------------------------------------
43 *	V4L2 Common IOCTLs
44 * ------------------------------------------------------------------
45 */
46
47static int cal_querycap(struct file *file, void *priv,
48			struct v4l2_capability *cap)
49{
50	strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
51	strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
52
53	return 0;
54}
55
56static int cal_g_fmt_vid_cap(struct file *file, void *priv,
57			     struct v4l2_format *f)
58{
59	struct cal_ctx *ctx = video_drvdata(file);
60
61	*f = ctx->v_fmt;
62
63	return 0;
64}
65
66/* ------------------------------------------------------------------
67 *	V4L2 Video Node Centric IOCTLs
68 * ------------------------------------------------------------------
69 */
70
71static const struct cal_format_info *find_format_by_pix(struct cal_ctx *ctx,
72							u32 pixelformat)
73{
74	const struct cal_format_info *fmtinfo;
75	unsigned int k;
76
77	for (k = 0; k < ctx->num_active_fmt; k++) {
78		fmtinfo = ctx->active_fmt[k];
79		if (fmtinfo->fourcc == pixelformat)
80			return fmtinfo;
81	}
82
83	return NULL;
84}
85
86static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx,
87							 u32 code)
88{
89	const struct cal_format_info *fmtinfo;
90	unsigned int k;
91
92	for (k = 0; k < ctx->num_active_fmt; k++) {
93		fmtinfo = ctx->active_fmt[k];
94		if (fmtinfo->code == code)
95			return fmtinfo;
96	}
97
98	return NULL;
99}
100
101static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv,
102				       struct v4l2_fmtdesc *f)
103{
104	struct cal_ctx *ctx = video_drvdata(file);
105	const struct cal_format_info *fmtinfo;
106
107	if (f->index >= ctx->num_active_fmt)
108		return -EINVAL;
109
110	fmtinfo = ctx->active_fmt[f->index];
111
112	f->pixelformat = fmtinfo->fourcc;
113	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
114	return 0;
115}
116
117static int __subdev_get_format(struct cal_ctx *ctx,
118			       struct v4l2_mbus_framefmt *fmt)
119{
120	struct v4l2_subdev_format sd_fmt = {
121		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
122		.pad = 0,
123	};
124	struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
125	int ret;
126
127	ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt);
128	if (ret)
129		return ret;
130
131	*fmt = *mbus_fmt;
132
133	ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
134		fmt->width, fmt->height, fmt->code);
135
136	return 0;
137}
138
139static int __subdev_set_format(struct cal_ctx *ctx,
140			       struct v4l2_mbus_framefmt *fmt)
141{
142	struct v4l2_subdev_format sd_fmt = {
143		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
144		.pad = 0,
145	};
146	struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
147	int ret;
148
149	*mbus_fmt = *fmt;
150
151	ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt);
152	if (ret)
153		return ret;
154
155	ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
156		fmt->width, fmt->height, fmt->code);
157
158	return 0;
159}
160
161static void cal_calc_format_size(struct cal_ctx *ctx,
162				 const struct cal_format_info *fmtinfo,
163				 struct v4l2_format *f)
164{
165	u32 bpl, max_width;
166
167	/*
168	 * Maximum width is bound by the DMA max width in bytes.
169	 * We need to recalculate the actual maxi width depending on the
170	 * number of bytes per pixels required.
171	 */
172	max_width = CAL_MAX_WIDTH_BYTES / (ALIGN(fmtinfo->bpp, 8) >> 3);
173	v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2,
174			      &f->fmt.pix.height, 32, CAL_MAX_HEIGHT_LINES,
175			      0, 0);
176
177	bpl = (f->fmt.pix.width * ALIGN(fmtinfo->bpp, 8)) >> 3;
178	f->fmt.pix.bytesperline = ALIGN(bpl, 16);
179
180	f->fmt.pix.sizeimage = f->fmt.pix.height *
181			       f->fmt.pix.bytesperline;
182
183	ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
184		__func__, fourcc_to_str(f->fmt.pix.pixelformat),
185		f->fmt.pix.width, f->fmt.pix.height,
186		f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
187}
188
189static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
190				      struct v4l2_format *f)
191{
192	struct cal_ctx *ctx = video_drvdata(file);
193	const struct cal_format_info *fmtinfo;
194	struct v4l2_subdev_frame_size_enum fse = {
195		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
196	};
197	int found;
198
199	fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
200	if (!fmtinfo) {
201		ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n",
202			f->fmt.pix.pixelformat);
203
204		/* Just get the first one enumerated */
205		fmtinfo = ctx->active_fmt[0];
206		f->fmt.pix.pixelformat = fmtinfo->fourcc;
207	}
208
209	f->fmt.pix.field = ctx->v_fmt.fmt.pix.field;
210
211	/* check for/find a valid width/height */
212	found = false;
213	fse.pad = 0;
214	fse.code = fmtinfo->code;
215	for (fse.index = 0; ; fse.index++) {
216		int ret;
217
218		ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size,
219				       NULL, &fse);
220		if (ret)
221			break;
222
223		if ((f->fmt.pix.width == fse.max_width) &&
224		    (f->fmt.pix.height == fse.max_height)) {
225			found = true;
226			break;
227		} else if ((f->fmt.pix.width >= fse.min_width) &&
228			 (f->fmt.pix.width <= fse.max_width) &&
229			 (f->fmt.pix.height >= fse.min_height) &&
230			 (f->fmt.pix.height <= fse.max_height)) {
231			found = true;
232			break;
233		}
234	}
235
236	if (!found) {
237		/* use existing values as default */
238		f->fmt.pix.width = ctx->v_fmt.fmt.pix.width;
239		f->fmt.pix.height =  ctx->v_fmt.fmt.pix.height;
240	}
241
242	/*
243	 * Use current colorspace for now, it will get
244	 * updated properly during s_fmt
245	 */
246	f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace;
247	cal_calc_format_size(ctx, fmtinfo, f);
248	return 0;
249}
250
251static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
252				    struct v4l2_format *f)
253{
254	struct cal_ctx *ctx = video_drvdata(file);
255	struct vb2_queue *q = &ctx->vb_vidq;
256	struct v4l2_subdev_format sd_fmt = {
257		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
258		.pad = CAL_CAMERARX_PAD_SINK,
259	};
260	const struct cal_format_info *fmtinfo;
261	int ret;
262
263	if (vb2_is_busy(q)) {
264		ctx_dbg(3, ctx, "%s device busy\n", __func__);
265		return -EBUSY;
266	}
267
268	ret = cal_legacy_try_fmt_vid_cap(file, priv, f);
269	if (ret < 0)
270		return ret;
271
272	fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
273
274	v4l2_fill_mbus_format(&sd_fmt.format, &f->fmt.pix, fmtinfo->code);
275
276	ret = __subdev_set_format(ctx, &sd_fmt.format);
277	if (ret)
278		return ret;
279
280	/* Just double check nothing has gone wrong */
281	if (sd_fmt.format.code != fmtinfo->code) {
282		ctx_dbg(3, ctx,
283			"%s subdev changed format on us, this should not happen\n",
284			__func__);
285		return -EINVAL;
286	}
287
288	v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &sd_fmt.format);
289	ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
290	ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc;
291	ctx->v_fmt.fmt.pix.field = sd_fmt.format.field;
292	cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
293
294	v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt);
295
296	ctx->fmtinfo = fmtinfo;
297	*f = ctx->v_fmt;
298
299	return 0;
300}
301
302static int cal_legacy_enum_framesizes(struct file *file, void *fh,
303				      struct v4l2_frmsizeenum *fsize)
304{
305	struct cal_ctx *ctx = video_drvdata(file);
306	const struct cal_format_info *fmtinfo;
307	struct v4l2_subdev_frame_size_enum fse = {
308		.index = fsize->index,
309		.pad = 0,
310		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
311	};
312	int ret;
313
314	/* check for valid format */
315	fmtinfo = find_format_by_pix(ctx, fsize->pixel_format);
316	if (!fmtinfo) {
317		ctx_dbg(3, ctx, "Invalid pixel code: %x\n",
318			fsize->pixel_format);
319		return -EINVAL;
320	}
321
322	fse.code = fmtinfo->code;
323
324	ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL,
325			       &fse);
326	if (ret)
327		return ret;
328
329	ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
330		__func__, fse.index, fse.code, fse.min_width, fse.max_width,
331		fse.min_height, fse.max_height);
332
333	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
334	fsize->discrete.width = fse.max_width;
335	fsize->discrete.height = fse.max_height;
336
337	return 0;
338}
339
340static int cal_legacy_enum_input(struct file *file, void *priv,
341				 struct v4l2_input *inp)
342{
343	if (inp->index > 0)
344		return -EINVAL;
345
346	inp->type = V4L2_INPUT_TYPE_CAMERA;
347	sprintf(inp->name, "Camera %u", inp->index);
348	return 0;
349}
350
351static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i)
352{
353	*i = 0;
354	return 0;
355}
356
357static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i)
358{
359	return i > 0 ? -EINVAL : 0;
360}
361
362/* timeperframe is arbitrary and continuous */
363static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
364					  struct v4l2_frmivalenum *fival)
365{
366	struct cal_ctx *ctx = video_drvdata(file);
367	const struct cal_format_info *fmtinfo;
368	struct v4l2_subdev_frame_interval_enum fie = {
369		.index = fival->index,
370		.width = fival->width,
371		.height = fival->height,
372		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
373	};
374	int ret;
375
376	fmtinfo = find_format_by_pix(ctx, fival->pixel_format);
377	if (!fmtinfo)
378		return -EINVAL;
379
380	fie.code = fmtinfo->code;
381	ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval,
382			       NULL, &fie);
383	if (ret)
384		return ret;
385	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
386	fival->discrete = fie.interval;
387
388	return 0;
389}
390
391static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
392{
393	struct cal_ctx *ctx = video_drvdata(file);
394
395	return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a);
396}
397
398static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
399{
400	struct cal_ctx *ctx = video_drvdata(file);
401
402	return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a);
403}
404
405static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = {
406	.vidioc_querycap      = cal_querycap,
407	.vidioc_enum_fmt_vid_cap  = cal_legacy_enum_fmt_vid_cap,
408	.vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
409	.vidioc_try_fmt_vid_cap   = cal_legacy_try_fmt_vid_cap,
410	.vidioc_s_fmt_vid_cap     = cal_legacy_s_fmt_vid_cap,
411	.vidioc_enum_framesizes   = cal_legacy_enum_framesizes,
412	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
413	.vidioc_create_bufs   = vb2_ioctl_create_bufs,
414	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
415	.vidioc_querybuf      = vb2_ioctl_querybuf,
416	.vidioc_qbuf          = vb2_ioctl_qbuf,
417	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
418	.vidioc_expbuf        = vb2_ioctl_expbuf,
419	.vidioc_enum_input    = cal_legacy_enum_input,
420	.vidioc_g_input       = cal_legacy_g_input,
421	.vidioc_s_input       = cal_legacy_s_input,
422	.vidioc_enum_frameintervals = cal_legacy_enum_frameintervals,
423	.vidioc_streamon      = vb2_ioctl_streamon,
424	.vidioc_streamoff     = vb2_ioctl_streamoff,
425	.vidioc_log_status    = v4l2_ctrl_log_status,
426	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
427	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
428	.vidioc_g_parm		= cal_legacy_g_parm,
429	.vidioc_s_parm		= cal_legacy_s_parm,
430};
431
432/* ------------------------------------------------------------------
433 *	V4L2 Media Controller Centric IOCTLs
434 * ------------------------------------------------------------------
435 */
436
437static int cal_mc_enum_fmt_vid_cap(struct file *file, void  *priv,
438				   struct v4l2_fmtdesc *f)
439{
440	unsigned int i;
441	unsigned int idx;
442
443	if (f->index >= cal_num_formats)
444		return -EINVAL;
445
446	idx = 0;
447
448	for (i = 0; i < cal_num_formats; ++i) {
449		if (f->mbus_code && cal_formats[i].code != f->mbus_code)
450			continue;
451
452		if (idx == f->index) {
453			f->pixelformat = cal_formats[i].fourcc;
454			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
455			return 0;
456		}
457
458		idx++;
459	}
460
461	return -EINVAL;
462}
463
464static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f,
465			   const struct cal_format_info **info)
466{
467	struct v4l2_pix_format *format = &f->fmt.pix;
468	const struct cal_format_info *fmtinfo;
469	unsigned int bpp;
470
471	/*
472	 * Default to the first format if the requested pixel format code isn't
473	 * supported.
474	 */
475	fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat);
476	if (!fmtinfo)
477		fmtinfo = &cal_formats[0];
478
479	/*
480	 * Clamp the size, update the pixel format. The field and colorspace are
481	 * accepted as-is, except for V4L2_FIELD_ANY that is turned into
482	 * V4L2_FIELD_NONE.
483	 */
484	bpp = ALIGN(fmtinfo->bpp, 8);
485
486	format->width = clamp_t(unsigned int, format->width,
487				CAL_MIN_WIDTH_BYTES * 8 / bpp,
488				CAL_MAX_WIDTH_BYTES * 8 / bpp);
489	format->height = clamp_t(unsigned int, format->height,
490				 CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES);
491	format->pixelformat = fmtinfo->fourcc;
492
493	if (format->field == V4L2_FIELD_ANY)
494		format->field = V4L2_FIELD_NONE;
495
496	/*
497	 * Calculate the number of bytes per line and the image size. The
498	 * hardware stores the stride as a number of 16 bytes words, in a
499	 * signed 15-bit value. Only 14 bits are thus usable.
500	 */
501	format->bytesperline = ALIGN(clamp(format->bytesperline,
502					   format->width * bpp / 8,
503					   ((1U << 14) - 1) * 16), 16);
504
505	format->sizeimage = format->height * format->bytesperline;
506
507	format->colorspace = ctx->v_fmt.fmt.pix.colorspace;
508
509	if (info)
510		*info = fmtinfo;
511
512	ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n",
513		__func__, fourcc_to_str(format->pixelformat),
514		format->width, format->height,
515		format->bytesperline, format->sizeimage);
516}
517
518static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv,
519				  struct v4l2_format *f)
520{
521	struct cal_ctx *ctx = video_drvdata(file);
522
523	cal_mc_try_fmt(ctx, f, NULL);
524	return 0;
525}
526
527static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv,
528				struct v4l2_format *f)
529{
530	struct cal_ctx *ctx = video_drvdata(file);
531	const struct cal_format_info *fmtinfo;
532
533	if (vb2_is_busy(&ctx->vb_vidq)) {
534		ctx_dbg(3, ctx, "%s device busy\n", __func__);
535		return -EBUSY;
536	}
537
538	cal_mc_try_fmt(ctx, f, &fmtinfo);
539
540	ctx->v_fmt = *f;
541	ctx->fmtinfo = fmtinfo;
542
543	return 0;
544}
545
546static int cal_mc_enum_framesizes(struct file *file, void *fh,
547				  struct v4l2_frmsizeenum *fsize)
548{
549	struct cal_ctx *ctx = video_drvdata(file);
550	const struct cal_format_info *fmtinfo;
551	unsigned int bpp;
552
553	if (fsize->index > 0)
554		return -EINVAL;
555
556	fmtinfo = cal_format_by_fourcc(fsize->pixel_format);
557	if (!fmtinfo) {
558		ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n",
559			fsize->pixel_format);
560		return -EINVAL;
561	}
562
563	bpp = ALIGN(fmtinfo->bpp, 8);
564
565	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
566	fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp;
567	fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp;
568	fsize->stepwise.step_width = 64 / bpp;
569	fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES;
570	fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES;
571	fsize->stepwise.step_height = 1;
572
573	return 0;
574}
575
576static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = {
577	.vidioc_querycap      = cal_querycap,
578	.vidioc_enum_fmt_vid_cap  = cal_mc_enum_fmt_vid_cap,
579	.vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
580	.vidioc_try_fmt_vid_cap   = cal_mc_try_fmt_vid_cap,
581	.vidioc_s_fmt_vid_cap     = cal_mc_s_fmt_vid_cap,
582	.vidioc_enum_framesizes   = cal_mc_enum_framesizes,
583	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
584	.vidioc_create_bufs   = vb2_ioctl_create_bufs,
585	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
586	.vidioc_querybuf      = vb2_ioctl_querybuf,
587	.vidioc_qbuf          = vb2_ioctl_qbuf,
588	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
589	.vidioc_expbuf        = vb2_ioctl_expbuf,
590	.vidioc_streamon      = vb2_ioctl_streamon,
591	.vidioc_streamoff     = vb2_ioctl_streamoff,
592	.vidioc_log_status    = v4l2_ctrl_log_status,
593};
594
595/* ------------------------------------------------------------------
596 *	videobuf2 Common Operations
597 * ------------------------------------------------------------------
598 */
599
600static int cal_queue_setup(struct vb2_queue *vq,
601			   unsigned int *nbuffers, unsigned int *nplanes,
602			   unsigned int sizes[], struct device *alloc_devs[])
603{
604	struct cal_ctx *ctx = vb2_get_drv_priv(vq);
605	unsigned int size = ctx->v_fmt.fmt.pix.sizeimage;
606
607	if (vq->num_buffers + *nbuffers < 3)
608		*nbuffers = 3 - vq->num_buffers;
609
610	if (*nplanes) {
611		if (sizes[0] < size)
612			return -EINVAL;
613		size = sizes[0];
614	}
615
616	*nplanes = 1;
617	sizes[0] = size;
618
619	ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]);
620
621	return 0;
622}
623
624static int cal_buffer_prepare(struct vb2_buffer *vb)
625{
626	struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
627	struct cal_buffer *buf = container_of(vb, struct cal_buffer,
628					      vb.vb2_buf);
629	unsigned long size;
630
631	size = ctx->v_fmt.fmt.pix.sizeimage;
632	if (vb2_plane_size(vb, 0) < size) {
633		ctx_err(ctx,
634			"data will not fit into plane (%lu < %lu)\n",
635			vb2_plane_size(vb, 0), size);
636		return -EINVAL;
637	}
638
639	vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
640	return 0;
641}
642
643static void cal_buffer_queue(struct vb2_buffer *vb)
644{
645	struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
646	struct cal_buffer *buf = container_of(vb, struct cal_buffer,
647					      vb.vb2_buf);
648	unsigned long flags;
649
650	/* recheck locking */
651	spin_lock_irqsave(&ctx->dma.lock, flags);
652	list_add_tail(&buf->list, &ctx->dma.queue);
653	spin_unlock_irqrestore(&ctx->dma.lock, flags);
654}
655
656static void cal_release_buffers(struct cal_ctx *ctx,
657				enum vb2_buffer_state state)
658{
659	struct cal_buffer *buf, *tmp;
660
661	/* Release all queued buffers. */
662	spin_lock_irq(&ctx->dma.lock);
663
664	list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) {
665		list_del(&buf->list);
666		vb2_buffer_done(&buf->vb.vb2_buf, state);
667	}
668
669	if (ctx->dma.pending) {
670		vb2_buffer_done(&ctx->dma.pending->vb.vb2_buf, state);
671		ctx->dma.pending = NULL;
672	}
673
674	if (ctx->dma.active) {
675		vb2_buffer_done(&ctx->dma.active->vb.vb2_buf, state);
676		ctx->dma.active = NULL;
677	}
678
679	spin_unlock_irq(&ctx->dma.lock);
680}
681
682/* ------------------------------------------------------------------
683 *	videobuf2 Operations
684 * ------------------------------------------------------------------
685 */
686
687static int cal_video_check_format(struct cal_ctx *ctx)
688{
689	const struct v4l2_mbus_framefmt *format;
690	struct v4l2_subdev_state *state;
691	struct media_pad *remote_pad;
692	int ret = 0;
693
694	remote_pad = media_pad_remote_pad_first(&ctx->pad);
695	if (!remote_pad)
696		return -ENODEV;
697
698	state = v4l2_subdev_lock_and_get_active_state(&ctx->phy->subdev);
699
700	format = v4l2_subdev_get_pad_format(&ctx->phy->subdev, state, remote_pad->index);
701	if (!format) {
702		ret = -EINVAL;
703		goto out;
704	}
705
706	if (ctx->fmtinfo->code != format->code ||
707	    ctx->v_fmt.fmt.pix.height != format->height ||
708	    ctx->v_fmt.fmt.pix.width != format->width ||
709	    ctx->v_fmt.fmt.pix.field != format->field) {
710		ret = -EPIPE;
711		goto out;
712	}
713
714out:
715	v4l2_subdev_unlock_state(state);
716
717	return ret;
718}
719
720static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
721{
722	struct cal_ctx *ctx = vb2_get_drv_priv(vq);
723	struct cal_buffer *buf;
724	dma_addr_t addr;
725	int ret;
726
727	ret = video_device_pipeline_alloc_start(&ctx->vdev);
728	if (ret < 0) {
729		ctx_err(ctx, "Failed to start media pipeline: %d\n", ret);
730		goto error_release_buffers;
731	}
732
733	/*
734	 * Verify that the currently configured format matches the output of
735	 * the connected CAMERARX.
736	 */
737	ret = cal_video_check_format(ctx);
738	if (ret < 0) {
739		ctx_dbg(3, ctx,
740			"Format mismatch between CAMERARX and video node\n");
741		goto error_pipeline;
742	}
743
744	ret = cal_ctx_prepare(ctx);
745	if (ret) {
746		ctx_err(ctx, "Failed to prepare context: %d\n", ret);
747		goto error_pipeline;
748	}
749
750	spin_lock_irq(&ctx->dma.lock);
751	buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list);
752	ctx->dma.active = buf;
753	list_del(&buf->list);
754	spin_unlock_irq(&ctx->dma.lock);
755
756	addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
757
758	ret = pm_runtime_resume_and_get(ctx->cal->dev);
759	if (ret < 0)
760		goto error_pipeline;
761
762	cal_ctx_set_dma_addr(ctx, addr);
763	cal_ctx_start(ctx);
764
765	ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1);
766	if (ret)
767		goto error_stop;
768
769	if (cal_debug >= 4)
770		cal_quickdump_regs(ctx->cal);
771
772	return 0;
773
774error_stop:
775	cal_ctx_stop(ctx);
776	pm_runtime_put_sync(ctx->cal->dev);
777	cal_ctx_unprepare(ctx);
778
779error_pipeline:
780	video_device_pipeline_stop(&ctx->vdev);
781error_release_buffers:
782	cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED);
783
784	return ret;
785}
786
787static void cal_stop_streaming(struct vb2_queue *vq)
788{
789	struct cal_ctx *ctx = vb2_get_drv_priv(vq);
790
791	cal_ctx_stop(ctx);
792
793	v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0);
794
795	pm_runtime_put_sync(ctx->cal->dev);
796
797	cal_ctx_unprepare(ctx);
798
799	cal_release_buffers(ctx, VB2_BUF_STATE_ERROR);
800
801	video_device_pipeline_stop(&ctx->vdev);
802}
803
804static const struct vb2_ops cal_video_qops = {
805	.queue_setup		= cal_queue_setup,
806	.buf_prepare		= cal_buffer_prepare,
807	.buf_queue		= cal_buffer_queue,
808	.start_streaming	= cal_start_streaming,
809	.stop_streaming		= cal_stop_streaming,
810	.wait_prepare		= vb2_ops_wait_prepare,
811	.wait_finish		= vb2_ops_wait_finish,
812};
813
814/* ------------------------------------------------------------------
815 *	V4L2 Initialization and Registration
816 * ------------------------------------------------------------------
817 */
818
819static const struct v4l2_file_operations cal_fops = {
820	.owner		= THIS_MODULE,
821	.open           = v4l2_fh_open,
822	.release        = vb2_fop_release,
823	.poll		= vb2_fop_poll,
824	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
825	.mmap           = vb2_fop_mmap,
826};
827
828static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
829{
830	struct v4l2_mbus_framefmt mbus_fmt;
831	const struct cal_format_info *fmtinfo;
832	unsigned int i, j, k;
833	int ret = 0;
834
835	/* Enumerate sub device formats and enable all matching local formats */
836	ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats,
837				       sizeof(*ctx->active_fmt), GFP_KERNEL);
838	if (!ctx->active_fmt)
839		return -ENOMEM;
840
841	ctx->num_active_fmt = 0;
842
843	for (j = 0, i = 0; ; ++j) {
844		struct v4l2_subdev_mbus_code_enum mbus_code = {
845			.index = j,
846			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
847		};
848
849		ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
850				       NULL, &mbus_code);
851		if (ret == -EINVAL)
852			break;
853
854		if (ret) {
855			ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
856				ctx->phy->source->name, ret);
857			return ret;
858		}
859
860		ctx_dbg(2, ctx,
861			"subdev %s: code: %04x idx: %u\n",
862			ctx->phy->source->name, mbus_code.code, j);
863
864		for (k = 0; k < cal_num_formats; k++) {
865			fmtinfo = &cal_formats[k];
866
867			if (mbus_code.code == fmtinfo->code) {
868				ctx->active_fmt[i] = fmtinfo;
869				ctx_dbg(2, ctx,
870					"matched fourcc: %s: code: %04x idx: %u\n",
871					fourcc_to_str(fmtinfo->fourcc),
872					fmtinfo->code, i);
873				ctx->num_active_fmt = ++i;
874			}
875		}
876	}
877
878	if (i == 0) {
879		ctx_err(ctx, "No suitable format reported by subdev %s\n",
880			ctx->phy->source->name);
881		return -EINVAL;
882	}
883
884	ret = __subdev_get_format(ctx, &mbus_fmt);
885	if (ret)
886		return ret;
887
888	fmtinfo = find_format_by_code(ctx, mbus_fmt.code);
889	if (!fmtinfo) {
890		ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n",
891			mbus_fmt.code);
892		return -EINVAL;
893	}
894
895	/* Save current format */
896	v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
897	ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
898	ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc;
899	cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
900	ctx->fmtinfo = fmtinfo;
901
902	return 0;
903}
904
905static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx)
906{
907	const struct cal_format_info *fmtinfo;
908	struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix;
909
910	fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_1X16);
911	if (!fmtinfo)
912		return -EINVAL;
913
914	pix_fmt->width = 640;
915	pix_fmt->height = 480;
916	pix_fmt->field = V4L2_FIELD_NONE;
917	pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
918	pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
919	pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
920	pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
921	pix_fmt->pixelformat = fmtinfo->fourcc;
922
923	ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
924
925	/* Save current format */
926	cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
927	ctx->fmtinfo = fmtinfo;
928
929	return 0;
930}
931
932int cal_ctx_v4l2_register(struct cal_ctx *ctx)
933{
934	struct video_device *vfd = &ctx->vdev;
935	int ret;
936
937	if (!cal_mc_api) {
938		struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
939
940		ret = cal_ctx_v4l2_init_formats(ctx);
941		if (ret) {
942			ctx_err(ctx, "Failed to init formats: %d\n", ret);
943			return ret;
944		}
945
946		ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler,
947					    NULL, true);
948		if (ret < 0) {
949			ctx_err(ctx, "Failed to add source ctrl handler\n");
950			return ret;
951		}
952	} else {
953		ret = cal_ctx_v4l2_init_mc_format(ctx);
954		if (ret) {
955			ctx_err(ctx, "Failed to init format: %d\n", ret);
956			return ret;
957		}
958	}
959
960	ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr);
961	if (ret < 0) {
962		ctx_err(ctx, "Failed to register video device\n");
963		return ret;
964	}
965
966	ret = media_create_pad_link(&ctx->phy->subdev.entity,
967				    CAL_CAMERARX_PAD_FIRST_SOURCE,
968				    &vfd->entity, 0,
969				    MEDIA_LNK_FL_IMMUTABLE |
970				    MEDIA_LNK_FL_ENABLED);
971	if (ret) {
972		ctx_err(ctx, "Failed to create media link for context %u\n",
973			ctx->dma_ctx);
974		video_unregister_device(vfd);
975		return ret;
976	}
977
978	ctx_info(ctx, "V4L2 device registered as %s\n",
979		 video_device_node_name(vfd));
980
981	return 0;
982}
983
984void cal_ctx_v4l2_unregister(struct cal_ctx *ctx)
985{
986	ctx_dbg(1, ctx, "unregistering %s\n",
987		video_device_node_name(&ctx->vdev));
988
989	video_unregister_device(&ctx->vdev);
990}
991
992int cal_ctx_v4l2_init(struct cal_ctx *ctx)
993{
994	struct video_device *vfd = &ctx->vdev;
995	struct vb2_queue *q = &ctx->vb_vidq;
996	int ret;
997
998	INIT_LIST_HEAD(&ctx->dma.queue);
999	spin_lock_init(&ctx->dma.lock);
1000	mutex_init(&ctx->mutex);
1001	init_waitqueue_head(&ctx->dma.wait);
1002
1003	/* Initialize the vb2 queue. */
1004	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1005	q->io_modes = VB2_MMAP | VB2_DMABUF;
1006	q->drv_priv = ctx;
1007	q->buf_struct_size = sizeof(struct cal_buffer);
1008	q->ops = &cal_video_qops;
1009	q->mem_ops = &vb2_dma_contig_memops;
1010	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1011	q->lock = &ctx->mutex;
1012	q->min_buffers_needed = 3;
1013	q->dev = ctx->cal->dev;
1014
1015	ret = vb2_queue_init(q);
1016	if (ret)
1017		return ret;
1018
1019	/* Initialize the video device and media entity. */
1020	vfd->fops = &cal_fops;
1021	vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
1022			 | (cal_mc_api ? V4L2_CAP_IO_MC : 0);
1023	vfd->v4l2_dev = &ctx->cal->v4l2_dev;
1024	vfd->queue = q;
1025	snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx);
1026	vfd->release = video_device_release_empty;
1027	vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops;
1028	vfd->lock = &ctx->mutex;
1029	video_set_drvdata(vfd, ctx);
1030
1031	ctx->pad.flags = MEDIA_PAD_FL_SINK;
1032	ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad);
1033	if (ret < 0)
1034		return ret;
1035
1036	if (!cal_mc_api) {
1037		/* Initialize the control handler. */
1038		struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
1039
1040		ret = v4l2_ctrl_handler_init(hdl, 11);
1041		if (ret < 0) {
1042			ctx_err(ctx, "Failed to init ctrl handler\n");
1043			goto error;
1044		}
1045
1046		vfd->ctrl_handler = hdl;
1047	}
1048
1049	return 0;
1050
1051error:
1052	media_entity_cleanup(&vfd->entity);
1053	return ret;
1054}
1055
1056void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx)
1057{
1058	if (!cal_mc_api)
1059		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1060
1061	media_entity_cleanup(&ctx->vdev.entity);
1062}
1063