1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2017 Linaro Ltd.
5 */
6#include <linux/list.h>
7#include <linux/mutex.h>
8#include <linux/slab.h>
9#include <linux/kernel.h>
10#include <media/videobuf2-dma-sg.h>
11#include <media/v4l2-mem2mem.h>
12#include <asm/div64.h>
13
14#include "core.h"
15#include "helpers.h"
16#include "hfi_helper.h"
17#include "pm_helpers.h"
18
19struct intbuf {
20	struct list_head list;
21	u32 type;
22	size_t size;
23	void *va;
24	dma_addr_t da;
25	unsigned long attrs;
26};
27
28bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt)
29{
30	struct venus_core *core = inst->core;
31	u32 session_type = inst->session_type;
32	u32 codec;
33
34	switch (v4l2_pixfmt) {
35	case V4L2_PIX_FMT_H264:
36		codec = HFI_VIDEO_CODEC_H264;
37		break;
38	case V4L2_PIX_FMT_H263:
39		codec = HFI_VIDEO_CODEC_H263;
40		break;
41	case V4L2_PIX_FMT_MPEG1:
42		codec = HFI_VIDEO_CODEC_MPEG1;
43		break;
44	case V4L2_PIX_FMT_MPEG2:
45		codec = HFI_VIDEO_CODEC_MPEG2;
46		break;
47	case V4L2_PIX_FMT_MPEG4:
48		codec = HFI_VIDEO_CODEC_MPEG4;
49		break;
50	case V4L2_PIX_FMT_VC1_ANNEX_G:
51	case V4L2_PIX_FMT_VC1_ANNEX_L:
52		codec = HFI_VIDEO_CODEC_VC1;
53		break;
54	case V4L2_PIX_FMT_VP8:
55		codec = HFI_VIDEO_CODEC_VP8;
56		break;
57	case V4L2_PIX_FMT_VP9:
58		codec = HFI_VIDEO_CODEC_VP9;
59		break;
60	case V4L2_PIX_FMT_XVID:
61		codec = HFI_VIDEO_CODEC_DIVX;
62		break;
63	case V4L2_PIX_FMT_HEVC:
64		codec = HFI_VIDEO_CODEC_HEVC;
65		break;
66	default:
67		return false;
68	}
69
70	if (session_type == VIDC_SESSION_TYPE_ENC && core->enc_codecs & codec)
71		return true;
72
73	if (session_type == VIDC_SESSION_TYPE_DEC && core->dec_codecs & codec)
74		return true;
75
76	return false;
77}
78EXPORT_SYMBOL_GPL(venus_helper_check_codec);
79
80int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
81{
82	struct intbuf *buf;
83	int ret = 0;
84
85	list_for_each_entry(buf, &inst->dpbbufs, list) {
86		struct hfi_frame_data fdata;
87
88		memset(&fdata, 0, sizeof(fdata));
89		fdata.alloc_len = buf->size;
90		fdata.device_addr = buf->da;
91		fdata.buffer_type = buf->type;
92
93		ret = hfi_session_process_buf(inst, &fdata);
94		if (ret)
95			goto fail;
96	}
97
98fail:
99	return ret;
100}
101EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs);
102
103int venus_helper_free_dpb_bufs(struct venus_inst *inst)
104{
105	struct intbuf *buf, *n;
106
107	list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) {
108		list_del_init(&buf->list);
109		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
110			       buf->attrs);
111		kfree(buf);
112	}
113
114	INIT_LIST_HEAD(&inst->dpbbufs);
115
116	return 0;
117}
118EXPORT_SYMBOL_GPL(venus_helper_free_dpb_bufs);
119
120int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
121{
122	struct venus_core *core = inst->core;
123	struct device *dev = core->dev;
124	enum hfi_version ver = core->res->hfi_version;
125	struct hfi_buffer_requirements bufreq;
126	u32 buftype = inst->dpb_buftype;
127	unsigned int dpb_size = 0;
128	struct intbuf *buf;
129	unsigned int i;
130	u32 count;
131	int ret;
132
133	/* no need to allocate dpb buffers */
134	if (!inst->dpb_fmt)
135		return 0;
136
137	if (inst->dpb_buftype == HFI_BUFFER_OUTPUT)
138		dpb_size = inst->output_buf_size;
139	else if (inst->dpb_buftype == HFI_BUFFER_OUTPUT2)
140		dpb_size = inst->output2_buf_size;
141
142	if (!dpb_size)
143		return 0;
144
145	ret = venus_helper_get_bufreq(inst, buftype, &bufreq);
146	if (ret)
147		return ret;
148
149	count = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
150
151	for (i = 0; i < count; i++) {
152		buf = kzalloc(sizeof(*buf), GFP_KERNEL);
153		if (!buf) {
154			ret = -ENOMEM;
155			goto fail;
156		}
157
158		buf->type = buftype;
159		buf->size = dpb_size;
160		buf->attrs = DMA_ATTR_WRITE_COMBINE |
161			     DMA_ATTR_NO_KERNEL_MAPPING;
162		buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
163					  buf->attrs);
164		if (!buf->va) {
165			kfree(buf);
166			ret = -ENOMEM;
167			goto fail;
168		}
169
170		list_add_tail(&buf->list, &inst->dpbbufs);
171	}
172
173	return 0;
174
175fail:
176	venus_helper_free_dpb_bufs(inst);
177	return ret;
178}
179EXPORT_SYMBOL_GPL(venus_helper_alloc_dpb_bufs);
180
181static int intbufs_set_buffer(struct venus_inst *inst, u32 type)
182{
183	struct venus_core *core = inst->core;
184	struct device *dev = core->dev;
185	struct hfi_buffer_requirements bufreq;
186	struct hfi_buffer_desc bd;
187	struct intbuf *buf;
188	unsigned int i;
189	int ret;
190
191	ret = venus_helper_get_bufreq(inst, type, &bufreq);
192	if (ret)
193		return 0;
194
195	if (!bufreq.size)
196		return 0;
197
198	for (i = 0; i < bufreq.count_actual; i++) {
199		buf = kzalloc(sizeof(*buf), GFP_KERNEL);
200		if (!buf) {
201			ret = -ENOMEM;
202			goto fail;
203		}
204
205		buf->type = bufreq.type;
206		buf->size = bufreq.size;
207		buf->attrs = DMA_ATTR_WRITE_COMBINE |
208			     DMA_ATTR_NO_KERNEL_MAPPING;
209		buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
210					  buf->attrs);
211		if (!buf->va) {
212			ret = -ENOMEM;
213			goto fail;
214		}
215
216		memset(&bd, 0, sizeof(bd));
217		bd.buffer_size = buf->size;
218		bd.buffer_type = buf->type;
219		bd.num_buffers = 1;
220		bd.device_addr = buf->da;
221
222		ret = hfi_session_set_buffers(inst, &bd);
223		if (ret) {
224			dev_err(dev, "set session buffers failed\n");
225			goto dma_free;
226		}
227
228		list_add_tail(&buf->list, &inst->internalbufs);
229	}
230
231	return 0;
232
233dma_free:
234	dma_free_attrs(dev, buf->size, buf->va, buf->da, buf->attrs);
235fail:
236	kfree(buf);
237	return ret;
238}
239
240static int intbufs_unset_buffers(struct venus_inst *inst)
241{
242	struct hfi_buffer_desc bd = {0};
243	struct intbuf *buf, *n;
244	int ret = 0;
245
246	list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
247		bd.buffer_size = buf->size;
248		bd.buffer_type = buf->type;
249		bd.num_buffers = 1;
250		bd.device_addr = buf->da;
251		bd.response_required = true;
252
253		ret = hfi_session_unset_buffers(inst, &bd);
254
255		list_del_init(&buf->list);
256		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
257			       buf->attrs);
258		kfree(buf);
259	}
260
261	return ret;
262}
263
264static const unsigned int intbuf_types_1xx[] = {
265	HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_1XX),
266	HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_1XX),
267	HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_1XX),
268	HFI_BUFFER_INTERNAL_PERSIST,
269	HFI_BUFFER_INTERNAL_PERSIST_1,
270};
271
272static const unsigned int intbuf_types_4xx[] = {
273	HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_4XX),
274	HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_4XX),
275	HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_4XX),
276	HFI_BUFFER_INTERNAL_PERSIST,
277	HFI_BUFFER_INTERNAL_PERSIST_1,
278};
279
280int venus_helper_intbufs_alloc(struct venus_inst *inst)
281{
282	const unsigned int *intbuf;
283	size_t arr_sz, i;
284	int ret;
285
286	if (IS_V4(inst->core)) {
287		arr_sz = ARRAY_SIZE(intbuf_types_4xx);
288		intbuf = intbuf_types_4xx;
289	} else {
290		arr_sz = ARRAY_SIZE(intbuf_types_1xx);
291		intbuf = intbuf_types_1xx;
292	}
293
294	for (i = 0; i < arr_sz; i++) {
295		ret = intbufs_set_buffer(inst, intbuf[i]);
296		if (ret)
297			goto error;
298	}
299
300	return 0;
301
302error:
303	intbufs_unset_buffers(inst);
304	return ret;
305}
306EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc);
307
308int venus_helper_intbufs_free(struct venus_inst *inst)
309{
310	return intbufs_unset_buffers(inst);
311}
312EXPORT_SYMBOL_GPL(venus_helper_intbufs_free);
313
314int venus_helper_intbufs_realloc(struct venus_inst *inst)
315{
316	enum hfi_version ver = inst->core->res->hfi_version;
317	struct hfi_buffer_desc bd;
318	struct intbuf *buf, *n;
319	int ret;
320
321	list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
322		if (buf->type == HFI_BUFFER_INTERNAL_PERSIST ||
323		    buf->type == HFI_BUFFER_INTERNAL_PERSIST_1)
324			continue;
325
326		memset(&bd, 0, sizeof(bd));
327		bd.buffer_size = buf->size;
328		bd.buffer_type = buf->type;
329		bd.num_buffers = 1;
330		bd.device_addr = buf->da;
331		bd.response_required = true;
332
333		ret = hfi_session_unset_buffers(inst, &bd);
334
335		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
336			       buf->attrs);
337
338		list_del_init(&buf->list);
339		kfree(buf);
340	}
341
342	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH(ver));
343	if (ret)
344		goto err;
345
346	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_1(ver));
347	if (ret)
348		goto err;
349
350	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_2(ver));
351	if (ret)
352		goto err;
353
354	return 0;
355err:
356	return ret;
357}
358EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
359
360static void fill_buffer_desc(const struct venus_buffer *buf,
361			     struct hfi_buffer_desc *bd, bool response)
362{
363	memset(bd, 0, sizeof(*bd));
364	bd->buffer_type = HFI_BUFFER_OUTPUT;
365	bd->buffer_size = buf->size;
366	bd->num_buffers = 1;
367	bd->device_addr = buf->dma_addr;
368	bd->response_required = response;
369}
370
371static void return_buf_error(struct venus_inst *inst,
372			     struct vb2_v4l2_buffer *vbuf)
373{
374	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
375
376	if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
377		v4l2_m2m_src_buf_remove_by_buf(m2m_ctx, vbuf);
378	else
379		v4l2_m2m_dst_buf_remove_by_buf(m2m_ctx, vbuf);
380
381	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
382}
383
384static void
385put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
386{
387	struct vb2_buffer *vb = &vbuf->vb2_buf;
388	unsigned int i;
389	int slot = -1;
390	u64 ts_us = vb->timestamp;
391
392	for (i = 0; i < ARRAY_SIZE(inst->tss); i++) {
393		if (!inst->tss[i].used) {
394			slot = i;
395			break;
396		}
397	}
398
399	if (slot == -1) {
400		dev_dbg(inst->core->dev, VDBGL "no free slot\n");
401		return;
402	}
403
404	do_div(ts_us, NSEC_PER_USEC);
405
406	inst->tss[slot].used = true;
407	inst->tss[slot].flags = vbuf->flags;
408	inst->tss[slot].tc = vbuf->timecode;
409	inst->tss[slot].ts_us = ts_us;
410	inst->tss[slot].ts_ns = vb->timestamp;
411}
412
413void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
414				  struct vb2_v4l2_buffer *vbuf)
415{
416	struct vb2_buffer *vb = &vbuf->vb2_buf;
417	unsigned int i;
418
419	for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) {
420		if (!inst->tss[i].used)
421			continue;
422
423		if (inst->tss[i].ts_us != timestamp_us)
424			continue;
425
426		inst->tss[i].used = false;
427		vbuf->flags |= inst->tss[i].flags;
428		vbuf->timecode = inst->tss[i].tc;
429		vb->timestamp = inst->tss[i].ts_ns;
430		break;
431	}
432}
433EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata);
434
435static int
436session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
437{
438	struct venus_buffer *buf = to_venus_buffer(vbuf);
439	struct vb2_buffer *vb = &vbuf->vb2_buf;
440	unsigned int type = vb->type;
441	struct hfi_frame_data fdata;
442	int ret;
443
444	memset(&fdata, 0, sizeof(fdata));
445	fdata.alloc_len = buf->size;
446	fdata.device_addr = buf->dma_addr;
447	fdata.timestamp = vb->timestamp;
448	do_div(fdata.timestamp, NSEC_PER_USEC);
449	fdata.flags = 0;
450	fdata.clnt_data = vbuf->vb2_buf.index;
451
452	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
453		fdata.buffer_type = HFI_BUFFER_INPUT;
454		fdata.filled_len = vb2_get_plane_payload(vb, 0);
455		fdata.offset = vb->planes[0].data_offset;
456
457		if (vbuf->flags & V4L2_BUF_FLAG_LAST || !fdata.filled_len)
458			fdata.flags |= HFI_BUFFERFLAG_EOS;
459
460		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
461			put_ts_metadata(inst, vbuf);
462
463		venus_pm_load_scale(inst);
464	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
465		if (inst->session_type == VIDC_SESSION_TYPE_ENC)
466			fdata.buffer_type = HFI_BUFFER_OUTPUT;
467		else
468			fdata.buffer_type = inst->opb_buftype;
469		fdata.filled_len = 0;
470		fdata.offset = 0;
471	}
472
473	ret = hfi_session_process_buf(inst, &fdata);
474	if (ret)
475		return ret;
476
477	return 0;
478}
479
480static bool is_dynamic_bufmode(struct venus_inst *inst)
481{
482	struct venus_core *core = inst->core;
483	struct venus_caps *caps;
484
485	/*
486	 * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports
487	 * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2.
488	 */
489	if (IS_V4(core))
490		return true;
491
492	caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
493	if (!caps)
494		return false;
495
496	return caps->cap_bufs_mode_dynamic;
497}
498
499int venus_helper_unregister_bufs(struct venus_inst *inst)
500{
501	struct venus_buffer *buf, *n;
502	struct hfi_buffer_desc bd;
503	int ret = 0;
504
505	if (is_dynamic_bufmode(inst))
506		return 0;
507
508	list_for_each_entry_safe(buf, n, &inst->registeredbufs, reg_list) {
509		fill_buffer_desc(buf, &bd, true);
510		ret = hfi_session_unset_buffers(inst, &bd);
511		list_del_init(&buf->reg_list);
512	}
513
514	return ret;
515}
516EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs);
517
518static int session_register_bufs(struct venus_inst *inst)
519{
520	struct venus_core *core = inst->core;
521	struct device *dev = core->dev;
522	struct hfi_buffer_desc bd;
523	struct venus_buffer *buf;
524	int ret = 0;
525
526	if (is_dynamic_bufmode(inst))
527		return 0;
528
529	list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
530		fill_buffer_desc(buf, &bd, false);
531		ret = hfi_session_set_buffers(inst, &bd);
532		if (ret) {
533			dev_err(dev, "%s: set buffer failed\n", __func__);
534			break;
535		}
536	}
537
538	return ret;
539}
540
541static u32 to_hfi_raw_fmt(u32 v4l2_fmt)
542{
543	switch (v4l2_fmt) {
544	case V4L2_PIX_FMT_NV12:
545		return HFI_COLOR_FORMAT_NV12;
546	case V4L2_PIX_FMT_NV21:
547		return HFI_COLOR_FORMAT_NV21;
548	default:
549		break;
550	}
551
552	return 0;
553}
554
555int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
556			    struct hfi_buffer_requirements *req)
557{
558	u32 ptype = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
559	union hfi_get_property hprop;
560	unsigned int i;
561	int ret;
562
563	if (req)
564		memset(req, 0, sizeof(*req));
565
566	ret = hfi_session_get_property(inst, ptype, &hprop);
567	if (ret)
568		return ret;
569
570	ret = -EINVAL;
571
572	for (i = 0; i < HFI_BUFFER_TYPE_MAX; i++) {
573		if (hprop.bufreq[i].type != type)
574			continue;
575
576		if (req)
577			memcpy(req, &hprop.bufreq[i], sizeof(*req));
578		ret = 0;
579		break;
580	}
581
582	return ret;
583}
584EXPORT_SYMBOL_GPL(venus_helper_get_bufreq);
585
586struct id_mapping {
587	u32 hfi_id;
588	u32 v4l2_id;
589};
590
591static const struct id_mapping mpeg4_profiles[] = {
592	{ HFI_MPEG4_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE },
593	{ HFI_MPEG4_PROFILE_ADVANCEDSIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE },
594};
595
596static const struct id_mapping mpeg4_levels[] = {
597	{ HFI_MPEG4_LEVEL_0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 },
598	{ HFI_MPEG4_LEVEL_0b, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B },
599	{ HFI_MPEG4_LEVEL_1, V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 },
600	{ HFI_MPEG4_LEVEL_2, V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 },
601	{ HFI_MPEG4_LEVEL_3, V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 },
602	{ HFI_MPEG4_LEVEL_4, V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 },
603	{ HFI_MPEG4_LEVEL_5, V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 },
604};
605
606static const struct id_mapping mpeg2_profiles[] = {
607	{ HFI_MPEG2_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE },
608	{ HFI_MPEG2_PROFILE_MAIN, V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN },
609	{ HFI_MPEG2_PROFILE_SNR, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE },
610	{ HFI_MPEG2_PROFILE_SPATIAL, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE },
611	{ HFI_MPEG2_PROFILE_HIGH, V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH },
612};
613
614static const struct id_mapping mpeg2_levels[] = {
615	{ HFI_MPEG2_LEVEL_LL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW },
616	{ HFI_MPEG2_LEVEL_ML, V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN },
617	{ HFI_MPEG2_LEVEL_H14, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440 },
618	{ HFI_MPEG2_LEVEL_HL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH },
619};
620
621static const struct id_mapping h264_profiles[] = {
622	{ HFI_H264_PROFILE_BASELINE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE },
623	{ HFI_H264_PROFILE_MAIN, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN },
624	{ HFI_H264_PROFILE_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH },
625	{ HFI_H264_PROFILE_STEREO_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH },
626	{ HFI_H264_PROFILE_MULTIVIEW_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH },
627	{ HFI_H264_PROFILE_CONSTRAINED_BASE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE },
628	{ HFI_H264_PROFILE_CONSTRAINED_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH },
629};
630
631static const struct id_mapping h264_levels[] = {
632	{ HFI_H264_LEVEL_1, V4L2_MPEG_VIDEO_H264_LEVEL_1_0 },
633	{ HFI_H264_LEVEL_1b, V4L2_MPEG_VIDEO_H264_LEVEL_1B },
634	{ HFI_H264_LEVEL_11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1 },
635	{ HFI_H264_LEVEL_12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2 },
636	{ HFI_H264_LEVEL_13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3 },
637	{ HFI_H264_LEVEL_2, V4L2_MPEG_VIDEO_H264_LEVEL_2_0 },
638	{ HFI_H264_LEVEL_21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1 },
639	{ HFI_H264_LEVEL_22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2 },
640	{ HFI_H264_LEVEL_3, V4L2_MPEG_VIDEO_H264_LEVEL_3_0 },
641	{ HFI_H264_LEVEL_31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1 },
642	{ HFI_H264_LEVEL_32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2 },
643	{ HFI_H264_LEVEL_4, V4L2_MPEG_VIDEO_H264_LEVEL_4_0 },
644	{ HFI_H264_LEVEL_41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1 },
645	{ HFI_H264_LEVEL_42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2 },
646	{ HFI_H264_LEVEL_5, V4L2_MPEG_VIDEO_H264_LEVEL_5_0 },
647	{ HFI_H264_LEVEL_51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 },
648	{ HFI_H264_LEVEL_52, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 },
649};
650
651static const struct id_mapping hevc_profiles[] = {
652	{ HFI_HEVC_PROFILE_MAIN, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN },
653	{ HFI_HEVC_PROFILE_MAIN_STILL_PIC, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE },
654	{ HFI_HEVC_PROFILE_MAIN10, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 },
655};
656
657static const struct id_mapping hevc_levels[] = {
658	{ HFI_HEVC_LEVEL_1, V4L2_MPEG_VIDEO_HEVC_LEVEL_1 },
659	{ HFI_HEVC_LEVEL_2, V4L2_MPEG_VIDEO_HEVC_LEVEL_2 },
660	{ HFI_HEVC_LEVEL_21, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 },
661	{ HFI_HEVC_LEVEL_3, V4L2_MPEG_VIDEO_HEVC_LEVEL_3 },
662	{ HFI_HEVC_LEVEL_31, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 },
663	{ HFI_HEVC_LEVEL_4, V4L2_MPEG_VIDEO_HEVC_LEVEL_4 },
664	{ HFI_HEVC_LEVEL_41, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 },
665	{ HFI_HEVC_LEVEL_5, V4L2_MPEG_VIDEO_HEVC_LEVEL_5 },
666	{ HFI_HEVC_LEVEL_51, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 },
667	{ HFI_HEVC_LEVEL_52, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 },
668	{ HFI_HEVC_LEVEL_6, V4L2_MPEG_VIDEO_HEVC_LEVEL_6 },
669	{ HFI_HEVC_LEVEL_61, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 },
670	{ HFI_HEVC_LEVEL_62, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 },
671};
672
673static const struct id_mapping vp8_profiles[] = {
674	{ HFI_VPX_PROFILE_VERSION_0, V4L2_MPEG_VIDEO_VP8_PROFILE_0 },
675	{ HFI_VPX_PROFILE_VERSION_1, V4L2_MPEG_VIDEO_VP8_PROFILE_1 },
676	{ HFI_VPX_PROFILE_VERSION_2, V4L2_MPEG_VIDEO_VP8_PROFILE_2 },
677	{ HFI_VPX_PROFILE_VERSION_3, V4L2_MPEG_VIDEO_VP8_PROFILE_3 },
678};
679
680static const struct id_mapping vp9_profiles[] = {
681	{ HFI_VP9_PROFILE_P0, V4L2_MPEG_VIDEO_VP9_PROFILE_0 },
682	{ HFI_VP9_PROFILE_P2_10B, V4L2_MPEG_VIDEO_VP9_PROFILE_2 },
683};
684
685static const struct id_mapping vp9_levels[] = {
686	{ HFI_VP9_LEVEL_1, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0 },
687	{ HFI_VP9_LEVEL_11, V4L2_MPEG_VIDEO_VP9_LEVEL_1_1 },
688	{ HFI_VP9_LEVEL_2, V4L2_MPEG_VIDEO_VP9_LEVEL_2_0},
689	{ HFI_VP9_LEVEL_21, V4L2_MPEG_VIDEO_VP9_LEVEL_2_1 },
690	{ HFI_VP9_LEVEL_3, V4L2_MPEG_VIDEO_VP9_LEVEL_3_0},
691	{ HFI_VP9_LEVEL_31, V4L2_MPEG_VIDEO_VP9_LEVEL_3_1 },
692	{ HFI_VP9_LEVEL_4, V4L2_MPEG_VIDEO_VP9_LEVEL_4_0 },
693	{ HFI_VP9_LEVEL_41, V4L2_MPEG_VIDEO_VP9_LEVEL_4_1 },
694	{ HFI_VP9_LEVEL_5, V4L2_MPEG_VIDEO_VP9_LEVEL_5_0 },
695	{ HFI_VP9_LEVEL_51, V4L2_MPEG_VIDEO_VP9_LEVEL_5_1 },
696	{ HFI_VP9_LEVEL_6, V4L2_MPEG_VIDEO_VP9_LEVEL_6_0 },
697	{ HFI_VP9_LEVEL_61, V4L2_MPEG_VIDEO_VP9_LEVEL_6_1 },
698};
699
700static u32 find_v4l2_id(u32 hfi_id, const struct id_mapping *array, unsigned int array_sz)
701{
702	unsigned int i;
703
704	if (!array || !array_sz)
705		return 0;
706
707	for (i = 0; i < array_sz; i++)
708		if (hfi_id == array[i].hfi_id)
709			return array[i].v4l2_id;
710
711	return 0;
712}
713
714static u32 find_hfi_id(u32 v4l2_id, const struct id_mapping *array, unsigned int array_sz)
715{
716	unsigned int i;
717
718	if (!array || !array_sz)
719		return 0;
720
721	for (i = 0; i < array_sz; i++)
722		if (v4l2_id == array[i].v4l2_id)
723			return array[i].hfi_id;
724
725	return 0;
726}
727
728static void
729v4l2_id_profile_level(u32 hfi_codec, struct hfi_profile_level *pl, u32 *profile, u32 *level)
730{
731	u32 hfi_pf = pl->profile;
732	u32 hfi_lvl = pl->level;
733
734	switch (hfi_codec) {
735	case HFI_VIDEO_CODEC_H264:
736		*profile = find_v4l2_id(hfi_pf, h264_profiles, ARRAY_SIZE(h264_profiles));
737		*level = find_v4l2_id(hfi_lvl, h264_levels, ARRAY_SIZE(h264_levels));
738		break;
739	case HFI_VIDEO_CODEC_MPEG2:
740		*profile = find_v4l2_id(hfi_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles));
741		*level = find_v4l2_id(hfi_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels));
742		break;
743	case HFI_VIDEO_CODEC_MPEG4:
744		*profile = find_v4l2_id(hfi_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles));
745		*level = find_v4l2_id(hfi_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels));
746		break;
747	case HFI_VIDEO_CODEC_VP8:
748		*profile = find_v4l2_id(hfi_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles));
749		*level = 0;
750		break;
751	case HFI_VIDEO_CODEC_VP9:
752		*profile = find_v4l2_id(hfi_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles));
753		*level = find_v4l2_id(hfi_lvl, vp9_levels, ARRAY_SIZE(vp9_levels));
754		break;
755	case HFI_VIDEO_CODEC_HEVC:
756		*profile = find_v4l2_id(hfi_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles));
757		*level = find_v4l2_id(hfi_lvl, hevc_levels, ARRAY_SIZE(hevc_levels));
758		break;
759	default:
760		break;
761	}
762}
763
764static void
765hfi_id_profile_level(u32 hfi_codec, u32 v4l2_pf, u32 v4l2_lvl, struct hfi_profile_level *pl)
766{
767	switch (hfi_codec) {
768	case HFI_VIDEO_CODEC_H264:
769		pl->profile = find_hfi_id(v4l2_pf, h264_profiles, ARRAY_SIZE(h264_profiles));
770		pl->level = find_hfi_id(v4l2_lvl, h264_levels, ARRAY_SIZE(h264_levels));
771		break;
772	case HFI_VIDEO_CODEC_MPEG2:
773		pl->profile = find_hfi_id(v4l2_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles));
774		pl->level = find_hfi_id(v4l2_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels));
775		break;
776	case HFI_VIDEO_CODEC_MPEG4:
777		pl->profile = find_hfi_id(v4l2_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles));
778		pl->level = find_hfi_id(v4l2_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels));
779		break;
780	case HFI_VIDEO_CODEC_VP8:
781		pl->profile = find_hfi_id(v4l2_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles));
782		pl->level = 0;
783		break;
784	case HFI_VIDEO_CODEC_VP9:
785		pl->profile = find_hfi_id(v4l2_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles));
786		pl->level = find_hfi_id(v4l2_lvl, vp9_levels, ARRAY_SIZE(vp9_levels));
787		break;
788	case HFI_VIDEO_CODEC_HEVC:
789		pl->profile = find_hfi_id(v4l2_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles));
790		pl->level = find_hfi_id(v4l2_lvl, hevc_levels, ARRAY_SIZE(hevc_levels));
791		break;
792	default:
793		break;
794	}
795}
796
797int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level)
798{
799	const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
800	union hfi_get_property hprop;
801	int ret;
802
803	ret = hfi_session_get_property(inst, ptype, &hprop);
804	if (ret)
805		return ret;
806
807	v4l2_id_profile_level(inst->hfi_codec, &hprop.profile_level, profile, level);
808
809	return 0;
810}
811EXPORT_SYMBOL_GPL(venus_helper_get_profile_level);
812
813int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level)
814{
815	const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
816	struct hfi_profile_level pl;
817
818	hfi_id_profile_level(inst->hfi_codec, profile, level, &pl);
819
820	return hfi_session_set_property(inst, ptype, &pl);
821}
822EXPORT_SYMBOL_GPL(venus_helper_set_profile_level);
823
824static u32 get_framesize_raw_nv12(u32 width, u32 height)
825{
826	u32 y_stride, uv_stride, y_plane;
827	u32 y_sclines, uv_sclines, uv_plane;
828	u32 size;
829
830	y_stride = ALIGN(width, 128);
831	uv_stride = ALIGN(width, 128);
832	y_sclines = ALIGN(height, 32);
833	uv_sclines = ALIGN(((height + 1) >> 1), 16);
834
835	y_plane = y_stride * y_sclines;
836	uv_plane = uv_stride * uv_sclines + SZ_4K;
837	size = y_plane + uv_plane + SZ_8K;
838
839	return ALIGN(size, SZ_4K);
840}
841
842static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height)
843{
844	u32 y_meta_stride, y_meta_plane;
845	u32 y_stride, y_plane;
846	u32 uv_meta_stride, uv_meta_plane;
847	u32 uv_stride, uv_plane;
848	u32 extradata = SZ_16K;
849
850	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
851	y_meta_plane = y_meta_stride * ALIGN(DIV_ROUND_UP(height, 8), 16);
852	y_meta_plane = ALIGN(y_meta_plane, SZ_4K);
853
854	y_stride = ALIGN(width, 128);
855	y_plane = ALIGN(y_stride * ALIGN(height, 32), SZ_4K);
856
857	uv_meta_stride = ALIGN(DIV_ROUND_UP(width / 2, 16), 64);
858	uv_meta_plane = uv_meta_stride * ALIGN(DIV_ROUND_UP(height / 2, 8), 16);
859	uv_meta_plane = ALIGN(uv_meta_plane, SZ_4K);
860
861	uv_stride = ALIGN(width, 128);
862	uv_plane = ALIGN(uv_stride * ALIGN(height / 2, 32), SZ_4K);
863
864	return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane +
865		     max(extradata, y_stride * 48), SZ_4K);
866}
867
868static u32 get_framesize_raw_p010(u32 width, u32 height)
869{
870	u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
871
872	y_stride = ALIGN(width * 2, 256);
873	uv_stride = ALIGN(width * 2, 256);
874	y_sclines = ALIGN(height, 32);
875	uv_sclines = ALIGN((height + 1) >> 1, 16);
876	y_plane = y_stride * y_sclines;
877	uv_plane = uv_stride * uv_sclines;
878
879	return ALIGN((y_plane + uv_plane), SZ_4K);
880}
881
882static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height)
883{
884	u32 y_stride, uv_stride, y_sclines, uv_sclines;
885	u32 y_ubwc_plane, uv_ubwc_plane;
886	u32 y_meta_stride, y_meta_scanlines;
887	u32 uv_meta_stride, uv_meta_scanlines;
888	u32 y_meta_plane, uv_meta_plane;
889	u32 size;
890
891	y_stride = ALIGN(width * 2, 256);
892	uv_stride = ALIGN(width * 2, 256);
893	y_sclines = ALIGN(height, 16);
894	uv_sclines = ALIGN((height + 1) >> 1, 16);
895
896	y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
897	uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
898	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
899	y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
900	y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
901	uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64);
902	uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
903	uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
904
905	size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
906
907	return ALIGN(size, SZ_4K);
908}
909
910static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height)
911{
912	u32 y_stride, uv_stride, y_sclines, uv_sclines;
913	u32 y_ubwc_plane, uv_ubwc_plane;
914	u32 y_meta_stride, y_meta_scanlines;
915	u32 uv_meta_stride, uv_meta_scanlines;
916	u32 y_meta_plane, uv_meta_plane;
917	u32 extradata = SZ_16K;
918	u32 size;
919
920	y_stride = ALIGN(width * 4 / 3, 256);
921	uv_stride = ALIGN(width * 4 / 3, 256);
922	y_sclines = ALIGN(height, 16);
923	uv_sclines = ALIGN((height + 1) >> 1, 16);
924
925	y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
926	uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
927	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64);
928	y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
929	y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
930	uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64);
931	uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
932	uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
933
934	size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
935	size += max(extradata + SZ_8K, y_stride * 48);
936
937	return ALIGN(size, SZ_4K);
938}
939
940u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
941{
942	switch (hfi_fmt) {
943	case HFI_COLOR_FORMAT_NV12:
944	case HFI_COLOR_FORMAT_NV21:
945		return get_framesize_raw_nv12(width, height);
946	case HFI_COLOR_FORMAT_NV12_UBWC:
947		return get_framesize_raw_nv12_ubwc(width, height);
948	case HFI_COLOR_FORMAT_P010:
949		return get_framesize_raw_p010(width, height);
950	case HFI_COLOR_FORMAT_P010_UBWC:
951		return get_framesize_raw_p010_ubwc(width, height);
952	case HFI_COLOR_FORMAT_YUV420_TP10_UBWC:
953		return get_framesize_raw_yuv420_tp10_ubwc(width, height);
954	default:
955		return 0;
956	}
957}
958EXPORT_SYMBOL_GPL(venus_helper_get_framesz_raw);
959
960u32 venus_helper_get_framesz(u32 v4l2_fmt, u32 width, u32 height)
961{
962	u32 hfi_fmt, sz;
963	bool compressed;
964
965	switch (v4l2_fmt) {
966	case V4L2_PIX_FMT_MPEG:
967	case V4L2_PIX_FMT_H264:
968	case V4L2_PIX_FMT_H264_NO_SC:
969	case V4L2_PIX_FMT_H264_MVC:
970	case V4L2_PIX_FMT_H263:
971	case V4L2_PIX_FMT_MPEG1:
972	case V4L2_PIX_FMT_MPEG2:
973	case V4L2_PIX_FMT_MPEG4:
974	case V4L2_PIX_FMT_XVID:
975	case V4L2_PIX_FMT_VC1_ANNEX_G:
976	case V4L2_PIX_FMT_VC1_ANNEX_L:
977	case V4L2_PIX_FMT_VP8:
978	case V4L2_PIX_FMT_VP9:
979	case V4L2_PIX_FMT_HEVC:
980		compressed = true;
981		break;
982	default:
983		compressed = false;
984		break;
985	}
986
987	if (compressed) {
988		sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2 / 2;
989		return ALIGN(sz, SZ_4K);
990	}
991
992	hfi_fmt = to_hfi_raw_fmt(v4l2_fmt);
993	if (!hfi_fmt)
994		return 0;
995
996	return venus_helper_get_framesz_raw(hfi_fmt, width, height);
997}
998EXPORT_SYMBOL_GPL(venus_helper_get_framesz);
999
1000int venus_helper_set_input_resolution(struct venus_inst *inst,
1001				      unsigned int width, unsigned int height)
1002{
1003	u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
1004	struct hfi_framesize fs;
1005
1006	fs.buffer_type = HFI_BUFFER_INPUT;
1007	fs.width = width;
1008	fs.height = height;
1009
1010	return hfi_session_set_property(inst, ptype, &fs);
1011}
1012EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution);
1013
1014int venus_helper_set_output_resolution(struct venus_inst *inst,
1015				       unsigned int width, unsigned int height,
1016				       u32 buftype)
1017{
1018	u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
1019	struct hfi_framesize fs;
1020
1021	fs.buffer_type = buftype;
1022	fs.width = width;
1023	fs.height = height;
1024
1025	return hfi_session_set_property(inst, ptype, &fs);
1026}
1027EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution);
1028
1029int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode)
1030{
1031	const u32 ptype = HFI_PROPERTY_PARAM_WORK_MODE;
1032	struct hfi_video_work_mode wm;
1033
1034	if (!IS_V4(inst->core))
1035		return 0;
1036
1037	wm.video_work_mode = mode;
1038
1039	return hfi_session_set_property(inst, ptype, &wm);
1040}
1041EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
1042
1043int venus_helper_init_codec_freq_data(struct venus_inst *inst)
1044{
1045	const struct codec_freq_data *data;
1046	unsigned int i, data_size;
1047	u32 pixfmt;
1048	int ret = 0;
1049
1050	if (!IS_V4(inst->core))
1051		return 0;
1052
1053	data = inst->core->res->codec_freq_data;
1054	data_size = inst->core->res->codec_freq_data_size;
1055	pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ?
1056			inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
1057
1058	for (i = 0; i < data_size; i++) {
1059		if (data[i].pixfmt == pixfmt &&
1060		    data[i].session_type == inst->session_type) {
1061			inst->clk_data.codec_freq_data = &data[i];
1062			break;
1063		}
1064	}
1065
1066	if (!inst->clk_data.codec_freq_data)
1067		ret = -EINVAL;
1068
1069	return ret;
1070}
1071EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
1072
1073int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
1074			      unsigned int output_bufs,
1075			      unsigned int output2_bufs)
1076{
1077	u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
1078	struct hfi_buffer_count_actual buf_count;
1079	int ret;
1080
1081	buf_count.type = HFI_BUFFER_INPUT;
1082	buf_count.count_actual = input_bufs;
1083
1084	ret = hfi_session_set_property(inst, ptype, &buf_count);
1085	if (ret)
1086		return ret;
1087
1088	buf_count.type = HFI_BUFFER_OUTPUT;
1089	buf_count.count_actual = output_bufs;
1090
1091	ret = hfi_session_set_property(inst, ptype, &buf_count);
1092	if (ret)
1093		return ret;
1094
1095	if (output2_bufs) {
1096		buf_count.type = HFI_BUFFER_OUTPUT2;
1097		buf_count.count_actual = output2_bufs;
1098
1099		ret = hfi_session_set_property(inst, ptype, &buf_count);
1100	}
1101
1102	return ret;
1103}
1104EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs);
1105
1106int venus_helper_set_raw_format(struct venus_inst *inst, u32 hfi_format,
1107				u32 buftype)
1108{
1109	const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
1110	struct hfi_uncompressed_format_select fmt;
1111
1112	fmt.buffer_type = buftype;
1113	fmt.format = hfi_format;
1114
1115	return hfi_session_set_property(inst, ptype, &fmt);
1116}
1117EXPORT_SYMBOL_GPL(venus_helper_set_raw_format);
1118
1119int venus_helper_set_color_format(struct venus_inst *inst, u32 pixfmt)
1120{
1121	u32 hfi_format, buftype;
1122
1123	if (inst->session_type == VIDC_SESSION_TYPE_DEC)
1124		buftype = HFI_BUFFER_OUTPUT;
1125	else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
1126		buftype = HFI_BUFFER_INPUT;
1127	else
1128		return -EINVAL;
1129
1130	hfi_format = to_hfi_raw_fmt(pixfmt);
1131	if (!hfi_format)
1132		return -EINVAL;
1133
1134	return venus_helper_set_raw_format(inst, hfi_format, buftype);
1135}
1136EXPORT_SYMBOL_GPL(venus_helper_set_color_format);
1137
1138int venus_helper_set_multistream(struct venus_inst *inst, bool out_en,
1139				 bool out2_en)
1140{
1141	struct hfi_multi_stream multi = {0};
1142	u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
1143	int ret;
1144
1145	multi.buffer_type = HFI_BUFFER_OUTPUT;
1146	multi.enable = out_en;
1147
1148	ret = hfi_session_set_property(inst, ptype, &multi);
1149	if (ret)
1150		return ret;
1151
1152	multi.buffer_type = HFI_BUFFER_OUTPUT2;
1153	multi.enable = out2_en;
1154
1155	return hfi_session_set_property(inst, ptype, &multi);
1156}
1157EXPORT_SYMBOL_GPL(venus_helper_set_multistream);
1158
1159int venus_helper_set_dyn_bufmode(struct venus_inst *inst)
1160{
1161	const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
1162	struct hfi_buffer_alloc_mode mode;
1163	int ret;
1164
1165	if (!is_dynamic_bufmode(inst))
1166		return 0;
1167
1168	mode.type = HFI_BUFFER_OUTPUT;
1169	mode.mode = HFI_BUFFER_MODE_DYNAMIC;
1170
1171	ret = hfi_session_set_property(inst, ptype, &mode);
1172	if (ret)
1173		return ret;
1174
1175	mode.type = HFI_BUFFER_OUTPUT2;
1176
1177	return hfi_session_set_property(inst, ptype, &mode);
1178}
1179EXPORT_SYMBOL_GPL(venus_helper_set_dyn_bufmode);
1180
1181int venus_helper_set_bufsize(struct venus_inst *inst, u32 bufsize, u32 buftype)
1182{
1183	const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL;
1184	struct hfi_buffer_size_actual bufsz;
1185
1186	bufsz.type = buftype;
1187	bufsz.size = bufsize;
1188
1189	return hfi_session_set_property(inst, ptype, &bufsz);
1190}
1191EXPORT_SYMBOL_GPL(venus_helper_set_bufsize);
1192
1193unsigned int venus_helper_get_opb_size(struct venus_inst *inst)
1194{
1195	/* the encoder has only one output */
1196	if (inst->session_type == VIDC_SESSION_TYPE_ENC)
1197		return inst->output_buf_size;
1198
1199	if (inst->opb_buftype == HFI_BUFFER_OUTPUT)
1200		return inst->output_buf_size;
1201	else if (inst->opb_buftype == HFI_BUFFER_OUTPUT2)
1202		return inst->output2_buf_size;
1203
1204	return 0;
1205}
1206EXPORT_SYMBOL_GPL(venus_helper_get_opb_size);
1207
1208static void delayed_process_buf_func(struct work_struct *work)
1209{
1210	struct venus_buffer *buf, *n;
1211	struct venus_inst *inst;
1212	int ret;
1213
1214	inst = container_of(work, struct venus_inst, delayed_process_work);
1215
1216	mutex_lock(&inst->lock);
1217
1218	if (!(inst->streamon_out & inst->streamon_cap))
1219		goto unlock;
1220
1221	list_for_each_entry_safe(buf, n, &inst->delayed_process, ref_list) {
1222		if (buf->flags & HFI_BUFFERFLAG_READONLY)
1223			continue;
1224
1225		ret = session_process_buf(inst, &buf->vb);
1226		if (ret)
1227			return_buf_error(inst, &buf->vb);
1228
1229		list_del_init(&buf->ref_list);
1230	}
1231unlock:
1232	mutex_unlock(&inst->lock);
1233}
1234
1235void venus_helper_release_buf_ref(struct venus_inst *inst, unsigned int idx)
1236{
1237	struct venus_buffer *buf;
1238
1239	list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
1240		if (buf->vb.vb2_buf.index == idx) {
1241			buf->flags &= ~HFI_BUFFERFLAG_READONLY;
1242			schedule_work(&inst->delayed_process_work);
1243			break;
1244		}
1245	}
1246}
1247EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref);
1248
1249void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer *vbuf)
1250{
1251	struct venus_buffer *buf = to_venus_buffer(vbuf);
1252
1253	buf->flags |= HFI_BUFFERFLAG_READONLY;
1254}
1255EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref);
1256
1257static int is_buf_refed(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
1258{
1259	struct venus_buffer *buf = to_venus_buffer(vbuf);
1260
1261	if (buf->flags & HFI_BUFFERFLAG_READONLY) {
1262		list_add_tail(&buf->ref_list, &inst->delayed_process);
1263		schedule_work(&inst->delayed_process_work);
1264		return 1;
1265	}
1266
1267	return 0;
1268}
1269
1270struct vb2_v4l2_buffer *
1271venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx)
1272{
1273	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1274
1275	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1276		return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx);
1277	else
1278		return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx);
1279}
1280EXPORT_SYMBOL_GPL(venus_helper_find_buf);
1281
1282int venus_helper_vb2_buf_init(struct vb2_buffer *vb)
1283{
1284	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1285	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1286	struct venus_buffer *buf = to_venus_buffer(vbuf);
1287	struct sg_table *sgt;
1288
1289	sgt = vb2_dma_sg_plane_desc(vb, 0);
1290	if (!sgt)
1291		return -EFAULT;
1292
1293	buf->size = vb2_plane_size(vb, 0);
1294	buf->dma_addr = sg_dma_address(sgt->sgl);
1295
1296	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1297		list_add_tail(&buf->reg_list, &inst->registeredbufs);
1298
1299	return 0;
1300}
1301EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init);
1302
1303int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb)
1304{
1305	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1306	unsigned int out_buf_size = venus_helper_get_opb_size(inst);
1307	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1308
1309	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1310		if (vbuf->field == V4L2_FIELD_ANY)
1311			vbuf->field = V4L2_FIELD_NONE;
1312		if (vbuf->field != V4L2_FIELD_NONE) {
1313			dev_err(inst->core->dev, "%s field isn't supported\n",
1314				__func__);
1315			return -EINVAL;
1316		}
1317	}
1318
1319	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
1320	    vb2_plane_size(vb, 0) < out_buf_size)
1321		return -EINVAL;
1322	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
1323	    vb2_plane_size(vb, 0) < inst->input_buf_size)
1324		return -EINVAL;
1325
1326	return 0;
1327}
1328EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare);
1329
1330static void cache_payload(struct venus_inst *inst, struct vb2_buffer *vb)
1331{
1332	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1333	unsigned int idx = vbuf->vb2_buf.index;
1334
1335	if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1336		inst->payloads[idx] = vb2_get_plane_payload(vb, 0);
1337}
1338
1339void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
1340{
1341	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1342	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1343	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1344	int ret;
1345
1346	mutex_lock(&inst->lock);
1347
1348	v4l2_m2m_buf_queue(m2m_ctx, vbuf);
1349
1350	/* Skip processing queued capture buffers after LAST flag */
1351	if (inst->session_type == VIDC_SESSION_TYPE_DEC &&
1352	    V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
1353	    inst->codec_state == VENUS_DEC_STATE_DRC)
1354		goto unlock;
1355
1356	cache_payload(inst, vb);
1357
1358	if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
1359	    !(inst->streamon_out && inst->streamon_cap))
1360		goto unlock;
1361
1362	if (vb2_start_streaming_called(vb->vb2_queue)) {
1363		ret = is_buf_refed(inst, vbuf);
1364		if (ret)
1365			goto unlock;
1366
1367		ret = session_process_buf(inst, vbuf);
1368		if (ret)
1369			return_buf_error(inst, vbuf);
1370	}
1371
1372unlock:
1373	mutex_unlock(&inst->lock);
1374}
1375EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue);
1376
1377void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type,
1378			       enum vb2_buffer_state state)
1379{
1380	struct vb2_v4l2_buffer *buf;
1381
1382	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
1383		while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx)))
1384			v4l2_m2m_buf_done(buf, state);
1385	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
1386		while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
1387			v4l2_m2m_buf_done(buf, state);
1388	}
1389}
1390EXPORT_SYMBOL_GPL(venus_helper_buffers_done);
1391
1392void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
1393{
1394	struct venus_inst *inst = vb2_get_drv_priv(q);
1395	struct venus_core *core = inst->core;
1396	int ret;
1397
1398	mutex_lock(&inst->lock);
1399
1400	if (inst->streamon_out & inst->streamon_cap) {
1401		ret = hfi_session_stop(inst);
1402		ret |= hfi_session_unload_res(inst);
1403		ret |= venus_helper_unregister_bufs(inst);
1404		ret |= venus_helper_intbufs_free(inst);
1405		ret |= hfi_session_deinit(inst);
1406
1407		if (inst->session_error || core->sys_error)
1408			ret = -EIO;
1409
1410		if (ret)
1411			hfi_session_abort(inst);
1412
1413		venus_helper_free_dpb_bufs(inst);
1414
1415		venus_pm_load_scale(inst);
1416		INIT_LIST_HEAD(&inst->registeredbufs);
1417	}
1418
1419	venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
1420				  VB2_BUF_STATE_ERROR);
1421	venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
1422				  VB2_BUF_STATE_ERROR);
1423
1424	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1425		inst->streamon_out = 0;
1426	else
1427		inst->streamon_cap = 0;
1428
1429	venus_pm_release_core(inst);
1430
1431	mutex_unlock(&inst->lock);
1432}
1433EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
1434
1435int venus_helper_process_initial_cap_bufs(struct venus_inst *inst)
1436{
1437	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1438	struct v4l2_m2m_buffer *buf, *n;
1439	int ret;
1440
1441	v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1442		ret = session_process_buf(inst, &buf->vb);
1443		if (ret) {
1444			return_buf_error(inst, &buf->vb);
1445			return ret;
1446		}
1447	}
1448
1449	return 0;
1450}
1451EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
1452
1453int venus_helper_process_initial_out_bufs(struct venus_inst *inst)
1454{
1455	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1456	struct v4l2_m2m_buffer *buf, *n;
1457	int ret;
1458
1459	v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1460		ret = session_process_buf(inst, &buf->vb);
1461		if (ret) {
1462			return_buf_error(inst, &buf->vb);
1463			return ret;
1464		}
1465	}
1466
1467	return 0;
1468}
1469EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
1470
1471int venus_helper_vb2_start_streaming(struct venus_inst *inst)
1472{
1473	int ret;
1474
1475	ret = venus_helper_intbufs_alloc(inst);
1476	if (ret)
1477		return ret;
1478
1479	ret = session_register_bufs(inst);
1480	if (ret)
1481		goto err_bufs_free;
1482
1483	venus_pm_load_scale(inst);
1484
1485	ret = hfi_session_load_res(inst);
1486	if (ret)
1487		goto err_unreg_bufs;
1488
1489	ret = hfi_session_start(inst);
1490	if (ret)
1491		goto err_unload_res;
1492
1493	return 0;
1494
1495err_unload_res:
1496	hfi_session_unload_res(inst);
1497err_unreg_bufs:
1498	venus_helper_unregister_bufs(inst);
1499err_bufs_free:
1500	venus_helper_intbufs_free(inst);
1501	return ret;
1502}
1503EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
1504
1505void venus_helper_m2m_device_run(void *priv)
1506{
1507	struct venus_inst *inst = priv;
1508	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1509	struct v4l2_m2m_buffer *buf, *n;
1510	int ret;
1511
1512	mutex_lock(&inst->lock);
1513
1514	v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1515		ret = session_process_buf(inst, &buf->vb);
1516		if (ret)
1517			return_buf_error(inst, &buf->vb);
1518	}
1519
1520	v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1521		ret = session_process_buf(inst, &buf->vb);
1522		if (ret)
1523			return_buf_error(inst, &buf->vb);
1524	}
1525
1526	mutex_unlock(&inst->lock);
1527}
1528EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run);
1529
1530void venus_helper_m2m_job_abort(void *priv)
1531{
1532	struct venus_inst *inst = priv;
1533
1534	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
1535}
1536EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
1537
1538void venus_helper_init_instance(struct venus_inst *inst)
1539{
1540	if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1541		INIT_LIST_HEAD(&inst->delayed_process);
1542		INIT_WORK(&inst->delayed_process_work,
1543			  delayed_process_buf_func);
1544	}
1545}
1546EXPORT_SYMBOL_GPL(venus_helper_init_instance);
1547
1548static bool find_fmt_from_caps(struct venus_caps *caps, u32 buftype, u32 fmt)
1549{
1550	unsigned int i;
1551
1552	for (i = 0; i < caps->num_fmts; i++) {
1553		if (caps->fmts[i].buftype == buftype &&
1554		    caps->fmts[i].fmt == fmt)
1555			return true;
1556	}
1557
1558	return false;
1559}
1560
1561int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
1562			      u32 *out_fmt, u32 *out2_fmt, bool ubwc)
1563{
1564	struct venus_core *core = inst->core;
1565	struct venus_caps *caps;
1566	u32 ubwc_fmt, fmt = to_hfi_raw_fmt(v4l2_fmt);
1567	bool found, found_ubwc;
1568
1569	*out_fmt = *out2_fmt = 0;
1570
1571	if (!fmt)
1572		return -EINVAL;
1573
1574	caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
1575	if (!caps)
1576		return -EINVAL;
1577
1578	if (inst->bit_depth == VIDC_BITDEPTH_10 &&
1579	    inst->session_type == VIDC_SESSION_TYPE_DEC) {
1580		found_ubwc =
1581			find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1582					   HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
1583		found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
1584					   HFI_COLOR_FORMAT_NV12);
1585		if (found_ubwc && found) {
1586			/*
1587			 * Hard-code DPB buffers to be 10bit UBWC and decoder
1588			 * output buffers in 8bit NV12 until V4L2 is able to
1589			 * expose compressed/tiled formats to applications.
1590			 */
1591			*out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
1592			*out2_fmt = HFI_COLOR_FORMAT_NV12;
1593			return 0;
1594		}
1595
1596		return -EINVAL;
1597	}
1598
1599	if (ubwc) {
1600		ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
1601		found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1602						ubwc_fmt);
1603		found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1604
1605		if (found_ubwc && found) {
1606			*out_fmt = ubwc_fmt;
1607			*out2_fmt = fmt;
1608			return 0;
1609		}
1610	}
1611
1612	found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt);
1613	if (found) {
1614		*out_fmt = fmt;
1615		*out2_fmt = 0;
1616		return 0;
1617	}
1618
1619	found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1620	if (found) {
1621		*out_fmt = 0;
1622		*out2_fmt = fmt;
1623		return 0;
1624	}
1625
1626	return -EINVAL;
1627}
1628EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
1629