162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2020-2021 NXP
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/interconnect.h>
862306a36Sopenharmony_ci#include <linux/ioctl.h>
962306a36Sopenharmony_ci#include <linux/list.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/videodev2.h>
1462306a36Sopenharmony_ci#include <linux/ktime.h>
1562306a36Sopenharmony_ci#include <linux/rational.h>
1662306a36Sopenharmony_ci#include <linux/vmalloc.h>
1762306a36Sopenharmony_ci#include <media/v4l2-device.h>
1862306a36Sopenharmony_ci#include <media/v4l2-event.h>
1962306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h>
2062306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
2162306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
2262306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
2362306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
2462306a36Sopenharmony_ci#include "vpu.h"
2562306a36Sopenharmony_ci#include "vpu_defs.h"
2662306a36Sopenharmony_ci#include "vpu_core.h"
2762306a36Sopenharmony_ci#include "vpu_helpers.h"
2862306a36Sopenharmony_ci#include "vpu_v4l2.h"
2962306a36Sopenharmony_ci#include "vpu_cmds.h"
3062306a36Sopenharmony_ci#include "vpu_rpc.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define VENC_OUTPUT_ENABLE	BIT(0)
3362306a36Sopenharmony_ci#define VENC_CAPTURE_ENABLE	BIT(1)
3462306a36Sopenharmony_ci#define VENC_ENABLE_MASK	(VENC_OUTPUT_ENABLE | VENC_CAPTURE_ENABLE)
3562306a36Sopenharmony_ci#define VENC_MAX_BUF_CNT	8
3662306a36Sopenharmony_ci#define VENC_MIN_BUFFER_OUT	6
3762306a36Sopenharmony_ci#define VENC_MIN_BUFFER_CAP	6
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct venc_t {
4062306a36Sopenharmony_ci	struct vpu_encode_params params;
4162306a36Sopenharmony_ci	u32 request_key_frame;
4262306a36Sopenharmony_ci	u32 input_ready;
4362306a36Sopenharmony_ci	u32 cpb_size;
4462306a36Sopenharmony_ci	bool bitrate_change;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	struct vpu_buffer enc[VENC_MAX_BUF_CNT];
4762306a36Sopenharmony_ci	struct vpu_buffer ref[VENC_MAX_BUF_CNT];
4862306a36Sopenharmony_ci	struct vpu_buffer act[VENC_MAX_BUF_CNT];
4962306a36Sopenharmony_ci	struct list_head frames;
5062306a36Sopenharmony_ci	u32 frame_count;
5162306a36Sopenharmony_ci	u32 encode_count;
5262306a36Sopenharmony_ci	u32 ready_count;
5362306a36Sopenharmony_ci	u32 enable;
5462306a36Sopenharmony_ci	u32 stopped;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	u32 skipped_count;
5762306a36Sopenharmony_ci	u32 skipped_bytes;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	wait_queue_head_t wq;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct venc_frame_t {
6362306a36Sopenharmony_ci	struct list_head list;
6462306a36Sopenharmony_ci	struct vpu_enc_pic_info info;
6562306a36Sopenharmony_ci	u32 bytesused;
6662306a36Sopenharmony_ci	s64 timestamp;
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct vpu_format venc_formats[] = {
7062306a36Sopenharmony_ci	{
7162306a36Sopenharmony_ci		.pixfmt = V4L2_PIX_FMT_NV12M,
7262306a36Sopenharmony_ci		.mem_planes = 2,
7362306a36Sopenharmony_ci		.comp_planes = 2,
7462306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
7562306a36Sopenharmony_ci		.sibling = V4L2_PIX_FMT_NV12,
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci	{
7862306a36Sopenharmony_ci		.pixfmt = V4L2_PIX_FMT_NV12,
7962306a36Sopenharmony_ci		.mem_planes = 1,
8062306a36Sopenharmony_ci		.comp_planes = 2,
8162306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
8262306a36Sopenharmony_ci		.sibling = V4L2_PIX_FMT_NV12M,
8362306a36Sopenharmony_ci	},
8462306a36Sopenharmony_ci	{
8562306a36Sopenharmony_ci		.pixfmt = V4L2_PIX_FMT_H264,
8662306a36Sopenharmony_ci		.mem_planes = 1,
8762306a36Sopenharmony_ci		.comp_planes = 1,
8862306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
8962306a36Sopenharmony_ci		.flags = V4L2_FMT_FLAG_COMPRESSED
9062306a36Sopenharmony_ci	},
9162306a36Sopenharmony_ci	{0, 0, 0, 0},
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	strscpy(cap->driver, "amphion-vpu", sizeof(cap->driver));
9762306a36Sopenharmony_ci	strscpy(cap->card, "amphion vpu encoder", sizeof(cap->card));
9862306a36Sopenharmony_ci	strscpy(cap->bus_info, "platform: amphion-vpu", sizeof(cap->bus_info));
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int venc_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
10662306a36Sopenharmony_ci	const struct vpu_format *fmt;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	memset(f->reserved, 0, sizeof(f->reserved));
10962306a36Sopenharmony_ci	fmt = vpu_helper_enum_format(inst, f->type, f->index);
11062306a36Sopenharmony_ci	if (!fmt)
11162306a36Sopenharmony_ci		return -EINVAL;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	f->pixelformat = fmt->pixfmt;
11462306a36Sopenharmony_ci	f->flags = fmt->flags;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int venc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
12262306a36Sopenharmony_ci	const struct vpu_core_resources *res;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!fsize || fsize->index)
12562306a36Sopenharmony_ci		return -EINVAL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (!vpu_helper_find_format(inst, 0, fsize->pixel_format))
12862306a36Sopenharmony_ci		return -EINVAL;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	res = vpu_get_resource(inst);
13162306a36Sopenharmony_ci	if (!res)
13262306a36Sopenharmony_ci		return -EINVAL;
13362306a36Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
13462306a36Sopenharmony_ci	fsize->stepwise.max_width = res->max_width;
13562306a36Sopenharmony_ci	fsize->stepwise.max_height = res->max_height;
13662306a36Sopenharmony_ci	fsize->stepwise.min_width = res->min_width;
13762306a36Sopenharmony_ci	fsize->stepwise.min_height = res->min_height;
13862306a36Sopenharmony_ci	fsize->stepwise.step_width = res->step_width;
13962306a36Sopenharmony_ci	fsize->stepwise.step_height = res->step_height;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return 0;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int venc_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
14762306a36Sopenharmony_ci	const struct vpu_core_resources *res;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (!fival || fival->index)
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (!vpu_helper_find_format(inst, 0, fival->pixel_format))
15362306a36Sopenharmony_ci		return -EINVAL;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (!fival->width || !fival->height)
15662306a36Sopenharmony_ci		return -EINVAL;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	res = vpu_get_resource(inst);
15962306a36Sopenharmony_ci	if (!res)
16062306a36Sopenharmony_ci		return -EINVAL;
16162306a36Sopenharmony_ci	if (fival->width < res->min_width || fival->width > res->max_width ||
16262306a36Sopenharmony_ci	    fival->height < res->min_height || fival->height > res->max_height)
16362306a36Sopenharmony_ci		return -EINVAL;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
16662306a36Sopenharmony_ci	fival->stepwise.min.numerator = 1;
16762306a36Sopenharmony_ci	fival->stepwise.min.denominator = USHRT_MAX;
16862306a36Sopenharmony_ci	fival->stepwise.max.numerator = USHRT_MAX;
16962306a36Sopenharmony_ci	fival->stepwise.max.denominator = 1;
17062306a36Sopenharmony_ci	fival->stepwise.step.numerator = 1;
17162306a36Sopenharmony_ci	fival->stepwise.step.denominator = 1;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
17962306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
18062306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
18162306a36Sopenharmony_ci	struct vpu_format *cur_fmt;
18262306a36Sopenharmony_ci	int i;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	cur_fmt = vpu_get_format(inst, f->type);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	pixmp->pixelformat = cur_fmt->pixfmt;
18762306a36Sopenharmony_ci	pixmp->num_planes = cur_fmt->mem_planes;
18862306a36Sopenharmony_ci	pixmp->width = cur_fmt->width;
18962306a36Sopenharmony_ci	pixmp->height = cur_fmt->height;
19062306a36Sopenharmony_ci	pixmp->field = cur_fmt->field;
19162306a36Sopenharmony_ci	pixmp->flags = cur_fmt->flags;
19262306a36Sopenharmony_ci	for (i = 0; i < pixmp->num_planes; i++) {
19362306a36Sopenharmony_ci		pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
19462306a36Sopenharmony_ci		pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	f->fmt.pix_mp.colorspace = venc->params.color.primaries;
19862306a36Sopenharmony_ci	f->fmt.pix_mp.xfer_func = venc->params.color.transfer;
19962306a36Sopenharmony_ci	f->fmt.pix_mp.ycbcr_enc = venc->params.color.matrix;
20062306a36Sopenharmony_ci	f->fmt.pix_mp.quantization = venc->params.color.full_range;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
20862306a36Sopenharmony_ci	struct vpu_format fmt;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	vpu_try_fmt_common(inst, f, &fmt);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
21862306a36Sopenharmony_ci	struct vpu_format fmt;
21962306a36Sopenharmony_ci	struct vpu_format *cur_fmt;
22062306a36Sopenharmony_ci	struct vb2_queue *q;
22162306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
22262306a36Sopenharmony_ci	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	q = v4l2_m2m_get_vq(inst->fh.m2m_ctx, f->type);
22562306a36Sopenharmony_ci	if (!q)
22662306a36Sopenharmony_ci		return -EINVAL;
22762306a36Sopenharmony_ci	if (vb2_is_busy(q))
22862306a36Sopenharmony_ci		return -EBUSY;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (vpu_try_fmt_common(inst, f, &fmt))
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	cur_fmt = vpu_get_format(inst, f->type);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	memcpy(cur_fmt, &fmt, sizeof(*cur_fmt));
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
23862306a36Sopenharmony_ci		venc->params.input_format = cur_fmt->pixfmt;
23962306a36Sopenharmony_ci		venc->params.src_stride = cur_fmt->bytesperline[0];
24062306a36Sopenharmony_ci		venc->params.src_width = cur_fmt->width;
24162306a36Sopenharmony_ci		venc->params.src_height = cur_fmt->height;
24262306a36Sopenharmony_ci		venc->params.crop.left = 0;
24362306a36Sopenharmony_ci		venc->params.crop.top = 0;
24462306a36Sopenharmony_ci		venc->params.crop.width = cur_fmt->width;
24562306a36Sopenharmony_ci		venc->params.crop.height = cur_fmt->height;
24662306a36Sopenharmony_ci	} else {
24762306a36Sopenharmony_ci		venc->params.codec_format = cur_fmt->pixfmt;
24862306a36Sopenharmony_ci		venc->params.out_width = cur_fmt->width;
24962306a36Sopenharmony_ci		venc->params.out_height = cur_fmt->height;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
25362306a36Sopenharmony_ci		venc->params.color.primaries = pix_mp->colorspace;
25462306a36Sopenharmony_ci		venc->params.color.transfer = pix_mp->xfer_func;
25562306a36Sopenharmony_ci		venc->params.color.matrix = pix_mp->ycbcr_enc;
25662306a36Sopenharmony_ci		venc->params.color.full_range = pix_mp->quantization;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	pix_mp->colorspace = venc->params.color.primaries;
26062306a36Sopenharmony_ci	pix_mp->xfer_func = venc->params.color.transfer;
26162306a36Sopenharmony_ci	pix_mp->ycbcr_enc = venc->params.color.matrix;
26262306a36Sopenharmony_ci	pix_mp->quantization = venc->params.color.full_range;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
27062306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
27162306a36Sopenharmony_ci	struct v4l2_fract *timeperframe;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (!parm)
27462306a36Sopenharmony_ci		return -EINVAL;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (!V4L2_TYPE_IS_OUTPUT(parm->type))
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (!vpu_helper_check_type(inst, parm->type))
28062306a36Sopenharmony_ci		return -EINVAL;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	timeperframe = &parm->parm.capture.timeperframe;
28362306a36Sopenharmony_ci	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
28462306a36Sopenharmony_ci	parm->parm.capture.readbuffers = 0;
28562306a36Sopenharmony_ci	timeperframe->numerator = venc->params.frame_rate.numerator;
28662306a36Sopenharmony_ci	timeperframe->denominator = venc->params.frame_rate.denominator;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
29462306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
29562306a36Sopenharmony_ci	struct v4l2_fract *timeperframe;
29662306a36Sopenharmony_ci	unsigned long n, d;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (!parm)
29962306a36Sopenharmony_ci		return -EINVAL;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!V4L2_TYPE_IS_OUTPUT(parm->type))
30262306a36Sopenharmony_ci		return -EINVAL;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!vpu_helper_check_type(inst, parm->type))
30562306a36Sopenharmony_ci		return -EINVAL;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	timeperframe = &parm->parm.capture.timeperframe;
30862306a36Sopenharmony_ci	if (!timeperframe->numerator)
30962306a36Sopenharmony_ci		timeperframe->numerator = venc->params.frame_rate.numerator;
31062306a36Sopenharmony_ci	if (!timeperframe->denominator)
31162306a36Sopenharmony_ci		timeperframe->denominator = venc->params.frame_rate.denominator;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	venc->params.frame_rate.numerator = timeperframe->numerator;
31462306a36Sopenharmony_ci	venc->params.frame_rate.denominator = timeperframe->denominator;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	rational_best_approximation(venc->params.frame_rate.numerator,
31762306a36Sopenharmony_ci				    venc->params.frame_rate.denominator,
31862306a36Sopenharmony_ci				    venc->params.frame_rate.numerator,
31962306a36Sopenharmony_ci				    venc->params.frame_rate.denominator,
32062306a36Sopenharmony_ci				    &n, &d);
32162306a36Sopenharmony_ci	venc->params.frame_rate.numerator = n;
32262306a36Sopenharmony_ci	venc->params.frame_rate.denominator = d;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
32562306a36Sopenharmony_ci	memset(parm->parm.capture.reserved, 0, sizeof(parm->parm.capture.reserved));
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return 0;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int venc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
33362306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
33662306a36Sopenharmony_ci		return -EINVAL;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	switch (s->target) {
33962306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
34062306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
34162306a36Sopenharmony_ci		s->r.left = 0;
34262306a36Sopenharmony_ci		s->r.top = 0;
34362306a36Sopenharmony_ci		s->r.width = inst->out_format.width;
34462306a36Sopenharmony_ci		s->r.height = inst->out_format.height;
34562306a36Sopenharmony_ci		break;
34662306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
34762306a36Sopenharmony_ci		s->r = venc->params.crop;
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	default:
35062306a36Sopenharmony_ci		return -EINVAL;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int venc_valid_crop(struct venc_t *venc, const struct vpu_core_resources *res)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct v4l2_rect *rect = NULL;
35962306a36Sopenharmony_ci	u32 min_width;
36062306a36Sopenharmony_ci	u32 min_height;
36162306a36Sopenharmony_ci	u32 src_width;
36262306a36Sopenharmony_ci	u32 src_height;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	rect = &venc->params.crop;
36562306a36Sopenharmony_ci	min_width = res->min_width;
36662306a36Sopenharmony_ci	min_height = res->min_height;
36762306a36Sopenharmony_ci	src_width = venc->params.src_width;
36862306a36Sopenharmony_ci	src_height = venc->params.src_height;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (rect->width == 0 || rect->height == 0)
37162306a36Sopenharmony_ci		return -EINVAL;
37262306a36Sopenharmony_ci	if (rect->left > src_width - min_width || rect->top > src_height - min_height)
37362306a36Sopenharmony_ci		return -EINVAL;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	rect->width = min(rect->width, src_width - rect->left);
37662306a36Sopenharmony_ci	rect->width = max_t(u32, rect->width, min_width);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	rect->height = min(rect->height, src_height - rect->top);
37962306a36Sopenharmony_ci	rect->height = max_t(u32, rect->height, min_height);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int venc_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
38762306a36Sopenharmony_ci	const struct vpu_core_resources *res;
38862306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	res = vpu_get_resource(inst);
39162306a36Sopenharmony_ci	if (!res)
39262306a36Sopenharmony_ci		return -EINVAL;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
39562306a36Sopenharmony_ci		return -EINVAL;
39662306a36Sopenharmony_ci	if (s->target != V4L2_SEL_TGT_CROP)
39762306a36Sopenharmony_ci		return -EINVAL;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	venc->params.crop.left = ALIGN(s->r.left, res->step_width);
40062306a36Sopenharmony_ci	venc->params.crop.top = ALIGN(s->r.top, res->step_height);
40162306a36Sopenharmony_ci	venc->params.crop.width = ALIGN(s->r.width, res->step_width);
40262306a36Sopenharmony_ci	venc->params.crop.height = ALIGN(s->r.height, res->step_height);
40362306a36Sopenharmony_ci	if (venc_valid_crop(venc, res)) {
40462306a36Sopenharmony_ci		venc->params.crop.left = 0;
40562306a36Sopenharmony_ci		venc->params.crop.top = 0;
40662306a36Sopenharmony_ci		venc->params.crop.width = venc->params.src_width;
40762306a36Sopenharmony_ci		venc->params.crop.height = venc->params.src_height;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	inst->crop = venc->params.crop;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int venc_drain(struct vpu_inst *inst)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
41862306a36Sopenharmony_ci	int ret;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (!inst->fh.m2m_ctx)
42162306a36Sopenharmony_ci		return 0;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (inst->state != VPU_CODEC_STATE_DRAIN)
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (!vpu_is_source_empty(inst))
42762306a36Sopenharmony_ci		return 0;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (!venc->input_ready)
43062306a36Sopenharmony_ci		return 0;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	venc->input_ready = false;
43362306a36Sopenharmony_ci	vpu_trace(inst->dev, "[%d]\n", inst->id);
43462306a36Sopenharmony_ci	ret = vpu_session_stop(inst);
43562306a36Sopenharmony_ci	if (ret)
43662306a36Sopenharmony_ci		return ret;
43762306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_STOP;
43862306a36Sopenharmony_ci	wake_up_all(&venc->wq);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return 0;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int venc_request_eos(struct vpu_inst *inst)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_DRAIN;
44662306a36Sopenharmony_ci	venc_drain(inst);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int venc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
45462306a36Sopenharmony_ci	int ret;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
45762306a36Sopenharmony_ci	if (ret)
45862306a36Sopenharmony_ci		return ret;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	vpu_inst_lock(inst);
46162306a36Sopenharmony_ci	if (cmd->cmd == V4L2_ENC_CMD_STOP) {
46262306a36Sopenharmony_ci		if (inst->state == VPU_CODEC_STATE_DEINIT)
46362306a36Sopenharmony_ci			vpu_set_last_buffer_dequeued(inst, true);
46462306a36Sopenharmony_ci		else
46562306a36Sopenharmony_ci			venc_request_eos(inst);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	vpu_inst_unlock(inst);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic int venc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	switch (sub->type) {
47562306a36Sopenharmony_ci	case V4L2_EVENT_EOS:
47662306a36Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 0, NULL);
47762306a36Sopenharmony_ci	case V4L2_EVENT_CTRL:
47862306a36Sopenharmony_ci		return v4l2_ctrl_subscribe_event(fh, sub);
47962306a36Sopenharmony_ci	default:
48062306a36Sopenharmony_ci		return -EINVAL;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops venc_ioctl_ops = {
48562306a36Sopenharmony_ci	.vidioc_querycap               = venc_querycap,
48662306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap       = venc_enum_fmt,
48762306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_out       = venc_enum_fmt,
48862306a36Sopenharmony_ci	.vidioc_enum_framesizes        = venc_enum_framesizes,
48962306a36Sopenharmony_ci	.vidioc_enum_frameintervals    = venc_enum_frameintervals,
49062306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap_mplane   = venc_g_fmt,
49162306a36Sopenharmony_ci	.vidioc_g_fmt_vid_out_mplane   = venc_g_fmt,
49262306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap_mplane = venc_try_fmt,
49362306a36Sopenharmony_ci	.vidioc_try_fmt_vid_out_mplane = venc_try_fmt,
49462306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap_mplane   = venc_s_fmt,
49562306a36Sopenharmony_ci	.vidioc_s_fmt_vid_out_mplane   = venc_s_fmt,
49662306a36Sopenharmony_ci	.vidioc_g_parm                 = venc_g_parm,
49762306a36Sopenharmony_ci	.vidioc_s_parm                 = venc_s_parm,
49862306a36Sopenharmony_ci	.vidioc_g_selection            = venc_g_selection,
49962306a36Sopenharmony_ci	.vidioc_s_selection            = venc_s_selection,
50062306a36Sopenharmony_ci	.vidioc_try_encoder_cmd        = v4l2_m2m_ioctl_try_encoder_cmd,
50162306a36Sopenharmony_ci	.vidioc_encoder_cmd            = venc_encoder_cmd,
50262306a36Sopenharmony_ci	.vidioc_subscribe_event        = venc_subscribe_event,
50362306a36Sopenharmony_ci	.vidioc_unsubscribe_event      = v4l2_event_unsubscribe,
50462306a36Sopenharmony_ci	.vidioc_reqbufs                = v4l2_m2m_ioctl_reqbufs,
50562306a36Sopenharmony_ci	.vidioc_querybuf               = v4l2_m2m_ioctl_querybuf,
50662306a36Sopenharmony_ci	.vidioc_create_bufs	       = v4l2_m2m_ioctl_create_bufs,
50762306a36Sopenharmony_ci	.vidioc_prepare_buf	       = v4l2_m2m_ioctl_prepare_buf,
50862306a36Sopenharmony_ci	.vidioc_qbuf                   = v4l2_m2m_ioctl_qbuf,
50962306a36Sopenharmony_ci	.vidioc_expbuf                 = v4l2_m2m_ioctl_expbuf,
51062306a36Sopenharmony_ci	.vidioc_dqbuf                  = v4l2_m2m_ioctl_dqbuf,
51162306a36Sopenharmony_ci	.vidioc_streamon               = v4l2_m2m_ioctl_streamon,
51262306a36Sopenharmony_ci	.vidioc_streamoff              = v4l2_m2m_ioctl_streamoff,
51362306a36Sopenharmony_ci};
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct vpu_inst *inst = ctrl_to_inst(ctrl);
51862306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
51962306a36Sopenharmony_ci	int ret = 0;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	vpu_inst_lock(inst);
52262306a36Sopenharmony_ci	switch (ctrl->id) {
52362306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
52462306a36Sopenharmony_ci		venc->params.profile = ctrl->val;
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
52762306a36Sopenharmony_ci		venc->params.level = ctrl->val;
52862306a36Sopenharmony_ci		break;
52962306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
53062306a36Sopenharmony_ci		venc->params.rc_enable = ctrl->val;
53162306a36Sopenharmony_ci		break;
53262306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
53362306a36Sopenharmony_ci		venc->params.rc_mode = ctrl->val;
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_BITRATE:
53662306a36Sopenharmony_ci		if (ctrl->val != venc->params.bitrate)
53762306a36Sopenharmony_ci			venc->bitrate_change = true;
53862306a36Sopenharmony_ci		venc->params.bitrate = ctrl->val;
53962306a36Sopenharmony_ci		break;
54062306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
54162306a36Sopenharmony_ci		venc->params.bitrate_max = ctrl->val;
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
54462306a36Sopenharmony_ci		venc->params.gop_length = ctrl->val;
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
54762306a36Sopenharmony_ci		venc->params.bframes = ctrl->val;
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
55062306a36Sopenharmony_ci		venc->params.i_frame_qp = ctrl->val;
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
55362306a36Sopenharmony_ci		venc->params.p_frame_qp = ctrl->val;
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
55662306a36Sopenharmony_ci		venc->params.b_frame_qp = ctrl->val;
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
55962306a36Sopenharmony_ci		venc->request_key_frame = 1;
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
56262306a36Sopenharmony_ci		venc->cpb_size = ctrl->val * 1024;
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
56562306a36Sopenharmony_ci		venc->params.sar.enable = ctrl->val;
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
56862306a36Sopenharmony_ci		venc->params.sar.idc = ctrl->val;
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
57162306a36Sopenharmony_ci		venc->params.sar.width = ctrl->val;
57262306a36Sopenharmony_ci		break;
57362306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
57462306a36Sopenharmony_ci		venc->params.sar.height = ctrl->val;
57562306a36Sopenharmony_ci		break;
57662306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci	default:
57962306a36Sopenharmony_ci		ret = -EINVAL;
58062306a36Sopenharmony_ci		break;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci	vpu_inst_unlock(inst);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return ret;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops venc_ctrl_ops = {
58862306a36Sopenharmony_ci	.s_ctrl = venc_op_s_ctrl,
58962306a36Sopenharmony_ci	.g_volatile_ctrl = vpu_helper_g_volatile_ctrl,
59062306a36Sopenharmony_ci};
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic int venc_ctrl_init(struct vpu_inst *inst)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct v4l2_ctrl *ctrl;
59562306a36Sopenharmony_ci	int ret;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 20);
59862306a36Sopenharmony_ci	if (ret)
59962306a36Sopenharmony_ci		return ret;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
60262306a36Sopenharmony_ci			       V4L2_CID_MPEG_VIDEO_H264_PROFILE,
60362306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
60462306a36Sopenharmony_ci			       ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
60562306a36Sopenharmony_ci				 (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
60662306a36Sopenharmony_ci				 (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
60762306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
61062306a36Sopenharmony_ci			       V4L2_CID_MPEG_VIDEO_H264_LEVEL,
61162306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
61262306a36Sopenharmony_ci			       0x0,
61362306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
61662306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
61962306a36Sopenharmony_ci			       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
62062306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
62162306a36Sopenharmony_ci			       ~((1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
62262306a36Sopenharmony_ci				 (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)),
62362306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
62662306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_BITRATE,
62762306a36Sopenharmony_ci			  BITRATE_MIN,
62862306a36Sopenharmony_ci			  BITRATE_MAX,
62962306a36Sopenharmony_ci			  BITRATE_STEP,
63062306a36Sopenharmony_ci			  BITRATE_DEFAULT);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
63362306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
63462306a36Sopenharmony_ci			  BITRATE_MIN, BITRATE_MAX,
63562306a36Sopenharmony_ci			  BITRATE_STEP,
63662306a36Sopenharmony_ci			  BITRATE_DEFAULT_PEAK);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
63962306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 8000, 1, 30);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
64262306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 4, 1, 0);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
64562306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 26);
64662306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
64762306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 28);
64862306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
64962306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, 1, 51, 1, 30);
65062306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
65162306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0);
65262306a36Sopenharmony_ci	ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
65362306a36Sopenharmony_ci				 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2);
65462306a36Sopenharmony_ci	if (ctrl)
65562306a36Sopenharmony_ci		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
65662306a36Sopenharmony_ci	ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
65762306a36Sopenharmony_ci				 V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 2);
65862306a36Sopenharmony_ci	if (ctrl)
65962306a36Sopenharmony_ci		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
66262306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, 64, 10240, 1, 1024);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
66562306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, 0, 1, 1, 1);
66662306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
66762306a36Sopenharmony_ci			       V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
66862306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
66962306a36Sopenharmony_ci			       0x0,
67062306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1);
67162306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
67262306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
67362306a36Sopenharmony_ci			  0, USHRT_MAX, 1, 1);
67462306a36Sopenharmony_ci	v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
67562306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
67662306a36Sopenharmony_ci			  0, USHRT_MAX, 1, 1);
67762306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
67862306a36Sopenharmony_ci			       V4L2_CID_MPEG_VIDEO_HEADER_MODE,
67962306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
68062306a36Sopenharmony_ci			       ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
68162306a36Sopenharmony_ci			       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (inst->ctrl_handler.error) {
68462306a36Sopenharmony_ci		ret = inst->ctrl_handler.error;
68562306a36Sopenharmony_ci		v4l2_ctrl_handler_free(&inst->ctrl_handler);
68662306a36Sopenharmony_ci		return ret;
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
69062306a36Sopenharmony_ci	if (ret) {
69162306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret);
69262306a36Sopenharmony_ci		v4l2_ctrl_handler_free(&inst->ctrl_handler);
69362306a36Sopenharmony_ci		return ret;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return 0;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic bool venc_check_ready(struct vpu_inst *inst, unsigned int type)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(type)) {
70462306a36Sopenharmony_ci		if (vpu_helper_get_free_space(inst) < venc->cpb_size)
70562306a36Sopenharmony_ci			return false;
70662306a36Sopenharmony_ci		return venc->input_ready;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (list_empty(&venc->frames))
71062306a36Sopenharmony_ci		return false;
71162306a36Sopenharmony_ci	return true;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic u32 venc_get_enable_mask(u32 type)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(type))
71762306a36Sopenharmony_ci		return VENC_OUTPUT_ENABLE;
71862306a36Sopenharmony_ci	else
71962306a36Sopenharmony_ci		return VENC_CAPTURE_ENABLE;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic void venc_set_enable(struct venc_t *venc, u32 type, int enable)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	u32 mask = venc_get_enable_mask(type);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (enable)
72762306a36Sopenharmony_ci		venc->enable |= mask;
72862306a36Sopenharmony_ci	else
72962306a36Sopenharmony_ci		venc->enable &= ~mask;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic u32 venc_get_enable(struct venc_t *venc, u32 type)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	return venc->enable & venc_get_enable_mask(type);
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic void venc_input_done(struct vpu_inst *inst)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	vpu_inst_lock(inst);
74262306a36Sopenharmony_ci	venc->input_ready = true;
74362306a36Sopenharmony_ci	vpu_process_output_buffer(inst);
74462306a36Sopenharmony_ci	if (inst->state == VPU_CODEC_STATE_DRAIN)
74562306a36Sopenharmony_ci		venc_drain(inst);
74662306a36Sopenharmony_ci	vpu_inst_unlock(inst);
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci/*
75062306a36Sopenharmony_ci * It's hardware limitation, that there may be several bytes
75162306a36Sopenharmony_ci * redundant data at the beginning of frame.
75262306a36Sopenharmony_ci * For android platform, the redundant data may cause cts test fail
75362306a36Sopenharmony_ci * So driver will strip them
75462306a36Sopenharmony_ci */
75562306a36Sopenharmony_cistatic int venc_precheck_encoded_frame(struct vpu_inst *inst, struct venc_frame_t *frame)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct venc_t *venc;
75862306a36Sopenharmony_ci	int skipped;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (!frame || !frame->bytesused)
76162306a36Sopenharmony_ci		return -EINVAL;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	venc = inst->priv;
76462306a36Sopenharmony_ci	skipped = vpu_helper_find_startcode(&inst->stream_buffer,
76562306a36Sopenharmony_ci					    inst->cap_format.pixfmt,
76662306a36Sopenharmony_ci					    frame->info.wptr - inst->stream_buffer.phys,
76762306a36Sopenharmony_ci					    frame->bytesused);
76862306a36Sopenharmony_ci	if (skipped > 0) {
76962306a36Sopenharmony_ci		frame->bytesused -= skipped;
77062306a36Sopenharmony_ci		frame->info.wptr = vpu_helper_step_walk(&inst->stream_buffer,
77162306a36Sopenharmony_ci							frame->info.wptr, skipped);
77262306a36Sopenharmony_ci		venc->skipped_bytes += skipped;
77362306a36Sopenharmony_ci		venc->skipped_count++;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	return 0;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic int venc_get_one_encoded_frame(struct vpu_inst *inst,
78062306a36Sopenharmony_ci				      struct venc_frame_t *frame,
78162306a36Sopenharmony_ci				      struct vb2_v4l2_buffer *vbuf)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
78462306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_buf;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (!vbuf)
78762306a36Sopenharmony_ci		return -EAGAIN;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id);
79062306a36Sopenharmony_ci	if (src_buf) {
79162306a36Sopenharmony_ci		v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true);
79262306a36Sopenharmony_ci		vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
79362306a36Sopenharmony_ci		v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf);
79462306a36Sopenharmony_ci		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
79562306a36Sopenharmony_ci	} else {
79662306a36Sopenharmony_ci		vbuf->vb2_buf.timestamp = frame->info.timestamp;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci	if (!venc_get_enable(inst->priv, vbuf->vb2_buf.type)) {
79962306a36Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
80062306a36Sopenharmony_ci		return 0;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci	if (frame->bytesused > vbuf->vb2_buf.planes[0].length) {
80362306a36Sopenharmony_ci		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
80462306a36Sopenharmony_ci		return -ENOMEM;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	venc_precheck_encoded_frame(inst, frame);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (frame->bytesused) {
81062306a36Sopenharmony_ci		u32 rptr = frame->info.wptr;
81162306a36Sopenharmony_ci		void *dst = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		vpu_helper_copy_from_stream_buffer(&inst->stream_buffer,
81462306a36Sopenharmony_ci						   &rptr, frame->bytesused, dst);
81562306a36Sopenharmony_ci		vpu_iface_update_stream_buffer(inst, rptr, 0);
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci	vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->bytesused);
81862306a36Sopenharmony_ci	vbuf->sequence = frame->info.frame_id;
81962306a36Sopenharmony_ci	vbuf->field = inst->cap_format.field;
82062306a36Sopenharmony_ci	vbuf->flags |= frame->info.pic_type;
82162306a36Sopenharmony_ci	vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
82262306a36Sopenharmony_ci	dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
82362306a36Sopenharmony_ci	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
82462306a36Sopenharmony_ci	venc->ready_count++;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME)
82762306a36Sopenharmony_ci		dev_dbg(inst->dev, "[%d][%d]key frame\n", inst->id, frame->info.frame_id);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	return 0;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic int venc_get_encoded_frames(struct vpu_inst *inst)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct venc_t *venc;
83562306a36Sopenharmony_ci	struct venc_frame_t *frame;
83662306a36Sopenharmony_ci	struct venc_frame_t *tmp;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (!inst->fh.m2m_ctx)
83962306a36Sopenharmony_ci		return 0;
84062306a36Sopenharmony_ci	venc = inst->priv;
84162306a36Sopenharmony_ci	list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
84262306a36Sopenharmony_ci		if (venc_get_one_encoded_frame(inst, frame,
84362306a36Sopenharmony_ci					       v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx)))
84462306a36Sopenharmony_ci			break;
84562306a36Sopenharmony_ci		list_del_init(&frame->list);
84662306a36Sopenharmony_ci		vfree(frame);
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	return 0;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic int venc_frame_encoded(struct vpu_inst *inst, void *arg)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct vpu_enc_pic_info *info = arg;
85562306a36Sopenharmony_ci	struct venc_frame_t *frame;
85662306a36Sopenharmony_ci	struct venc_t *venc;
85762306a36Sopenharmony_ci	int ret = 0;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (!info)
86062306a36Sopenharmony_ci		return -EINVAL;
86162306a36Sopenharmony_ci	venc = inst->priv;
86262306a36Sopenharmony_ci	frame = vzalloc(sizeof(*frame));
86362306a36Sopenharmony_ci	if (!frame)
86462306a36Sopenharmony_ci		return -ENOMEM;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	memcpy(&frame->info, info, sizeof(frame->info));
86762306a36Sopenharmony_ci	frame->bytesused = info->frame_size;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	vpu_inst_lock(inst);
87062306a36Sopenharmony_ci	list_add_tail(&frame->list, &venc->frames);
87162306a36Sopenharmony_ci	venc->encode_count++;
87262306a36Sopenharmony_ci	venc_get_encoded_frames(inst);
87362306a36Sopenharmony_ci	vpu_inst_unlock(inst);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	return ret;
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic void venc_set_last_buffer_dequeued(struct vpu_inst *inst)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (venc->stopped && list_empty(&venc->frames))
88362306a36Sopenharmony_ci		vpu_set_last_buffer_dequeued(inst, true);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic void venc_stop_done(struct vpu_inst *inst)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	vpu_inst_lock(inst);
89162306a36Sopenharmony_ci	venc->stopped = true;
89262306a36Sopenharmony_ci	venc_set_last_buffer_dequeued(inst);
89362306a36Sopenharmony_ci	vpu_inst_unlock(inst);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	wake_up_all(&venc->wq);
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic void venc_event_notify(struct vpu_inst *inst, u32 event, void *data)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void venc_release(struct vpu_inst *inst)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic void venc_cleanup(struct vpu_inst *inst)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct venc_t *venc;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (!inst)
91162306a36Sopenharmony_ci		return;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	venc = inst->priv;
91462306a36Sopenharmony_ci	vfree(venc);
91562306a36Sopenharmony_ci	inst->priv = NULL;
91662306a36Sopenharmony_ci	vfree(inst);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic int venc_start_session(struct vpu_inst *inst, u32 type)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
92262306a36Sopenharmony_ci	int stream_buffer_size;
92362306a36Sopenharmony_ci	int ret;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	venc_set_enable(venc, type, 1);
92662306a36Sopenharmony_ci	if ((venc->enable & VENC_ENABLE_MASK) != VENC_ENABLE_MASK)
92762306a36Sopenharmony_ci		return 0;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	vpu_iface_init_instance(inst);
93062306a36Sopenharmony_ci	stream_buffer_size = vpu_iface_get_stream_buffer_size(inst->core);
93162306a36Sopenharmony_ci	if (stream_buffer_size > 0) {
93262306a36Sopenharmony_ci		inst->stream_buffer.length = max_t(u32, stream_buffer_size, venc->cpb_size * 3);
93362306a36Sopenharmony_ci		ret = vpu_alloc_dma(inst->core, &inst->stream_buffer);
93462306a36Sopenharmony_ci		if (ret)
93562306a36Sopenharmony_ci			goto error;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		inst->use_stream_buffer = true;
93862306a36Sopenharmony_ci		vpu_iface_config_stream_buffer(inst, &inst->stream_buffer);
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	ret = vpu_iface_set_encode_params(inst, &venc->params, 0);
94262306a36Sopenharmony_ci	if (ret)
94362306a36Sopenharmony_ci		goto error;
94462306a36Sopenharmony_ci	ret = vpu_session_configure_codec(inst);
94562306a36Sopenharmony_ci	if (ret)
94662306a36Sopenharmony_ci		goto error;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_CONFIGURED;
94962306a36Sopenharmony_ci	/*vpu_iface_config_memory_resource*/
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/*config enc expert mode parameter*/
95262306a36Sopenharmony_ci	ret = vpu_iface_set_encode_params(inst, &venc->params, 1);
95362306a36Sopenharmony_ci	if (ret)
95462306a36Sopenharmony_ci		goto error;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	ret = vpu_session_start(inst);
95762306a36Sopenharmony_ci	if (ret)
95862306a36Sopenharmony_ci		goto error;
95962306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_STARTED;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	venc->bitrate_change = false;
96262306a36Sopenharmony_ci	venc->input_ready = true;
96362306a36Sopenharmony_ci	venc->frame_count = 0;
96462306a36Sopenharmony_ci	venc->encode_count = 0;
96562306a36Sopenharmony_ci	venc->ready_count = 0;
96662306a36Sopenharmony_ci	venc->stopped = false;
96762306a36Sopenharmony_ci	vpu_process_output_buffer(inst);
96862306a36Sopenharmony_ci	if (venc->frame_count == 0)
96962306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] there is no input when starting\n", inst->id);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return 0;
97262306a36Sopenharmony_cierror:
97362306a36Sopenharmony_ci	venc_set_enable(venc, type, 0);
97462306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_DEINIT;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	vpu_free_dma(&inst->stream_buffer);
97762306a36Sopenharmony_ci	return ret;
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic void venc_cleanup_mem_resource(struct vpu_inst *inst)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct venc_t *venc;
98362306a36Sopenharmony_ci	u32 i;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	venc = inst->priv;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(venc->enc); i++)
98862306a36Sopenharmony_ci		vpu_free_dma(&venc->enc[i]);
98962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(venc->ref); i++)
99062306a36Sopenharmony_ci		vpu_free_dma(&venc->ref[i]);
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic void venc_request_mem_resource(struct vpu_inst *inst,
99462306a36Sopenharmony_ci				      u32 enc_frame_size,
99562306a36Sopenharmony_ci				      u32 enc_frame_num,
99662306a36Sopenharmony_ci				      u32 ref_frame_size,
99762306a36Sopenharmony_ci				      u32 ref_frame_num,
99862306a36Sopenharmony_ci				      u32 act_frame_size,
99962306a36Sopenharmony_ci				      u32 act_frame_num)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct venc_t *venc;
100262306a36Sopenharmony_ci	u32 i;
100362306a36Sopenharmony_ci	int ret;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	venc = inst->priv;
100662306a36Sopenharmony_ci	if (enc_frame_num > ARRAY_SIZE(venc->enc)) {
100762306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] enc num(%d) is out of range\n", inst->id, enc_frame_num);
100862306a36Sopenharmony_ci		return;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci	if (ref_frame_num > ARRAY_SIZE(venc->ref)) {
101162306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] ref num(%d) is out of range\n", inst->id, ref_frame_num);
101262306a36Sopenharmony_ci		return;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci	if (act_frame_num > ARRAY_SIZE(venc->act)) {
101562306a36Sopenharmony_ci		dev_err(inst->dev, "[%d] act num(%d) is out of range\n", inst->id, act_frame_num);
101662306a36Sopenharmony_ci		return;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	for (i = 0; i < enc_frame_num; i++) {
102062306a36Sopenharmony_ci		venc->enc[i].length = enc_frame_size;
102162306a36Sopenharmony_ci		ret = vpu_alloc_dma(inst->core, &venc->enc[i]);
102262306a36Sopenharmony_ci		if (ret) {
102362306a36Sopenharmony_ci			venc_cleanup_mem_resource(inst);
102462306a36Sopenharmony_ci			return;
102562306a36Sopenharmony_ci		}
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci	for (i = 0; i < ref_frame_num; i++) {
102862306a36Sopenharmony_ci		venc->ref[i].length = ref_frame_size;
102962306a36Sopenharmony_ci		ret = vpu_alloc_dma(inst->core, &venc->ref[i]);
103062306a36Sopenharmony_ci		if (ret) {
103162306a36Sopenharmony_ci			venc_cleanup_mem_resource(inst);
103262306a36Sopenharmony_ci			return;
103362306a36Sopenharmony_ci		}
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci	if (act_frame_num != 1 || act_frame_size > inst->act.length) {
103662306a36Sopenharmony_ci		venc_cleanup_mem_resource(inst);
103762306a36Sopenharmony_ci		return;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci	venc->act[0].length = act_frame_size;
104062306a36Sopenharmony_ci	venc->act[0].phys = inst->act.phys;
104162306a36Sopenharmony_ci	venc->act[0].virt = inst->act.virt;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	for (i = 0; i < enc_frame_num; i++)
104462306a36Sopenharmony_ci		vpu_iface_config_memory_resource(inst, MEM_RES_ENC, i, &venc->enc[i]);
104562306a36Sopenharmony_ci	for (i = 0; i < ref_frame_num; i++)
104662306a36Sopenharmony_ci		vpu_iface_config_memory_resource(inst, MEM_RES_REF, i, &venc->ref[i]);
104762306a36Sopenharmony_ci	for (i = 0; i < act_frame_num; i++)
104862306a36Sopenharmony_ci		vpu_iface_config_memory_resource(inst, MEM_RES_ACT, i, &venc->act[i]);
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic void venc_cleanup_frames(struct venc_t *venc)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct venc_frame_t *frame;
105462306a36Sopenharmony_ci	struct venc_frame_t *tmp;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
105762306a36Sopenharmony_ci		list_del_init(&frame->list);
105862306a36Sopenharmony_ci		vfree(frame);
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic int venc_stop_session(struct vpu_inst *inst, u32 type)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	venc_set_enable(venc, type, 0);
106762306a36Sopenharmony_ci	if (venc->enable & VENC_ENABLE_MASK)
106862306a36Sopenharmony_ci		return 0;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (inst->state == VPU_CODEC_STATE_DEINIT)
107162306a36Sopenharmony_ci		return 0;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (inst->state != VPU_CODEC_STATE_STOP)
107462306a36Sopenharmony_ci		venc_request_eos(inst);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	call_void_vop(inst, wait_prepare);
107762306a36Sopenharmony_ci	if (!wait_event_timeout(venc->wq, venc->stopped, VPU_TIMEOUT)) {
107862306a36Sopenharmony_ci		set_bit(inst->id, &inst->core->hang_mask);
107962306a36Sopenharmony_ci		vpu_session_debug(inst);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	call_void_vop(inst, wait_finish);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	inst->state = VPU_CODEC_STATE_DEINIT;
108462306a36Sopenharmony_ci	venc_cleanup_frames(inst->priv);
108562306a36Sopenharmony_ci	vpu_free_dma(&inst->stream_buffer);
108662306a36Sopenharmony_ci	venc_cleanup_mem_resource(inst);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	return 0;
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic int venc_process_output(struct vpu_inst *inst, struct vb2_buffer *vb)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
109462306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
109562306a36Sopenharmony_ci	u32 flags;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (inst->state == VPU_CODEC_STATE_DEINIT)
109862306a36Sopenharmony_ci		return -EINVAL;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	vbuf = to_vb2_v4l2_buffer(vb);
110162306a36Sopenharmony_ci	if (inst->state == VPU_CODEC_STATE_STARTED)
110262306a36Sopenharmony_ci		inst->state = VPU_CODEC_STATE_ACTIVE;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	flags = vbuf->flags;
110562306a36Sopenharmony_ci	if (venc->request_key_frame) {
110662306a36Sopenharmony_ci		vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
110762306a36Sopenharmony_ci		venc->request_key_frame = 0;
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci	if (venc->bitrate_change) {
111062306a36Sopenharmony_ci		vpu_session_update_parameters(inst, &venc->params);
111162306a36Sopenharmony_ci		venc->bitrate_change = false;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci	dev_dbg(inst->dev, "[%d][INPUT  TS]%32lld\n", inst->id, vb->timestamp);
111462306a36Sopenharmony_ci	vpu_iface_input_frame(inst, vb);
111562306a36Sopenharmony_ci	vbuf->flags = flags;
111662306a36Sopenharmony_ci	venc->input_ready = false;
111762306a36Sopenharmony_ci	venc->frame_count++;
111862306a36Sopenharmony_ci	vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	return 0;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic int venc_process_capture(struct vpu_inst *inst, struct vb2_buffer *vb)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	struct venc_t *venc;
112662306a36Sopenharmony_ci	struct venc_frame_t *frame = NULL;
112762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
112862306a36Sopenharmony_ci	int ret;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	venc = inst->priv;
113162306a36Sopenharmony_ci	if (list_empty(&venc->frames))
113262306a36Sopenharmony_ci		return -EINVAL;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	frame = list_first_entry(&venc->frames, struct venc_frame_t, list);
113562306a36Sopenharmony_ci	vbuf = to_vb2_v4l2_buffer(vb);
113662306a36Sopenharmony_ci	v4l2_m2m_dst_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
113762306a36Sopenharmony_ci	ret = venc_get_one_encoded_frame(inst, frame, vbuf);
113862306a36Sopenharmony_ci	if (ret)
113962306a36Sopenharmony_ci		return ret;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	list_del_init(&frame->list);
114262306a36Sopenharmony_ci	vfree(frame);
114362306a36Sopenharmony_ci	return 0;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic void venc_on_queue_empty(struct vpu_inst *inst, u32 type)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (V4L2_TYPE_IS_OUTPUT(type))
115162306a36Sopenharmony_ci		return;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (venc->stopped)
115462306a36Sopenharmony_ci		venc_set_last_buffer_dequeued(inst);
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic int venc_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct venc_t *venc = inst->priv;
116062306a36Sopenharmony_ci	int num = -1;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	switch (i) {
116362306a36Sopenharmony_ci	case 0:
116462306a36Sopenharmony_ci		num = scnprintf(str, size, "profile = %d\n", venc->params.profile);
116562306a36Sopenharmony_ci		break;
116662306a36Sopenharmony_ci	case 1:
116762306a36Sopenharmony_ci		num = scnprintf(str, size, "level = %d\n", venc->params.level);
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case 2:
117062306a36Sopenharmony_ci		num = scnprintf(str, size, "fps = %d/%d\n",
117162306a36Sopenharmony_ci				venc->params.frame_rate.numerator,
117262306a36Sopenharmony_ci				venc->params.frame_rate.denominator);
117362306a36Sopenharmony_ci		break;
117462306a36Sopenharmony_ci	case 3:
117562306a36Sopenharmony_ci		num = scnprintf(str, size, "%d x %d -> %d x %d\n",
117662306a36Sopenharmony_ci				venc->params.src_width,
117762306a36Sopenharmony_ci				venc->params.src_height,
117862306a36Sopenharmony_ci				venc->params.out_width,
117962306a36Sopenharmony_ci				venc->params.out_height);
118062306a36Sopenharmony_ci		break;
118162306a36Sopenharmony_ci	case 4:
118262306a36Sopenharmony_ci		num = scnprintf(str, size, "(%d, %d)  %d x %d\n",
118362306a36Sopenharmony_ci				venc->params.crop.left,
118462306a36Sopenharmony_ci				venc->params.crop.top,
118562306a36Sopenharmony_ci				venc->params.crop.width,
118662306a36Sopenharmony_ci				venc->params.crop.height);
118762306a36Sopenharmony_ci		break;
118862306a36Sopenharmony_ci	case 5:
118962306a36Sopenharmony_ci		num = scnprintf(str, size,
119062306a36Sopenharmony_ci				"enable = 0x%x, input = %d, encode = %d, ready = %d, stopped = %d\n",
119162306a36Sopenharmony_ci				venc->enable,
119262306a36Sopenharmony_ci				venc->frame_count, venc->encode_count,
119362306a36Sopenharmony_ci				venc->ready_count,
119462306a36Sopenharmony_ci				venc->stopped);
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci	case 6:
119762306a36Sopenharmony_ci		num = scnprintf(str, size, "gop = %d\n", venc->params.gop_length);
119862306a36Sopenharmony_ci		break;
119962306a36Sopenharmony_ci	case 7:
120062306a36Sopenharmony_ci		num = scnprintf(str, size, "bframes = %d\n", venc->params.bframes);
120162306a36Sopenharmony_ci		break;
120262306a36Sopenharmony_ci	case 8:
120362306a36Sopenharmony_ci		num = scnprintf(str, size, "rc: %s, mode = %d, bitrate = %d(%d), qp = %d\n",
120462306a36Sopenharmony_ci				venc->params.rc_enable ? "enable" : "disable",
120562306a36Sopenharmony_ci				venc->params.rc_mode,
120662306a36Sopenharmony_ci				venc->params.bitrate,
120762306a36Sopenharmony_ci				venc->params.bitrate_max,
120862306a36Sopenharmony_ci				venc->params.i_frame_qp);
120962306a36Sopenharmony_ci		break;
121062306a36Sopenharmony_ci	case 9:
121162306a36Sopenharmony_ci		num = scnprintf(str, size, "sar: enable = %d, idc = %d, %d x %d\n",
121262306a36Sopenharmony_ci				venc->params.sar.enable,
121362306a36Sopenharmony_ci				venc->params.sar.idc,
121462306a36Sopenharmony_ci				venc->params.sar.width,
121562306a36Sopenharmony_ci				venc->params.sar.height);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		break;
121862306a36Sopenharmony_ci	case 10:
121962306a36Sopenharmony_ci		num = scnprintf(str, size,
122062306a36Sopenharmony_ci				"colorspace: primaries = %d, transfer = %d, matrix = %d, full_range = %d\n",
122162306a36Sopenharmony_ci				venc->params.color.primaries,
122262306a36Sopenharmony_ci				venc->params.color.transfer,
122362306a36Sopenharmony_ci				venc->params.color.matrix,
122462306a36Sopenharmony_ci				venc->params.color.full_range);
122562306a36Sopenharmony_ci		break;
122662306a36Sopenharmony_ci	case 11:
122762306a36Sopenharmony_ci		num = scnprintf(str, size, "skipped: count = %d, bytes = %d\n",
122862306a36Sopenharmony_ci				venc->skipped_count, venc->skipped_bytes);
122962306a36Sopenharmony_ci		break;
123062306a36Sopenharmony_ci	default:
123162306a36Sopenharmony_ci		break;
123262306a36Sopenharmony_ci	}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return num;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic struct vpu_inst_ops venc_inst_ops = {
123862306a36Sopenharmony_ci	.ctrl_init = venc_ctrl_init,
123962306a36Sopenharmony_ci	.check_ready = venc_check_ready,
124062306a36Sopenharmony_ci	.input_done = venc_input_done,
124162306a36Sopenharmony_ci	.get_one_frame = venc_frame_encoded,
124262306a36Sopenharmony_ci	.stop_done = venc_stop_done,
124362306a36Sopenharmony_ci	.event_notify = venc_event_notify,
124462306a36Sopenharmony_ci	.release = venc_release,
124562306a36Sopenharmony_ci	.cleanup = venc_cleanup,
124662306a36Sopenharmony_ci	.start = venc_start_session,
124762306a36Sopenharmony_ci	.mem_request = venc_request_mem_resource,
124862306a36Sopenharmony_ci	.stop = venc_stop_session,
124962306a36Sopenharmony_ci	.process_output = venc_process_output,
125062306a36Sopenharmony_ci	.process_capture = venc_process_capture,
125162306a36Sopenharmony_ci	.on_queue_empty = venc_on_queue_empty,
125262306a36Sopenharmony_ci	.get_debug_info = venc_get_debug_info,
125362306a36Sopenharmony_ci	.wait_prepare = vpu_inst_unlock,
125462306a36Sopenharmony_ci	.wait_finish = vpu_inst_lock,
125562306a36Sopenharmony_ci};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic void venc_init(struct file *file)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct vpu_inst *inst = to_inst(file);
126062306a36Sopenharmony_ci	struct venc_t *venc;
126162306a36Sopenharmony_ci	struct v4l2_format f;
126262306a36Sopenharmony_ci	struct v4l2_streamparm parm;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	venc = inst->priv;
126562306a36Sopenharmony_ci	venc->params.qp_min = 1;
126662306a36Sopenharmony_ci	venc->params.qp_max = 51;
126762306a36Sopenharmony_ci	venc->params.qp_min_i = 1;
126862306a36Sopenharmony_ci	venc->params.qp_max_i = 51;
126962306a36Sopenharmony_ci	venc->params.bitrate_min = BITRATE_MIN;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	memset(&f, 0, sizeof(f));
127262306a36Sopenharmony_ci	f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
127362306a36Sopenharmony_ci	f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
127462306a36Sopenharmony_ci	f.fmt.pix_mp.width = 1280;
127562306a36Sopenharmony_ci	f.fmt.pix_mp.height = 720;
127662306a36Sopenharmony_ci	f.fmt.pix_mp.field = V4L2_FIELD_NONE;
127762306a36Sopenharmony_ci	venc_s_fmt(file, &inst->fh, &f);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	memset(&f, 0, sizeof(f));
128062306a36Sopenharmony_ci	f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
128162306a36Sopenharmony_ci	f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
128262306a36Sopenharmony_ci	f.fmt.pix_mp.width = 1280;
128362306a36Sopenharmony_ci	f.fmt.pix_mp.height = 720;
128462306a36Sopenharmony_ci	f.fmt.pix_mp.field = V4L2_FIELD_NONE;
128562306a36Sopenharmony_ci	venc_s_fmt(file, &inst->fh, &f);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	memset(&parm, 0, sizeof(parm));
128862306a36Sopenharmony_ci	parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
128962306a36Sopenharmony_ci	parm.parm.capture.timeperframe.numerator = 1;
129062306a36Sopenharmony_ci	parm.parm.capture.timeperframe.denominator = 30;
129162306a36Sopenharmony_ci	venc_s_parm(file, &inst->fh, &parm);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic int venc_open(struct file *file)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	struct vpu_inst *inst;
129762306a36Sopenharmony_ci	struct venc_t *venc;
129862306a36Sopenharmony_ci	int ret;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	inst = vzalloc(sizeof(*inst));
130162306a36Sopenharmony_ci	if (!inst)
130262306a36Sopenharmony_ci		return -ENOMEM;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	venc = vzalloc(sizeof(*venc));
130562306a36Sopenharmony_ci	if (!venc) {
130662306a36Sopenharmony_ci		vfree(inst);
130762306a36Sopenharmony_ci		return -ENOMEM;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	inst->ops = &venc_inst_ops;
131162306a36Sopenharmony_ci	inst->formats = venc_formats;
131262306a36Sopenharmony_ci	inst->type = VPU_CORE_TYPE_ENC;
131362306a36Sopenharmony_ci	inst->priv = venc;
131462306a36Sopenharmony_ci	INIT_LIST_HEAD(&venc->frames);
131562306a36Sopenharmony_ci	init_waitqueue_head(&venc->wq);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	ret = vpu_v4l2_open(file, inst);
131862306a36Sopenharmony_ci	if (ret)
131962306a36Sopenharmony_ci		return ret;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	inst->min_buffer_out = VENC_MIN_BUFFER_OUT;
132262306a36Sopenharmony_ci	inst->min_buffer_cap = VENC_MIN_BUFFER_CAP;
132362306a36Sopenharmony_ci	venc_init(file);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return 0;
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic const struct v4l2_file_operations venc_fops = {
132962306a36Sopenharmony_ci	.owner = THIS_MODULE,
133062306a36Sopenharmony_ci	.open = venc_open,
133162306a36Sopenharmony_ci	.release = vpu_v4l2_close,
133262306a36Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
133362306a36Sopenharmony_ci	.poll = v4l2_m2m_fop_poll,
133462306a36Sopenharmony_ci	.mmap = v4l2_m2m_fop_mmap,
133562306a36Sopenharmony_ci};
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ciconst struct v4l2_ioctl_ops *venc_get_ioctl_ops(void)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	return &venc_ioctl_ops;
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ciconst struct v4l2_file_operations *venc_get_fops(void)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	return &venc_fops;
134562306a36Sopenharmony_ci}
1346