162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Contains the driver implementation for the V4L2 stateless interface.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/debugfs.h>
762306a36Sopenharmony_ci#include <linux/font.h>
862306a36Sopenharmony_ci#include <media/v4l2-event.h>
962306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
1062306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
1162306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "visl-video.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "visl.h"
1662306a36Sopenharmony_ci#include "visl-debugfs.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define MIN_CODED_SZ (1024U * 256U)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void visl_set_current_codec(struct visl_ctx *ctx)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	u32 fourcc = ctx->coded_fmt.fmt.pix_mp.pixelformat;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	switch (fourcc) {
2562306a36Sopenharmony_ci	case V4L2_PIX_FMT_FWHT_STATELESS:
2662306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_FWHT;
2762306a36Sopenharmony_ci		break;
2862306a36Sopenharmony_ci	case V4L2_PIX_FMT_MPEG2_SLICE:
2962306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_MPEG2;
3062306a36Sopenharmony_ci		break;
3162306a36Sopenharmony_ci	case V4L2_PIX_FMT_VP8_FRAME:
3262306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_VP8;
3362306a36Sopenharmony_ci		break;
3462306a36Sopenharmony_ci	case V4L2_PIX_FMT_VP9_FRAME:
3562306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_VP9;
3662306a36Sopenharmony_ci		break;
3762306a36Sopenharmony_ci	case V4L2_PIX_FMT_H264_SLICE:
3862306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_H264;
3962306a36Sopenharmony_ci		break;
4062306a36Sopenharmony_ci	case V4L2_PIX_FMT_HEVC_SLICE:
4162306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_HEVC;
4262306a36Sopenharmony_ci		break;
4362306a36Sopenharmony_ci	default:
4462306a36Sopenharmony_ci		dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n", fourcc);
4562306a36Sopenharmony_ci		ctx->current_codec = VISL_CODEC_NONE;
4662306a36Sopenharmony_ci		break;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void visl_print_fmt(struct visl_ctx *ctx, const struct v4l2_format *f)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
5362306a36Sopenharmony_ci	u32 i;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	dprintk(ctx->dev, "width: %d\n", pix_mp->width);
5662306a36Sopenharmony_ci	dprintk(ctx->dev, "height: %d\n", pix_mp->height);
5762306a36Sopenharmony_ci	dprintk(ctx->dev, "pixelformat: %c%c%c%c\n",
5862306a36Sopenharmony_ci		pix_mp->pixelformat,
5962306a36Sopenharmony_ci		(pix_mp->pixelformat >> 8) & 0xff,
6062306a36Sopenharmony_ci		(pix_mp->pixelformat >> 16) & 0xff,
6162306a36Sopenharmony_ci		(pix_mp->pixelformat >> 24) & 0xff);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	dprintk(ctx->dev, "field: %d\n", pix_mp->field);
6462306a36Sopenharmony_ci	dprintk(ctx->dev, "colorspace: %d\n", pix_mp->colorspace);
6562306a36Sopenharmony_ci	dprintk(ctx->dev, "num_planes: %d\n", pix_mp->num_planes);
6662306a36Sopenharmony_ci	dprintk(ctx->dev, "flags: %d\n", pix_mp->flags);
6762306a36Sopenharmony_ci	dprintk(ctx->dev, "quantization: %d\n", pix_mp->quantization);
6862306a36Sopenharmony_ci	dprintk(ctx->dev, "xfer_func: %d\n", pix_mp->xfer_func);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	for (i = 0; i < pix_mp->num_planes; i++) {
7162306a36Sopenharmony_ci		dprintk(ctx->dev,
7262306a36Sopenharmony_ci			"plane[%d]: sizeimage: %d\n", i, pix_mp->plane_fmt[i].sizeimage);
7362306a36Sopenharmony_ci		dprintk(ctx->dev,
7462306a36Sopenharmony_ci			"plane[%d]: bytesperline: %d\n", i, pix_mp->plane_fmt[i].bytesperline);
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int visl_tpg_init(struct visl_ctx *ctx)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	const struct font_desc *font;
8162306a36Sopenharmony_ci	const char *font_name = "VGA8x16";
8262306a36Sopenharmony_ci	int ret;
8362306a36Sopenharmony_ci	u32 width = ctx->decoded_fmt.fmt.pix_mp.width;
8462306a36Sopenharmony_ci	u32 height = ctx->decoded_fmt.fmt.pix_mp.height;
8562306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *f = &ctx->decoded_fmt.fmt.pix_mp;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	tpg_free(&ctx->tpg);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	font = find_font(font_name);
9062306a36Sopenharmony_ci	if (font) {
9162306a36Sopenharmony_ci		tpg_init(&ctx->tpg, width, height);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		ret = tpg_alloc(&ctx->tpg, width);
9462306a36Sopenharmony_ci		if (ret)
9562306a36Sopenharmony_ci			goto err_alloc;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		tpg_set_font(font->data);
9862306a36Sopenharmony_ci		ret = tpg_s_fourcc(&ctx->tpg,
9962306a36Sopenharmony_ci				   f->pixelformat);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		if (!ret)
10262306a36Sopenharmony_ci			goto err_fourcc;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		tpg_reset_source(&ctx->tpg, width, height, f->field);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		tpg_s_pattern(&ctx->tpg, TPG_PAT_75_COLORBAR);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		tpg_s_field(&ctx->tpg, f->field, false);
10962306a36Sopenharmony_ci		tpg_s_colorspace(&ctx->tpg, f->colorspace);
11062306a36Sopenharmony_ci		tpg_s_ycbcr_enc(&ctx->tpg, f->ycbcr_enc);
11162306a36Sopenharmony_ci		tpg_s_quantization(&ctx->tpg, f->quantization);
11262306a36Sopenharmony_ci		tpg_s_xfer_func(&ctx->tpg, f->xfer_func);
11362306a36Sopenharmony_ci	} else {
11462306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
11562306a36Sopenharmony_ci			 "Font %s not found\n", font_name);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		return -EINVAL;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	dprintk(ctx->dev, "Initialized the V4L2 test pattern generator, w=%d, h=%d, max_w=%d\n",
12162306a36Sopenharmony_ci		width, height, width);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_cierr_alloc:
12562306a36Sopenharmony_ci	return ret;
12662306a36Sopenharmony_cierr_fourcc:
12762306a36Sopenharmony_ci	tpg_free(&ctx->tpg);
12862306a36Sopenharmony_ci	return ret;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const u32 visl_decoded_fmts[] = {
13262306a36Sopenharmony_ci	V4L2_PIX_FMT_NV12,
13362306a36Sopenharmony_ci	V4L2_PIX_FMT_YUV420,
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ciconst struct visl_coded_format_desc visl_coded_fmts[] = {
13762306a36Sopenharmony_ci	{
13862306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_FWHT_STATELESS,
13962306a36Sopenharmony_ci		.frmsize = {
14062306a36Sopenharmony_ci			.min_width = 640,
14162306a36Sopenharmony_ci			.max_width = 4096,
14262306a36Sopenharmony_ci			.step_width = 1,
14362306a36Sopenharmony_ci			.min_height = 360,
14462306a36Sopenharmony_ci			.max_height = 2160,
14562306a36Sopenharmony_ci			.step_height = 1,
14662306a36Sopenharmony_ci		},
14762306a36Sopenharmony_ci		.ctrls = &visl_fwht_ctrls,
14862306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
14962306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
15062306a36Sopenharmony_ci	},
15162306a36Sopenharmony_ci	{
15262306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
15362306a36Sopenharmony_ci		.frmsize = {
15462306a36Sopenharmony_ci			.min_width = 16,
15562306a36Sopenharmony_ci			.max_width = 1920,
15662306a36Sopenharmony_ci			.step_width = 1,
15762306a36Sopenharmony_ci			.min_height = 16,
15862306a36Sopenharmony_ci			.max_height = 1152,
15962306a36Sopenharmony_ci			.step_height = 1,
16062306a36Sopenharmony_ci		},
16162306a36Sopenharmony_ci		.ctrls = &visl_mpeg2_ctrls,
16262306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
16362306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
16462306a36Sopenharmony_ci	},
16562306a36Sopenharmony_ci	{
16662306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_VP8_FRAME,
16762306a36Sopenharmony_ci		.frmsize = {
16862306a36Sopenharmony_ci			.min_width = 64,
16962306a36Sopenharmony_ci			.max_width = 16383,
17062306a36Sopenharmony_ci			.step_width = 1,
17162306a36Sopenharmony_ci			.min_height = 64,
17262306a36Sopenharmony_ci			.max_height = 16383,
17362306a36Sopenharmony_ci			.step_height = 1,
17462306a36Sopenharmony_ci		},
17562306a36Sopenharmony_ci		.ctrls = &visl_vp8_ctrls,
17662306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
17762306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
17862306a36Sopenharmony_ci	},
17962306a36Sopenharmony_ci	{
18062306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_VP9_FRAME,
18162306a36Sopenharmony_ci		.frmsize = {
18262306a36Sopenharmony_ci			.min_width = 64,
18362306a36Sopenharmony_ci			.max_width = 8192,
18462306a36Sopenharmony_ci			.step_width = 1,
18562306a36Sopenharmony_ci			.min_height = 64,
18662306a36Sopenharmony_ci			.max_height = 4352,
18762306a36Sopenharmony_ci			.step_height = 1,
18862306a36Sopenharmony_ci		},
18962306a36Sopenharmony_ci		.ctrls = &visl_vp9_ctrls,
19062306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
19162306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
19262306a36Sopenharmony_ci	},
19362306a36Sopenharmony_ci	{
19462306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_H264_SLICE,
19562306a36Sopenharmony_ci		.frmsize = {
19662306a36Sopenharmony_ci			.min_width = 64,
19762306a36Sopenharmony_ci			.max_width = 4096,
19862306a36Sopenharmony_ci			.step_width = 1,
19962306a36Sopenharmony_ci			.min_height = 64,
20062306a36Sopenharmony_ci			.max_height = 2304,
20162306a36Sopenharmony_ci			.step_height = 1,
20262306a36Sopenharmony_ci		},
20362306a36Sopenharmony_ci		.ctrls = &visl_h264_ctrls,
20462306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
20562306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
20662306a36Sopenharmony_ci	},
20762306a36Sopenharmony_ci	{
20862306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_HEVC_SLICE,
20962306a36Sopenharmony_ci		.frmsize = {
21062306a36Sopenharmony_ci			.min_width = 64,
21162306a36Sopenharmony_ci			.max_width = 4096,
21262306a36Sopenharmony_ci			.step_width = 1,
21362306a36Sopenharmony_ci			.min_height = 64,
21462306a36Sopenharmony_ci			.max_height = 2304,
21562306a36Sopenharmony_ci			.step_height = 1,
21662306a36Sopenharmony_ci		},
21762306a36Sopenharmony_ci		.ctrls = &visl_hevc_ctrls,
21862306a36Sopenharmony_ci		.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
21962306a36Sopenharmony_ci		.decoded_fmts = visl_decoded_fmts,
22062306a36Sopenharmony_ci	},
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciconst size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic const struct visl_coded_format_desc*
22662306a36Sopenharmony_civisl_find_coded_fmt_desc(u32 fourcc)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	unsigned int i;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(visl_coded_fmts); i++) {
23162306a36Sopenharmony_ci		if (visl_coded_fmts[i].pixelformat == fourcc)
23262306a36Sopenharmony_ci			return &visl_coded_fmts[i];
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return NULL;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic void visl_init_fmt(struct v4l2_format *f, u32 fourcc)
23962306a36Sopenharmony_ci{	memset(f, 0, sizeof(*f));
24062306a36Sopenharmony_ci	f->fmt.pix_mp.pixelformat = fourcc;
24162306a36Sopenharmony_ci	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
24262306a36Sopenharmony_ci	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
24362306a36Sopenharmony_ci	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
24462306a36Sopenharmony_ci	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
24562306a36Sopenharmony_ci	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void visl_reset_coded_fmt(struct visl_ctx *ctx)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct v4l2_format *f = &ctx->coded_fmt;
25162306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ctx->coded_format_desc = &visl_coded_fmts[0];
25462306a36Sopenharmony_ci	visl_init_fmt(f, ctx->coded_format_desc->pixelformat);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
25762306a36Sopenharmony_ci	f->fmt.pix_mp.width = ctx->coded_format_desc->frmsize.min_width;
25862306a36Sopenharmony_ci	f->fmt.pix_mp.height = ctx->coded_format_desc->frmsize.min_height;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	pix_mp->num_planes = 1;
26162306a36Sopenharmony_ci	pix_mp->plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * 8;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	dprintk(ctx->dev, "OUTPUT format was set to:\n");
26462306a36Sopenharmony_ci	visl_print_fmt(ctx, &ctx->coded_fmt);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	visl_set_current_codec(ctx);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int visl_reset_decoded_fmt(struct visl_ctx *ctx)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct v4l2_format *f = &ctx->decoded_fmt;
27262306a36Sopenharmony_ci	u32 decoded_fmt = ctx->coded_format_desc[0].decoded_fmts[0];
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	visl_init_fmt(f, decoded_fmt);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
27962306a36Sopenharmony_ci			    ctx->coded_format_desc->decoded_fmts[0],
28062306a36Sopenharmony_ci			    ctx->coded_fmt.fmt.pix_mp.width,
28162306a36Sopenharmony_ci			    ctx->coded_fmt.fmt.pix_mp.height);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	dprintk(ctx->dev, "CAPTURE format was set to:\n");
28462306a36Sopenharmony_ci	visl_print_fmt(ctx, &ctx->decoded_fmt);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return visl_tpg_init(ctx);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciint visl_set_default_format(struct visl_ctx *ctx)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	visl_reset_coded_fmt(ctx);
29262306a36Sopenharmony_ci	return visl_reset_decoded_fmt(ctx);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic struct visl_q_data *get_q_data(struct visl_ctx *ctx,
29662306a36Sopenharmony_ci				      enum v4l2_buf_type type)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	switch (type) {
29962306a36Sopenharmony_ci	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
30062306a36Sopenharmony_ci	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
30162306a36Sopenharmony_ci		return &ctx->q_data[V4L2_M2M_SRC];
30262306a36Sopenharmony_ci	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
30362306a36Sopenharmony_ci	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
30462306a36Sopenharmony_ci		return &ctx->q_data[V4L2_M2M_DST];
30562306a36Sopenharmony_ci	default:
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	return NULL;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int visl_querycap(struct file *file, void *priv,
31262306a36Sopenharmony_ci			 struct v4l2_capability *cap)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	strscpy(cap->driver, VISL_NAME, sizeof(cap->driver));
31562306a36Sopenharmony_ci	strscpy(cap->card, VISL_NAME, sizeof(cap->card));
31662306a36Sopenharmony_ci	snprintf(cap->bus_info, sizeof(cap->bus_info),
31762306a36Sopenharmony_ci		 "platform:%s", VISL_NAME);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic int visl_enum_fmt_vid_cap(struct file *file, void *priv,
32362306a36Sopenharmony_ci				 struct v4l2_fmtdesc *f)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (f->index >= ctx->coded_format_desc->num_decoded_fmts)
32862306a36Sopenharmony_ci		return -EINVAL;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index];
33162306a36Sopenharmony_ci	return 0;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic int visl_enum_fmt_vid_out(struct file *file, void *priv,
33562306a36Sopenharmony_ci				 struct v4l2_fmtdesc *f)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	if (f->index >= ARRAY_SIZE(visl_coded_fmts))
33862306a36Sopenharmony_ci		return -EINVAL;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	f->pixelformat = visl_coded_fmts[f->index].pixelformat;
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int visl_g_fmt_vid_cap(struct file *file, void *priv,
34562306a36Sopenharmony_ci			      struct v4l2_format *f)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
34862306a36Sopenharmony_ci	*f = ctx->decoded_fmt;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int visl_g_fmt_vid_out(struct file *file, void *priv,
35462306a36Sopenharmony_ci			      struct v4l2_format *f)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	*f = ctx->coded_fmt;
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int visl_try_fmt_vid_cap(struct file *file, void *priv,
36362306a36Sopenharmony_ci				struct v4l2_format *f)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
36662306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
36762306a36Sopenharmony_ci	const struct visl_coded_format_desc *coded_desc;
36862306a36Sopenharmony_ci	unsigned int i;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	coded_desc = ctx->coded_format_desc;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
37362306a36Sopenharmony_ci		if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
37462306a36Sopenharmony_ci			break;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (i == coded_desc->num_decoded_fmts)
37862306a36Sopenharmony_ci		pix_mp->pixelformat = coded_desc->decoded_fmts[0];
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	v4l2_apply_frmsize_constraints(&pix_mp->width,
38162306a36Sopenharmony_ci				       &pix_mp->height,
38262306a36Sopenharmony_ci				       &coded_desc->frmsize);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
38562306a36Sopenharmony_ci			    pix_mp->width, pix_mp->height);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	pix_mp->field = V4L2_FIELD_NONE;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int visl_try_fmt_vid_out(struct file *file, void *priv,
39362306a36Sopenharmony_ci				struct v4l2_format *f)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
39662306a36Sopenharmony_ci	const struct visl_coded_format_desc *coded_desc;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	coded_desc = visl_find_coded_fmt_desc(pix_mp->pixelformat);
39962306a36Sopenharmony_ci	if (!coded_desc) {
40062306a36Sopenharmony_ci		pix_mp->pixelformat = visl_coded_fmts[0].pixelformat;
40162306a36Sopenharmony_ci		coded_desc = &visl_coded_fmts[0];
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	v4l2_apply_frmsize_constraints(&pix_mp->width,
40562306a36Sopenharmony_ci				       &pix_mp->height,
40662306a36Sopenharmony_ci				       &coded_desc->frmsize);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	pix_mp->field = V4L2_FIELD_NONE;
40962306a36Sopenharmony_ci	pix_mp->num_planes = 1;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (pix_mp->plane_fmt[0].sizeimage == 0)
41262306a36Sopenharmony_ci		pix_mp->plane_fmt[0].sizeimage = max(MIN_CODED_SZ,
41362306a36Sopenharmony_ci						     pix_mp->width * pix_mp->height * 3);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return 0;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int visl_s_fmt_vid_out(struct file *file, void *priv,
41962306a36Sopenharmony_ci			      struct v4l2_format *f)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
42262306a36Sopenharmony_ci	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
42362306a36Sopenharmony_ci	const struct visl_coded_format_desc *desc;
42462306a36Sopenharmony_ci	struct vb2_queue *peer_vq;
42562306a36Sopenharmony_ci	int ret;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
42862306a36Sopenharmony_ci	if (vb2_is_busy(peer_vq))
42962306a36Sopenharmony_ci		return -EBUSY;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dprintk(ctx->dev, "Trying to set the OUTPUT format to:\n");
43262306a36Sopenharmony_ci	visl_print_fmt(ctx, f);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret = visl_try_fmt_vid_out(file, priv, f);
43562306a36Sopenharmony_ci	if (ret)
43662306a36Sopenharmony_ci		return ret;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	desc = visl_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat);
43962306a36Sopenharmony_ci	ctx->coded_format_desc = desc;
44062306a36Sopenharmony_ci	ctx->coded_fmt = *f;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	ret = visl_reset_decoded_fmt(ctx);
44362306a36Sopenharmony_ci	if (ret)
44462306a36Sopenharmony_ci		return ret;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ctx->decoded_fmt.fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
44762306a36Sopenharmony_ci	ctx->decoded_fmt.fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
44862306a36Sopenharmony_ci	ctx->decoded_fmt.fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
44962306a36Sopenharmony_ci	ctx->decoded_fmt.fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	dprintk(ctx->dev, "OUTPUT format was set to:\n");
45262306a36Sopenharmony_ci	visl_print_fmt(ctx, &ctx->coded_fmt);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	visl_set_current_codec(ctx);
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int visl_s_fmt_vid_cap(struct file *file, void *priv,
45962306a36Sopenharmony_ci			      struct v4l2_format *f)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
46262306a36Sopenharmony_ci	int ret;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	dprintk(ctx->dev, "Trying to set the CAPTURE format to:\n");
46562306a36Sopenharmony_ci	visl_print_fmt(ctx, f);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	ret = visl_try_fmt_vid_cap(file, priv, f);
46862306a36Sopenharmony_ci	if (ret)
46962306a36Sopenharmony_ci		return ret;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	ctx->decoded_fmt = *f;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	dprintk(ctx->dev, "CAPTURE format was set to:\n");
47462306a36Sopenharmony_ci	visl_print_fmt(ctx, &ctx->decoded_fmt);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	visl_tpg_init(ctx);
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int visl_enum_framesizes(struct file *file, void *priv,
48162306a36Sopenharmony_ci				struct v4l2_frmsizeenum *fsize)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	const struct visl_coded_format_desc *fmt;
48462306a36Sopenharmony_ci	struct visl_ctx *ctx = visl_file_to_ctx(file);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (fsize->index != 0)
48762306a36Sopenharmony_ci		return -EINVAL;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	fmt = visl_find_coded_fmt_desc(fsize->pixel_format);
49062306a36Sopenharmony_ci	if (!fmt) {
49162306a36Sopenharmony_ci		dprintk(ctx->dev,
49262306a36Sopenharmony_ci			"Unsupported format for the OUTPUT queue: %d\n",
49362306a36Sopenharmony_ci			fsize->pixel_format);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		return -EINVAL;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
49962306a36Sopenharmony_ci	fsize->stepwise = fmt->frmsize;
50062306a36Sopenharmony_ci	return 0;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ciconst struct v4l2_ioctl_ops visl_ioctl_ops = {
50462306a36Sopenharmony_ci	.vidioc_querycap		= visl_querycap,
50562306a36Sopenharmony_ci	.vidioc_enum_framesizes		= visl_enum_framesizes,
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap	= visl_enum_fmt_vid_cap,
50862306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap_mplane	= visl_g_fmt_vid_cap,
50962306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap_mplane	= visl_try_fmt_vid_cap,
51062306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap_mplane	= visl_s_fmt_vid_cap,
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_out	= visl_enum_fmt_vid_out,
51362306a36Sopenharmony_ci	.vidioc_g_fmt_vid_out_mplane	= visl_g_fmt_vid_out,
51462306a36Sopenharmony_ci	.vidioc_try_fmt_vid_out_mplane	= visl_try_fmt_vid_out,
51562306a36Sopenharmony_ci	.vidioc_s_fmt_vid_out_mplane	= visl_s_fmt_vid_out,
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
51862306a36Sopenharmony_ci	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
51962306a36Sopenharmony_ci	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
52062306a36Sopenharmony_ci	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
52162306a36Sopenharmony_ci	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
52262306a36Sopenharmony_ci	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
52362306a36Sopenharmony_ci	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
52662306a36Sopenharmony_ci	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	.vidioc_decoder_cmd		= v4l2_m2m_ioctl_stateless_decoder_cmd,
52962306a36Sopenharmony_ci	.vidioc_try_decoder_cmd		= v4l2_m2m_ioctl_stateless_try_decoder_cmd,
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
53262306a36Sopenharmony_ci	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
53362306a36Sopenharmony_ci};
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic int visl_queue_setup(struct vb2_queue *vq,
53662306a36Sopenharmony_ci			    unsigned int *nbuffers,
53762306a36Sopenharmony_ci			    unsigned int *num_planes,
53862306a36Sopenharmony_ci			    unsigned int sizes[],
53962306a36Sopenharmony_ci			    struct device *alloc_devs[])
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
54262306a36Sopenharmony_ci	struct v4l2_format *f;
54362306a36Sopenharmony_ci	u32 i;
54462306a36Sopenharmony_ci	char *qname;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
54762306a36Sopenharmony_ci		f = &ctx->coded_fmt;
54862306a36Sopenharmony_ci		qname = "Output";
54962306a36Sopenharmony_ci	} else {
55062306a36Sopenharmony_ci		f = &ctx->decoded_fmt;
55162306a36Sopenharmony_ci		qname = "Capture";
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (*num_planes) {
55562306a36Sopenharmony_ci		if (*num_planes != f->fmt.pix_mp.num_planes)
55662306a36Sopenharmony_ci			return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
55962306a36Sopenharmony_ci			if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
56062306a36Sopenharmony_ci				return -EINVAL;
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci	} else {
56362306a36Sopenharmony_ci		*num_planes = f->fmt.pix_mp.num_planes;
56462306a36Sopenharmony_ci		for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
56562306a36Sopenharmony_ci			sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	dprintk(ctx->dev, "%s: %d buffer(s) requested, num_planes=%d.\n",
56962306a36Sopenharmony_ci		qname, *nbuffers, *num_planes);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
57262306a36Sopenharmony_ci		dprintk(ctx->dev, "plane[%d].sizeimage=%d\n",
57362306a36Sopenharmony_ci			i, f->fmt.pix_mp.plane_fmt[i].sizeimage);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void visl_queue_cleanup(struct vb2_queue *vq, u32 state)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
58162306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	dprintk(ctx->dev, "Cleaning up queues\n");
58462306a36Sopenharmony_ci	for (;;) {
58562306a36Sopenharmony_ci		if (V4L2_TYPE_IS_OUTPUT(vq->type))
58662306a36Sopenharmony_ci			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
58762306a36Sopenharmony_ci		else
58862306a36Sopenharmony_ci			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		if (!vbuf)
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
59462306a36Sopenharmony_ci					   &ctx->hdl);
59562306a36Sopenharmony_ci		dprintk(ctx->dev, "Marked request %p as complete\n",
59662306a36Sopenharmony_ci			vbuf->vb2_buf.req_obj.req);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, state);
59962306a36Sopenharmony_ci		dprintk(ctx->dev,
60062306a36Sopenharmony_ci			"Marked buffer %llu as done, state is %d\n",
60162306a36Sopenharmony_ci			vbuf->vb2_buf.timestamp,
60262306a36Sopenharmony_ci			state);
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic int visl_buf_out_validate(struct vb2_buffer *vb)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	vbuf->field = V4L2_FIELD_NONE;
61162306a36Sopenharmony_ci	return 0;
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic int visl_buf_prepare(struct vb2_buffer *vb)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
61762306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
61862306a36Sopenharmony_ci	u32 plane_sz = vb2_plane_size(vb, 0);
61962306a36Sopenharmony_ci	struct v4l2_pix_format *pix_fmt;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
62262306a36Sopenharmony_ci		pix_fmt = &ctx->coded_fmt.fmt.pix;
62362306a36Sopenharmony_ci	} else {
62462306a36Sopenharmony_ci		pix_fmt = &ctx->decoded_fmt.fmt.pix;
62562306a36Sopenharmony_ci		vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (plane_sz < pix_fmt->sizeimage) {
62962306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "plane[0] size is %d, sizeimage is %d\n",
63062306a36Sopenharmony_ci			 plane_sz, pix_fmt->sizeimage);
63162306a36Sopenharmony_ci		return -EINVAL;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic int visl_start_streaming(struct vb2_queue *vq, unsigned int count)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
64062306a36Sopenharmony_ci	struct visl_q_data *q_data = get_q_data(ctx, vq->type);
64162306a36Sopenharmony_ci	int rc = 0;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (!q_data) {
64462306a36Sopenharmony_ci		rc = -EINVAL;
64562306a36Sopenharmony_ci		goto err;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	q_data->sequence = 0;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (V4L2_TYPE_IS_CAPTURE(vq->type)) {
65162306a36Sopenharmony_ci		ctx->capture_streamon_jiffies = get_jiffies_64();
65262306a36Sopenharmony_ci		return 0;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (WARN_ON(!ctx->coded_format_desc)) {
65662306a36Sopenharmony_ci		rc =  -EINVAL;
65762306a36Sopenharmony_ci		goto err;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	return 0;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cierr:
66362306a36Sopenharmony_ci	visl_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
66462306a36Sopenharmony_ci	return rc;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void visl_stop_streaming(struct vb2_queue *vq)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vq);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	dprintk(ctx->dev, "Stop streaming\n");
67262306a36Sopenharmony_ci	visl_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (!keep_bitstream_buffers)
67562306a36Sopenharmony_ci		visl_debugfs_clear_bitstream(ctx->dev);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic void visl_buf_queue(struct vb2_buffer *vb)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
68162306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic void visl_buf_request_complete(struct vb2_buffer *vb)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct visl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic const struct vb2_ops visl_qops = {
69462306a36Sopenharmony_ci	.queue_setup          = visl_queue_setup,
69562306a36Sopenharmony_ci	.buf_out_validate     = visl_buf_out_validate,
69662306a36Sopenharmony_ci	.buf_prepare          = visl_buf_prepare,
69762306a36Sopenharmony_ci	.buf_queue            = visl_buf_queue,
69862306a36Sopenharmony_ci	.start_streaming      = visl_start_streaming,
69962306a36Sopenharmony_ci	.stop_streaming       = visl_stop_streaming,
70062306a36Sopenharmony_ci	.wait_prepare         = vb2_ops_wait_prepare,
70162306a36Sopenharmony_ci	.wait_finish          = vb2_ops_wait_finish,
70262306a36Sopenharmony_ci	.buf_request_complete = visl_buf_request_complete,
70362306a36Sopenharmony_ci};
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ciint visl_queue_init(void *priv, struct vb2_queue *src_vq,
70662306a36Sopenharmony_ci		    struct vb2_queue *dst_vq)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct visl_ctx *ctx = priv;
70962306a36Sopenharmony_ci	int ret;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
71262306a36Sopenharmony_ci	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
71362306a36Sopenharmony_ci	src_vq->drv_priv = ctx;
71462306a36Sopenharmony_ci	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
71562306a36Sopenharmony_ci	src_vq->ops = &visl_qops;
71662306a36Sopenharmony_ci	src_vq->mem_ops = &vb2_vmalloc_memops;
71762306a36Sopenharmony_ci	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
71862306a36Sopenharmony_ci	src_vq->lock = &ctx->vb_mutex;
71962306a36Sopenharmony_ci	src_vq->supports_requests = true;
72062306a36Sopenharmony_ci	src_vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	ret = vb2_queue_init(src_vq);
72362306a36Sopenharmony_ci	if (ret)
72462306a36Sopenharmony_ci		return ret;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
72762306a36Sopenharmony_ci	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
72862306a36Sopenharmony_ci	dst_vq->drv_priv = ctx;
72962306a36Sopenharmony_ci	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
73062306a36Sopenharmony_ci	dst_vq->ops = &visl_qops;
73162306a36Sopenharmony_ci	dst_vq->mem_ops = &vb2_vmalloc_memops;
73262306a36Sopenharmony_ci	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
73362306a36Sopenharmony_ci	dst_vq->lock = &ctx->vb_mutex;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return vb2_queue_init(dst_vq);
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciint visl_request_validate(struct media_request *req)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct media_request_object *obj;
74162306a36Sopenharmony_ci	struct visl_ctx *ctx = NULL;
74262306a36Sopenharmony_ci	unsigned int count;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	list_for_each_entry(obj, &req->objects, list) {
74562306a36Sopenharmony_ci		struct vb2_buffer *vb;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		if (vb2_request_object_is_buffer(obj)) {
74862306a36Sopenharmony_ci			vb = container_of(obj, struct vb2_buffer, req_obj);
74962306a36Sopenharmony_ci			ctx = vb2_get_drv_priv(vb->vb2_queue);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci			break;
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (!ctx)
75662306a36Sopenharmony_ci		return -ENOENT;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	count = vb2_request_buffer_cnt(req);
75962306a36Sopenharmony_ci	if (!count) {
76062306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
76162306a36Sopenharmony_ci			 "No buffer was provided with the request\n");
76262306a36Sopenharmony_ci		return -ENOENT;
76362306a36Sopenharmony_ci	} else if (count > 1) {
76462306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
76562306a36Sopenharmony_ci			 "More than one buffer was provided with the request\n");
76662306a36Sopenharmony_ci		return -EINVAL;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	return vb2_request_validate(req);
77062306a36Sopenharmony_ci}
771