xref: /linux/drivers/media/test-drivers/vicodec/vicodec-core.c (revision 3abfc314c5e60a54973a6f3cefd591bfdad8adf6)
1256bf813SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only
2256bf813SHans Verkuil /*
3256bf813SHans Verkuil  * A virtual codec example device.
4256bf813SHans Verkuil  *
5256bf813SHans Verkuil  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6256bf813SHans Verkuil  *
7256bf813SHans Verkuil  * This is a virtual codec device driver for testing the codec framework.
8256bf813SHans Verkuil  * It simulates a device that uses memory buffers for both source and
9256bf813SHans Verkuil  * destination and encodes or decodes the data.
10256bf813SHans Verkuil  */
11256bf813SHans Verkuil 
12256bf813SHans Verkuil #include <linux/module.h>
13256bf813SHans Verkuil #include <linux/delay.h>
14256bf813SHans Verkuil #include <linux/fs.h>
15256bf813SHans Verkuil #include <linux/sched.h>
16256bf813SHans Verkuil #include <linux/slab.h>
17256bf813SHans Verkuil 
18256bf813SHans Verkuil #include <linux/platform_device.h>
19256bf813SHans Verkuil #include <media/v4l2-mem2mem.h>
20256bf813SHans Verkuil #include <media/v4l2-device.h>
21256bf813SHans Verkuil #include <media/v4l2-ioctl.h>
22256bf813SHans Verkuil #include <media/v4l2-ctrls.h>
23256bf813SHans Verkuil #include <media/v4l2-event.h>
24256bf813SHans Verkuil #include <media/videobuf2-vmalloc.h>
25256bf813SHans Verkuil 
26cd12b401SHans Verkuil #include "codec-v4l2-fwht.h"
27256bf813SHans Verkuil 
28256bf813SHans Verkuil MODULE_DESCRIPTION("Virtual codec device");
29256bf813SHans Verkuil MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
30256bf813SHans Verkuil MODULE_LICENSE("GPL v2");
31256bf813SHans Verkuil 
32256bf813SHans Verkuil static bool multiplanar;
33256bf813SHans Verkuil module_param(multiplanar, bool, 0444);
34256bf813SHans Verkuil MODULE_PARM_DESC(multiplanar,
35256bf813SHans Verkuil 		 " use multi-planar API instead of single-planar API");
36256bf813SHans Verkuil 
37256bf813SHans Verkuil static unsigned int debug;
38256bf813SHans Verkuil module_param(debug, uint, 0644);
39256bf813SHans Verkuil MODULE_PARM_DESC(debug, " activates debug info");
40256bf813SHans Verkuil 
41256bf813SHans Verkuil #define VICODEC_NAME		"vicodec"
42256bf813SHans Verkuil #define MAX_WIDTH		4096U
43256bf813SHans Verkuil #define MIN_WIDTH		640U
44256bf813SHans Verkuil #define MAX_HEIGHT		2160U
457cf7b2e9SHans Verkuil #define MIN_HEIGHT		360U
46256bf813SHans Verkuil 
47256bf813SHans Verkuil #define dprintk(dev, fmt, arg...) \
48256bf813SHans Verkuil 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
49256bf813SHans Verkuil 
50256bf813SHans Verkuil 
5129a7a5e9SHans Verkuil struct pixfmt_info {
5229a7a5e9SHans Verkuil 	u32 id;
5329a7a5e9SHans Verkuil 	unsigned int bytesperline_mult;
5429a7a5e9SHans Verkuil 	unsigned int sizeimage_mult;
5529a7a5e9SHans Verkuil 	unsigned int sizeimage_div;
5629a7a5e9SHans Verkuil 	unsigned int luma_step;
5729a7a5e9SHans Verkuil 	unsigned int chroma_step;
5829a7a5e9SHans Verkuil 	/* Chroma plane subsampling */
5929a7a5e9SHans Verkuil 	unsigned int width_div;
6029a7a5e9SHans Verkuil 	unsigned int height_div;
6129a7a5e9SHans Verkuil };
6229a7a5e9SHans Verkuil 
63cd12b401SHans Verkuil static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
648c1d02f1SDafna Hirschfeld 	V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
6529a7a5e9SHans Verkuil };
6629a7a5e9SHans Verkuil 
672495f39cSDafna Hirschfeld static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = {
682495f39cSDafna Hirschfeld 	V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1
692495f39cSDafna Hirschfeld };
702495f39cSDafna Hirschfeld 
71256bf813SHans Verkuil static void vicodec_dev_release(struct device *dev)
72256bf813SHans Verkuil {
73256bf813SHans Verkuil }
74256bf813SHans Verkuil 
75256bf813SHans Verkuil static struct platform_device vicodec_pdev = {
76256bf813SHans Verkuil 	.name		= VICODEC_NAME,
77256bf813SHans Verkuil 	.dev.release	= vicodec_dev_release,
78256bf813SHans Verkuil };
79256bf813SHans Verkuil 
80256bf813SHans Verkuil /* Per-queue, driver-specific private data */
81256bf813SHans Verkuil struct vicodec_q_data {
829e812549SDafna Hirschfeld 	unsigned int		coded_width;
839e812549SDafna Hirschfeld 	unsigned int		coded_height;
849e812549SDafna Hirschfeld 	unsigned int		visible_width;
859e812549SDafna Hirschfeld 	unsigned int		visible_height;
86256bf813SHans Verkuil 	unsigned int		sizeimage;
878307f0abSHans Verkuil 	unsigned int		vb2_sizeimage;
88256bf813SHans Verkuil 	unsigned int		sequence;
89cd12b401SHans Verkuil 	const struct v4l2_fwht_pixfmt_info *info;
90256bf813SHans Verkuil };
91256bf813SHans Verkuil 
92256bf813SHans Verkuil enum {
93256bf813SHans Verkuil 	V4L2_M2M_SRC = 0,
94256bf813SHans Verkuil 	V4L2_M2M_DST = 1,
95256bf813SHans Verkuil };
96256bf813SHans Verkuil 
97c022a4a9SDafna Hirschfeld struct vicodec_dev_instance {
98c022a4a9SDafna Hirschfeld 	struct video_device     vfd;
99c022a4a9SDafna Hirschfeld 	struct mutex            mutex;
100c022a4a9SDafna Hirschfeld 	spinlock_t              lock;
101c022a4a9SDafna Hirschfeld 	struct v4l2_m2m_dev     *m2m_dev;
102c022a4a9SDafna Hirschfeld };
103c022a4a9SDafna Hirschfeld 
104256bf813SHans Verkuil struct vicodec_dev {
105256bf813SHans Verkuil 	struct v4l2_device	v4l2_dev;
106c022a4a9SDafna Hirschfeld 	struct vicodec_dev_instance stateful_enc;
107c022a4a9SDafna Hirschfeld 	struct vicodec_dev_instance stateful_dec;
108fde649b4SDafna Hirschfeld 	struct vicodec_dev_instance stateless_dec;
109256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
110256bf813SHans Verkuil 	struct media_device	mdev;
111256bf813SHans Verkuil #endif
112256bf813SHans Verkuil 
113256bf813SHans Verkuil };
114256bf813SHans Verkuil 
115256bf813SHans Verkuil struct vicodec_ctx {
116256bf813SHans Verkuil 	struct v4l2_fh		fh;
117256bf813SHans Verkuil 	struct vicodec_dev	*dev;
118256bf813SHans Verkuil 	bool			is_enc;
119fde649b4SDafna Hirschfeld 	bool			is_stateless;
120256bf813SHans Verkuil 	spinlock_t		*lock;
121256bf813SHans Verkuil 
122256bf813SHans Verkuil 	struct v4l2_ctrl_handler hdl;
123256bf813SHans Verkuil 
124256bf813SHans Verkuil 	/* Source and destination queue data */
125256bf813SHans Verkuil 	struct vicodec_q_data   q_data[2];
126cd12b401SHans Verkuil 	struct v4l2_fwht_state	state;
127cd12b401SHans Verkuil 
128256bf813SHans Verkuil 	u32			cur_buf_offset;
129256bf813SHans Verkuil 	u32			comp_max_size;
130256bf813SHans Verkuil 	u32			comp_size;
131ddc1b085SDafna Hirschfeld 	u32			header_size;
132256bf813SHans Verkuil 	u32			comp_magic_cnt;
133256bf813SHans Verkuil 	bool			comp_has_frame;
134256bf813SHans Verkuil 	bool			comp_has_next_frame;
1353b15f68eSDafna Hirschfeld 	bool			first_source_change_sent;
1363b15f68eSDafna Hirschfeld 	bool			source_changed;
137256bf813SHans Verkuil };
138256bf813SHans Verkuil 
139d17589afSHans Verkuil static const struct v4l2_event vicodec_eos_event = {
140d17589afSHans Verkuil 	.type = V4L2_EVENT_EOS
141d17589afSHans Verkuil };
142d17589afSHans Verkuil 
143256bf813SHans Verkuil static inline struct vicodec_ctx *file2ctx(struct file *file)
144256bf813SHans Verkuil {
145256bf813SHans Verkuil 	return container_of(file->private_data, struct vicodec_ctx, fh);
146256bf813SHans Verkuil }
147256bf813SHans Verkuil 
148256bf813SHans Verkuil static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
149256bf813SHans Verkuil 					 enum v4l2_buf_type type)
150256bf813SHans Verkuil {
151256bf813SHans Verkuil 	switch (type) {
152256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
153256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
154256bf813SHans Verkuil 		return &ctx->q_data[V4L2_M2M_SRC];
155256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
156256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
157256bf813SHans Verkuil 		return &ctx->q_data[V4L2_M2M_DST];
158256bf813SHans Verkuil 	default:
159256bf813SHans Verkuil 		break;
160256bf813SHans Verkuil 	}
161256bf813SHans Verkuil 	return NULL;
162256bf813SHans Verkuil }
163256bf813SHans Verkuil 
16486764b88SDafna Hirschfeld static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info,
16586764b88SDafna Hirschfeld 		struct v4l2_fwht_state *state)
16686764b88SDafna Hirschfeld {
16786764b88SDafna Hirschfeld 	int plane_idx;
16886764b88SDafna Hirschfeld 	u8 *p_ref = state->ref_frame.buf;
16986764b88SDafna Hirschfeld 	unsigned int cap_stride = state->stride;
17086764b88SDafna Hirschfeld 	unsigned int ref_stride = state->ref_stride;
17186764b88SDafna Hirschfeld 
17286764b88SDafna Hirschfeld 	for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) {
17386764b88SDafna Hirschfeld 		int i;
17486764b88SDafna Hirschfeld 		unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ?
17586764b88SDafna Hirschfeld 			info->height_div : 1;
17686764b88SDafna Hirschfeld 		const u8 *row_cap = cap;
17786764b88SDafna Hirschfeld 		u8 *row_ref = p_ref;
17886764b88SDafna Hirschfeld 
17986764b88SDafna Hirschfeld 		if (info->planes_num == 3 && plane_idx == 1) {
18086764b88SDafna Hirschfeld 			cap_stride /= 2;
18186764b88SDafna Hirschfeld 			ref_stride /= 2;
18286764b88SDafna Hirschfeld 		}
18386764b88SDafna Hirschfeld 
18486764b88SDafna Hirschfeld 		if (plane_idx == 1 &&
18586764b88SDafna Hirschfeld 		    (info->id == V4L2_PIX_FMT_NV24 ||
18686764b88SDafna Hirschfeld 		     info->id == V4L2_PIX_FMT_NV42)) {
18786764b88SDafna Hirschfeld 			cap_stride *= 2;
18886764b88SDafna Hirschfeld 			ref_stride *= 2;
18986764b88SDafna Hirschfeld 		}
19086764b88SDafna Hirschfeld 
19186764b88SDafna Hirschfeld 		for (i = 0; i < state->visible_height / h_div; i++) {
19286764b88SDafna Hirschfeld 			memcpy(row_ref, row_cap, ref_stride);
19386764b88SDafna Hirschfeld 			row_ref += ref_stride;
19486764b88SDafna Hirschfeld 			row_cap += cap_stride;
19586764b88SDafna Hirschfeld 		}
19686764b88SDafna Hirschfeld 		cap += cap_stride * (state->coded_height / h_div);
19786764b88SDafna Hirschfeld 		p_ref += ref_stride * (state->coded_height / h_div);
19886764b88SDafna Hirschfeld 	}
19986764b88SDafna Hirschfeld }
20086764b88SDafna Hirschfeld 
20192dc64d4SDafna Hirschfeld static bool validate_by_version(unsigned int flags, unsigned int version)
20292dc64d4SDafna Hirschfeld {
2033abfc314SHans Verkuil 	if (!version || version > V4L2_FWHT_VERSION)
20492dc64d4SDafna Hirschfeld 		return false;
20592dc64d4SDafna Hirschfeld 
20692dc64d4SDafna Hirschfeld 	if (version >= 2) {
20792dc64d4SDafna Hirschfeld 		unsigned int components_num = 1 +
2083abfc314SHans Verkuil 			((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
2093abfc314SHans Verkuil 			 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
2103abfc314SHans Verkuil 		unsigned int pixenc = flags & V4L2_FWHT_FL_PIXENC_MSK;
21192dc64d4SDafna Hirschfeld 
21292dc64d4SDafna Hirschfeld 		if (components_num == 0 || components_num > 4 || !pixenc)
21392dc64d4SDafna Hirschfeld 			return false;
21492dc64d4SDafna Hirschfeld 	}
21592dc64d4SDafna Hirschfeld 	return true;
21692dc64d4SDafna Hirschfeld }
21792dc64d4SDafna Hirschfeld 
218997deb81SDafna Hirschfeld static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params,
219997deb81SDafna Hirschfeld 					    const struct v4l2_fwht_pixfmt_info *cur_info)
220997deb81SDafna Hirschfeld {
221997deb81SDafna Hirschfeld 	unsigned int width_div =
2223abfc314SHans Verkuil 		(params->flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
223997deb81SDafna Hirschfeld 	unsigned int height_div =
2243abfc314SHans Verkuil 		(params->flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
225997deb81SDafna Hirschfeld 	unsigned int components_num = 3;
226997deb81SDafna Hirschfeld 	unsigned int pixenc = 0;
227997deb81SDafna Hirschfeld 
228997deb81SDafna Hirschfeld 	if (params->version < 3)
229997deb81SDafna Hirschfeld 		return false;
230997deb81SDafna Hirschfeld 
2313abfc314SHans Verkuil 	components_num = 1 + ((params->flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
2323abfc314SHans Verkuil 			      V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
2333abfc314SHans Verkuil 	pixenc = (params->flags & V4L2_FWHT_FL_PIXENC_MSK);
234997deb81SDafna Hirschfeld 	if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div,
235997deb81SDafna Hirschfeld 				    components_num, pixenc))
236997deb81SDafna Hirschfeld 		return true;
237997deb81SDafna Hirschfeld 	return false;
238997deb81SDafna Hirschfeld }
239997deb81SDafna Hirschfeld 
240997deb81SDafna Hirschfeld 
241997deb81SDafna Hirschfeld static void update_state_from_header(struct vicodec_ctx *ctx)
242997deb81SDafna Hirschfeld {
243997deb81SDafna Hirschfeld 	const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
244997deb81SDafna Hirschfeld 
245997deb81SDafna Hirschfeld 	ctx->state.visible_width = ntohl(p_hdr->width);
246997deb81SDafna Hirschfeld 	ctx->state.visible_height = ntohl(p_hdr->height);
247997deb81SDafna Hirschfeld 	ctx->state.colorspace = ntohl(p_hdr->colorspace);
248997deb81SDafna Hirschfeld 	ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
249997deb81SDafna Hirschfeld 	ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
250997deb81SDafna Hirschfeld 	ctx->state.quantization = ntohl(p_hdr->quantization);
251997deb81SDafna Hirschfeld }
252997deb81SDafna Hirschfeld 
253256bf813SHans Verkuil static int device_process(struct vicodec_ctx *ctx,
254b9bbbbfeSDafna Hirschfeld 			  struct vb2_v4l2_buffer *src_vb,
255b9bbbbfeSDafna Hirschfeld 			  struct vb2_v4l2_buffer *dst_vb)
256256bf813SHans Verkuil {
257256bf813SHans Verkuil 	struct vicodec_dev *dev = ctx->dev;
258cd12b401SHans Verkuil 	struct v4l2_fwht_state *state = &ctx->state;
259b9bbbbfeSDafna Hirschfeld 	u8 *p_src, *p_dst;
260997deb81SDafna Hirschfeld 	int ret = 0;
261256bf813SHans Verkuil 
262997deb81SDafna Hirschfeld 	if (ctx->is_enc || ctx->is_stateless)
263b9bbbbfeSDafna Hirschfeld 		p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
264256bf813SHans Verkuil 	else
265b9bbbbfeSDafna Hirschfeld 		p_src = state->compressed_frame;
266997deb81SDafna Hirschfeld 
267997deb81SDafna Hirschfeld 	if (ctx->is_stateless) {
268997deb81SDafna Hirschfeld 		struct media_request *src_req = src_vb->vb2_buf.req_obj.req;
269997deb81SDafna Hirschfeld 
270997deb81SDafna Hirschfeld 		ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl);
271997deb81SDafna Hirschfeld 		if (ret)
272997deb81SDafna Hirschfeld 			return ret;
273997deb81SDafna Hirschfeld 		update_state_from_header(ctx);
274997deb81SDafna Hirschfeld 
275997deb81SDafna Hirschfeld 		ctx->state.header.size =
276997deb81SDafna Hirschfeld 			htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0));
277997deb81SDafna Hirschfeld 		/*
278997deb81SDafna Hirschfeld 		 * set the reference buffer from the reference timestamp
279997deb81SDafna Hirschfeld 		 * only if this is a P-frame
280997deb81SDafna Hirschfeld 		 */
2813abfc314SHans Verkuil 		if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) {
282997deb81SDafna Hirschfeld 			struct vb2_buffer *ref_vb2_buf;
283997deb81SDafna Hirschfeld 			int ref_buf_idx;
284997deb81SDafna Hirschfeld 			struct vb2_queue *vq_cap =
285997deb81SDafna Hirschfeld 				v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
286997deb81SDafna Hirschfeld 						V4L2_BUF_TYPE_VIDEO_CAPTURE);
287997deb81SDafna Hirschfeld 
288997deb81SDafna Hirschfeld 			ref_buf_idx = vb2_find_timestamp(vq_cap,
289997deb81SDafna Hirschfeld 							 ctx->state.ref_frame_ts, 0);
290997deb81SDafna Hirschfeld 			if (ref_buf_idx < 0)
291997deb81SDafna Hirschfeld 				return -EINVAL;
292997deb81SDafna Hirschfeld 
293997deb81SDafna Hirschfeld 			ref_vb2_buf = vq_cap->bufs[ref_buf_idx];
294997deb81SDafna Hirschfeld 			if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR)
295997deb81SDafna Hirschfeld 				ret = -EINVAL;
296997deb81SDafna Hirschfeld 			ctx->state.ref_frame.buf =
297997deb81SDafna Hirschfeld 				vb2_plane_vaddr(ref_vb2_buf, 0);
298997deb81SDafna Hirschfeld 		} else {
299997deb81SDafna Hirschfeld 			ctx->state.ref_frame.buf = NULL;
300997deb81SDafna Hirschfeld 		}
301997deb81SDafna Hirschfeld 	}
302b9bbbbfeSDafna Hirschfeld 	p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
303b9bbbbfeSDafna Hirschfeld 	if (!p_src || !p_dst) {
304256bf813SHans Verkuil 		v4l2_err(&dev->v4l2_dev,
305256bf813SHans Verkuil 			 "Acquiring kernel pointers to buffers failed\n");
306256bf813SHans Verkuil 		return -EFAULT;
307256bf813SHans Verkuil 	}
308256bf813SHans Verkuil 
309256bf813SHans Verkuil 	if (ctx->is_enc) {
310b9bbbbfeSDafna Hirschfeld 		struct vicodec_q_data *q_src;
311f902796aSDafna Hirschfeld 		int comp_sz_or_errcode;
312256bf813SHans Verkuil 
313b9bbbbfeSDafna Hirschfeld 		q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
314b9bbbbfeSDafna Hirschfeld 		state->info = q_src->info;
315f902796aSDafna Hirschfeld 		comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst);
316f902796aSDafna Hirschfeld 		if (comp_sz_or_errcode < 0)
317f902796aSDafna Hirschfeld 			return comp_sz_or_errcode;
318f902796aSDafna Hirschfeld 		vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode);
319256bf813SHans Verkuil 	} else {
3208eead25cSDafna Hirschfeld 		struct vicodec_q_data *q_dst;
321f863f222SDafna Hirschfeld 		unsigned int comp_frame_size = ntohl(ctx->state.header.size);
322f863f222SDafna Hirschfeld 
3238eead25cSDafna Hirschfeld 		q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
324f863f222SDafna Hirschfeld 		if (comp_frame_size > ctx->comp_max_size)
325f863f222SDafna Hirschfeld 			return -EINVAL;
326b9bbbbfeSDafna Hirschfeld 		state->info = q_dst->info;
327b9bbbbfeSDafna Hirschfeld 		ret = v4l2_fwht_decode(state, p_src, p_dst);
328b09d8b25SHans Verkuil 		if (ret < 0)
329256bf813SHans Verkuil 			return ret;
330997deb81SDafna Hirschfeld 		if (!ctx->is_stateless)
33186764b88SDafna Hirschfeld 			copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state);
33286764b88SDafna Hirschfeld 
333b9bbbbfeSDafna Hirschfeld 		vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
3343abfc314SHans Verkuil 		if (ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)
335fbbbb2cdSHans Verkuil 			dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME;
336fbbbb2cdSHans Verkuil 		else
337fbbbb2cdSHans Verkuil 			dst_vb->flags |= V4L2_BUF_FLAG_PFRAME;
338256bf813SHans Verkuil 	}
339997deb81SDafna Hirschfeld 	return ret;
340256bf813SHans Verkuil }
341256bf813SHans Verkuil 
342256bf813SHans Verkuil /*
343256bf813SHans Verkuil  * mem2mem callbacks
344256bf813SHans Verkuil  */
345c9d06df6SMauro Carvalho Chehab static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx,
346c9d06df6SMauro Carvalho Chehab 					     u8 **pp, u32 sz)
347ddc1b085SDafna Hirschfeld {
348ddc1b085SDafna Hirschfeld 	static const u8 magic[] = {
349ddc1b085SDafna Hirschfeld 		0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
350ddc1b085SDafna Hirschfeld 	};
351ddc1b085SDafna Hirschfeld 	u8 *p = *pp;
352ddc1b085SDafna Hirschfeld 	u32 state;
353ddc1b085SDafna Hirschfeld 	u8 *header = (u8 *)&ctx->state.header;
354ddc1b085SDafna Hirschfeld 
355ddc1b085SDafna Hirschfeld 	state = VB2_BUF_STATE_DONE;
356ddc1b085SDafna Hirschfeld 
357ddc1b085SDafna Hirschfeld 	if (!ctx->header_size) {
358ddc1b085SDafna Hirschfeld 		state = VB2_BUF_STATE_ERROR;
359ddc1b085SDafna Hirschfeld 		for (; p < *pp + sz; p++) {
360ddc1b085SDafna Hirschfeld 			u32 copy;
361ddc1b085SDafna Hirschfeld 
362ddc1b085SDafna Hirschfeld 			p = memchr(p, magic[ctx->comp_magic_cnt],
363ddc1b085SDafna Hirschfeld 				   *pp + sz - p);
364ddc1b085SDafna Hirschfeld 			if (!p) {
365ddc1b085SDafna Hirschfeld 				ctx->comp_magic_cnt = 0;
366ddc1b085SDafna Hirschfeld 				p = *pp + sz;
367ddc1b085SDafna Hirschfeld 				break;
368ddc1b085SDafna Hirschfeld 			}
369ddc1b085SDafna Hirschfeld 			copy = sizeof(magic) - ctx->comp_magic_cnt;
370ddc1b085SDafna Hirschfeld 			if (*pp + sz - p < copy)
371ddc1b085SDafna Hirschfeld 				copy = *pp + sz - p;
372ddc1b085SDafna Hirschfeld 
373ddc1b085SDafna Hirschfeld 			memcpy(header + ctx->comp_magic_cnt, p, copy);
374ddc1b085SDafna Hirschfeld 			ctx->comp_magic_cnt += copy;
375ddc1b085SDafna Hirschfeld 			if (!memcmp(header, magic, ctx->comp_magic_cnt)) {
376ddc1b085SDafna Hirschfeld 				p += copy;
377ddc1b085SDafna Hirschfeld 				state = VB2_BUF_STATE_DONE;
378ddc1b085SDafna Hirschfeld 				break;
379ddc1b085SDafna Hirschfeld 			}
380ddc1b085SDafna Hirschfeld 			ctx->comp_magic_cnt = 0;
381ddc1b085SDafna Hirschfeld 		}
382ddc1b085SDafna Hirschfeld 		if (ctx->comp_magic_cnt < sizeof(magic)) {
383ddc1b085SDafna Hirschfeld 			*pp = p;
384ddc1b085SDafna Hirschfeld 			return state;
385ddc1b085SDafna Hirschfeld 		}
386ddc1b085SDafna Hirschfeld 		ctx->header_size = sizeof(magic);
387ddc1b085SDafna Hirschfeld 	}
388ddc1b085SDafna Hirschfeld 
389ddc1b085SDafna Hirschfeld 	if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
390ddc1b085SDafna Hirschfeld 		u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size;
391ddc1b085SDafna Hirschfeld 
392ddc1b085SDafna Hirschfeld 		if (*pp + sz - p < copy)
393ddc1b085SDafna Hirschfeld 			copy = *pp + sz - p;
394ddc1b085SDafna Hirschfeld 
395ddc1b085SDafna Hirschfeld 		memcpy(header + ctx->header_size, p, copy);
396ddc1b085SDafna Hirschfeld 		p += copy;
397ddc1b085SDafna Hirschfeld 		ctx->header_size += copy;
398ddc1b085SDafna Hirschfeld 	}
399ddc1b085SDafna Hirschfeld 	*pp = p;
400ddc1b085SDafna Hirschfeld 	return state;
401ddc1b085SDafna Hirschfeld }
402256bf813SHans Verkuil 
403256bf813SHans Verkuil /* device_run() - prepares and starts the device */
404256bf813SHans Verkuil static void device_run(void *priv)
405256bf813SHans Verkuil {
406256bf813SHans Verkuil 	struct vicodec_ctx *ctx = priv;
407256bf813SHans Verkuil 	struct vicodec_dev *dev = ctx->dev;
408256bf813SHans Verkuil 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
4098eead25cSDafna Hirschfeld 	struct vicodec_q_data *q_src, *q_dst;
410256bf813SHans Verkuil 	u32 state;
411997deb81SDafna Hirschfeld 	struct media_request *src_req;
412997deb81SDafna Hirschfeld 
413256bf813SHans Verkuil 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
414256bf813SHans Verkuil 	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
415997deb81SDafna Hirschfeld 	src_req = src_buf->vb2_buf.req_obj.req;
416997deb81SDafna Hirschfeld 
417b9bbbbfeSDafna Hirschfeld 	q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
4188eead25cSDafna Hirschfeld 	q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
419256bf813SHans Verkuil 
420256bf813SHans Verkuil 	state = VB2_BUF_STATE_DONE;
421256bf813SHans Verkuil 	if (device_process(ctx, src_buf, dst_buf))
422256bf813SHans Verkuil 		state = VB2_BUF_STATE_ERROR;
4238eead25cSDafna Hirschfeld 	else
4248eead25cSDafna Hirschfeld 		dst_buf->sequence = q_dst->sequence++;
4258eead25cSDafna Hirschfeld 	dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
426fbbbb2cdSHans Verkuil 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
4278eead25cSDafna Hirschfeld 
428256bf813SHans Verkuil 	spin_lock(ctx->lock);
429d4d137deSNeil Armstrong 	if (!ctx->comp_has_next_frame &&
430d4d137deSNeil Armstrong 	    v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
431256bf813SHans Verkuil 		dst_buf->flags |= V4L2_BUF_FLAG_LAST;
432d17589afSHans Verkuil 		v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
433d4d137deSNeil Armstrong 		v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
434256bf813SHans Verkuil 	}
435997deb81SDafna Hirschfeld 	if (ctx->is_enc || ctx->is_stateless) {
436b9bbbbfeSDafna Hirschfeld 		src_buf->sequence = q_src->sequence++;
437256bf813SHans Verkuil 		src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
438256bf813SHans Verkuil 		v4l2_m2m_buf_done(src_buf, state);
439256bf813SHans Verkuil 	} else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
440b9bbbbfeSDafna Hirschfeld 		src_buf->sequence = q_src->sequence++;
441256bf813SHans Verkuil 		src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
442256bf813SHans Verkuil 		v4l2_m2m_buf_done(src_buf, state);
443256bf813SHans Verkuil 		ctx->cur_buf_offset = 0;
444256bf813SHans Verkuil 		ctx->comp_has_next_frame = false;
445256bf813SHans Verkuil 	}
446256bf813SHans Verkuil 	v4l2_m2m_buf_done(dst_buf, state);
447997deb81SDafna Hirschfeld 
448256bf813SHans Verkuil 	ctx->comp_size = 0;
449ddc1b085SDafna Hirschfeld 	ctx->header_size = 0;
450256bf813SHans Verkuil 	ctx->comp_magic_cnt = 0;
451256bf813SHans Verkuil 	ctx->comp_has_frame = false;
452256bf813SHans Verkuil 	spin_unlock(ctx->lock);
453e5bc0e1dSHans Verkuil 	if (ctx->is_stateless && src_req)
454e5bc0e1dSHans Verkuil 		v4l2_ctrl_request_complete(src_req, &ctx->hdl);
455256bf813SHans Verkuil 
456256bf813SHans Verkuil 	if (ctx->is_enc)
457c022a4a9SDafna Hirschfeld 		v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx);
458fde649b4SDafna Hirschfeld 	else if (ctx->is_stateless)
459fde649b4SDafna Hirschfeld 		v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev,
460fde649b4SDafna Hirschfeld 				    ctx->fh.m2m_ctx);
461256bf813SHans Verkuil 	else
462c022a4a9SDafna Hirschfeld 		v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx);
463256bf813SHans Verkuil }
464256bf813SHans Verkuil 
465b9bbbbfeSDafna Hirschfeld static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
466256bf813SHans Verkuil {
467256bf813SHans Verkuil 	struct vb2_v4l2_buffer *src_buf;
468b9bbbbfeSDafna Hirschfeld 	struct vicodec_q_data *q_src;
469256bf813SHans Verkuil 
470b9bbbbfeSDafna Hirschfeld 	q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
471256bf813SHans Verkuil 	spin_lock(ctx->lock);
472256bf813SHans Verkuil 	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
473b9bbbbfeSDafna Hirschfeld 	src_buf->sequence = q_src->sequence++;
474256bf813SHans Verkuil 	v4l2_m2m_buf_done(src_buf, state);
475256bf813SHans Verkuil 	ctx->cur_buf_offset = 0;
476256bf813SHans Verkuil 	spin_unlock(ctx->lock);
477256bf813SHans Verkuil }
478256bf813SHans Verkuil 
4793b15f68eSDafna Hirschfeld static const struct v4l2_fwht_pixfmt_info *
4803b15f68eSDafna Hirschfeld info_from_header(const struct fwht_cframe_hdr *p_hdr)
4813b15f68eSDafna Hirschfeld {
4823b15f68eSDafna Hirschfeld 	unsigned int flags = ntohl(p_hdr->flags);
4833abfc314SHans Verkuil 	unsigned int width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
4843abfc314SHans Verkuil 	unsigned int height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
4853b15f68eSDafna Hirschfeld 	unsigned int components_num = 3;
4863b15f68eSDafna Hirschfeld 	unsigned int pixenc = 0;
4873b15f68eSDafna Hirschfeld 	unsigned int version = ntohl(p_hdr->version);
4883b15f68eSDafna Hirschfeld 
48975e3e5b8SDafna Hirschfeld 	if (version >= 2) {
4903abfc314SHans Verkuil 		components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
4913abfc314SHans Verkuil 				V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
4923abfc314SHans Verkuil 		pixenc = (flags & V4L2_FWHT_FL_PIXENC_MSK);
4933b15f68eSDafna Hirschfeld 	}
49450e4c5e1SDafna Hirschfeld 	return v4l2_fwht_find_nth_fmt(width_div, height_div,
4953b15f68eSDafna Hirschfeld 				     components_num, pixenc, 0);
4963b15f68eSDafna Hirschfeld }
4973b15f68eSDafna Hirschfeld 
4983b15f68eSDafna Hirschfeld static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
4993b15f68eSDafna Hirschfeld {
5003b15f68eSDafna Hirschfeld 	const struct v4l2_fwht_pixfmt_info *info;
5013b15f68eSDafna Hirschfeld 	unsigned int w = ntohl(p_hdr->width);
5023b15f68eSDafna Hirschfeld 	unsigned int h = ntohl(p_hdr->height);
5033b15f68eSDafna Hirschfeld 	unsigned int version = ntohl(p_hdr->version);
5043b15f68eSDafna Hirschfeld 	unsigned int flags = ntohl(p_hdr->flags);
5053b15f68eSDafna Hirschfeld 
5063b15f68eSDafna Hirschfeld 	if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
5073b15f68eSDafna Hirschfeld 		return false;
5083b15f68eSDafna Hirschfeld 
50992dc64d4SDafna Hirschfeld 	if (!validate_by_version(flags, version))
5103b15f68eSDafna Hirschfeld 		return false;
5113b15f68eSDafna Hirschfeld 
5123b15f68eSDafna Hirschfeld 	info = info_from_header(p_hdr);
5133b15f68eSDafna Hirschfeld 	if (!info)
5143b15f68eSDafna Hirschfeld 		return false;
5153b15f68eSDafna Hirschfeld 	return true;
5163b15f68eSDafna Hirschfeld }
5173b15f68eSDafna Hirschfeld 
5183b15f68eSDafna Hirschfeld static void update_capture_data_from_header(struct vicodec_ctx *ctx)
5193b15f68eSDafna Hirschfeld {
5203b15f68eSDafna Hirschfeld 	struct vicodec_q_data *q_dst = get_q_data(ctx,
5213b15f68eSDafna Hirschfeld 						  V4L2_BUF_TYPE_VIDEO_CAPTURE);
5223b15f68eSDafna Hirschfeld 	const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
5233b15f68eSDafna Hirschfeld 	const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr);
5243b15f68eSDafna Hirschfeld 	unsigned int flags = ntohl(p_hdr->flags);
5253abfc314SHans Verkuil 	unsigned int hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
5263abfc314SHans Verkuil 	unsigned int hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
5273b15f68eSDafna Hirschfeld 
528997deb81SDafna Hirschfeld 	/*
529997deb81SDafna Hirschfeld 	 * This function should not be used by a stateless codec since
530997deb81SDafna Hirschfeld 	 * it changes values in q_data that are not request specific
531997deb81SDafna Hirschfeld 	 */
532997deb81SDafna Hirschfeld 	WARN_ON(ctx->is_stateless);
533997deb81SDafna Hirschfeld 
5343b15f68eSDafna Hirschfeld 	q_dst->info = info;
5353b15f68eSDafna Hirschfeld 	q_dst->visible_width = ntohl(p_hdr->width);
5363b15f68eSDafna Hirschfeld 	q_dst->visible_height = ntohl(p_hdr->height);
5373b15f68eSDafna Hirschfeld 	q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div);
5383b15f68eSDafna Hirschfeld 	q_dst->coded_height = vic_round_dim(q_dst->visible_height,
5393b15f68eSDafna Hirschfeld 					    hdr_height_div);
5403b15f68eSDafna Hirschfeld 
5413b15f68eSDafna Hirschfeld 	q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height *
5423b15f68eSDafna Hirschfeld 		q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div;
5433b15f68eSDafna Hirschfeld 	ctx->state.colorspace = ntohl(p_hdr->colorspace);
5443b15f68eSDafna Hirschfeld 
5453b15f68eSDafna Hirschfeld 	ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
5463b15f68eSDafna Hirschfeld 	ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
5473b15f68eSDafna Hirschfeld 	ctx->state.quantization = ntohl(p_hdr->quantization);
5483b15f68eSDafna Hirschfeld }
5493b15f68eSDafna Hirschfeld 
5503b15f68eSDafna Hirschfeld static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf,
5513b15f68eSDafna Hirschfeld 			    const struct vb2_v4l2_buffer *src_buf,
5523b15f68eSDafna Hirschfeld 			    struct vicodec_ctx *ctx)
5533b15f68eSDafna Hirschfeld {
5543b15f68eSDafna Hirschfeld 	struct vicodec_q_data *q_dst = get_q_data(ctx,
5553b15f68eSDafna Hirschfeld 						  V4L2_BUF_TYPE_VIDEO_CAPTURE);
5563b15f68eSDafna Hirschfeld 
5573b15f68eSDafna Hirschfeld 	vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
5583b15f68eSDafna Hirschfeld 	dst_buf->sequence = q_dst->sequence++;
5593b15f68eSDafna Hirschfeld 
560a4d3d612SEzequiel Garcia 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
5613b15f68eSDafna Hirschfeld 	dst_buf->flags |= V4L2_BUF_FLAG_LAST;
5623b15f68eSDafna Hirschfeld 	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
5633b15f68eSDafna Hirschfeld }
5643b15f68eSDafna Hirschfeld 
565256bf813SHans Verkuil static int job_ready(void *priv)
566256bf813SHans Verkuil {
567256bf813SHans Verkuil 	static const u8 magic[] = {
568256bf813SHans Verkuil 		0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
569256bf813SHans Verkuil 	};
570256bf813SHans Verkuil 	struct vicodec_ctx *ctx = priv;
571256bf813SHans Verkuil 	struct vb2_v4l2_buffer *src_buf;
572b9bbbbfeSDafna Hirschfeld 	u8 *p_src;
573256bf813SHans Verkuil 	u8 *p;
574256bf813SHans Verkuil 	u32 sz;
575256bf813SHans Verkuil 	u32 state;
5763b15f68eSDafna Hirschfeld 	struct vicodec_q_data *q_dst = get_q_data(ctx,
5773b15f68eSDafna Hirschfeld 						  V4L2_BUF_TYPE_VIDEO_CAPTURE);
5783b15f68eSDafna Hirschfeld 	unsigned int flags;
5793b15f68eSDafna Hirschfeld 	unsigned int hdr_width_div;
5803b15f68eSDafna Hirschfeld 	unsigned int hdr_height_div;
5813b15f68eSDafna Hirschfeld 	unsigned int max_to_copy;
5823b15f68eSDafna Hirschfeld 	unsigned int comp_frame_size;
583256bf813SHans Verkuil 
5843b15f68eSDafna Hirschfeld 	if (ctx->source_changed)
5853b15f68eSDafna Hirschfeld 		return 0;
586997deb81SDafna Hirschfeld 	if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
587256bf813SHans Verkuil 		return 1;
588256bf813SHans Verkuil 
589256bf813SHans Verkuil restart:
590256bf813SHans Verkuil 	ctx->comp_has_next_frame = false;
591256bf813SHans Verkuil 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
592256bf813SHans Verkuil 	if (!src_buf)
593256bf813SHans Verkuil 		return 0;
594b9bbbbfeSDafna Hirschfeld 	p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
595256bf813SHans Verkuil 	sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
596b9bbbbfeSDafna Hirschfeld 	p = p_src + ctx->cur_buf_offset;
597256bf813SHans Verkuil 
598256bf813SHans Verkuil 	state = VB2_BUF_STATE_DONE;
599256bf813SHans Verkuil 
600ddc1b085SDafna Hirschfeld 	if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
601ddc1b085SDafna Hirschfeld 		state = get_next_header(ctx, &p, p_src + sz - p);
602ddc1b085SDafna Hirschfeld 		if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
603d4d137deSNeil Armstrong 			if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
604d4d137deSNeil Armstrong 							      src_buf))
605d17589afSHans Verkuil 				return 1;
606b9bbbbfeSDafna Hirschfeld 			job_remove_src_buf(ctx, state);
607256bf813SHans Verkuil 			goto restart;
608256bf813SHans Verkuil 		}
609256bf813SHans Verkuil 	}
6103b15f68eSDafna Hirschfeld 
6113b15f68eSDafna Hirschfeld 	comp_frame_size = ntohl(ctx->state.header.size);
6123b15f68eSDafna Hirschfeld 
6133b15f68eSDafna Hirschfeld 	/*
6143b15f68eSDafna Hirschfeld 	 * The current scanned frame might be the first frame of a new
6153b15f68eSDafna Hirschfeld 	 * resolution so its size might be larger than ctx->comp_max_size.
6163b15f68eSDafna Hirschfeld 	 * In that case it is copied up to the current buffer capacity and
6173b15f68eSDafna Hirschfeld 	 * the copy will continue after allocating new large enough buffer
6183b15f68eSDafna Hirschfeld 	 * when restreaming
6193b15f68eSDafna Hirschfeld 	 */
6203b15f68eSDafna Hirschfeld 	max_to_copy = min(comp_frame_size, ctx->comp_max_size);
6213b15f68eSDafna Hirschfeld 
6223b15f68eSDafna Hirschfeld 	if (ctx->comp_size < max_to_copy) {
6233b15f68eSDafna Hirschfeld 		u32 copy = max_to_copy - ctx->comp_size;
624256bf813SHans Verkuil 
625b9bbbbfeSDafna Hirschfeld 		if (copy > p_src + sz - p)
626b9bbbbfeSDafna Hirschfeld 			copy = p_src + sz - p;
627b9bbbbfeSDafna Hirschfeld 
628cd12b401SHans Verkuil 		memcpy(ctx->state.compressed_frame + ctx->comp_size,
629256bf813SHans Verkuil 		       p, copy);
630256bf813SHans Verkuil 		p += copy;
631256bf813SHans Verkuil 		ctx->comp_size += copy;
6323b15f68eSDafna Hirschfeld 		if (ctx->comp_size < max_to_copy) {
633d4d137deSNeil Armstrong 			if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
634d4d137deSNeil Armstrong 							      src_buf))
635d17589afSHans Verkuil 				return 1;
636b9bbbbfeSDafna Hirschfeld 			job_remove_src_buf(ctx, state);
637256bf813SHans Verkuil 			goto restart;
638256bf813SHans Verkuil 		}
639256bf813SHans Verkuil 	}
640b9bbbbfeSDafna Hirschfeld 	ctx->cur_buf_offset = p - p_src;
6413b15f68eSDafna Hirschfeld 	if (ctx->comp_size == comp_frame_size)
642256bf813SHans Verkuil 		ctx->comp_has_frame = true;
643256bf813SHans Verkuil 	ctx->comp_has_next_frame = false;
6443b15f68eSDafna Hirschfeld 	if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >=
6453b15f68eSDafna Hirschfeld 			sizeof(struct fwht_cframe_hdr)) {
64621abebf0SHans Verkuil 		struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
647256bf813SHans Verkuil 		u32 frame_size = ntohl(p_hdr->size);
648256bf813SHans Verkuil 		u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
649256bf813SHans Verkuil 
650256bf813SHans Verkuil 		if (!memcmp(p, magic, sizeof(magic)))
651256bf813SHans Verkuil 			ctx->comp_has_next_frame = remaining >= frame_size;
652256bf813SHans Verkuil 	}
6533b15f68eSDafna Hirschfeld 	/*
6543b15f68eSDafna Hirschfeld 	 * if the header is invalid the device_run will just drop the frame
6553b15f68eSDafna Hirschfeld 	 * with an error
6563b15f68eSDafna Hirschfeld 	 */
6573b15f68eSDafna Hirschfeld 	if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame)
6583b15f68eSDafna Hirschfeld 		return 1;
6593b15f68eSDafna Hirschfeld 	flags = ntohl(ctx->state.header.flags);
6603abfc314SHans Verkuil 	hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
6613abfc314SHans Verkuil 	hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
6623b15f68eSDafna Hirschfeld 
6633b15f68eSDafna Hirschfeld 	if (ntohl(ctx->state.header.width) != q_dst->visible_width ||
6643b15f68eSDafna Hirschfeld 	    ntohl(ctx->state.header.height) != q_dst->visible_height ||
6653b15f68eSDafna Hirschfeld 	    !q_dst->info ||
6663b15f68eSDafna Hirschfeld 	    hdr_width_div != q_dst->info->width_div ||
6673b15f68eSDafna Hirschfeld 	    hdr_height_div != q_dst->info->height_div) {
6683b15f68eSDafna Hirschfeld 		static const struct v4l2_event rs_event = {
6693b15f68eSDafna Hirschfeld 			.type = V4L2_EVENT_SOURCE_CHANGE,
6703b15f68eSDafna Hirschfeld 			.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
6713b15f68eSDafna Hirschfeld 		};
6723b15f68eSDafna Hirschfeld 
6733b15f68eSDafna Hirschfeld 		struct vb2_v4l2_buffer *dst_buf =
6743b15f68eSDafna Hirschfeld 			v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
6753b15f68eSDafna Hirschfeld 
6763b15f68eSDafna Hirschfeld 		update_capture_data_from_header(ctx);
6773b15f68eSDafna Hirschfeld 		v4l2_event_queue_fh(&ctx->fh, &rs_event);
6783b15f68eSDafna Hirschfeld 		set_last_buffer(dst_buf, src_buf, ctx);
6793b15f68eSDafna Hirschfeld 		ctx->source_changed = true;
6803b15f68eSDafna Hirschfeld 		return 0;
6813b15f68eSDafna Hirschfeld 	}
682256bf813SHans Verkuil 	return 1;
683256bf813SHans Verkuil }
684256bf813SHans Verkuil 
685256bf813SHans Verkuil /*
686256bf813SHans Verkuil  * video ioctls
687256bf813SHans Verkuil  */
688256bf813SHans Verkuil 
689cd12b401SHans Verkuil static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
690256bf813SHans Verkuil {
691cd12b401SHans Verkuil 	const struct v4l2_fwht_pixfmt_info *info =
692cd12b401SHans Verkuil 		v4l2_fwht_find_pixfmt(fmt);
693256bf813SHans Verkuil 
694cd12b401SHans Verkuil 	if (!info)
695cd12b401SHans Verkuil 		info = v4l2_fwht_get_pixfmt(0);
696cd12b401SHans Verkuil 	return info;
697256bf813SHans Verkuil }
698256bf813SHans Verkuil 
699256bf813SHans Verkuil static int vidioc_querycap(struct file *file, void *priv,
700256bf813SHans Verkuil 			   struct v4l2_capability *cap)
701256bf813SHans Verkuil {
70285709cbfSMauro Carvalho Chehab 	strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver));
70385709cbfSMauro Carvalho Chehab 	strscpy(cap->card, VICODEC_NAME, sizeof(cap->card));
704256bf813SHans Verkuil 	snprintf(cap->bus_info, sizeof(cap->bus_info),
705256bf813SHans Verkuil 			"platform:%s", VICODEC_NAME);
706256bf813SHans Verkuil 	return 0;
707256bf813SHans Verkuil }
708256bf813SHans Verkuil 
7095fbd0729SDafna Hirschfeld static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
7105fbd0729SDafna Hirschfeld 		    bool is_out)
711256bf813SHans Verkuil {
7125fbd0729SDafna Hirschfeld 	bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out);
713256bf813SHans Verkuil 
714256bf813SHans Verkuil 	if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
715256bf813SHans Verkuil 		return -EINVAL;
716256bf813SHans Verkuil 	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
717256bf813SHans Verkuil 		return -EINVAL;
718256bf813SHans Verkuil 
719cd12b401SHans Verkuil 	if (is_uncomp) {
720cd12b401SHans Verkuil 		const struct v4l2_fwht_pixfmt_info *info =
7215fbd0729SDafna Hirschfeld 					get_q_data(ctx, f->type)->info;
722cd12b401SHans Verkuil 
723d17589afSHans Verkuil 		if (ctx->is_enc ||
724d17589afSHans Verkuil 		    !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q))
7255fbd0729SDafna Hirschfeld 			info = v4l2_fwht_get_pixfmt(f->index);
7265fbd0729SDafna Hirschfeld 		else
72750e4c5e1SDafna Hirschfeld 			info = v4l2_fwht_find_nth_fmt(info->width_div,
7285fbd0729SDafna Hirschfeld 						     info->height_div,
7295fbd0729SDafna Hirschfeld 						     info->components_num,
7305fbd0729SDafna Hirschfeld 						     info->pixenc,
7315fbd0729SDafna Hirschfeld 						     f->index);
732cd12b401SHans Verkuil 		if (!info)
733cd12b401SHans Verkuil 			return -EINVAL;
734cd12b401SHans Verkuil 		f->pixelformat = info->id;
735cd12b401SHans Verkuil 	} else {
736cd12b401SHans Verkuil 		if (f->index)
737cd12b401SHans Verkuil 			return -EINVAL;
73835e2e8b5SDafna Hirschfeld 		f->pixelformat = ctx->is_stateless ?
73935e2e8b5SDafna Hirschfeld 			V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT;
740b867d9ceSMaxime Jourdan 		if (!ctx->is_enc && !ctx->is_stateless)
741b867d9ceSMaxime Jourdan 			f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
742b867d9ceSMaxime Jourdan 				   V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM;
743cd12b401SHans Verkuil 	}
744256bf813SHans Verkuil 	return 0;
745256bf813SHans Verkuil }
746256bf813SHans Verkuil 
747256bf813SHans Verkuil static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
748256bf813SHans Verkuil 				   struct v4l2_fmtdesc *f)
749256bf813SHans Verkuil {
750256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
751256bf813SHans Verkuil 
7525fbd0729SDafna Hirschfeld 	return enum_fmt(f, ctx, false);
753256bf813SHans Verkuil }
754256bf813SHans Verkuil 
755256bf813SHans Verkuil static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
756256bf813SHans Verkuil 				   struct v4l2_fmtdesc *f)
757256bf813SHans Verkuil {
758256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
759256bf813SHans Verkuil 
7605fbd0729SDafna Hirschfeld 	return enum_fmt(f, ctx, true);
761256bf813SHans Verkuil }
762256bf813SHans Verkuil 
763256bf813SHans Verkuil static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
764256bf813SHans Verkuil {
765256bf813SHans Verkuil 	struct vb2_queue *vq;
766256bf813SHans Verkuil 	struct vicodec_q_data *q_data;
767256bf813SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
768256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
769cd12b401SHans Verkuil 	const struct v4l2_fwht_pixfmt_info *info;
770256bf813SHans Verkuil 
771256bf813SHans Verkuil 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
772256bf813SHans Verkuil 	if (!vq)
773256bf813SHans Verkuil 		return -EINVAL;
774256bf813SHans Verkuil 
775256bf813SHans Verkuil 	q_data = get_q_data(ctx, f->type);
77629a7a5e9SHans Verkuil 	info = q_data->info;
777256bf813SHans Verkuil 
778256bf813SHans Verkuil 	switch (f->type) {
779256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
780256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
781256bf813SHans Verkuil 		if (multiplanar)
782256bf813SHans Verkuil 			return -EINVAL;
783256bf813SHans Verkuil 		pix = &f->fmt.pix;
7849e812549SDafna Hirschfeld 		pix->width = q_data->coded_width;
7859e812549SDafna Hirschfeld 		pix->height = q_data->coded_height;
786256bf813SHans Verkuil 		pix->field = V4L2_FIELD_NONE;
78729a7a5e9SHans Verkuil 		pix->pixelformat = info->id;
7889e812549SDafna Hirschfeld 		pix->bytesperline = q_data->coded_width *
7899e812549SDafna Hirschfeld 					info->bytesperline_mult;
790256bf813SHans Verkuil 		pix->sizeimage = q_data->sizeimage;
791cd12b401SHans Verkuil 		pix->colorspace = ctx->state.colorspace;
792cd12b401SHans Verkuil 		pix->xfer_func = ctx->state.xfer_func;
793cd12b401SHans Verkuil 		pix->ycbcr_enc = ctx->state.ycbcr_enc;
794cd12b401SHans Verkuil 		pix->quantization = ctx->state.quantization;
795256bf813SHans Verkuil 		break;
796256bf813SHans Verkuil 
797256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
798256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
799256bf813SHans Verkuil 		if (!multiplanar)
800256bf813SHans Verkuil 			return -EINVAL;
801256bf813SHans Verkuil 		pix_mp = &f->fmt.pix_mp;
8029e812549SDafna Hirschfeld 		pix_mp->width = q_data->coded_width;
8039e812549SDafna Hirschfeld 		pix_mp->height = q_data->coded_height;
804256bf813SHans Verkuil 		pix_mp->field = V4L2_FIELD_NONE;
80529a7a5e9SHans Verkuil 		pix_mp->pixelformat = info->id;
806256bf813SHans Verkuil 		pix_mp->num_planes = 1;
80729a7a5e9SHans Verkuil 		pix_mp->plane_fmt[0].bytesperline =
8089e812549SDafna Hirschfeld 				q_data->coded_width * info->bytesperline_mult;
809256bf813SHans Verkuil 		pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
810cd12b401SHans Verkuil 		pix_mp->colorspace = ctx->state.colorspace;
811cd12b401SHans Verkuil 		pix_mp->xfer_func = ctx->state.xfer_func;
812cd12b401SHans Verkuil 		pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
813cd12b401SHans Verkuil 		pix_mp->quantization = ctx->state.quantization;
814256bf813SHans Verkuil 		memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
815256bf813SHans Verkuil 		memset(pix_mp->plane_fmt[0].reserved, 0,
816256bf813SHans Verkuil 		       sizeof(pix_mp->plane_fmt[0].reserved));
817256bf813SHans Verkuil 		break;
818256bf813SHans Verkuil 	default:
819256bf813SHans Verkuil 		return -EINVAL;
820256bf813SHans Verkuil 	}
821256bf813SHans Verkuil 	return 0;
822256bf813SHans Verkuil }
823256bf813SHans Verkuil 
824256bf813SHans Verkuil static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
825256bf813SHans Verkuil 				struct v4l2_format *f)
826256bf813SHans Verkuil {
827256bf813SHans Verkuil 	return vidioc_g_fmt(file2ctx(file), f);
828256bf813SHans Verkuil }
829256bf813SHans Verkuil 
830256bf813SHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
831256bf813SHans Verkuil 				struct v4l2_format *f)
832256bf813SHans Verkuil {
833256bf813SHans Verkuil 	return vidioc_g_fmt(file2ctx(file), f);
834256bf813SHans Verkuil }
835256bf813SHans Verkuil 
836256bf813SHans Verkuil static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
837256bf813SHans Verkuil {
838256bf813SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
839256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
84029a7a5e9SHans Verkuil 	struct v4l2_plane_pix_format *plane;
84135e2e8b5SDafna Hirschfeld 	const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
84235e2e8b5SDafna Hirschfeld 		&pixfmt_stateless_fwht : &pixfmt_fwht;
843256bf813SHans Verkuil 
844256bf813SHans Verkuil 	switch (f->type) {
845256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
846256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
847256bf813SHans Verkuil 		pix = &f->fmt.pix;
84835e2e8b5SDafna Hirschfeld 		if (pix->pixelformat != V4L2_PIX_FMT_FWHT &&
84935e2e8b5SDafna Hirschfeld 		    pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
85029a7a5e9SHans Verkuil 			info = find_fmt(pix->pixelformat);
8519e812549SDafna Hirschfeld 
8529e812549SDafna Hirschfeld 		pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
8539e812549SDafna Hirschfeld 		pix->width = vic_round_dim(pix->width, info->width_div);
8549e812549SDafna Hirschfeld 
8559e812549SDafna Hirschfeld 		pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
8569e812549SDafna Hirschfeld 		pix->height = vic_round_dim(pix->height, info->height_div);
8579e812549SDafna Hirschfeld 
858256bf813SHans Verkuil 		pix->field = V4L2_FIELD_NONE;
85929a7a5e9SHans Verkuil 		pix->bytesperline =
86029a7a5e9SHans Verkuil 			pix->width * info->bytesperline_mult;
86129a7a5e9SHans Verkuil 		pix->sizeimage = pix->width * pix->height *
86229a7a5e9SHans Verkuil 			info->sizeimage_mult / info->sizeimage_div;
86329a7a5e9SHans Verkuil 		if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
86421abebf0SHans Verkuil 			pix->sizeimage += sizeof(struct fwht_cframe_hdr);
865256bf813SHans Verkuil 		break;
866256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
867256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
868256bf813SHans Verkuil 		pix_mp = &f->fmt.pix_mp;
86929a7a5e9SHans Verkuil 		plane = pix_mp->plane_fmt;
87035e2e8b5SDafna Hirschfeld 		if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT &&
87135e2e8b5SDafna Hirschfeld 		    pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
87229a7a5e9SHans Verkuil 			info = find_fmt(pix_mp->pixelformat);
87329a7a5e9SHans Verkuil 		pix_mp->num_planes = 1;
8749e812549SDafna Hirschfeld 
8759e812549SDafna Hirschfeld 		pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH);
8769e812549SDafna Hirschfeld 		pix_mp->width = vic_round_dim(pix_mp->width, info->width_div);
8779e812549SDafna Hirschfeld 
8789e812549SDafna Hirschfeld 		pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT);
8799e812549SDafna Hirschfeld 		pix_mp->height = vic_round_dim(pix_mp->height,
8809e812549SDafna Hirschfeld 					       info->height_div);
8819e812549SDafna Hirschfeld 
882256bf813SHans Verkuil 		pix_mp->field = V4L2_FIELD_NONE;
88329a7a5e9SHans Verkuil 		plane->bytesperline =
88429a7a5e9SHans Verkuil 			pix_mp->width * info->bytesperline_mult;
88529a7a5e9SHans Verkuil 		plane->sizeimage = pix_mp->width * pix_mp->height *
88629a7a5e9SHans Verkuil 			info->sizeimage_mult / info->sizeimage_div;
88729a7a5e9SHans Verkuil 		if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
88821abebf0SHans Verkuil 			plane->sizeimage += sizeof(struct fwht_cframe_hdr);
889256bf813SHans Verkuil 		memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
89029a7a5e9SHans Verkuil 		memset(plane->reserved, 0, sizeof(plane->reserved));
891256bf813SHans Verkuil 		break;
892256bf813SHans Verkuil 	default:
893256bf813SHans Verkuil 		return -EINVAL;
894256bf813SHans Verkuil 	}
895256bf813SHans Verkuil 
896256bf813SHans Verkuil 	return 0;
897256bf813SHans Verkuil }
898256bf813SHans Verkuil 
899256bf813SHans Verkuil static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
900256bf813SHans Verkuil 				  struct v4l2_format *f)
901256bf813SHans Verkuil {
902256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
903256bf813SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
904256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
905256bf813SHans Verkuil 
906256bf813SHans Verkuil 	switch (f->type) {
907256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
908256bf813SHans Verkuil 		if (multiplanar)
909256bf813SHans Verkuil 			return -EINVAL;
910256bf813SHans Verkuil 		pix = &f->fmt.pix;
911256bf813SHans Verkuil 		pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
91229a7a5e9SHans Verkuil 				   find_fmt(f->fmt.pix.pixelformat)->id;
913cd12b401SHans Verkuil 		pix->colorspace = ctx->state.colorspace;
914cd12b401SHans Verkuil 		pix->xfer_func = ctx->state.xfer_func;
915cd12b401SHans Verkuil 		pix->ycbcr_enc = ctx->state.ycbcr_enc;
916cd12b401SHans Verkuil 		pix->quantization = ctx->state.quantization;
917256bf813SHans Verkuil 		break;
918256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
919256bf813SHans Verkuil 		if (!multiplanar)
920256bf813SHans Verkuil 			return -EINVAL;
921256bf813SHans Verkuil 		pix_mp = &f->fmt.pix_mp;
922256bf813SHans Verkuil 		pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
92329a7a5e9SHans Verkuil 				      find_fmt(pix_mp->pixelformat)->id;
924cd12b401SHans Verkuil 		pix_mp->colorspace = ctx->state.colorspace;
925cd12b401SHans Verkuil 		pix_mp->xfer_func = ctx->state.xfer_func;
926cd12b401SHans Verkuil 		pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
927cd12b401SHans Verkuil 		pix_mp->quantization = ctx->state.quantization;
928256bf813SHans Verkuil 		break;
929256bf813SHans Verkuil 	default:
930256bf813SHans Verkuil 		return -EINVAL;
931256bf813SHans Verkuil 	}
932256bf813SHans Verkuil 
933256bf813SHans Verkuil 	return vidioc_try_fmt(ctx, f);
934256bf813SHans Verkuil }
935256bf813SHans Verkuil 
936256bf813SHans Verkuil static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
937256bf813SHans Verkuil 				  struct v4l2_format *f)
938256bf813SHans Verkuil {
939256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
940256bf813SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
941256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
942256bf813SHans Verkuil 
943256bf813SHans Verkuil 	switch (f->type) {
944256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
945256bf813SHans Verkuil 		if (multiplanar)
946256bf813SHans Verkuil 			return -EINVAL;
947256bf813SHans Verkuil 		pix = &f->fmt.pix;
94835e2e8b5SDafna Hirschfeld 		if (ctx->is_enc)
94935e2e8b5SDafna Hirschfeld 			pix->pixelformat = find_fmt(pix->pixelformat)->id;
95035e2e8b5SDafna Hirschfeld 		else if (ctx->is_stateless)
95135e2e8b5SDafna Hirschfeld 			pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
95235e2e8b5SDafna Hirschfeld 		else
95335e2e8b5SDafna Hirschfeld 			pix->pixelformat = V4L2_PIX_FMT_FWHT;
954256bf813SHans Verkuil 		if (!pix->colorspace)
955256bf813SHans Verkuil 			pix->colorspace = V4L2_COLORSPACE_REC709;
956256bf813SHans Verkuil 		break;
957256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
958256bf813SHans Verkuil 		if (!multiplanar)
959256bf813SHans Verkuil 			return -EINVAL;
960256bf813SHans Verkuil 		pix_mp = &f->fmt.pix_mp;
96135e2e8b5SDafna Hirschfeld 		if (ctx->is_enc)
96235e2e8b5SDafna Hirschfeld 			pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id;
96335e2e8b5SDafna Hirschfeld 		else if (ctx->is_stateless)
96435e2e8b5SDafna Hirschfeld 			pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
96535e2e8b5SDafna Hirschfeld 		else
96635e2e8b5SDafna Hirschfeld 			pix_mp->pixelformat = V4L2_PIX_FMT_FWHT;
967256bf813SHans Verkuil 		if (!pix_mp->colorspace)
968256bf813SHans Verkuil 			pix_mp->colorspace = V4L2_COLORSPACE_REC709;
969256bf813SHans Verkuil 		break;
970256bf813SHans Verkuil 	default:
971256bf813SHans Verkuil 		return -EINVAL;
972256bf813SHans Verkuil 	}
973256bf813SHans Verkuil 
974256bf813SHans Verkuil 	return vidioc_try_fmt(ctx, f);
975256bf813SHans Verkuil }
976256bf813SHans Verkuil 
977256bf813SHans Verkuil static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
978256bf813SHans Verkuil {
979256bf813SHans Verkuil 	struct vicodec_q_data *q_data;
980256bf813SHans Verkuil 	struct vb2_queue *vq;
981256bf813SHans Verkuil 	bool fmt_changed = true;
982256bf813SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
983256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
984256bf813SHans Verkuil 
985256bf813SHans Verkuil 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
986256bf813SHans Verkuil 	if (!vq)
987256bf813SHans Verkuil 		return -EINVAL;
988256bf813SHans Verkuil 
989256bf813SHans Verkuil 	q_data = get_q_data(ctx, f->type);
990256bf813SHans Verkuil 	if (!q_data)
991256bf813SHans Verkuil 		return -EINVAL;
992256bf813SHans Verkuil 
993256bf813SHans Verkuil 	switch (f->type) {
994256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
995256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
996256bf813SHans Verkuil 		pix = &f->fmt.pix;
997256bf813SHans Verkuil 		if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
998256bf813SHans Verkuil 			fmt_changed =
9993b15f68eSDafna Hirschfeld 				!q_data->info ||
100029a7a5e9SHans Verkuil 				q_data->info->id != pix->pixelformat ||
10019e812549SDafna Hirschfeld 				q_data->coded_width != pix->width ||
10029e812549SDafna Hirschfeld 				q_data->coded_height != pix->height;
1003256bf813SHans Verkuil 
1004256bf813SHans Verkuil 		if (vb2_is_busy(vq) && fmt_changed)
1005256bf813SHans Verkuil 			return -EBUSY;
1006256bf813SHans Verkuil 
100729a7a5e9SHans Verkuil 		if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
100829a7a5e9SHans Verkuil 			q_data->info = &pixfmt_fwht;
100935e2e8b5SDafna Hirschfeld 		else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
101035e2e8b5SDafna Hirschfeld 			q_data->info = &pixfmt_stateless_fwht;
101129a7a5e9SHans Verkuil 		else
101229a7a5e9SHans Verkuil 			q_data->info = find_fmt(pix->pixelformat);
10139e812549SDafna Hirschfeld 		q_data->coded_width = pix->width;
10149e812549SDafna Hirschfeld 		q_data->coded_height = pix->height;
1015256bf813SHans Verkuil 		q_data->sizeimage = pix->sizeimage;
1016256bf813SHans Verkuil 		break;
1017256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1018256bf813SHans Verkuil 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1019256bf813SHans Verkuil 		pix_mp = &f->fmt.pix_mp;
1020256bf813SHans Verkuil 		if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
1021256bf813SHans Verkuil 			fmt_changed =
10223b15f68eSDafna Hirschfeld 				!q_data->info ||
102329a7a5e9SHans Verkuil 				q_data->info->id != pix_mp->pixelformat ||
10249e812549SDafna Hirschfeld 				q_data->coded_width != pix_mp->width ||
10259e812549SDafna Hirschfeld 				q_data->coded_height != pix_mp->height;
1026256bf813SHans Verkuil 
1027256bf813SHans Verkuil 		if (vb2_is_busy(vq) && fmt_changed)
1028256bf813SHans Verkuil 			return -EBUSY;
1029256bf813SHans Verkuil 
103029a7a5e9SHans Verkuil 		if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
103129a7a5e9SHans Verkuil 			q_data->info = &pixfmt_fwht;
103235e2e8b5SDafna Hirschfeld 		else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
103335e2e8b5SDafna Hirschfeld 			q_data->info = &pixfmt_stateless_fwht;
103429a7a5e9SHans Verkuil 		else
103529a7a5e9SHans Verkuil 			q_data->info = find_fmt(pix_mp->pixelformat);
10369e812549SDafna Hirschfeld 		q_data->coded_width = pix_mp->width;
10379e812549SDafna Hirschfeld 		q_data->coded_height = pix_mp->height;
1038256bf813SHans Verkuil 		q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
1039256bf813SHans Verkuil 		break;
1040256bf813SHans Verkuil 	default:
1041256bf813SHans Verkuil 		return -EINVAL;
1042256bf813SHans Verkuil 	}
1043256bf813SHans Verkuil 
1044256bf813SHans Verkuil 	dprintk(ctx->dev,
1045efec9c81SHans Verkuil 		"Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n",
10469e812549SDafna Hirschfeld 		f->type, q_data->coded_width, q_data->coded_height,
10479e812549SDafna Hirschfeld 		q_data->info->id);
1048256bf813SHans Verkuil 
1049256bf813SHans Verkuil 	return 0;
1050256bf813SHans Verkuil }
1051256bf813SHans Verkuil 
1052256bf813SHans Verkuil static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1053256bf813SHans Verkuil 				struct v4l2_format *f)
1054256bf813SHans Verkuil {
1055256bf813SHans Verkuil 	int ret;
1056256bf813SHans Verkuil 
1057256bf813SHans Verkuil 	ret = vidioc_try_fmt_vid_cap(file, priv, f);
1058256bf813SHans Verkuil 	if (ret)
1059256bf813SHans Verkuil 		return ret;
1060256bf813SHans Verkuil 
1061256bf813SHans Verkuil 	return vidioc_s_fmt(file2ctx(file), f);
1062256bf813SHans Verkuil }
1063256bf813SHans Verkuil 
1064256bf813SHans Verkuil static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
1065256bf813SHans Verkuil 				struct v4l2_format *f)
1066256bf813SHans Verkuil {
1067256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
1068efec9c81SHans Verkuil 	struct vicodec_q_data *q_data;
1069efec9c81SHans Verkuil 	struct vicodec_q_data *q_data_cap;
1070256bf813SHans Verkuil 	struct v4l2_pix_format *pix;
1071efec9c81SHans Verkuil 	struct v4l2_pix_format_mplane *pix_mp;
1072efec9c81SHans Verkuil 	u32 coded_w = 0, coded_h = 0;
1073efec9c81SHans Verkuil 	unsigned int size = 0;
1074256bf813SHans Verkuil 	int ret;
1075256bf813SHans Verkuil 
1076efec9c81SHans Verkuil 	q_data = get_q_data(ctx, f->type);
1077efec9c81SHans Verkuil 	q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
1078efec9c81SHans Verkuil 
1079256bf813SHans Verkuil 	ret = vidioc_try_fmt_vid_out(file, priv, f);
1080256bf813SHans Verkuil 	if (ret)
1081256bf813SHans Verkuil 		return ret;
1082256bf813SHans Verkuil 
1083efec9c81SHans Verkuil 	if (ctx->is_enc) {
1084efec9c81SHans Verkuil 		struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
1085efec9c81SHans Verkuil 		struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1086efec9c81SHans Verkuil 							   V4L2_BUF_TYPE_VIDEO_CAPTURE);
1087efec9c81SHans Verkuil 		const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
1088efec9c81SHans Verkuil 			&pixfmt_stateless_fwht : &pixfmt_fwht;
1089efec9c81SHans Verkuil 
1090efec9c81SHans Verkuil 		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1091efec9c81SHans Verkuil 			coded_w = f->fmt.pix.width;
1092efec9c81SHans Verkuil 			coded_h = f->fmt.pix.height;
1093efec9c81SHans Verkuil 		} else {
1094efec9c81SHans Verkuil 			coded_w = f->fmt.pix_mp.width;
1095efec9c81SHans Verkuil 			coded_h = f->fmt.pix_mp.height;
1096efec9c81SHans Verkuil 		}
1097efec9c81SHans Verkuil 		if (vb2_is_busy(vq) && (coded_w != q_data->coded_width ||
1098efec9c81SHans Verkuil 					coded_h != q_data->coded_height))
1099efec9c81SHans Verkuil 			return -EBUSY;
1100efec9c81SHans Verkuil 		size = coded_w * coded_h *
1101efec9c81SHans Verkuil 			info->sizeimage_mult / info->sizeimage_div;
1102efec9c81SHans Verkuil 		if (!ctx->is_stateless)
1103efec9c81SHans Verkuil 			size += sizeof(struct fwht_cframe_hdr);
1104efec9c81SHans Verkuil 
1105efec9c81SHans Verkuil 		if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage)
1106efec9c81SHans Verkuil 			return -EBUSY;
1107efec9c81SHans Verkuil 	}
1108efec9c81SHans Verkuil 
1109256bf813SHans Verkuil 	ret = vidioc_s_fmt(file2ctx(file), f);
1110256bf813SHans Verkuil 	if (!ret) {
1111efec9c81SHans Verkuil 		if (ctx->is_enc) {
1112efec9c81SHans Verkuil 			q_data->visible_width = coded_w;
1113efec9c81SHans Verkuil 			q_data->visible_height = coded_h;
1114efec9c81SHans Verkuil 			q_data_cap->coded_width = coded_w;
1115efec9c81SHans Verkuil 			q_data_cap->coded_height = coded_h;
1116efec9c81SHans Verkuil 			q_data_cap->sizeimage = size;
1117efec9c81SHans Verkuil 		}
1118efec9c81SHans Verkuil 
1119256bf813SHans Verkuil 		switch (f->type) {
1120256bf813SHans Verkuil 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1121256bf813SHans Verkuil 			pix = &f->fmt.pix;
1122cd12b401SHans Verkuil 			ctx->state.colorspace = pix->colorspace;
1123cd12b401SHans Verkuil 			ctx->state.xfer_func = pix->xfer_func;
1124cd12b401SHans Verkuil 			ctx->state.ycbcr_enc = pix->ycbcr_enc;
1125cd12b401SHans Verkuil 			ctx->state.quantization = pix->quantization;
1126256bf813SHans Verkuil 			break;
1127256bf813SHans Verkuil 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1128256bf813SHans Verkuil 			pix_mp = &f->fmt.pix_mp;
1129cd12b401SHans Verkuil 			ctx->state.colorspace = pix_mp->colorspace;
1130cd12b401SHans Verkuil 			ctx->state.xfer_func = pix_mp->xfer_func;
1131cd12b401SHans Verkuil 			ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
1132cd12b401SHans Verkuil 			ctx->state.quantization = pix_mp->quantization;
1133256bf813SHans Verkuil 			break;
1134256bf813SHans Verkuil 		default:
1135256bf813SHans Verkuil 			break;
1136256bf813SHans Verkuil 		}
1137256bf813SHans Verkuil 	}
1138256bf813SHans Verkuil 	return ret;
1139256bf813SHans Verkuil }
1140256bf813SHans Verkuil 
11419e812549SDafna Hirschfeld static int vidioc_g_selection(struct file *file, void *priv,
11429e812549SDafna Hirschfeld 			      struct v4l2_selection *s)
11439e812549SDafna Hirschfeld {
11449e812549SDafna Hirschfeld 	struct vicodec_ctx *ctx = file2ctx(file);
11459e812549SDafna Hirschfeld 	struct vicodec_q_data *q_data;
1146db9a01b3SHans Verkuil 
11479e812549SDafna Hirschfeld 	q_data = get_q_data(ctx, s->type);
11489e812549SDafna Hirschfeld 	if (!q_data)
11499e812549SDafna Hirschfeld 		return -EINVAL;
11509e812549SDafna Hirschfeld 	/*
11519e812549SDafna Hirschfeld 	 * encoder supports only cropping on the OUTPUT buffer
11529e812549SDafna Hirschfeld 	 * decoder supports only composing on the CAPTURE buffer
11539e812549SDafna Hirschfeld 	 */
1154fb56f4beSHans Verkuil 	if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1155fb56f4beSHans Verkuil 		switch (s->target) {
1156fb56f4beSHans Verkuil 		case V4L2_SEL_TGT_CROP:
1157fb56f4beSHans Verkuil 			s->r.left = 0;
1158fb56f4beSHans Verkuil 			s->r.top = 0;
1159fb56f4beSHans Verkuil 			s->r.width = q_data->visible_width;
1160fb56f4beSHans Verkuil 			s->r.height = q_data->visible_height;
1161fb56f4beSHans Verkuil 			return 0;
1162fb56f4beSHans Verkuil 		case V4L2_SEL_TGT_CROP_DEFAULT:
1163fb56f4beSHans Verkuil 		case V4L2_SEL_TGT_CROP_BOUNDS:
1164fb56f4beSHans Verkuil 			s->r.left = 0;
1165fb56f4beSHans Verkuil 			s->r.top = 0;
1166fb56f4beSHans Verkuil 			s->r.width = q_data->coded_width;
1167fb56f4beSHans Verkuil 			s->r.height = q_data->coded_height;
1168fb56f4beSHans Verkuil 			return 0;
1169fb56f4beSHans Verkuil 		}
1170fb56f4beSHans Verkuil 	} else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
11719e812549SDafna Hirschfeld 		switch (s->target) {
11729e812549SDafna Hirschfeld 		case V4L2_SEL_TGT_COMPOSE:
11739e812549SDafna Hirschfeld 			s->r.left = 0;
11749e812549SDafna Hirschfeld 			s->r.top = 0;
11759e812549SDafna Hirschfeld 			s->r.width = q_data->visible_width;
11769e812549SDafna Hirschfeld 			s->r.height = q_data->visible_height;
11779e812549SDafna Hirschfeld 			return 0;
11789e812549SDafna Hirschfeld 		case V4L2_SEL_TGT_COMPOSE_DEFAULT:
11799e812549SDafna Hirschfeld 		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
11809e812549SDafna Hirschfeld 			s->r.left = 0;
11819e812549SDafna Hirschfeld 			s->r.top = 0;
11829e812549SDafna Hirschfeld 			s->r.width = q_data->coded_width;
11839e812549SDafna Hirschfeld 			s->r.height = q_data->coded_height;
11849e812549SDafna Hirschfeld 			return 0;
11859e812549SDafna Hirschfeld 		}
11869e812549SDafna Hirschfeld 	}
11879e812549SDafna Hirschfeld 	return -EINVAL;
11889e812549SDafna Hirschfeld }
11899e812549SDafna Hirschfeld 
11909e812549SDafna Hirschfeld static int vidioc_s_selection(struct file *file, void *priv,
11919e812549SDafna Hirschfeld 			      struct v4l2_selection *s)
11929e812549SDafna Hirschfeld {
11939e812549SDafna Hirschfeld 	struct vicodec_ctx *ctx = file2ctx(file);
11949e812549SDafna Hirschfeld 	struct vicodec_q_data *q_data;
11959e812549SDafna Hirschfeld 
11967243e5a0SDafna Hirschfeld 	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1197db9a01b3SHans Verkuil 		return -EINVAL;
1198db9a01b3SHans Verkuil 
11999e812549SDafna Hirschfeld 	q_data = get_q_data(ctx, s->type);
12009e812549SDafna Hirschfeld 	if (!q_data)
12019e812549SDafna Hirschfeld 		return -EINVAL;
12029e812549SDafna Hirschfeld 
1203db9a01b3SHans Verkuil 	if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP)
12049e812549SDafna Hirschfeld 		return -EINVAL;
12059e812549SDafna Hirschfeld 
12069e812549SDafna Hirschfeld 	s->r.left = 0;
12079e812549SDafna Hirschfeld 	s->r.top = 0;
12089e812549SDafna Hirschfeld 	q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
12099e812549SDafna Hirschfeld 				      q_data->coded_width);
12109e812549SDafna Hirschfeld 	s->r.width = q_data->visible_width;
12119e812549SDafna Hirschfeld 	q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
12129e812549SDafna Hirschfeld 				       q_data->coded_height);
12139e812549SDafna Hirschfeld 	s->r.height = q_data->visible_height;
12149e812549SDafna Hirschfeld 	return 0;
12159e812549SDafna Hirschfeld }
12169e812549SDafna Hirschfeld 
1217256bf813SHans Verkuil static int vicodec_encoder_cmd(struct file *file, void *fh,
1218256bf813SHans Verkuil 			    struct v4l2_encoder_cmd *ec)
1219256bf813SHans Verkuil {
1220256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
1221256bf813SHans Verkuil 	int ret;
1222256bf813SHans Verkuil 
12239b925365SHans Verkuil 	ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
1224256bf813SHans Verkuil 	if (ret < 0)
1225256bf813SHans Verkuil 		return ret;
1226256bf813SHans Verkuil 
1227d17589afSHans Verkuil 	if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) ||
1228d17589afSHans Verkuil 	    !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
1229256bf813SHans Verkuil 		return 0;
1230d17589afSHans Verkuil 
1231d4d137deSNeil Armstrong 	ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec);
1232d4d137deSNeil Armstrong 	if (ret < 0)
1233d17589afSHans Verkuil 		return ret;
1234d4d137deSNeil Armstrong 
1235d4d137deSNeil Armstrong 	if (ec->cmd == V4L2_ENC_CMD_STOP &&
1236d4d137deSNeil Armstrong 	    v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1237d4d137deSNeil Armstrong 		v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1238d4d137deSNeil Armstrong 
1239d4d137deSNeil Armstrong 	if (ec->cmd == V4L2_ENC_CMD_START &&
1240d4d137deSNeil Armstrong 	    v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1241d4d137deSNeil Armstrong 		vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
1242d4d137deSNeil Armstrong 
1243d4d137deSNeil Armstrong 	return 0;
1244256bf813SHans Verkuil }
1245256bf813SHans Verkuil 
1246256bf813SHans Verkuil static int vicodec_decoder_cmd(struct file *file, void *fh,
1247256bf813SHans Verkuil 			    struct v4l2_decoder_cmd *dc)
1248256bf813SHans Verkuil {
1249256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
1250256bf813SHans Verkuil 	int ret;
1251256bf813SHans Verkuil 
12529b925365SHans Verkuil 	ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
1253256bf813SHans Verkuil 	if (ret < 0)
1254256bf813SHans Verkuil 		return ret;
1255256bf813SHans Verkuil 
1256d17589afSHans Verkuil 	if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) ||
1257d17589afSHans Verkuil 	    !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
1258256bf813SHans Verkuil 		return 0;
1259d17589afSHans Verkuil 
1260d4d137deSNeil Armstrong 	ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc);
1261d4d137deSNeil Armstrong 	if (ret < 0)
1262d17589afSHans Verkuil 		return ret;
1263d4d137deSNeil Armstrong 
1264d4d137deSNeil Armstrong 	if (dc->cmd == V4L2_DEC_CMD_STOP &&
1265d4d137deSNeil Armstrong 	    v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1266d4d137deSNeil Armstrong 		v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1267d4d137deSNeil Armstrong 
1268d4d137deSNeil Armstrong 	if (dc->cmd == V4L2_DEC_CMD_START &&
1269d4d137deSNeil Armstrong 	    v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1270d4d137deSNeil Armstrong 		vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
1271d4d137deSNeil Armstrong 
1272d4d137deSNeil Armstrong 	return 0;
1273256bf813SHans Verkuil }
1274256bf813SHans Verkuil 
1275256bf813SHans Verkuil static int vicodec_enum_framesizes(struct file *file, void *fh,
1276256bf813SHans Verkuil 				   struct v4l2_frmsizeenum *fsize)
1277256bf813SHans Verkuil {
1278256bf813SHans Verkuil 	switch (fsize->pixel_format) {
127935e2e8b5SDafna Hirschfeld 	case V4L2_PIX_FMT_FWHT_STATELESS:
128035e2e8b5SDafna Hirschfeld 		break;
1281256bf813SHans Verkuil 	case V4L2_PIX_FMT_FWHT:
1282256bf813SHans Verkuil 		break;
1283256bf813SHans Verkuil 	default:
128429a7a5e9SHans Verkuil 		if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
1285256bf813SHans Verkuil 			break;
1286256bf813SHans Verkuil 		return -EINVAL;
1287256bf813SHans Verkuil 	}
1288256bf813SHans Verkuil 
1289256bf813SHans Verkuil 	if (fsize->index)
1290256bf813SHans Verkuil 		return -EINVAL;
1291256bf813SHans Verkuil 
1292256bf813SHans Verkuil 	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1293256bf813SHans Verkuil 
1294256bf813SHans Verkuil 	fsize->stepwise.min_width = MIN_WIDTH;
1295256bf813SHans Verkuil 	fsize->stepwise.max_width = MAX_WIDTH;
1296256bf813SHans Verkuil 	fsize->stepwise.step_width = 8;
1297256bf813SHans Verkuil 	fsize->stepwise.min_height = MIN_HEIGHT;
1298256bf813SHans Verkuil 	fsize->stepwise.max_height = MAX_HEIGHT;
1299256bf813SHans Verkuil 	fsize->stepwise.step_height = 8;
1300256bf813SHans Verkuil 
1301256bf813SHans Verkuil 	return 0;
1302256bf813SHans Verkuil }
1303256bf813SHans Verkuil 
1304256bf813SHans Verkuil static int vicodec_subscribe_event(struct v4l2_fh *fh,
1305256bf813SHans Verkuil 				const struct v4l2_event_subscription *sub)
1306256bf813SHans Verkuil {
130769a90057SHans Verkuil 	struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh);
130869a90057SHans Verkuil 
1309256bf813SHans Verkuil 	switch (sub->type) {
13103b15f68eSDafna Hirschfeld 	case V4L2_EVENT_SOURCE_CHANGE:
131169a90057SHans Verkuil 		if (ctx->is_enc)
131269a90057SHans Verkuil 			return -EINVAL;
13131771e9fbSGustavo A. R. Silva 		fallthrough;
131469a90057SHans Verkuil 	case V4L2_EVENT_EOS:
13153b6813d6SHans Verkuil 		if (ctx->is_stateless)
13163b6813d6SHans Verkuil 			return -EINVAL;
1317256bf813SHans Verkuil 		return v4l2_event_subscribe(fh, sub, 0, NULL);
1318256bf813SHans Verkuil 	default:
1319256bf813SHans Verkuil 		return v4l2_ctrl_subscribe_event(fh, sub);
1320256bf813SHans Verkuil 	}
1321256bf813SHans Verkuil }
1322256bf813SHans Verkuil 
1323256bf813SHans Verkuil static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1324256bf813SHans Verkuil 	.vidioc_querycap	= vidioc_querycap,
1325256bf813SHans Verkuil 
1326256bf813SHans Verkuil 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1327256bf813SHans Verkuil 	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
1328256bf813SHans Verkuil 	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
1329256bf813SHans Verkuil 	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
1330256bf813SHans Verkuil 
1331256bf813SHans Verkuil 	.vidioc_g_fmt_vid_cap_mplane	= vidioc_g_fmt_vid_cap,
1332256bf813SHans Verkuil 	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap,
1333256bf813SHans Verkuil 	.vidioc_s_fmt_vid_cap_mplane	= vidioc_s_fmt_vid_cap,
1334256bf813SHans Verkuil 
1335256bf813SHans Verkuil 	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1336256bf813SHans Verkuil 	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
1337256bf813SHans Verkuil 	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
1338256bf813SHans Verkuil 	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
1339256bf813SHans Verkuil 
1340256bf813SHans Verkuil 	.vidioc_g_fmt_vid_out_mplane	= vidioc_g_fmt_vid_out,
1341256bf813SHans Verkuil 	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out,
1342256bf813SHans Verkuil 	.vidioc_s_fmt_vid_out_mplane	= vidioc_s_fmt_vid_out,
1343256bf813SHans Verkuil 
1344256bf813SHans Verkuil 	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
1345256bf813SHans Verkuil 	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
1346256bf813SHans Verkuil 	.vidioc_qbuf		= v4l2_m2m_ioctl_qbuf,
1347256bf813SHans Verkuil 	.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
1348256bf813SHans Verkuil 	.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
1349256bf813SHans Verkuil 	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
1350256bf813SHans Verkuil 	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
1351256bf813SHans Verkuil 
1352256bf813SHans Verkuil 	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
1353256bf813SHans Verkuil 	.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
1354256bf813SHans Verkuil 
13559e812549SDafna Hirschfeld 	.vidioc_g_selection	= vidioc_g_selection,
13569e812549SDafna Hirschfeld 	.vidioc_s_selection	= vidioc_s_selection,
13579e812549SDafna Hirschfeld 
13589b925365SHans Verkuil 	.vidioc_try_encoder_cmd	= v4l2_m2m_ioctl_try_encoder_cmd,
1359256bf813SHans Verkuil 	.vidioc_encoder_cmd	= vicodec_encoder_cmd,
13609b925365SHans Verkuil 	.vidioc_try_decoder_cmd	= v4l2_m2m_ioctl_try_decoder_cmd,
1361256bf813SHans Verkuil 	.vidioc_decoder_cmd	= vicodec_decoder_cmd,
1362256bf813SHans Verkuil 	.vidioc_enum_framesizes = vicodec_enum_framesizes,
1363256bf813SHans Verkuil 
1364256bf813SHans Verkuil 	.vidioc_subscribe_event = vicodec_subscribe_event,
1365256bf813SHans Verkuil 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1366256bf813SHans Verkuil };
1367256bf813SHans Verkuil 
1368256bf813SHans Verkuil 
1369256bf813SHans Verkuil /*
1370256bf813SHans Verkuil  * Queue operations
1371256bf813SHans Verkuil  */
1372256bf813SHans Verkuil 
1373256bf813SHans Verkuil static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1374256bf813SHans Verkuil 			       unsigned int *nplanes, unsigned int sizes[],
1375256bf813SHans Verkuil 			       struct device *alloc_devs[])
1376256bf813SHans Verkuil {
1377256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1378256bf813SHans Verkuil 	struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1379256bf813SHans Verkuil 	unsigned int size = q_data->sizeimage;
1380256bf813SHans Verkuil 
1381256bf813SHans Verkuil 	if (*nplanes)
1382256bf813SHans Verkuil 		return sizes[0] < size ? -EINVAL : 0;
1383256bf813SHans Verkuil 
1384256bf813SHans Verkuil 	*nplanes = 1;
1385256bf813SHans Verkuil 	sizes[0] = size;
13868307f0abSHans Verkuil 	q_data->vb2_sizeimage = size;
1387256bf813SHans Verkuil 	return 0;
1388256bf813SHans Verkuil }
1389256bf813SHans Verkuil 
1390997deb81SDafna Hirschfeld static int vicodec_buf_out_validate(struct vb2_buffer *vb)
1391997deb81SDafna Hirschfeld {
1392997deb81SDafna Hirschfeld 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1393997deb81SDafna Hirschfeld 
1394997deb81SDafna Hirschfeld 	vbuf->field = V4L2_FIELD_NONE;
1395997deb81SDafna Hirschfeld 	return 0;
1396997deb81SDafna Hirschfeld }
1397997deb81SDafna Hirschfeld 
1398256bf813SHans Verkuil static int vicodec_buf_prepare(struct vb2_buffer *vb)
1399256bf813SHans Verkuil {
1400256bf813SHans Verkuil 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1401256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1402256bf813SHans Verkuil 	struct vicodec_q_data *q_data;
1403256bf813SHans Verkuil 
1404256bf813SHans Verkuil 	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1405256bf813SHans Verkuil 
1406256bf813SHans Verkuil 	q_data = get_q_data(ctx, vb->vb2_queue->type);
1407256bf813SHans Verkuil 	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1408256bf813SHans Verkuil 		if (vbuf->field == V4L2_FIELD_ANY)
1409256bf813SHans Verkuil 			vbuf->field = V4L2_FIELD_NONE;
1410256bf813SHans Verkuil 		if (vbuf->field != V4L2_FIELD_NONE) {
1411256bf813SHans Verkuil 			dprintk(ctx->dev, "%s field isn't supported\n",
1412256bf813SHans Verkuil 					__func__);
1413256bf813SHans Verkuil 			return -EINVAL;
1414256bf813SHans Verkuil 		}
1415256bf813SHans Verkuil 	}
1416256bf813SHans Verkuil 
14178307f0abSHans Verkuil 	if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) {
1418256bf813SHans Verkuil 		dprintk(ctx->dev,
1419256bf813SHans Verkuil 			"%s data will not fit into plane (%lu < %lu)\n",
1420256bf813SHans Verkuil 			__func__, vb2_plane_size(vb, 0),
14218307f0abSHans Verkuil 			(long)q_data->vb2_sizeimage);
1422256bf813SHans Verkuil 		return -EINVAL;
1423256bf813SHans Verkuil 	}
1424256bf813SHans Verkuil 
1425256bf813SHans Verkuil 	return 0;
1426256bf813SHans Verkuil }
1427256bf813SHans Verkuil 
1428256bf813SHans Verkuil static void vicodec_buf_queue(struct vb2_buffer *vb)
1429256bf813SHans Verkuil {
1430256bf813SHans Verkuil 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1431256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
14323b15f68eSDafna Hirschfeld 	unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
14333b15f68eSDafna Hirschfeld 	u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
14343b15f68eSDafna Hirschfeld 	u8 *p = p_src;
14353b15f68eSDafna Hirschfeld 	struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
14363b15f68eSDafna Hirschfeld 						   V4L2_BUF_TYPE_VIDEO_OUTPUT);
14373b15f68eSDafna Hirschfeld 	struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
14383b15f68eSDafna Hirschfeld 						   V4L2_BUF_TYPE_VIDEO_CAPTURE);
14393b15f68eSDafna Hirschfeld 	bool header_valid = false;
14403b15f68eSDafna Hirschfeld 	static const struct v4l2_event rs_event = {
14413b15f68eSDafna Hirschfeld 		.type = V4L2_EVENT_SOURCE_CHANGE,
14423b15f68eSDafna Hirschfeld 		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
14433b15f68eSDafna Hirschfeld 	};
1444256bf813SHans Verkuil 
1445b3ab1c60SEzequiel Garcia 	if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
1446d4d137deSNeil Armstrong 	    vb2_is_streaming(vb->vb2_queue) &&
1447d4d137deSNeil Armstrong 	    v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
1448d17589afSHans Verkuil 		unsigned int i;
1449d17589afSHans Verkuil 
1450d17589afSHans Verkuil 		for (i = 0; i < vb->num_planes; i++)
1451d17589afSHans Verkuil 			vb->planes[i].bytesused = 0;
1452d4d137deSNeil Armstrong 
1453d17589afSHans Verkuil 		vbuf->field = V4L2_FIELD_NONE;
1454d4d137deSNeil Armstrong 		vbuf->sequence =
1455d4d137deSNeil Armstrong 			get_q_data(ctx, vb->vb2_queue->type)->sequence++;
1456d4d137deSNeil Armstrong 
1457d4d137deSNeil Armstrong 		v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
1458d17589afSHans Verkuil 		v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1459d17589afSHans Verkuil 		return;
1460d17589afSHans Verkuil 	}
1461d17589afSHans Verkuil 
14623b15f68eSDafna Hirschfeld 	/* buf_queue handles only the first source change event */
14633b15f68eSDafna Hirschfeld 	if (ctx->first_source_change_sent) {
14643b15f68eSDafna Hirschfeld 		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
14653b15f68eSDafna Hirschfeld 		return;
14663b15f68eSDafna Hirschfeld 	}
14673b15f68eSDafna Hirschfeld 
14683b15f68eSDafna Hirschfeld 	/*
14693b15f68eSDafna Hirschfeld 	 * if both queues are streaming, the source change event is
14703b15f68eSDafna Hirschfeld 	 * handled in job_ready
14713b15f68eSDafna Hirschfeld 	 */
14723b15f68eSDafna Hirschfeld 	if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
14733b15f68eSDafna Hirschfeld 		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
14743b15f68eSDafna Hirschfeld 		return;
14753b15f68eSDafna Hirschfeld 	}
14763b15f68eSDafna Hirschfeld 
14773b15f68eSDafna Hirschfeld 	/*
1478997deb81SDafna Hirschfeld 	 * source change event is relevant only for the stateful decoder
14793b15f68eSDafna Hirschfeld 	 * in the compressed stream
14803b15f68eSDafna Hirschfeld 	 */
1481997deb81SDafna Hirschfeld 	if (ctx->is_stateless || ctx->is_enc ||
1482b3ab1c60SEzequiel Garcia 	    V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) {
14833b15f68eSDafna Hirschfeld 		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
14843b15f68eSDafna Hirschfeld 		return;
14853b15f68eSDafna Hirschfeld 	}
14863b15f68eSDafna Hirschfeld 
14873b15f68eSDafna Hirschfeld 	do {
14883b15f68eSDafna Hirschfeld 		enum vb2_buffer_state state =
14893b15f68eSDafna Hirschfeld 			get_next_header(ctx, &p, p_src + sz - p);
14903b15f68eSDafna Hirschfeld 
14913b15f68eSDafna Hirschfeld 		if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
14923b15f68eSDafna Hirschfeld 			v4l2_m2m_buf_done(vbuf, state);
14933b15f68eSDafna Hirschfeld 			return;
14943b15f68eSDafna Hirschfeld 		}
14953b15f68eSDafna Hirschfeld 		header_valid = is_header_valid(&ctx->state.header);
14963b15f68eSDafna Hirschfeld 		/*
14973b15f68eSDafna Hirschfeld 		 * p points right after the end of the header in the
14983b15f68eSDafna Hirschfeld 		 * buffer. If the header is invalid we set p to point
14993b15f68eSDafna Hirschfeld 		 * to the next byte after the start of the header
15003b15f68eSDafna Hirschfeld 		 */
15013b15f68eSDafna Hirschfeld 		if (!header_valid) {
15023b15f68eSDafna Hirschfeld 			p = p - sizeof(struct fwht_cframe_hdr) + 1;
15033b15f68eSDafna Hirschfeld 			if (p < p_src)
15043b15f68eSDafna Hirschfeld 				p = p_src;
15053b15f68eSDafna Hirschfeld 			ctx->header_size = 0;
15063b15f68eSDafna Hirschfeld 			ctx->comp_magic_cnt = 0;
15073b15f68eSDafna Hirschfeld 		}
15083b15f68eSDafna Hirschfeld 
15093b15f68eSDafna Hirschfeld 	} while (!header_valid);
15103b15f68eSDafna Hirschfeld 
15113b15f68eSDafna Hirschfeld 	ctx->cur_buf_offset = p - p_src;
15123b15f68eSDafna Hirschfeld 	update_capture_data_from_header(ctx);
15133b15f68eSDafna Hirschfeld 	ctx->first_source_change_sent = true;
15143b15f68eSDafna Hirschfeld 	v4l2_event_queue_fh(&ctx->fh, &rs_event);
1515256bf813SHans Verkuil 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1516256bf813SHans Verkuil }
1517256bf813SHans Verkuil 
1518256bf813SHans Verkuil static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1519256bf813SHans Verkuil {
1520256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1521256bf813SHans Verkuil 	struct vb2_v4l2_buffer *vbuf;
1522256bf813SHans Verkuil 
1523256bf813SHans Verkuil 	for (;;) {
1524256bf813SHans Verkuil 		if (V4L2_TYPE_IS_OUTPUT(q->type))
1525256bf813SHans Verkuil 			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1526256bf813SHans Verkuil 		else
1527256bf813SHans Verkuil 			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1528256bf813SHans Verkuil 		if (vbuf == NULL)
1529256bf813SHans Verkuil 			return;
1530997deb81SDafna Hirschfeld 		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
1531997deb81SDafna Hirschfeld 					   &ctx->hdl);
1532256bf813SHans Verkuil 		spin_lock(ctx->lock);
1533256bf813SHans Verkuil 		v4l2_m2m_buf_done(vbuf, state);
1534256bf813SHans Verkuil 		spin_unlock(ctx->lock);
1535256bf813SHans Verkuil 	}
1536256bf813SHans Verkuil }
1537256bf813SHans Verkuil 
1538997deb81SDafna Hirschfeld static unsigned int total_frame_size(struct vicodec_q_data *q_data)
1539997deb81SDafna Hirschfeld {
1540997deb81SDafna Hirschfeld 	unsigned int size;
1541997deb81SDafna Hirschfeld 	unsigned int chroma_div;
1542997deb81SDafna Hirschfeld 
1543997deb81SDafna Hirschfeld 	if (!q_data->info) {
1544997deb81SDafna Hirschfeld 		WARN_ON(1);
1545997deb81SDafna Hirschfeld 		return 0;
1546997deb81SDafna Hirschfeld 	}
1547997deb81SDafna Hirschfeld 	size = q_data->coded_width * q_data->coded_height;
1548997deb81SDafna Hirschfeld 	chroma_div = q_data->info->width_div * q_data->info->height_div;
1549997deb81SDafna Hirschfeld 
1550997deb81SDafna Hirschfeld 	if (q_data->info->components_num == 4)
1551997deb81SDafna Hirschfeld 		return 2 * size + 2 * (size / chroma_div);
1552997deb81SDafna Hirschfeld 	else if (q_data->info->components_num == 3)
1553997deb81SDafna Hirschfeld 		return size + 2 * (size / chroma_div);
1554997deb81SDafna Hirschfeld 	return size;
1555997deb81SDafna Hirschfeld }
1556997deb81SDafna Hirschfeld 
1557256bf813SHans Verkuil static int vicodec_start_streaming(struct vb2_queue *q,
1558256bf813SHans Verkuil 				   unsigned int count)
1559256bf813SHans Verkuil {
1560256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1561256bf813SHans Verkuil 	struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
1562cd12b401SHans Verkuil 	struct v4l2_fwht_state *state = &ctx->state;
1563cd12b401SHans Verkuil 	const struct v4l2_fwht_pixfmt_info *info = q_data->info;
15649e812549SDafna Hirschfeld 	unsigned int size = q_data->coded_width * q_data->coded_height;
15653b15f68eSDafna Hirschfeld 	unsigned int chroma_div;
156619505719SDafna Hirschfeld 	unsigned int total_planes_size;
1567997deb81SDafna Hirschfeld 	u8 *new_comp_frame = NULL;
156819505719SDafna Hirschfeld 
15693b15f68eSDafna Hirschfeld 	chroma_div = info->width_div * info->height_div;
15703b15f68eSDafna Hirschfeld 	q_data->sequence = 0;
15713b15f68eSDafna Hirschfeld 
1572d4d137deSNeil Armstrong 	v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
157376eb24fcSHans Verkuil 
15743b15f68eSDafna Hirschfeld 	state->gop_cnt = 0;
15753b15f68eSDafna Hirschfeld 
15763b15f68eSDafna Hirschfeld 	if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1577b3ab1c60SEzequiel Garcia 	    (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc))
15783b15f68eSDafna Hirschfeld 		return 0;
15793b15f68eSDafna Hirschfeld 
158035e2e8b5SDafna Hirschfeld 	if (info->id == V4L2_PIX_FMT_FWHT ||
158135e2e8b5SDafna Hirschfeld 	    info->id == V4L2_PIX_FMT_FWHT_STATELESS) {
15823b15f68eSDafna Hirschfeld 		vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
15833b15f68eSDafna Hirschfeld 		return -EINVAL;
15843b15f68eSDafna Hirschfeld 	}
1585997deb81SDafna Hirschfeld 	total_planes_size = total_frame_size(q_data);
1586997deb81SDafna Hirschfeld 	ctx->comp_max_size = total_planes_size;
1587256bf813SHans Verkuil 
15889e812549SDafna Hirschfeld 	state->visible_width = q_data->visible_width;
15899e812549SDafna Hirschfeld 	state->visible_height = q_data->visible_height;
15909e812549SDafna Hirschfeld 	state->coded_width = q_data->coded_width;
15919e812549SDafna Hirschfeld 	state->coded_height = q_data->coded_height;
15929e812549SDafna Hirschfeld 	state->stride = q_data->coded_width *
15939e812549SDafna Hirschfeld 				info->bytesperline_mult;
1594daa3fc44SHans Verkuil 
1595997deb81SDafna Hirschfeld 	if (ctx->is_stateless) {
1596997deb81SDafna Hirschfeld 		state->ref_stride = state->stride;
1597997deb81SDafna Hirschfeld 		return 0;
1598997deb81SDafna Hirschfeld 	}
159986764b88SDafna Hirschfeld 	state->ref_stride = q_data->coded_width * info->luma_alpha_step;
1600997deb81SDafna Hirschfeld 
1601bdbfd992SDafna Hirschfeld 	state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL);
1602bdbfd992SDafna Hirschfeld 	state->ref_frame.luma = state->ref_frame.buf;
16033b15f68eSDafna Hirschfeld 	new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
16043b15f68eSDafna Hirschfeld 
16053b15f68eSDafna Hirschfeld 	if (!state->ref_frame.luma || !new_comp_frame) {
1606cd12b401SHans Verkuil 		kvfree(state->ref_frame.luma);
16073b15f68eSDafna Hirschfeld 		kvfree(new_comp_frame);
1608256bf813SHans Verkuil 		vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1609256bf813SHans Verkuil 		return -ENOMEM;
1610256bf813SHans Verkuil 	}
16113b15f68eSDafna Hirschfeld 	/*
16123b15f68eSDafna Hirschfeld 	 * if state->compressed_frame was already allocated then
16133b15f68eSDafna Hirschfeld 	 * it contain data of the first frame of the new resolution
16143b15f68eSDafna Hirschfeld 	 */
16153b15f68eSDafna Hirschfeld 	if (state->compressed_frame) {
16163b15f68eSDafna Hirschfeld 		if (ctx->comp_size > ctx->comp_max_size)
16173b15f68eSDafna Hirschfeld 			ctx->comp_size = ctx->comp_max_size;
16183b15f68eSDafna Hirschfeld 
16193b15f68eSDafna Hirschfeld 		memcpy(new_comp_frame,
16203b15f68eSDafna Hirschfeld 		       state->compressed_frame, ctx->comp_size);
16213b15f68eSDafna Hirschfeld 	}
16223b15f68eSDafna Hirschfeld 
16233b15f68eSDafna Hirschfeld 	kvfree(state->compressed_frame);
16243b15f68eSDafna Hirschfeld 	state->compressed_frame = new_comp_frame;
16253b15f68eSDafna Hirschfeld 
1626cb804507SMauro Carvalho Chehab 	if (info->components_num < 3) {
162719505719SDafna Hirschfeld 		state->ref_frame.cb = NULL;
162819505719SDafna Hirschfeld 		state->ref_frame.cr = NULL;
1629cb804507SMauro Carvalho Chehab 		state->ref_frame.alpha = NULL;
1630cb804507SMauro Carvalho Chehab 		return 0;
163119505719SDafna Hirschfeld 	}
163216ecf6dfSDafna Hirschfeld 
1633cb804507SMauro Carvalho Chehab 	state->ref_frame.cb = state->ref_frame.luma + size;
1634cb804507SMauro Carvalho Chehab 	state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1635cb804507SMauro Carvalho Chehab 
16363b15f68eSDafna Hirschfeld 	if (info->components_num == 4)
163716ecf6dfSDafna Hirschfeld 		state->ref_frame.alpha =
163816ecf6dfSDafna Hirschfeld 			state->ref_frame.cr + size / chroma_div;
163916ecf6dfSDafna Hirschfeld 	else
164016ecf6dfSDafna Hirschfeld 		state->ref_frame.alpha = NULL;
1641cb804507SMauro Carvalho Chehab 
1642256bf813SHans Verkuil 	return 0;
1643256bf813SHans Verkuil }
1644256bf813SHans Verkuil 
1645256bf813SHans Verkuil static void vicodec_stop_streaming(struct vb2_queue *q)
1646256bf813SHans Verkuil {
1647256bf813SHans Verkuil 	struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1648256bf813SHans Verkuil 
1649256bf813SHans Verkuil 	vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1650256bf813SHans Verkuil 
1651d4d137deSNeil Armstrong 	v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
1652d17589afSHans Verkuil 
1653d4d137deSNeil Armstrong 	if (V4L2_TYPE_IS_OUTPUT(q->type) &&
1654d4d137deSNeil Armstrong 	    v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
1655d17589afSHans Verkuil 		v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
1656d4d137deSNeil Armstrong 
1657d17589afSHans Verkuil 	if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
1658d17589afSHans Verkuil 		ctx->first_source_change_sent = false;
1659d17589afSHans Verkuil 
16603b15f68eSDafna Hirschfeld 	if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
16613b15f68eSDafna Hirschfeld 	    (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1662997deb81SDafna Hirschfeld 		if (!ctx->is_stateless)
1663bdbfd992SDafna Hirschfeld 			kvfree(ctx->state.ref_frame.buf);
1664bdbfd992SDafna Hirschfeld 		ctx->state.ref_frame.buf = NULL;
1665bdbfd992SDafna Hirschfeld 		ctx->state.ref_frame.luma = NULL;
16663b15f68eSDafna Hirschfeld 		ctx->comp_max_size = 0;
16673b15f68eSDafna Hirschfeld 		ctx->source_changed = false;
16683b15f68eSDafna Hirschfeld 	}
16693b15f68eSDafna Hirschfeld 	if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
16703b15f68eSDafna Hirschfeld 		ctx->cur_buf_offset = 0;
16713b15f68eSDafna Hirschfeld 		ctx->comp_size = 0;
16723b15f68eSDafna Hirschfeld 		ctx->header_size = 0;
16733b15f68eSDafna Hirschfeld 		ctx->comp_magic_cnt = 0;
1674333b90fbSDaniel W. S. Almeida 		ctx->comp_has_frame = false;
1675333b90fbSDaniel W. S. Almeida 		ctx->comp_has_next_frame = false;
16763b15f68eSDafna Hirschfeld 	}
1677256bf813SHans Verkuil }
1678256bf813SHans Verkuil 
1679997deb81SDafna Hirschfeld static void vicodec_buf_request_complete(struct vb2_buffer *vb)
1680997deb81SDafna Hirschfeld {
1681997deb81SDafna Hirschfeld 	struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1682997deb81SDafna Hirschfeld 
1683997deb81SDafna Hirschfeld 	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
1684997deb81SDafna Hirschfeld }
1685997deb81SDafna Hirschfeld 
1686997deb81SDafna Hirschfeld 
1687256bf813SHans Verkuil static const struct vb2_ops vicodec_qops = {
1688256bf813SHans Verkuil 	.queue_setup		= vicodec_queue_setup,
1689997deb81SDafna Hirschfeld 	.buf_out_validate	= vicodec_buf_out_validate,
1690256bf813SHans Verkuil 	.buf_prepare		= vicodec_buf_prepare,
1691256bf813SHans Verkuil 	.buf_queue		= vicodec_buf_queue,
1692997deb81SDafna Hirschfeld 	.buf_request_complete	= vicodec_buf_request_complete,
1693256bf813SHans Verkuil 	.start_streaming	= vicodec_start_streaming,
1694256bf813SHans Verkuil 	.stop_streaming		= vicodec_stop_streaming,
1695256bf813SHans Verkuil 	.wait_prepare		= vb2_ops_wait_prepare,
1696256bf813SHans Verkuil 	.wait_finish		= vb2_ops_wait_finish,
1697256bf813SHans Verkuil };
1698256bf813SHans Verkuil 
1699256bf813SHans Verkuil static int queue_init(void *priv, struct vb2_queue *src_vq,
1700256bf813SHans Verkuil 		      struct vb2_queue *dst_vq)
1701256bf813SHans Verkuil {
1702256bf813SHans Verkuil 	struct vicodec_ctx *ctx = priv;
1703256bf813SHans Verkuil 	int ret;
1704256bf813SHans Verkuil 
1705256bf813SHans Verkuil 	src_vq->type = (multiplanar ?
1706256bf813SHans Verkuil 			V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1707256bf813SHans Verkuil 			V4L2_BUF_TYPE_VIDEO_OUTPUT);
1708256bf813SHans Verkuil 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1709256bf813SHans Verkuil 	src_vq->drv_priv = ctx;
1710256bf813SHans Verkuil 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1711256bf813SHans Verkuil 	src_vq->ops = &vicodec_qops;
1712256bf813SHans Verkuil 	src_vq->mem_ops = &vb2_vmalloc_memops;
1713256bf813SHans Verkuil 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1714fde649b4SDafna Hirschfeld 	if (ctx->is_enc)
1715fde649b4SDafna Hirschfeld 		src_vq->lock = &ctx->dev->stateful_enc.mutex;
1716fde649b4SDafna Hirschfeld 	else if (ctx->is_stateless)
1717fde649b4SDafna Hirschfeld 		src_vq->lock = &ctx->dev->stateless_dec.mutex;
1718fde649b4SDafna Hirschfeld 	else
1719fde649b4SDafna Hirschfeld 		src_vq->lock = &ctx->dev->stateful_dec.mutex;
1720fde649b4SDafna Hirschfeld 	src_vq->supports_requests = ctx->is_stateless;
1721fde649b4SDafna Hirschfeld 	src_vq->requires_requests = ctx->is_stateless;
1722256bf813SHans Verkuil 	ret = vb2_queue_init(src_vq);
1723256bf813SHans Verkuil 	if (ret)
1724256bf813SHans Verkuil 		return ret;
1725256bf813SHans Verkuil 
1726256bf813SHans Verkuil 	dst_vq->type = (multiplanar ?
1727256bf813SHans Verkuil 			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1728256bf813SHans Verkuil 			V4L2_BUF_TYPE_VIDEO_CAPTURE);
1729256bf813SHans Verkuil 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1730256bf813SHans Verkuil 	dst_vq->drv_priv = ctx;
1731256bf813SHans Verkuil 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1732256bf813SHans Verkuil 	dst_vq->ops = &vicodec_qops;
1733256bf813SHans Verkuil 	dst_vq->mem_ops = &vb2_vmalloc_memops;
1734256bf813SHans Verkuil 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1735256bf813SHans Verkuil 	dst_vq->lock = src_vq->lock;
1736256bf813SHans Verkuil 
1737256bf813SHans Verkuil 	return vb2_queue_init(dst_vq);
1738256bf813SHans Verkuil }
1739256bf813SHans Verkuil 
1740997deb81SDafna Hirschfeld static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl)
1741997deb81SDafna Hirschfeld {
1742997deb81SDafna Hirschfeld 	struct vicodec_ctx *ctx = container_of(ctrl->handler,
1743997deb81SDafna Hirschfeld 			struct vicodec_ctx, hdl);
1744997deb81SDafna Hirschfeld 	const struct v4l2_ctrl_fwht_params *params;
1745997deb81SDafna Hirschfeld 	struct vicodec_q_data *q_dst = get_q_data(ctx,
1746997deb81SDafna Hirschfeld 			V4L2_BUF_TYPE_VIDEO_CAPTURE);
1747997deb81SDafna Hirschfeld 
1748997deb81SDafna Hirschfeld 	switch (ctrl->id) {
1749997deb81SDafna Hirschfeld 	case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS:
1750997deb81SDafna Hirschfeld 		if (!q_dst->info)
1751997deb81SDafna Hirschfeld 			return -EINVAL;
1752997deb81SDafna Hirschfeld 		params = ctrl->p_new.p_fwht_params;
1753997deb81SDafna Hirschfeld 		if (params->width > q_dst->coded_width ||
1754997deb81SDafna Hirschfeld 		    params->width < MIN_WIDTH ||
1755997deb81SDafna Hirschfeld 		    params->height > q_dst->coded_height ||
1756997deb81SDafna Hirschfeld 		    params->height < MIN_HEIGHT)
1757997deb81SDafna Hirschfeld 			return -EINVAL;
1758997deb81SDafna Hirschfeld 		if (!validate_by_version(params->flags, params->version))
1759997deb81SDafna Hirschfeld 			return -EINVAL;
1760997deb81SDafna Hirschfeld 		if (!validate_stateless_params_flags(params, q_dst->info))
1761997deb81SDafna Hirschfeld 			return -EINVAL;
1762997deb81SDafna Hirschfeld 		return 0;
1763997deb81SDafna Hirschfeld 	default:
1764997deb81SDafna Hirschfeld 		return 0;
1765997deb81SDafna Hirschfeld 	}
1766997deb81SDafna Hirschfeld 	return 0;
1767997deb81SDafna Hirschfeld }
1768997deb81SDafna Hirschfeld 
1769997deb81SDafna Hirschfeld static void update_header_from_stateless_params(struct vicodec_ctx *ctx,
1770997deb81SDafna Hirschfeld 						const struct v4l2_ctrl_fwht_params *params)
1771997deb81SDafna Hirschfeld {
1772997deb81SDafna Hirschfeld 	struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
1773997deb81SDafna Hirschfeld 
1774997deb81SDafna Hirschfeld 	p_hdr->magic1 = FWHT_MAGIC1;
1775997deb81SDafna Hirschfeld 	p_hdr->magic2 = FWHT_MAGIC2;
1776997deb81SDafna Hirschfeld 	p_hdr->version = htonl(params->version);
1777997deb81SDafna Hirschfeld 	p_hdr->width = htonl(params->width);
1778997deb81SDafna Hirschfeld 	p_hdr->height = htonl(params->height);
1779997deb81SDafna Hirschfeld 	p_hdr->flags = htonl(params->flags);
1780997deb81SDafna Hirschfeld 	p_hdr->colorspace = htonl(params->colorspace);
1781997deb81SDafna Hirschfeld 	p_hdr->xfer_func = htonl(params->xfer_func);
1782997deb81SDafna Hirschfeld 	p_hdr->ycbcr_enc = htonl(params->ycbcr_enc);
1783997deb81SDafna Hirschfeld 	p_hdr->quantization = htonl(params->quantization);
1784997deb81SDafna Hirschfeld }
1785997deb81SDafna Hirschfeld 
178648568b0cSHans Verkuil static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
178748568b0cSHans Verkuil {
178848568b0cSHans Verkuil 	struct vicodec_ctx *ctx = container_of(ctrl->handler,
178948568b0cSHans Verkuil 					       struct vicodec_ctx, hdl);
1790997deb81SDafna Hirschfeld 	const struct v4l2_ctrl_fwht_params *params;
179148568b0cSHans Verkuil 
179248568b0cSHans Verkuil 	switch (ctrl->id) {
179348568b0cSHans Verkuil 	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1794cd12b401SHans Verkuil 		ctx->state.gop_size = ctrl->val;
179548568b0cSHans Verkuil 		return 0;
17962495f39cSDafna Hirschfeld 	case V4L2_CID_FWHT_I_FRAME_QP:
1797cd12b401SHans Verkuil 		ctx->state.i_frame_qp = ctrl->val;
179848568b0cSHans Verkuil 		return 0;
17992495f39cSDafna Hirschfeld 	case V4L2_CID_FWHT_P_FRAME_QP:
1800cd12b401SHans Verkuil 		ctx->state.p_frame_qp = ctrl->val;
180148568b0cSHans Verkuil 		return 0;
1802997deb81SDafna Hirschfeld 	case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS:
1803997deb81SDafna Hirschfeld 		params = ctrl->p_new.p_fwht_params;
1804997deb81SDafna Hirschfeld 		update_header_from_stateless_params(ctx, params);
1805997deb81SDafna Hirschfeld 		ctx->state.ref_frame_ts = params->backward_ref_ts;
1806997deb81SDafna Hirschfeld 		return 0;
180748568b0cSHans Verkuil 	}
180848568b0cSHans Verkuil 	return -EINVAL;
180948568b0cSHans Verkuil }
181048568b0cSHans Verkuil 
1811299553d8SJulia Lawall static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
181248568b0cSHans Verkuil 	.s_ctrl = vicodec_s_ctrl,
1813997deb81SDafna Hirschfeld 	.try_ctrl = vicodec_try_ctrl,
181448568b0cSHans Verkuil };
181548568b0cSHans Verkuil 
18162495f39cSDafna Hirschfeld static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = {
1817997deb81SDafna Hirschfeld 	.ops		= &vicodec_ctrl_ops,
18182495f39cSDafna Hirschfeld 	.id		= V4L2_CID_MPEG_VIDEO_FWHT_PARAMS,
18192495f39cSDafna Hirschfeld 	.elem_size      = sizeof(struct v4l2_ctrl_fwht_params),
182048568b0cSHans Verkuil };
182148568b0cSHans Verkuil 
1822256bf813SHans Verkuil /*
1823256bf813SHans Verkuil  * File operations
1824256bf813SHans Verkuil  */
1825256bf813SHans Verkuil static int vicodec_open(struct file *file)
1826256bf813SHans Verkuil {
1827d421ba0cSHans Verkuil 	const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0);
1828256bf813SHans Verkuil 	struct video_device *vfd = video_devdata(file);
1829256bf813SHans Verkuil 	struct vicodec_dev *dev = video_drvdata(file);
1830256bf813SHans Verkuil 	struct vicodec_ctx *ctx = NULL;
1831256bf813SHans Verkuil 	struct v4l2_ctrl_handler *hdl;
1832d421ba0cSHans Verkuil 	unsigned int raw_size;
1833d421ba0cSHans Verkuil 	unsigned int comp_size;
1834256bf813SHans Verkuil 	int rc = 0;
1835256bf813SHans Verkuil 
1836256bf813SHans Verkuil 	if (mutex_lock_interruptible(vfd->lock))
1837256bf813SHans Verkuil 		return -ERESTARTSYS;
1838256bf813SHans Verkuil 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1839256bf813SHans Verkuil 	if (!ctx) {
1840256bf813SHans Verkuil 		rc = -ENOMEM;
1841256bf813SHans Verkuil 		goto open_unlock;
1842256bf813SHans Verkuil 	}
1843256bf813SHans Verkuil 
1844c022a4a9SDafna Hirschfeld 	if (vfd == &dev->stateful_enc.vfd)
1845256bf813SHans Verkuil 		ctx->is_enc = true;
1846fde649b4SDafna Hirschfeld 	else if (vfd == &dev->stateless_dec.vfd)
1847fde649b4SDafna Hirschfeld 		ctx->is_stateless = true;
1848256bf813SHans Verkuil 
1849256bf813SHans Verkuil 	v4l2_fh_init(&ctx->fh, video_devdata(file));
1850256bf813SHans Verkuil 	file->private_data = &ctx->fh;
1851256bf813SHans Verkuil 	ctx->dev = dev;
1852256bf813SHans Verkuil 	hdl = &ctx->hdl;
1853358387d3SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 5);
185448568b0cSHans Verkuil 	v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1855256bf813SHans Verkuil 			  1, 16, 1, 10);
18562495f39cSDafna Hirschfeld 	v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP,
18572495f39cSDafna Hirschfeld 			  1, 31, 1, 20);
18582495f39cSDafna Hirschfeld 	v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP,
18592495f39cSDafna Hirschfeld 			  1, 31, 1, 20);
1860358387d3SHans Verkuil 	if (ctx->is_enc)
1861358387d3SHans Verkuil 		v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops,
1862358387d3SHans Verkuil 				  V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1);
1863fde649b4SDafna Hirschfeld 	if (ctx->is_stateless)
1864fde649b4SDafna Hirschfeld 		v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL);
1865256bf813SHans Verkuil 	if (hdl->error) {
1866256bf813SHans Verkuil 		rc = hdl->error;
1867256bf813SHans Verkuil 		v4l2_ctrl_handler_free(hdl);
1868256bf813SHans Verkuil 		kfree(ctx);
1869256bf813SHans Verkuil 		goto open_unlock;
1870256bf813SHans Verkuil 	}
1871256bf813SHans Verkuil 	ctx->fh.ctrl_handler = hdl;
1872256bf813SHans Verkuil 	v4l2_ctrl_handler_setup(hdl);
1873256bf813SHans Verkuil 
187435e2e8b5SDafna Hirschfeld 	if (ctx->is_enc)
1875d421ba0cSHans Verkuil 		ctx->q_data[V4L2_M2M_SRC].info = info;
187635e2e8b5SDafna Hirschfeld 	else if (ctx->is_stateless)
187735e2e8b5SDafna Hirschfeld 		ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht;
187835e2e8b5SDafna Hirschfeld 	else
187935e2e8b5SDafna Hirschfeld 		ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht;
18809e812549SDafna Hirschfeld 	ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
18819e812549SDafna Hirschfeld 	ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
18829e812549SDafna Hirschfeld 	ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
18839e812549SDafna Hirschfeld 	ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
1884d421ba0cSHans Verkuil 	raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div;
1885d421ba0cSHans Verkuil 	comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult /
1886d421ba0cSHans Verkuil 				 pixfmt_fwht.sizeimage_div;
1887518f6b9aSHans Verkuil 	if (ctx->is_enc)
1888d421ba0cSHans Verkuil 		ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size;
1889518f6b9aSHans Verkuil 	else if (ctx->is_stateless)
1890518f6b9aSHans Verkuil 		ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size;
189155f6fe09SHans Verkuil 	else
189255f6fe09SHans Verkuil 		ctx->q_data[V4L2_M2M_SRC].sizeimage =
1893d421ba0cSHans Verkuil 			comp_size + sizeof(struct fwht_cframe_hdr);
1894256bf813SHans Verkuil 	ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1895d421ba0cSHans Verkuil 	if (ctx->is_enc) {
18963b15f68eSDafna Hirschfeld 		ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1897d421ba0cSHans Verkuil 		ctx->q_data[V4L2_M2M_DST].sizeimage =
1898d421ba0cSHans Verkuil 			comp_size + sizeof(struct fwht_cframe_hdr);
18993b15f68eSDafna Hirschfeld 	} else {
1900d421ba0cSHans Verkuil 		ctx->q_data[V4L2_M2M_DST].info = info;
1901d421ba0cSHans Verkuil 		ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size;
19023b15f68eSDafna Hirschfeld 	}
19033b15f68eSDafna Hirschfeld 
1904cd12b401SHans Verkuil 	ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1905256bf813SHans Verkuil 
1906256bf813SHans Verkuil 	if (ctx->is_enc) {
1907c022a4a9SDafna Hirschfeld 		ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev,
1908c022a4a9SDafna Hirschfeld 						    ctx, &queue_init);
1909c022a4a9SDafna Hirschfeld 		ctx->lock = &dev->stateful_enc.lock;
1910fde649b4SDafna Hirschfeld 	} else if (ctx->is_stateless) {
1911fde649b4SDafna Hirschfeld 		ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev,
1912fde649b4SDafna Hirschfeld 						    ctx, &queue_init);
1913fde649b4SDafna Hirschfeld 		ctx->lock = &dev->stateless_dec.lock;
1914256bf813SHans Verkuil 	} else {
1915c022a4a9SDafna Hirschfeld 		ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev,
1916c022a4a9SDafna Hirschfeld 						    ctx, &queue_init);
1917c022a4a9SDafna Hirschfeld 		ctx->lock = &dev->stateful_dec.lock;
1918256bf813SHans Verkuil 	}
1919256bf813SHans Verkuil 
1920256bf813SHans Verkuil 	if (IS_ERR(ctx->fh.m2m_ctx)) {
1921256bf813SHans Verkuil 		rc = PTR_ERR(ctx->fh.m2m_ctx);
1922256bf813SHans Verkuil 
1923256bf813SHans Verkuil 		v4l2_ctrl_handler_free(hdl);
1924256bf813SHans Verkuil 		v4l2_fh_exit(&ctx->fh);
1925256bf813SHans Verkuil 		kfree(ctx);
1926256bf813SHans Verkuil 		goto open_unlock;
1927256bf813SHans Verkuil 	}
1928256bf813SHans Verkuil 
1929256bf813SHans Verkuil 	v4l2_fh_add(&ctx->fh);
1930256bf813SHans Verkuil 
1931256bf813SHans Verkuil open_unlock:
1932256bf813SHans Verkuil 	mutex_unlock(vfd->lock);
1933256bf813SHans Verkuil 	return rc;
1934256bf813SHans Verkuil }
1935256bf813SHans Verkuil 
1936256bf813SHans Verkuil static int vicodec_release(struct file *file)
1937256bf813SHans Verkuil {
1938256bf813SHans Verkuil 	struct video_device *vfd = video_devdata(file);
1939256bf813SHans Verkuil 	struct vicodec_ctx *ctx = file2ctx(file);
1940256bf813SHans Verkuil 
1941256bf813SHans Verkuil 	mutex_lock(vfd->lock);
1942256bf813SHans Verkuil 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1943256bf813SHans Verkuil 	mutex_unlock(vfd->lock);
19444d10452cSDafna Hirschfeld 	v4l2_fh_del(&ctx->fh);
19454d10452cSDafna Hirschfeld 	v4l2_fh_exit(&ctx->fh);
19464d10452cSDafna Hirschfeld 	v4l2_ctrl_handler_free(&ctx->hdl);
1947a04a7a21SDafna Hirschfeld 	kvfree(ctx->state.compressed_frame);
1948256bf813SHans Verkuil 	kfree(ctx);
1949256bf813SHans Verkuil 
1950256bf813SHans Verkuil 	return 0;
1951256bf813SHans Verkuil }
1952256bf813SHans Verkuil 
1953997deb81SDafna Hirschfeld static int vicodec_request_validate(struct media_request *req)
1954997deb81SDafna Hirschfeld {
1955997deb81SDafna Hirschfeld 	struct media_request_object *obj;
1956997deb81SDafna Hirschfeld 	struct v4l2_ctrl_handler *parent_hdl, *hdl;
1957997deb81SDafna Hirschfeld 	struct vicodec_ctx *ctx = NULL;
1958997deb81SDafna Hirschfeld 	struct v4l2_ctrl *ctrl;
1959997deb81SDafna Hirschfeld 	unsigned int count;
1960997deb81SDafna Hirschfeld 
1961997deb81SDafna Hirschfeld 	list_for_each_entry(obj, &req->objects, list) {
1962997deb81SDafna Hirschfeld 		struct vb2_buffer *vb;
1963997deb81SDafna Hirschfeld 
1964997deb81SDafna Hirschfeld 		if (vb2_request_object_is_buffer(obj)) {
1965997deb81SDafna Hirschfeld 			vb = container_of(obj, struct vb2_buffer, req_obj);
1966997deb81SDafna Hirschfeld 			ctx = vb2_get_drv_priv(vb->vb2_queue);
1967997deb81SDafna Hirschfeld 
1968997deb81SDafna Hirschfeld 			break;
1969997deb81SDafna Hirschfeld 		}
1970997deb81SDafna Hirschfeld 	}
1971997deb81SDafna Hirschfeld 
1972997deb81SDafna Hirschfeld 	if (!ctx) {
1973997deb81SDafna Hirschfeld 		pr_err("No buffer was provided with the request\n");
1974997deb81SDafna Hirschfeld 		return -ENOENT;
1975997deb81SDafna Hirschfeld 	}
1976997deb81SDafna Hirschfeld 
1977997deb81SDafna Hirschfeld 	count = vb2_request_buffer_cnt(req);
1978997deb81SDafna Hirschfeld 	if (!count) {
1979997deb81SDafna Hirschfeld 		v4l2_info(&ctx->dev->v4l2_dev,
1980997deb81SDafna Hirschfeld 			  "No buffer was provided with the request\n");
1981997deb81SDafna Hirschfeld 		return -ENOENT;
1982997deb81SDafna Hirschfeld 	} else if (count > 1) {
1983997deb81SDafna Hirschfeld 		v4l2_info(&ctx->dev->v4l2_dev,
1984997deb81SDafna Hirschfeld 			  "More than one buffer was provided with the request\n");
1985997deb81SDafna Hirschfeld 		return -EINVAL;
1986997deb81SDafna Hirschfeld 	}
1987997deb81SDafna Hirschfeld 
1988997deb81SDafna Hirschfeld 	parent_hdl = &ctx->hdl;
1989997deb81SDafna Hirschfeld 
1990997deb81SDafna Hirschfeld 	hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
1991997deb81SDafna Hirschfeld 	if (!hdl) {
1992997deb81SDafna Hirschfeld 		v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n");
1993997deb81SDafna Hirschfeld 		return -ENOENT;
1994997deb81SDafna Hirschfeld 	}
1995997deb81SDafna Hirschfeld 	ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl,
1996997deb81SDafna Hirschfeld 					       vicodec_ctrl_stateless_state.id);
19972e7c8fb8SHans Verkuil 	v4l2_ctrl_request_hdl_put(hdl);
1998997deb81SDafna Hirschfeld 	if (!ctrl) {
1999997deb81SDafna Hirschfeld 		v4l2_info(&ctx->dev->v4l2_dev,
2000997deb81SDafna Hirschfeld 			  "Missing required codec control\n");
2001997deb81SDafna Hirschfeld 		return -ENOENT;
2002997deb81SDafna Hirschfeld 	}
2003997deb81SDafna Hirschfeld 
2004997deb81SDafna Hirschfeld 	return vb2_request_validate(req);
2005997deb81SDafna Hirschfeld }
2006997deb81SDafna Hirschfeld 
2007256bf813SHans Verkuil static const struct v4l2_file_operations vicodec_fops = {
2008256bf813SHans Verkuil 	.owner		= THIS_MODULE,
2009256bf813SHans Verkuil 	.open		= vicodec_open,
2010256bf813SHans Verkuil 	.release	= vicodec_release,
2011256bf813SHans Verkuil 	.poll		= v4l2_m2m_fop_poll,
2012256bf813SHans Verkuil 	.unlocked_ioctl	= video_ioctl2,
2013256bf813SHans Verkuil 	.mmap		= v4l2_m2m_fop_mmap,
2014256bf813SHans Verkuil };
2015256bf813SHans Verkuil 
2016256bf813SHans Verkuil static const struct video_device vicodec_videodev = {
2017256bf813SHans Verkuil 	.name		= VICODEC_NAME,
2018256bf813SHans Verkuil 	.vfl_dir	= VFL_DIR_M2M,
2019256bf813SHans Verkuil 	.fops		= &vicodec_fops,
2020256bf813SHans Verkuil 	.ioctl_ops	= &vicodec_ioctl_ops,
2021256bf813SHans Verkuil 	.minor		= -1,
2022256bf813SHans Verkuil 	.release	= video_device_release_empty,
2023256bf813SHans Verkuil };
2024256bf813SHans Verkuil 
2025997deb81SDafna Hirschfeld static const struct media_device_ops vicodec_m2m_media_ops = {
2026997deb81SDafna Hirschfeld 	.req_validate	= vicodec_request_validate,
2027997deb81SDafna Hirschfeld 	.req_queue	= v4l2_m2m_request_queue,
2028997deb81SDafna Hirschfeld };
2029997deb81SDafna Hirschfeld 
2030256bf813SHans Verkuil static const struct v4l2_m2m_ops m2m_ops = {
2031256bf813SHans Verkuil 	.device_run	= device_run,
2032256bf813SHans Verkuil 	.job_ready	= job_ready,
2033256bf813SHans Verkuil };
2034256bf813SHans Verkuil 
2035c022a4a9SDafna Hirschfeld static int register_instance(struct vicodec_dev *dev,
2036c022a4a9SDafna Hirschfeld 			     struct vicodec_dev_instance *dev_instance,
2037c022a4a9SDafna Hirschfeld 			     const char *name, bool is_enc)
2038c022a4a9SDafna Hirschfeld {
2039c022a4a9SDafna Hirschfeld 	struct video_device *vfd;
2040c022a4a9SDafna Hirschfeld 	int ret;
2041c022a4a9SDafna Hirschfeld 
2042c022a4a9SDafna Hirschfeld 	spin_lock_init(&dev_instance->lock);
2043c022a4a9SDafna Hirschfeld 	mutex_init(&dev_instance->mutex);
2044c022a4a9SDafna Hirschfeld 	dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops);
2045c022a4a9SDafna Hirschfeld 	if (IS_ERR(dev_instance->m2m_dev)) {
2046c022a4a9SDafna Hirschfeld 		v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n");
2047c022a4a9SDafna Hirschfeld 		return PTR_ERR(dev_instance->m2m_dev);
2048c022a4a9SDafna Hirschfeld 	}
2049c022a4a9SDafna Hirschfeld 
2050c022a4a9SDafna Hirschfeld 	dev_instance->vfd = vicodec_videodev;
2051c022a4a9SDafna Hirschfeld 	vfd = &dev_instance->vfd;
2052c022a4a9SDafna Hirschfeld 	vfd->lock = &dev_instance->mutex;
2053c022a4a9SDafna Hirschfeld 	vfd->v4l2_dev = &dev->v4l2_dev;
2054c022a4a9SDafna Hirschfeld 	strscpy(vfd->name, name, sizeof(vfd->name));
2055c022a4a9SDafna Hirschfeld 	vfd->device_caps = V4L2_CAP_STREAMING |
2056c022a4a9SDafna Hirschfeld 		(multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
2057c022a4a9SDafna Hirschfeld 	if (is_enc) {
2058c022a4a9SDafna Hirschfeld 		v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
2059c022a4a9SDafna Hirschfeld 		v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
2060c022a4a9SDafna Hirschfeld 	} else {
2061c022a4a9SDafna Hirschfeld 		v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
2062c022a4a9SDafna Hirschfeld 		v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
2063c022a4a9SDafna Hirschfeld 	}
2064c022a4a9SDafna Hirschfeld 	video_set_drvdata(vfd, dev);
2065c022a4a9SDafna Hirschfeld 
206670cad449SHans Verkuil 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
2067c022a4a9SDafna Hirschfeld 	if (ret) {
2068c022a4a9SDafna Hirschfeld 		v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name);
2069c022a4a9SDafna Hirschfeld 		v4l2_m2m_release(dev_instance->m2m_dev);
2070c022a4a9SDafna Hirschfeld 		return ret;
2071c022a4a9SDafna Hirschfeld 	}
2072c022a4a9SDafna Hirschfeld 	v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n",
2073c022a4a9SDafna Hirschfeld 		  name, vfd->num);
2074c022a4a9SDafna Hirschfeld 	return 0;
2075c022a4a9SDafna Hirschfeld }
2076c022a4a9SDafna Hirschfeld 
20770783525fSHans Verkuil static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev)
20780783525fSHans Verkuil {
20790783525fSHans Verkuil 	struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev);
20800783525fSHans Verkuil 
20810783525fSHans Verkuil 	v4l2_device_unregister(&dev->v4l2_dev);
20820783525fSHans Verkuil 	v4l2_m2m_release(dev->stateful_enc.m2m_dev);
20830783525fSHans Verkuil 	v4l2_m2m_release(dev->stateful_dec.m2m_dev);
20840783525fSHans Verkuil 	v4l2_m2m_release(dev->stateless_dec.m2m_dev);
2085693c5f14SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
2086693c5f14SHans Verkuil 	media_device_cleanup(&dev->mdev);
2087693c5f14SHans Verkuil #endif
20880783525fSHans Verkuil 	kfree(dev);
20890783525fSHans Verkuil }
20900783525fSHans Verkuil 
2091256bf813SHans Verkuil static int vicodec_probe(struct platform_device *pdev)
2092256bf813SHans Verkuil {
2093256bf813SHans Verkuil 	struct vicodec_dev *dev;
2094256bf813SHans Verkuil 	int ret;
2095256bf813SHans Verkuil 
20960783525fSHans Verkuil 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2097256bf813SHans Verkuil 	if (!dev)
2098256bf813SHans Verkuil 		return -ENOMEM;
2099256bf813SHans Verkuil 
2100256bf813SHans Verkuil 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
2101256bf813SHans Verkuil 	if (ret)
21020783525fSHans Verkuil 		goto free_dev;
21030783525fSHans Verkuil 
21040783525fSHans Verkuil 	dev->v4l2_dev.release = vicodec_v4l2_dev_release;
2105256bf813SHans Verkuil 
2106256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
2107256bf813SHans Verkuil 	dev->mdev.dev = &pdev->dev;
2108c0decac1SMauro Carvalho Chehab 	strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
21090247c75bSHans Verkuil 	strscpy(dev->mdev.bus_info, "platform:vicodec",
21100247c75bSHans Verkuil 		sizeof(dev->mdev.bus_info));
2111256bf813SHans Verkuil 	media_device_init(&dev->mdev);
2112997deb81SDafna Hirschfeld 	dev->mdev.ops = &vicodec_m2m_media_ops;
2113256bf813SHans Verkuil 	dev->v4l2_dev.mdev = &dev->mdev;
2114256bf813SHans Verkuil #endif
2115256bf813SHans Verkuil 
2116256bf813SHans Verkuil 	platform_set_drvdata(pdev, dev);
2117256bf813SHans Verkuil 
2118f36592e7SDan Carpenter 	ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder",
2119f36592e7SDan Carpenter 				true);
2120f36592e7SDan Carpenter 	if (ret)
2121256bf813SHans Verkuil 		goto unreg_dev;
2122256bf813SHans Verkuil 
2123f36592e7SDan Carpenter 	ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder",
2124f36592e7SDan Carpenter 				false);
2125f36592e7SDan Carpenter 	if (ret)
2126c022a4a9SDafna Hirschfeld 		goto unreg_sf_enc;
2127256bf813SHans Verkuil 
2128f36592e7SDan Carpenter 	ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder",
2129f36592e7SDan Carpenter 				false);
2130f36592e7SDan Carpenter 	if (ret)
2131fde649b4SDafna Hirschfeld 		goto unreg_sf_dec;
2132fde649b4SDafna Hirschfeld 
2133256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
2134c022a4a9SDafna Hirschfeld 	ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev,
2135c022a4a9SDafna Hirschfeld 						 &dev->stateful_enc.vfd,
2136c022a4a9SDafna Hirschfeld 						 MEDIA_ENT_F_PROC_VIDEO_ENCODER);
2137256bf813SHans Verkuil 	if (ret) {
2138c022a4a9SDafna Hirschfeld 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n");
2139256bf813SHans Verkuil 		goto unreg_m2m;
2140256bf813SHans Verkuil 	}
2141256bf813SHans Verkuil 
2142c022a4a9SDafna Hirschfeld 	ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev,
2143c022a4a9SDafna Hirschfeld 						 &dev->stateful_dec.vfd,
2144c022a4a9SDafna Hirschfeld 						 MEDIA_ENT_F_PROC_VIDEO_DECODER);
2145256bf813SHans Verkuil 	if (ret) {
2146c022a4a9SDafna Hirschfeld 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n");
2147c022a4a9SDafna Hirschfeld 		goto unreg_m2m_sf_enc_mc;
2148256bf813SHans Verkuil 	}
2149256bf813SHans Verkuil 
2150fde649b4SDafna Hirschfeld 	ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev,
2151fde649b4SDafna Hirschfeld 						 &dev->stateless_dec.vfd,
2152fde649b4SDafna Hirschfeld 						 MEDIA_ENT_F_PROC_VIDEO_DECODER);
2153fde649b4SDafna Hirschfeld 	if (ret) {
2154fde649b4SDafna Hirschfeld 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n");
2155fde649b4SDafna Hirschfeld 		goto unreg_m2m_sf_dec_mc;
2156fde649b4SDafna Hirschfeld 	}
2157fde649b4SDafna Hirschfeld 
2158256bf813SHans Verkuil 	ret = media_device_register(&dev->mdev);
2159256bf813SHans Verkuil 	if (ret) {
2160256bf813SHans Verkuil 		v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
2161fde649b4SDafna Hirschfeld 		goto unreg_m2m_sl_dec_mc;
2162256bf813SHans Verkuil 	}
2163256bf813SHans Verkuil #endif
2164256bf813SHans Verkuil 	return 0;
2165256bf813SHans Verkuil 
2166256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
2167fde649b4SDafna Hirschfeld unreg_m2m_sl_dec_mc:
2168fde649b4SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
2169c022a4a9SDafna Hirschfeld unreg_m2m_sf_dec_mc:
2170c022a4a9SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
2171c022a4a9SDafna Hirschfeld unreg_m2m_sf_enc_mc:
2172c022a4a9SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
2173256bf813SHans Verkuil unreg_m2m:
2174fde649b4SDafna Hirschfeld 	video_unregister_device(&dev->stateless_dec.vfd);
2175fde649b4SDafna Hirschfeld 	v4l2_m2m_release(dev->stateless_dec.m2m_dev);
2176fde649b4SDafna Hirschfeld #endif
2177fde649b4SDafna Hirschfeld unreg_sf_dec:
2178c022a4a9SDafna Hirschfeld 	video_unregister_device(&dev->stateful_dec.vfd);
2179c022a4a9SDafna Hirschfeld 	v4l2_m2m_release(dev->stateful_dec.m2m_dev);
2180c022a4a9SDafna Hirschfeld unreg_sf_enc:
2181c022a4a9SDafna Hirschfeld 	video_unregister_device(&dev->stateful_enc.vfd);
2182c022a4a9SDafna Hirschfeld 	v4l2_m2m_release(dev->stateful_enc.m2m_dev);
2183256bf813SHans Verkuil unreg_dev:
2184256bf813SHans Verkuil 	v4l2_device_unregister(&dev->v4l2_dev);
21850783525fSHans Verkuil free_dev:
21860783525fSHans Verkuil 	kfree(dev);
2187256bf813SHans Verkuil 
2188256bf813SHans Verkuil 	return ret;
2189256bf813SHans Verkuil }
2190256bf813SHans Verkuil 
2191256bf813SHans Verkuil static int vicodec_remove(struct platform_device *pdev)
2192256bf813SHans Verkuil {
2193256bf813SHans Verkuil 	struct vicodec_dev *dev = platform_get_drvdata(pdev);
2194256bf813SHans Verkuil 
2195256bf813SHans Verkuil 	v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
2196256bf813SHans Verkuil 
2197256bf813SHans Verkuil #ifdef CONFIG_MEDIA_CONTROLLER
2198256bf813SHans Verkuil 	media_device_unregister(&dev->mdev);
2199c022a4a9SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
2200c022a4a9SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
2201fde649b4SDafna Hirschfeld 	v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
2202256bf813SHans Verkuil #endif
2203256bf813SHans Verkuil 
2204c022a4a9SDafna Hirschfeld 	video_unregister_device(&dev->stateful_enc.vfd);
2205c022a4a9SDafna Hirschfeld 	video_unregister_device(&dev->stateful_dec.vfd);
2206fde649b4SDafna Hirschfeld 	video_unregister_device(&dev->stateless_dec.vfd);
22070783525fSHans Verkuil 	v4l2_device_put(&dev->v4l2_dev);
2208256bf813SHans Verkuil 
2209256bf813SHans Verkuil 	return 0;
2210256bf813SHans Verkuil }
2211256bf813SHans Verkuil 
2212256bf813SHans Verkuil static struct platform_driver vicodec_pdrv = {
2213256bf813SHans Verkuil 	.probe		= vicodec_probe,
2214256bf813SHans Verkuil 	.remove		= vicodec_remove,
2215256bf813SHans Verkuil 	.driver		= {
2216256bf813SHans Verkuil 		.name	= VICODEC_NAME,
2217256bf813SHans Verkuil 	},
2218256bf813SHans Verkuil };
2219256bf813SHans Verkuil 
2220256bf813SHans Verkuil static void __exit vicodec_exit(void)
2221256bf813SHans Verkuil {
2222256bf813SHans Verkuil 	platform_driver_unregister(&vicodec_pdrv);
2223256bf813SHans Verkuil 	platform_device_unregister(&vicodec_pdev);
2224256bf813SHans Verkuil }
2225256bf813SHans Verkuil 
2226256bf813SHans Verkuil static int __init vicodec_init(void)
2227256bf813SHans Verkuil {
2228256bf813SHans Verkuil 	int ret;
2229256bf813SHans Verkuil 
2230256bf813SHans Verkuil 	ret = platform_device_register(&vicodec_pdev);
2231256bf813SHans Verkuil 	if (ret)
2232256bf813SHans Verkuil 		return ret;
2233256bf813SHans Verkuil 
2234256bf813SHans Verkuil 	ret = platform_driver_register(&vicodec_pdrv);
2235256bf813SHans Verkuil 	if (ret)
2236256bf813SHans Verkuil 		platform_device_unregister(&vicodec_pdev);
2237256bf813SHans Verkuil 
2238256bf813SHans Verkuil 	return ret;
2239256bf813SHans Verkuil }
2240256bf813SHans Verkuil 
2241256bf813SHans Verkuil module_init(vicodec_init);
2242256bf813SHans Verkuil module_exit(vicodec_exit);
2243