1*0c078e31SDaniel Almeida // SPDX-License-Identifier: GPL-2.0
2*0c078e31SDaniel Almeida /*
3*0c078e31SDaniel Almeida  * Contains the driver implementation for the V4L2 stateless interface.
4*0c078e31SDaniel Almeida  */
5*0c078e31SDaniel Almeida 
6*0c078e31SDaniel Almeida #include <linux/debugfs.h>
7*0c078e31SDaniel Almeida #include <linux/font.h>
8*0c078e31SDaniel Almeida #include <media/v4l2-event.h>
9*0c078e31SDaniel Almeida #include <media/v4l2-ioctl.h>
10*0c078e31SDaniel Almeida #include <media/videobuf2-vmalloc.h>
11*0c078e31SDaniel Almeida #include <media/videobuf2-v4l2.h>
12*0c078e31SDaniel Almeida 
13*0c078e31SDaniel Almeida #include "visl-video.h"
14*0c078e31SDaniel Almeida 
15*0c078e31SDaniel Almeida #include "visl.h"
16*0c078e31SDaniel Almeida #include "visl-debugfs.h"
17*0c078e31SDaniel Almeida 
18*0c078e31SDaniel Almeida #define MIN_CODED_SZ (1024U * 256U)
19*0c078e31SDaniel Almeida 
20*0c078e31SDaniel Almeida static void visl_set_current_codec(struct visl_ctx *ctx)
21*0c078e31SDaniel Almeida {
22*0c078e31SDaniel Almeida 	u32 fourcc = ctx->coded_fmt.fmt.pix_mp.pixelformat;
23*0c078e31SDaniel Almeida 
24*0c078e31SDaniel Almeida 	switch (fourcc) {
25*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_FWHT_STATELESS:
26*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_FWHT;
27*0c078e31SDaniel Almeida 		break;
28*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_MPEG2_SLICE:
29*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_MPEG2;
30*0c078e31SDaniel Almeida 		break;
31*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_VP8_FRAME:
32*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_VP8;
33*0c078e31SDaniel Almeida 		break;
34*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_VP9_FRAME:
35*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_VP9;
36*0c078e31SDaniel Almeida 		break;
37*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_H264_SLICE:
38*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_H264;
39*0c078e31SDaniel Almeida 		break;
40*0c078e31SDaniel Almeida 	case V4L2_PIX_FMT_HEVC_SLICE:
41*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_HEVC;
42*0c078e31SDaniel Almeida 		break;
43*0c078e31SDaniel Almeida 	default:
44*0c078e31SDaniel Almeida 		dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n", fourcc);
45*0c078e31SDaniel Almeida 		ctx->current_codec = VISL_CODEC_NONE;
46*0c078e31SDaniel Almeida 		break;
47*0c078e31SDaniel Almeida 	}
48*0c078e31SDaniel Almeida }
49*0c078e31SDaniel Almeida 
50*0c078e31SDaniel Almeida static void visl_print_fmt(struct visl_ctx *ctx, const struct v4l2_format *f)
51*0c078e31SDaniel Almeida {
52*0c078e31SDaniel Almeida 	const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
53*0c078e31SDaniel Almeida 	u32 i;
54*0c078e31SDaniel Almeida 
55*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "width: %d\n", pix_mp->width);
56*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "height: %d\n", pix_mp->height);
57*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "pixelformat: %c%c%c%c\n",
58*0c078e31SDaniel Almeida 		pix_mp->pixelformat,
59*0c078e31SDaniel Almeida 		(pix_mp->pixelformat >> 8) & 0xff,
60*0c078e31SDaniel Almeida 		(pix_mp->pixelformat >> 16) & 0xff,
61*0c078e31SDaniel Almeida 		(pix_mp->pixelformat >> 24) & 0xff);
62*0c078e31SDaniel Almeida 
63*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "field: %d\n", pix_mp->field);
64*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "colorspace: %d\n", pix_mp->colorspace);
65*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "num_planes: %d\n", pix_mp->num_planes);
66*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "flags: %d\n", pix_mp->flags);
67*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "quantization: %d\n", pix_mp->quantization);
68*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "xfer_func: %d\n", pix_mp->xfer_func);
69*0c078e31SDaniel Almeida 
70*0c078e31SDaniel Almeida 	for (i = 0; i < pix_mp->num_planes; i++) {
71*0c078e31SDaniel Almeida 		dprintk(ctx->dev,
72*0c078e31SDaniel Almeida 			"plane[%d]: sizeimage: %d\n", i, pix_mp->plane_fmt[i].sizeimage);
73*0c078e31SDaniel Almeida 		dprintk(ctx->dev,
74*0c078e31SDaniel Almeida 			"plane[%d]: bytesperline: %d\n", i, pix_mp->plane_fmt[i].bytesperline);
75*0c078e31SDaniel Almeida 	}
76*0c078e31SDaniel Almeida }
77*0c078e31SDaniel Almeida 
78*0c078e31SDaniel Almeida static int visl_tpg_init(struct visl_ctx *ctx)
79*0c078e31SDaniel Almeida {
80*0c078e31SDaniel Almeida 	const struct font_desc *font;
81*0c078e31SDaniel Almeida 	const char *font_name = "VGA8x16";
82*0c078e31SDaniel Almeida 	int ret;
83*0c078e31SDaniel Almeida 	u32 width = ctx->decoded_fmt.fmt.pix_mp.width;
84*0c078e31SDaniel Almeida 	u32 height = ctx->decoded_fmt.fmt.pix_mp.height;
85*0c078e31SDaniel Almeida 	struct v4l2_pix_format_mplane *f = &ctx->decoded_fmt.fmt.pix_mp;
86*0c078e31SDaniel Almeida 
87*0c078e31SDaniel Almeida 	tpg_free(&ctx->tpg);
88*0c078e31SDaniel Almeida 
89*0c078e31SDaniel Almeida 	font = find_font(font_name);
90*0c078e31SDaniel Almeida 	if (font) {
91*0c078e31SDaniel Almeida 		tpg_init(&ctx->tpg, width, height);
92*0c078e31SDaniel Almeida 
93*0c078e31SDaniel Almeida 		ret = tpg_alloc(&ctx->tpg, width);
94*0c078e31SDaniel Almeida 		if (ret)
95*0c078e31SDaniel Almeida 			goto err_alloc;
96*0c078e31SDaniel Almeida 
97*0c078e31SDaniel Almeida 		tpg_set_font(font->data);
98*0c078e31SDaniel Almeida 		ret = tpg_s_fourcc(&ctx->tpg,
99*0c078e31SDaniel Almeida 				   f->pixelformat);
100*0c078e31SDaniel Almeida 
101*0c078e31SDaniel Almeida 		if (!ret)
102*0c078e31SDaniel Almeida 			goto err_fourcc;
103*0c078e31SDaniel Almeida 
104*0c078e31SDaniel Almeida 		tpg_reset_source(&ctx->tpg, width, height, f->field);
105*0c078e31SDaniel Almeida 
106*0c078e31SDaniel Almeida 		tpg_s_pattern(&ctx->tpg, TPG_PAT_75_COLORBAR);
107*0c078e31SDaniel Almeida 
108*0c078e31SDaniel Almeida 		tpg_s_field(&ctx->tpg, f->field, false);
109*0c078e31SDaniel Almeida 		tpg_s_colorspace(&ctx->tpg, f->colorspace);
110*0c078e31SDaniel Almeida 		tpg_s_ycbcr_enc(&ctx->tpg, f->ycbcr_enc);
111*0c078e31SDaniel Almeida 		tpg_s_quantization(&ctx->tpg, f->quantization);
112*0c078e31SDaniel Almeida 		tpg_s_xfer_func(&ctx->tpg, f->xfer_func);
113*0c078e31SDaniel Almeida 	} else {
114*0c078e31SDaniel Almeida 		v4l2_err(&ctx->dev->v4l2_dev,
115*0c078e31SDaniel Almeida 			 "Font %s not found\n", font_name);
116*0c078e31SDaniel Almeida 
117*0c078e31SDaniel Almeida 		return -EINVAL;
118*0c078e31SDaniel Almeida 	}
119*0c078e31SDaniel Almeida 
120*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "Initialized the V4L2 test pattern generator, w=%d, h=%d, max_w=%d\n",
121*0c078e31SDaniel Almeida 		width, height, width);
122*0c078e31SDaniel Almeida 
123*0c078e31SDaniel Almeida 	return 0;
124*0c078e31SDaniel Almeida err_alloc:
125*0c078e31SDaniel Almeida 	return ret;
126*0c078e31SDaniel Almeida err_fourcc:
127*0c078e31SDaniel Almeida 	tpg_free(&ctx->tpg);
128*0c078e31SDaniel Almeida 	return ret;
129*0c078e31SDaniel Almeida }
130*0c078e31SDaniel Almeida 
131*0c078e31SDaniel Almeida static const u32 visl_decoded_fmts[] = {
132*0c078e31SDaniel Almeida 	V4L2_PIX_FMT_NV12,
133*0c078e31SDaniel Almeida 	V4L2_PIX_FMT_YUV420,
134*0c078e31SDaniel Almeida };
135*0c078e31SDaniel Almeida 
136*0c078e31SDaniel Almeida const struct visl_coded_format_desc visl_coded_fmts[] = {
137*0c078e31SDaniel Almeida 	{
138*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_FWHT_STATELESS,
139*0c078e31SDaniel Almeida 		.frmsize = {
140*0c078e31SDaniel Almeida 			.min_width = 640,
141*0c078e31SDaniel Almeida 			.max_width = 4096,
142*0c078e31SDaniel Almeida 			.step_width = 1,
143*0c078e31SDaniel Almeida 			.min_height = 360,
144*0c078e31SDaniel Almeida 			.max_height = 2160,
145*0c078e31SDaniel Almeida 			.step_height = 1,
146*0c078e31SDaniel Almeida 		},
147*0c078e31SDaniel Almeida 		.ctrls = &visl_fwht_ctrls,
148*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
149*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
150*0c078e31SDaniel Almeida 	},
151*0c078e31SDaniel Almeida 	{
152*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
153*0c078e31SDaniel Almeida 		.frmsize = {
154*0c078e31SDaniel Almeida 			.min_width = 16,
155*0c078e31SDaniel Almeida 			.max_width = 1920,
156*0c078e31SDaniel Almeida 			.step_width = 1,
157*0c078e31SDaniel Almeida 			.min_height = 16,
158*0c078e31SDaniel Almeida 			.max_height = 1152,
159*0c078e31SDaniel Almeida 			.step_height = 1,
160*0c078e31SDaniel Almeida 		},
161*0c078e31SDaniel Almeida 		.ctrls = &visl_mpeg2_ctrls,
162*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
163*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
164*0c078e31SDaniel Almeida 	},
165*0c078e31SDaniel Almeida 	{
166*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_VP8_FRAME,
167*0c078e31SDaniel Almeida 		.frmsize = {
168*0c078e31SDaniel Almeida 			.min_width = 64,
169*0c078e31SDaniel Almeida 			.max_width = 16383,
170*0c078e31SDaniel Almeida 			.step_width = 1,
171*0c078e31SDaniel Almeida 			.min_height = 64,
172*0c078e31SDaniel Almeida 			.max_height = 16383,
173*0c078e31SDaniel Almeida 			.step_height = 1,
174*0c078e31SDaniel Almeida 		},
175*0c078e31SDaniel Almeida 		.ctrls = &visl_vp8_ctrls,
176*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
177*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
178*0c078e31SDaniel Almeida 	},
179*0c078e31SDaniel Almeida 	{
180*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_VP9_FRAME,
181*0c078e31SDaniel Almeida 		.frmsize = {
182*0c078e31SDaniel Almeida 			.min_width = 64,
183*0c078e31SDaniel Almeida 			.max_width = 8192,
184*0c078e31SDaniel Almeida 			.step_width = 1,
185*0c078e31SDaniel Almeida 			.min_height = 64,
186*0c078e31SDaniel Almeida 			.max_height = 4352,
187*0c078e31SDaniel Almeida 			.step_height = 1,
188*0c078e31SDaniel Almeida 		},
189*0c078e31SDaniel Almeida 		.ctrls = &visl_vp9_ctrls,
190*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
191*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
192*0c078e31SDaniel Almeida 	},
193*0c078e31SDaniel Almeida 	{
194*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_H264_SLICE,
195*0c078e31SDaniel Almeida 		.frmsize = {
196*0c078e31SDaniel Almeida 			.min_width = 64,
197*0c078e31SDaniel Almeida 			.max_width = 4096,
198*0c078e31SDaniel Almeida 			.step_width = 1,
199*0c078e31SDaniel Almeida 			.min_height = 64,
200*0c078e31SDaniel Almeida 			.max_height = 2304,
201*0c078e31SDaniel Almeida 			.step_height = 1,
202*0c078e31SDaniel Almeida 		},
203*0c078e31SDaniel Almeida 		.ctrls = &visl_h264_ctrls,
204*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
205*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
206*0c078e31SDaniel Almeida 	},
207*0c078e31SDaniel Almeida 	{
208*0c078e31SDaniel Almeida 		.pixelformat = V4L2_PIX_FMT_HEVC_SLICE,
209*0c078e31SDaniel Almeida 		.frmsize = {
210*0c078e31SDaniel Almeida 			.min_width = 64,
211*0c078e31SDaniel Almeida 			.max_width = 4096,
212*0c078e31SDaniel Almeida 			.step_width = 1,
213*0c078e31SDaniel Almeida 			.min_height = 64,
214*0c078e31SDaniel Almeida 			.max_height = 2304,
215*0c078e31SDaniel Almeida 			.step_height = 1,
216*0c078e31SDaniel Almeida 		},
217*0c078e31SDaniel Almeida 		.ctrls = &visl_hevc_ctrls,
218*0c078e31SDaniel Almeida 		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
219*0c078e31SDaniel Almeida 		.decoded_fmts = visl_decoded_fmts,
220*0c078e31SDaniel Almeida 	},
221*0c078e31SDaniel Almeida };
222*0c078e31SDaniel Almeida 
223*0c078e31SDaniel Almeida const size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts);
224*0c078e31SDaniel Almeida 
225*0c078e31SDaniel Almeida static const struct visl_coded_format_desc*
226*0c078e31SDaniel Almeida visl_find_coded_fmt_desc(u32 fourcc)
227*0c078e31SDaniel Almeida {
228*0c078e31SDaniel Almeida 	unsigned int i;
229*0c078e31SDaniel Almeida 
230*0c078e31SDaniel Almeida 	for (i = 0; i < ARRAY_SIZE(visl_coded_fmts); i++) {
231*0c078e31SDaniel Almeida 		if (visl_coded_fmts[i].pixelformat == fourcc)
232*0c078e31SDaniel Almeida 			return &visl_coded_fmts[i];
233*0c078e31SDaniel Almeida 	}
234*0c078e31SDaniel Almeida 
235*0c078e31SDaniel Almeida 	return NULL;
236*0c078e31SDaniel Almeida }
237*0c078e31SDaniel Almeida 
238*0c078e31SDaniel Almeida static void visl_init_fmt(struct v4l2_format *f, u32 fourcc)
239*0c078e31SDaniel Almeida {	memset(f, 0, sizeof(*f));
240*0c078e31SDaniel Almeida 	f->fmt.pix_mp.pixelformat = fourcc;
241*0c078e31SDaniel Almeida 	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
242*0c078e31SDaniel Almeida 	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
243*0c078e31SDaniel Almeida 	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
244*0c078e31SDaniel Almeida 	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
245*0c078e31SDaniel Almeida 	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
246*0c078e31SDaniel Almeida }
247*0c078e31SDaniel Almeida 
248*0c078e31SDaniel Almeida static void visl_reset_coded_fmt(struct visl_ctx *ctx)
249*0c078e31SDaniel Almeida {
250*0c078e31SDaniel Almeida 	struct v4l2_format *f = &ctx->coded_fmt;
251*0c078e31SDaniel Almeida 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
252*0c078e31SDaniel Almeida 
253*0c078e31SDaniel Almeida 	ctx->coded_format_desc = &visl_coded_fmts[0];
254*0c078e31SDaniel Almeida 	visl_init_fmt(f, ctx->coded_format_desc->pixelformat);
255*0c078e31SDaniel Almeida 
256*0c078e31SDaniel Almeida 	f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
257*0c078e31SDaniel Almeida 	f->fmt.pix_mp.width = ctx->coded_format_desc->frmsize.min_width;
258*0c078e31SDaniel Almeida 	f->fmt.pix_mp.height = ctx->coded_format_desc->frmsize.min_height;
259*0c078e31SDaniel Almeida 
260*0c078e31SDaniel Almeida 	pix_mp->num_planes = 1;
261*0c078e31SDaniel Almeida 	pix_mp->plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * 8;
262*0c078e31SDaniel Almeida 
263*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "OUTPUT format was set to:\n");
264*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, &ctx->coded_fmt);
265*0c078e31SDaniel Almeida 
266*0c078e31SDaniel Almeida 	visl_set_current_codec(ctx);
267*0c078e31SDaniel Almeida }
268*0c078e31SDaniel Almeida 
269*0c078e31SDaniel Almeida static int visl_reset_decoded_fmt(struct visl_ctx *ctx)
270*0c078e31SDaniel Almeida {
271*0c078e31SDaniel Almeida 	struct v4l2_format *f = &ctx->decoded_fmt;
272*0c078e31SDaniel Almeida 	u32 decoded_fmt = ctx->coded_format_desc[0].decoded_fmts[0];
273*0c078e31SDaniel Almeida 
274*0c078e31SDaniel Almeida 	visl_init_fmt(f, decoded_fmt);
275*0c078e31SDaniel Almeida 
276*0c078e31SDaniel Almeida 	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
277*0c078e31SDaniel Almeida 
278*0c078e31SDaniel Almeida 	v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
279*0c078e31SDaniel Almeida 			    ctx->coded_format_desc->decoded_fmts[0],
280*0c078e31SDaniel Almeida 			    ctx->coded_fmt.fmt.pix_mp.width,
281*0c078e31SDaniel Almeida 			    ctx->coded_fmt.fmt.pix_mp.height);
282*0c078e31SDaniel Almeida 
283*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "CAPTURE format was set to:\n");
284*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, &ctx->decoded_fmt);
285*0c078e31SDaniel Almeida 
286*0c078e31SDaniel Almeida 	return visl_tpg_init(ctx);
287*0c078e31SDaniel Almeida }
288*0c078e31SDaniel Almeida 
289*0c078e31SDaniel Almeida int visl_set_default_format(struct visl_ctx *ctx)
290*0c078e31SDaniel Almeida {
291*0c078e31SDaniel Almeida 	visl_reset_coded_fmt(ctx);
292*0c078e31SDaniel Almeida 	return visl_reset_decoded_fmt(ctx);
293*0c078e31SDaniel Almeida }
294*0c078e31SDaniel Almeida 
295*0c078e31SDaniel Almeida static struct visl_q_data *get_q_data(struct visl_ctx *ctx,
296*0c078e31SDaniel Almeida 				      enum v4l2_buf_type type)
297*0c078e31SDaniel Almeida {
298*0c078e31SDaniel Almeida 	switch (type) {
299*0c078e31SDaniel Almeida 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
300*0c078e31SDaniel Almeida 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
301*0c078e31SDaniel Almeida 		return &ctx->q_data[V4L2_M2M_SRC];
302*0c078e31SDaniel Almeida 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
303*0c078e31SDaniel Almeida 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
304*0c078e31SDaniel Almeida 		return &ctx->q_data[V4L2_M2M_DST];
305*0c078e31SDaniel Almeida 	default:
306*0c078e31SDaniel Almeida 		break;
307*0c078e31SDaniel Almeida 	}
308*0c078e31SDaniel Almeida 	return NULL;
309*0c078e31SDaniel Almeida }
310*0c078e31SDaniel Almeida 
311*0c078e31SDaniel Almeida static int visl_querycap(struct file *file, void *priv,
312*0c078e31SDaniel Almeida 			 struct v4l2_capability *cap)
313*0c078e31SDaniel Almeida {
314*0c078e31SDaniel Almeida 	strscpy(cap->driver, VISL_NAME, sizeof(cap->driver));
315*0c078e31SDaniel Almeida 	strscpy(cap->card, VISL_NAME, sizeof(cap->card));
316*0c078e31SDaniel Almeida 	snprintf(cap->bus_info, sizeof(cap->bus_info),
317*0c078e31SDaniel Almeida 		 "platform:%s", VISL_NAME);
318*0c078e31SDaniel Almeida 
319*0c078e31SDaniel Almeida 	return 0;
320*0c078e31SDaniel Almeida }
321*0c078e31SDaniel Almeida 
322*0c078e31SDaniel Almeida static int visl_enum_fmt_vid_cap(struct file *file, void *priv,
323*0c078e31SDaniel Almeida 				 struct v4l2_fmtdesc *f)
324*0c078e31SDaniel Almeida {
325*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
326*0c078e31SDaniel Almeida 
327*0c078e31SDaniel Almeida 	if (f->index >= ctx->coded_format_desc->num_decoded_fmts)
328*0c078e31SDaniel Almeida 		return -EINVAL;
329*0c078e31SDaniel Almeida 
330*0c078e31SDaniel Almeida 	f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index];
331*0c078e31SDaniel Almeida 	return 0;
332*0c078e31SDaniel Almeida }
333*0c078e31SDaniel Almeida 
334*0c078e31SDaniel Almeida static int visl_enum_fmt_vid_out(struct file *file, void *priv,
335*0c078e31SDaniel Almeida 				 struct v4l2_fmtdesc *f)
336*0c078e31SDaniel Almeida {
337*0c078e31SDaniel Almeida 	if (f->index >= ARRAY_SIZE(visl_coded_fmts))
338*0c078e31SDaniel Almeida 		return -EINVAL;
339*0c078e31SDaniel Almeida 
340*0c078e31SDaniel Almeida 	f->pixelformat = visl_coded_fmts[f->index].pixelformat;
341*0c078e31SDaniel Almeida 	return 0;
342*0c078e31SDaniel Almeida }
343*0c078e31SDaniel Almeida 
344*0c078e31SDaniel Almeida static int visl_g_fmt_vid_cap(struct file *file, void *priv,
345*0c078e31SDaniel Almeida 			      struct v4l2_format *f)
346*0c078e31SDaniel Almeida {
347*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
348*0c078e31SDaniel Almeida 	*f = ctx->decoded_fmt;
349*0c078e31SDaniel Almeida 
350*0c078e31SDaniel Almeida 	return 0;
351*0c078e31SDaniel Almeida }
352*0c078e31SDaniel Almeida 
353*0c078e31SDaniel Almeida static int visl_g_fmt_vid_out(struct file *file, void *priv,
354*0c078e31SDaniel Almeida 			      struct v4l2_format *f)
355*0c078e31SDaniel Almeida {
356*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
357*0c078e31SDaniel Almeida 
358*0c078e31SDaniel Almeida 	*f = ctx->coded_fmt;
359*0c078e31SDaniel Almeida 	return 0;
360*0c078e31SDaniel Almeida }
361*0c078e31SDaniel Almeida 
362*0c078e31SDaniel Almeida static int visl_try_fmt_vid_cap(struct file *file, void *priv,
363*0c078e31SDaniel Almeida 				struct v4l2_format *f)
364*0c078e31SDaniel Almeida {
365*0c078e31SDaniel Almeida 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
366*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
367*0c078e31SDaniel Almeida 	const struct visl_coded_format_desc *coded_desc;
368*0c078e31SDaniel Almeida 	unsigned int i;
369*0c078e31SDaniel Almeida 
370*0c078e31SDaniel Almeida 	coded_desc = ctx->coded_format_desc;
371*0c078e31SDaniel Almeida 
372*0c078e31SDaniel Almeida 	for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
373*0c078e31SDaniel Almeida 		if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
374*0c078e31SDaniel Almeida 			break;
375*0c078e31SDaniel Almeida 	}
376*0c078e31SDaniel Almeida 
377*0c078e31SDaniel Almeida 	if (i == coded_desc->num_decoded_fmts)
378*0c078e31SDaniel Almeida 		pix_mp->pixelformat = coded_desc->decoded_fmts[0];
379*0c078e31SDaniel Almeida 
380*0c078e31SDaniel Almeida 	v4l2_apply_frmsize_constraints(&pix_mp->width,
381*0c078e31SDaniel Almeida 				       &pix_mp->height,
382*0c078e31SDaniel Almeida 				       &coded_desc->frmsize);
383*0c078e31SDaniel Almeida 
384*0c078e31SDaniel Almeida 	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
385*0c078e31SDaniel Almeida 			    pix_mp->width, pix_mp->height);
386*0c078e31SDaniel Almeida 
387*0c078e31SDaniel Almeida 	pix_mp->field = V4L2_FIELD_NONE;
388*0c078e31SDaniel Almeida 
389*0c078e31SDaniel Almeida 	return 0;
390*0c078e31SDaniel Almeida }
391*0c078e31SDaniel Almeida 
392*0c078e31SDaniel Almeida static int visl_try_fmt_vid_out(struct file *file, void *priv,
393*0c078e31SDaniel Almeida 				struct v4l2_format *f)
394*0c078e31SDaniel Almeida {
395*0c078e31SDaniel Almeida 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
396*0c078e31SDaniel Almeida 	const struct visl_coded_format_desc *coded_desc;
397*0c078e31SDaniel Almeida 
398*0c078e31SDaniel Almeida 	coded_desc = visl_find_coded_fmt_desc(pix_mp->pixelformat);
399*0c078e31SDaniel Almeida 	if (!coded_desc) {
400*0c078e31SDaniel Almeida 		pix_mp->pixelformat = visl_coded_fmts[0].pixelformat;
401*0c078e31SDaniel Almeida 		coded_desc = &visl_coded_fmts[0];
402*0c078e31SDaniel Almeida 	}
403*0c078e31SDaniel Almeida 
404*0c078e31SDaniel Almeida 	v4l2_apply_frmsize_constraints(&pix_mp->width,
405*0c078e31SDaniel Almeida 				       &pix_mp->height,
406*0c078e31SDaniel Almeida 				       &coded_desc->frmsize);
407*0c078e31SDaniel Almeida 
408*0c078e31SDaniel Almeida 	pix_mp->field = V4L2_FIELD_NONE;
409*0c078e31SDaniel Almeida 	pix_mp->num_planes = 1;
410*0c078e31SDaniel Almeida 
411*0c078e31SDaniel Almeida 	if (pix_mp->plane_fmt[0].sizeimage == 0)
412*0c078e31SDaniel Almeida 		pix_mp->plane_fmt[0].sizeimage = max(MIN_CODED_SZ,
413*0c078e31SDaniel Almeida 						     pix_mp->width * pix_mp->height * 3);
414*0c078e31SDaniel Almeida 
415*0c078e31SDaniel Almeida 	return 0;
416*0c078e31SDaniel Almeida }
417*0c078e31SDaniel Almeida 
418*0c078e31SDaniel Almeida static int visl_s_fmt_vid_out(struct file *file, void *priv,
419*0c078e31SDaniel Almeida 			      struct v4l2_format *f)
420*0c078e31SDaniel Almeida {
421*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
422*0c078e31SDaniel Almeida 	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
423*0c078e31SDaniel Almeida 	const struct visl_coded_format_desc *desc;
424*0c078e31SDaniel Almeida 	struct vb2_queue *peer_vq;
425*0c078e31SDaniel Almeida 	int ret;
426*0c078e31SDaniel Almeida 
427*0c078e31SDaniel Almeida 	peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
428*0c078e31SDaniel Almeida 	if (vb2_is_busy(peer_vq))
429*0c078e31SDaniel Almeida 		return -EBUSY;
430*0c078e31SDaniel Almeida 
431*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "Trying to set the OUTPUT format to:\n");
432*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, f);
433*0c078e31SDaniel Almeida 
434*0c078e31SDaniel Almeida 	ret = visl_try_fmt_vid_out(file, priv, f);
435*0c078e31SDaniel Almeida 	if (ret)
436*0c078e31SDaniel Almeida 		return ret;
437*0c078e31SDaniel Almeida 
438*0c078e31SDaniel Almeida 	desc = visl_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat);
439*0c078e31SDaniel Almeida 	ctx->coded_format_desc = desc;
440*0c078e31SDaniel Almeida 	ctx->coded_fmt = *f;
441*0c078e31SDaniel Almeida 
442*0c078e31SDaniel Almeida 	ret = visl_reset_decoded_fmt(ctx);
443*0c078e31SDaniel Almeida 	if (ret)
444*0c078e31SDaniel Almeida 		return ret;
445*0c078e31SDaniel Almeida 
446*0c078e31SDaniel Almeida 	ctx->decoded_fmt.fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
447*0c078e31SDaniel Almeida 	ctx->decoded_fmt.fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
448*0c078e31SDaniel Almeida 	ctx->decoded_fmt.fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
449*0c078e31SDaniel Almeida 	ctx->decoded_fmt.fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
450*0c078e31SDaniel Almeida 
451*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "OUTPUT format was set to:\n");
452*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, &ctx->coded_fmt);
453*0c078e31SDaniel Almeida 
454*0c078e31SDaniel Almeida 	visl_set_current_codec(ctx);
455*0c078e31SDaniel Almeida 	return 0;
456*0c078e31SDaniel Almeida }
457*0c078e31SDaniel Almeida 
458*0c078e31SDaniel Almeida static int visl_s_fmt_vid_cap(struct file *file, void *priv,
459*0c078e31SDaniel Almeida 			      struct v4l2_format *f)
460*0c078e31SDaniel Almeida {
461*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
462*0c078e31SDaniel Almeida 	int ret;
463*0c078e31SDaniel Almeida 
464*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "Trying to set the CAPTURE format to:\n");
465*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, f);
466*0c078e31SDaniel Almeida 
467*0c078e31SDaniel Almeida 	ret = visl_try_fmt_vid_cap(file, priv, f);
468*0c078e31SDaniel Almeida 	if (ret)
469*0c078e31SDaniel Almeida 		return ret;
470*0c078e31SDaniel Almeida 
471*0c078e31SDaniel Almeida 	ctx->decoded_fmt = *f;
472*0c078e31SDaniel Almeida 
473*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "CAPTURE format was set to:\n");
474*0c078e31SDaniel Almeida 	visl_print_fmt(ctx, &ctx->decoded_fmt);
475*0c078e31SDaniel Almeida 
476*0c078e31SDaniel Almeida 	visl_tpg_init(ctx);
477*0c078e31SDaniel Almeida 	return 0;
478*0c078e31SDaniel Almeida }
479*0c078e31SDaniel Almeida 
480*0c078e31SDaniel Almeida static int visl_enum_framesizes(struct file *file, void *priv,
481*0c078e31SDaniel Almeida 				struct v4l2_frmsizeenum *fsize)
482*0c078e31SDaniel Almeida {
483*0c078e31SDaniel Almeida 	const struct visl_coded_format_desc *fmt;
484*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = visl_file_to_ctx(file);
485*0c078e31SDaniel Almeida 
486*0c078e31SDaniel Almeida 	if (fsize->index != 0)
487*0c078e31SDaniel Almeida 		return -EINVAL;
488*0c078e31SDaniel Almeida 
489*0c078e31SDaniel Almeida 	fmt = visl_find_coded_fmt_desc(fsize->pixel_format);
490*0c078e31SDaniel Almeida 	if (!fmt) {
491*0c078e31SDaniel Almeida 		dprintk(ctx->dev,
492*0c078e31SDaniel Almeida 			"Unsupported format for the OUTPUT queue: %d\n",
493*0c078e31SDaniel Almeida 			fsize->pixel_format);
494*0c078e31SDaniel Almeida 
495*0c078e31SDaniel Almeida 		return -EINVAL;
496*0c078e31SDaniel Almeida 	}
497*0c078e31SDaniel Almeida 
498*0c078e31SDaniel Almeida 	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
499*0c078e31SDaniel Almeida 	fsize->stepwise = fmt->frmsize;
500*0c078e31SDaniel Almeida 	return 0;
501*0c078e31SDaniel Almeida }
502*0c078e31SDaniel Almeida 
503*0c078e31SDaniel Almeida const struct v4l2_ioctl_ops visl_ioctl_ops = {
504*0c078e31SDaniel Almeida 	.vidioc_querycap		= visl_querycap,
505*0c078e31SDaniel Almeida 	.vidioc_enum_framesizes		= visl_enum_framesizes,
506*0c078e31SDaniel Almeida 
507*0c078e31SDaniel Almeida 	.vidioc_enum_fmt_vid_cap	= visl_enum_fmt_vid_cap,
508*0c078e31SDaniel Almeida 	.vidioc_g_fmt_vid_cap_mplane	= visl_g_fmt_vid_cap,
509*0c078e31SDaniel Almeida 	.vidioc_try_fmt_vid_cap_mplane	= visl_try_fmt_vid_cap,
510*0c078e31SDaniel Almeida 	.vidioc_s_fmt_vid_cap_mplane	= visl_s_fmt_vid_cap,
511*0c078e31SDaniel Almeida 
512*0c078e31SDaniel Almeida 	.vidioc_enum_fmt_vid_out	= visl_enum_fmt_vid_out,
513*0c078e31SDaniel Almeida 	.vidioc_g_fmt_vid_out_mplane	= visl_g_fmt_vid_out,
514*0c078e31SDaniel Almeida 	.vidioc_try_fmt_vid_out_mplane	= visl_try_fmt_vid_out,
515*0c078e31SDaniel Almeida 	.vidioc_s_fmt_vid_out_mplane	= visl_s_fmt_vid_out,
516*0c078e31SDaniel Almeida 
517*0c078e31SDaniel Almeida 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
518*0c078e31SDaniel Almeida 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
519*0c078e31SDaniel Almeida 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
520*0c078e31SDaniel Almeida 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
521*0c078e31SDaniel Almeida 	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
522*0c078e31SDaniel Almeida 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
523*0c078e31SDaniel Almeida 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
524*0c078e31SDaniel Almeida 
525*0c078e31SDaniel Almeida 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
526*0c078e31SDaniel Almeida 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
527*0c078e31SDaniel Almeida 
528*0c078e31SDaniel Almeida 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
529*0c078e31SDaniel Almeida 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
530*0c078e31SDaniel Almeida };
531*0c078e31SDaniel Almeida 
532*0c078e31SDaniel Almeida static int visl_queue_setup(struct vb2_queue *vq,
533*0c078e31SDaniel Almeida 			    unsigned int *nbuffers,
534*0c078e31SDaniel Almeida 			    unsigned int *num_planes,
535*0c078e31SDaniel Almeida 			    unsigned int sizes[],
536*0c078e31SDaniel Almeida 			    struct device *alloc_devs[])
537*0c078e31SDaniel Almeida {
538*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
539*0c078e31SDaniel Almeida 	struct v4l2_format *f;
540*0c078e31SDaniel Almeida 	u32 i;
541*0c078e31SDaniel Almeida 	char *qname;
542*0c078e31SDaniel Almeida 
543*0c078e31SDaniel Almeida 	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
544*0c078e31SDaniel Almeida 		f = &ctx->coded_fmt;
545*0c078e31SDaniel Almeida 		qname = "Output";
546*0c078e31SDaniel Almeida 	} else {
547*0c078e31SDaniel Almeida 		f = &ctx->decoded_fmt;
548*0c078e31SDaniel Almeida 		qname = "Capture";
549*0c078e31SDaniel Almeida 	}
550*0c078e31SDaniel Almeida 
551*0c078e31SDaniel Almeida 	if (*num_planes) {
552*0c078e31SDaniel Almeida 		if (*num_planes != f->fmt.pix_mp.num_planes)
553*0c078e31SDaniel Almeida 			return -EINVAL;
554*0c078e31SDaniel Almeida 
555*0c078e31SDaniel Almeida 		for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
556*0c078e31SDaniel Almeida 			if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
557*0c078e31SDaniel Almeida 				return -EINVAL;
558*0c078e31SDaniel Almeida 		}
559*0c078e31SDaniel Almeida 	} else {
560*0c078e31SDaniel Almeida 		*num_planes = f->fmt.pix_mp.num_planes;
561*0c078e31SDaniel Almeida 		for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
562*0c078e31SDaniel Almeida 			sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
563*0c078e31SDaniel Almeida 	}
564*0c078e31SDaniel Almeida 
565*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "%s: %d buffer(s) requested, num_planes=%d.\n",
566*0c078e31SDaniel Almeida 		qname, *nbuffers, *num_planes);
567*0c078e31SDaniel Almeida 
568*0c078e31SDaniel Almeida 	for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
569*0c078e31SDaniel Almeida 		dprintk(ctx->dev, "plane[%d].sizeimage=%d\n",
570*0c078e31SDaniel Almeida 			i, f->fmt.pix_mp.plane_fmt[i].sizeimage);
571*0c078e31SDaniel Almeida 
572*0c078e31SDaniel Almeida 	return 0;
573*0c078e31SDaniel Almeida }
574*0c078e31SDaniel Almeida 
575*0c078e31SDaniel Almeida static void visl_queue_cleanup(struct vb2_queue *vq, u32 state)
576*0c078e31SDaniel Almeida {
577*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
578*0c078e31SDaniel Almeida 	struct vb2_v4l2_buffer *vbuf;
579*0c078e31SDaniel Almeida 
580*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "Cleaning up queues\n");
581*0c078e31SDaniel Almeida 	for (;;) {
582*0c078e31SDaniel Almeida 		if (V4L2_TYPE_IS_OUTPUT(vq->type))
583*0c078e31SDaniel Almeida 			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
584*0c078e31SDaniel Almeida 		else
585*0c078e31SDaniel Almeida 			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
586*0c078e31SDaniel Almeida 
587*0c078e31SDaniel Almeida 		if (!vbuf)
588*0c078e31SDaniel Almeida 			break;
589*0c078e31SDaniel Almeida 
590*0c078e31SDaniel Almeida 		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
591*0c078e31SDaniel Almeida 					   &ctx->hdl);
592*0c078e31SDaniel Almeida 		dprintk(ctx->dev, "Marked request %p as complete\n",
593*0c078e31SDaniel Almeida 			vbuf->vb2_buf.req_obj.req);
594*0c078e31SDaniel Almeida 
595*0c078e31SDaniel Almeida 		v4l2_m2m_buf_done(vbuf, state);
596*0c078e31SDaniel Almeida 		dprintk(ctx->dev,
597*0c078e31SDaniel Almeida 			"Marked buffer %llu as done, state is %d\n",
598*0c078e31SDaniel Almeida 			vbuf->vb2_buf.timestamp,
599*0c078e31SDaniel Almeida 			state);
600*0c078e31SDaniel Almeida 	}
601*0c078e31SDaniel Almeida }
602*0c078e31SDaniel Almeida 
603*0c078e31SDaniel Almeida static int visl_buf_out_validate(struct vb2_buffer *vb)
604*0c078e31SDaniel Almeida {
605*0c078e31SDaniel Almeida 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
606*0c078e31SDaniel Almeida 
607*0c078e31SDaniel Almeida 	vbuf->field = V4L2_FIELD_NONE;
608*0c078e31SDaniel Almeida 	return 0;
609*0c078e31SDaniel Almeida }
610*0c078e31SDaniel Almeida 
611*0c078e31SDaniel Almeida static int visl_buf_prepare(struct vb2_buffer *vb)
612*0c078e31SDaniel Almeida {
613*0c078e31SDaniel Almeida 	struct vb2_queue *vq = vb->vb2_queue;
614*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
615*0c078e31SDaniel Almeida 	u32 plane_sz = vb2_plane_size(vb, 0);
616*0c078e31SDaniel Almeida 	struct v4l2_pix_format *pix_fmt;
617*0c078e31SDaniel Almeida 
618*0c078e31SDaniel Almeida 	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
619*0c078e31SDaniel Almeida 		pix_fmt = &ctx->coded_fmt.fmt.pix;
620*0c078e31SDaniel Almeida 	} else {
621*0c078e31SDaniel Almeida 		pix_fmt = &ctx->decoded_fmt.fmt.pix;
622*0c078e31SDaniel Almeida 		vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
623*0c078e31SDaniel Almeida 	}
624*0c078e31SDaniel Almeida 
625*0c078e31SDaniel Almeida 	if (plane_sz < pix_fmt->sizeimage) {
626*0c078e31SDaniel Almeida 		v4l2_err(&ctx->dev->v4l2_dev, "plane[0] size is %d, sizeimage is %d\n",
627*0c078e31SDaniel Almeida 			 plane_sz, pix_fmt->sizeimage);
628*0c078e31SDaniel Almeida 		return -EINVAL;
629*0c078e31SDaniel Almeida 	}
630*0c078e31SDaniel Almeida 
631*0c078e31SDaniel Almeida 	return 0;
632*0c078e31SDaniel Almeida }
633*0c078e31SDaniel Almeida 
634*0c078e31SDaniel Almeida static int visl_start_streaming(struct vb2_queue *vq, unsigned int count)
635*0c078e31SDaniel Almeida {
636*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
637*0c078e31SDaniel Almeida 	struct visl_q_data *q_data = get_q_data(ctx, vq->type);
638*0c078e31SDaniel Almeida 	int rc = 0;
639*0c078e31SDaniel Almeida 
640*0c078e31SDaniel Almeida 	if (!q_data) {
641*0c078e31SDaniel Almeida 		rc = -EINVAL;
642*0c078e31SDaniel Almeida 		goto err;
643*0c078e31SDaniel Almeida 	}
644*0c078e31SDaniel Almeida 
645*0c078e31SDaniel Almeida 	q_data->sequence = 0;
646*0c078e31SDaniel Almeida 
647*0c078e31SDaniel Almeida 	if (V4L2_TYPE_IS_CAPTURE(vq->type)) {
648*0c078e31SDaniel Almeida 		ctx->capture_streamon_jiffies = get_jiffies_64();
649*0c078e31SDaniel Almeida 		return 0;
650*0c078e31SDaniel Almeida 	}
651*0c078e31SDaniel Almeida 
652*0c078e31SDaniel Almeida 	if (WARN_ON(!ctx->coded_format_desc)) {
653*0c078e31SDaniel Almeida 		rc =  -EINVAL;
654*0c078e31SDaniel Almeida 		goto err;
655*0c078e31SDaniel Almeida 	}
656*0c078e31SDaniel Almeida 
657*0c078e31SDaniel Almeida 	return 0;
658*0c078e31SDaniel Almeida 
659*0c078e31SDaniel Almeida err:
660*0c078e31SDaniel Almeida 	visl_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
661*0c078e31SDaniel Almeida 	return rc;
662*0c078e31SDaniel Almeida }
663*0c078e31SDaniel Almeida 
664*0c078e31SDaniel Almeida static void visl_stop_streaming(struct vb2_queue *vq)
665*0c078e31SDaniel Almeida {
666*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
667*0c078e31SDaniel Almeida 
668*0c078e31SDaniel Almeida 	dprintk(ctx->dev, "Stop streaming\n");
669*0c078e31SDaniel Almeida 	visl_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
670*0c078e31SDaniel Almeida 
671*0c078e31SDaniel Almeida 	if (!keep_bitstream_buffers)
672*0c078e31SDaniel Almeida 		visl_debugfs_clear_bitstream(ctx->dev);
673*0c078e31SDaniel Almeida }
674*0c078e31SDaniel Almeida 
675*0c078e31SDaniel Almeida static void visl_buf_queue(struct vb2_buffer *vb)
676*0c078e31SDaniel Almeida {
677*0c078e31SDaniel Almeida 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
678*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
679*0c078e31SDaniel Almeida 
680*0c078e31SDaniel Almeida 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
681*0c078e31SDaniel Almeida }
682*0c078e31SDaniel Almeida 
683*0c078e31SDaniel Almeida static void visl_buf_request_complete(struct vb2_buffer *vb)
684*0c078e31SDaniel Almeida {
685*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
686*0c078e31SDaniel Almeida 
687*0c078e31SDaniel Almeida 	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
688*0c078e31SDaniel Almeida }
689*0c078e31SDaniel Almeida 
690*0c078e31SDaniel Almeida const struct vb2_ops visl_qops = {
691*0c078e31SDaniel Almeida 	.queue_setup          = visl_queue_setup,
692*0c078e31SDaniel Almeida 	.buf_out_validate     = visl_buf_out_validate,
693*0c078e31SDaniel Almeida 	.buf_prepare          = visl_buf_prepare,
694*0c078e31SDaniel Almeida 	.buf_queue            = visl_buf_queue,
695*0c078e31SDaniel Almeida 	.start_streaming      = visl_start_streaming,
696*0c078e31SDaniel Almeida 	.stop_streaming       = visl_stop_streaming,
697*0c078e31SDaniel Almeida 	.wait_prepare         = vb2_ops_wait_prepare,
698*0c078e31SDaniel Almeida 	.wait_finish          = vb2_ops_wait_finish,
699*0c078e31SDaniel Almeida 	.buf_request_complete = visl_buf_request_complete,
700*0c078e31SDaniel Almeida };
701*0c078e31SDaniel Almeida 
702*0c078e31SDaniel Almeida int visl_queue_init(void *priv, struct vb2_queue *src_vq,
703*0c078e31SDaniel Almeida 		    struct vb2_queue *dst_vq)
704*0c078e31SDaniel Almeida {
705*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = priv;
706*0c078e31SDaniel Almeida 	int ret;
707*0c078e31SDaniel Almeida 
708*0c078e31SDaniel Almeida 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
709*0c078e31SDaniel Almeida 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
710*0c078e31SDaniel Almeida 	src_vq->drv_priv = ctx;
711*0c078e31SDaniel Almeida 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
712*0c078e31SDaniel Almeida 	src_vq->ops = &visl_qops;
713*0c078e31SDaniel Almeida 	src_vq->mem_ops = &vb2_vmalloc_memops;
714*0c078e31SDaniel Almeida 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
715*0c078e31SDaniel Almeida 	src_vq->lock = &ctx->vb_mutex;
716*0c078e31SDaniel Almeida 	src_vq->supports_requests = true;
717*0c078e31SDaniel Almeida 	src_vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
718*0c078e31SDaniel Almeida 
719*0c078e31SDaniel Almeida 	ret = vb2_queue_init(src_vq);
720*0c078e31SDaniel Almeida 	if (ret)
721*0c078e31SDaniel Almeida 		return ret;
722*0c078e31SDaniel Almeida 
723*0c078e31SDaniel Almeida 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
724*0c078e31SDaniel Almeida 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
725*0c078e31SDaniel Almeida 	dst_vq->drv_priv = ctx;
726*0c078e31SDaniel Almeida 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
727*0c078e31SDaniel Almeida 	dst_vq->ops = &visl_qops;
728*0c078e31SDaniel Almeida 	dst_vq->mem_ops = &vb2_vmalloc_memops;
729*0c078e31SDaniel Almeida 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
730*0c078e31SDaniel Almeida 	dst_vq->lock = &ctx->vb_mutex;
731*0c078e31SDaniel Almeida 
732*0c078e31SDaniel Almeida 	return vb2_queue_init(dst_vq);
733*0c078e31SDaniel Almeida }
734*0c078e31SDaniel Almeida 
735*0c078e31SDaniel Almeida int visl_request_validate(struct media_request *req)
736*0c078e31SDaniel Almeida {
737*0c078e31SDaniel Almeida 	struct media_request_object *obj;
738*0c078e31SDaniel Almeida 	struct visl_ctx *ctx = NULL;
739*0c078e31SDaniel Almeida 	unsigned int count;
740*0c078e31SDaniel Almeida 
741*0c078e31SDaniel Almeida 	list_for_each_entry(obj, &req->objects, list) {
742*0c078e31SDaniel Almeida 		struct vb2_buffer *vb;
743*0c078e31SDaniel Almeida 
744*0c078e31SDaniel Almeida 		if (vb2_request_object_is_buffer(obj)) {
745*0c078e31SDaniel Almeida 			vb = container_of(obj, struct vb2_buffer, req_obj);
746*0c078e31SDaniel Almeida 			ctx = vb2_get_drv_priv(vb->vb2_queue);
747*0c078e31SDaniel Almeida 
748*0c078e31SDaniel Almeida 			break;
749*0c078e31SDaniel Almeida 		}
750*0c078e31SDaniel Almeida 	}
751*0c078e31SDaniel Almeida 
752*0c078e31SDaniel Almeida 	if (!ctx)
753*0c078e31SDaniel Almeida 		return -ENOENT;
754*0c078e31SDaniel Almeida 
755*0c078e31SDaniel Almeida 	count = vb2_request_buffer_cnt(req);
756*0c078e31SDaniel Almeida 	if (!count) {
757*0c078e31SDaniel Almeida 		v4l2_err(&ctx->dev->v4l2_dev,
758*0c078e31SDaniel Almeida 			 "No buffer was provided with the request\n");
759*0c078e31SDaniel Almeida 		return -ENOENT;
760*0c078e31SDaniel Almeida 	} else if (count > 1) {
761*0c078e31SDaniel Almeida 		v4l2_err(&ctx->dev->v4l2_dev,
762*0c078e31SDaniel Almeida 			 "More than one buffer was provided with the request\n");
763*0c078e31SDaniel Almeida 		return -EINVAL;
764*0c078e31SDaniel Almeida 	}
765*0c078e31SDaniel Almeida 
766*0c078e31SDaniel Almeida 	return vb2_request_validate(req);
767*0c078e31SDaniel Almeida }
768