xref: /linux/drivers/media/platform/qcom/venus/helpers.c (revision 06ed6aa56ffac9241e03a24649e8d048f8f1b10c)
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 <media/videobuf2-dma-sg.h>
10 #include <media/v4l2-mem2mem.h>
11 #include <asm/div64.h>
12 
13 #include "core.h"
14 #include "helpers.h"
15 #include "hfi_helper.h"
16 #include "pm_helpers.h"
17 
18 struct intbuf {
19 	struct list_head list;
20 	u32 type;
21 	size_t size;
22 	void *va;
23 	dma_addr_t da;
24 	unsigned long attrs;
25 };
26 
27 bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt)
28 {
29 	struct venus_core *core = inst->core;
30 	u32 session_type = inst->session_type;
31 	u32 codec;
32 
33 	switch (v4l2_pixfmt) {
34 	case V4L2_PIX_FMT_H264:
35 		codec = HFI_VIDEO_CODEC_H264;
36 		break;
37 	case V4L2_PIX_FMT_H263:
38 		codec = HFI_VIDEO_CODEC_H263;
39 		break;
40 	case V4L2_PIX_FMT_MPEG1:
41 		codec = HFI_VIDEO_CODEC_MPEG1;
42 		break;
43 	case V4L2_PIX_FMT_MPEG2:
44 		codec = HFI_VIDEO_CODEC_MPEG2;
45 		break;
46 	case V4L2_PIX_FMT_MPEG4:
47 		codec = HFI_VIDEO_CODEC_MPEG4;
48 		break;
49 	case V4L2_PIX_FMT_VC1_ANNEX_G:
50 	case V4L2_PIX_FMT_VC1_ANNEX_L:
51 		codec = HFI_VIDEO_CODEC_VC1;
52 		break;
53 	case V4L2_PIX_FMT_VP8:
54 		codec = HFI_VIDEO_CODEC_VP8;
55 		break;
56 	case V4L2_PIX_FMT_VP9:
57 		codec = HFI_VIDEO_CODEC_VP9;
58 		break;
59 	case V4L2_PIX_FMT_XVID:
60 		codec = HFI_VIDEO_CODEC_DIVX;
61 		break;
62 	case V4L2_PIX_FMT_HEVC:
63 		codec = HFI_VIDEO_CODEC_HEVC;
64 		break;
65 	default:
66 		return false;
67 	}
68 
69 	if (session_type == VIDC_SESSION_TYPE_ENC && core->enc_codecs & codec)
70 		return true;
71 
72 	if (session_type == VIDC_SESSION_TYPE_DEC && core->dec_codecs & codec)
73 		return true;
74 
75 	return false;
76 }
77 EXPORT_SYMBOL_GPL(venus_helper_check_codec);
78 
79 int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
80 {
81 	struct intbuf *buf;
82 	int ret = 0;
83 
84 	list_for_each_entry(buf, &inst->dpbbufs, list) {
85 		struct hfi_frame_data fdata;
86 
87 		memset(&fdata, 0, sizeof(fdata));
88 		fdata.alloc_len = buf->size;
89 		fdata.device_addr = buf->da;
90 		fdata.buffer_type = buf->type;
91 
92 		ret = hfi_session_process_buf(inst, &fdata);
93 		if (ret)
94 			goto fail;
95 	}
96 
97 fail:
98 	return ret;
99 }
100 EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs);
101 
102 int venus_helper_free_dpb_bufs(struct venus_inst *inst)
103 {
104 	struct intbuf *buf, *n;
105 
106 	list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) {
107 		list_del_init(&buf->list);
108 		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
109 			       buf->attrs);
110 		kfree(buf);
111 	}
112 
113 	INIT_LIST_HEAD(&inst->dpbbufs);
114 
115 	return 0;
116 }
117 EXPORT_SYMBOL_GPL(venus_helper_free_dpb_bufs);
118 
119 int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
120 {
121 	struct venus_core *core = inst->core;
122 	struct device *dev = core->dev;
123 	enum hfi_version ver = core->res->hfi_version;
124 	struct hfi_buffer_requirements bufreq;
125 	u32 buftype = inst->dpb_buftype;
126 	unsigned int dpb_size = 0;
127 	struct intbuf *buf;
128 	unsigned int i;
129 	u32 count;
130 	int ret;
131 
132 	/* no need to allocate dpb buffers */
133 	if (!inst->dpb_fmt)
134 		return 0;
135 
136 	if (inst->dpb_buftype == HFI_BUFFER_OUTPUT)
137 		dpb_size = inst->output_buf_size;
138 	else if (inst->dpb_buftype == HFI_BUFFER_OUTPUT2)
139 		dpb_size = inst->output2_buf_size;
140 
141 	if (!dpb_size)
142 		return 0;
143 
144 	ret = venus_helper_get_bufreq(inst, buftype, &bufreq);
145 	if (ret)
146 		return ret;
147 
148 	count = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
149 
150 	for (i = 0; i < count; i++) {
151 		buf = kzalloc(sizeof(*buf), GFP_KERNEL);
152 		if (!buf) {
153 			ret = -ENOMEM;
154 			goto fail;
155 		}
156 
157 		buf->type = buftype;
158 		buf->size = dpb_size;
159 		buf->attrs = DMA_ATTR_WRITE_COMBINE |
160 			     DMA_ATTR_NO_KERNEL_MAPPING;
161 		buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
162 					  buf->attrs);
163 		if (!buf->va) {
164 			kfree(buf);
165 			ret = -ENOMEM;
166 			goto fail;
167 		}
168 
169 		list_add_tail(&buf->list, &inst->dpbbufs);
170 	}
171 
172 	return 0;
173 
174 fail:
175 	venus_helper_free_dpb_bufs(inst);
176 	return ret;
177 }
178 EXPORT_SYMBOL_GPL(venus_helper_alloc_dpb_bufs);
179 
180 static int intbufs_set_buffer(struct venus_inst *inst, u32 type)
181 {
182 	struct venus_core *core = inst->core;
183 	struct device *dev = core->dev;
184 	struct hfi_buffer_requirements bufreq;
185 	struct hfi_buffer_desc bd;
186 	struct intbuf *buf;
187 	unsigned int i;
188 	int ret;
189 
190 	ret = venus_helper_get_bufreq(inst, type, &bufreq);
191 	if (ret)
192 		return 0;
193 
194 	if (!bufreq.size)
195 		return 0;
196 
197 	for (i = 0; i < bufreq.count_actual; i++) {
198 		buf = kzalloc(sizeof(*buf), GFP_KERNEL);
199 		if (!buf) {
200 			ret = -ENOMEM;
201 			goto fail;
202 		}
203 
204 		buf->type = bufreq.type;
205 		buf->size = bufreq.size;
206 		buf->attrs = DMA_ATTR_WRITE_COMBINE |
207 			     DMA_ATTR_NO_KERNEL_MAPPING;
208 		buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
209 					  buf->attrs);
210 		if (!buf->va) {
211 			ret = -ENOMEM;
212 			goto fail;
213 		}
214 
215 		memset(&bd, 0, sizeof(bd));
216 		bd.buffer_size = buf->size;
217 		bd.buffer_type = buf->type;
218 		bd.num_buffers = 1;
219 		bd.device_addr = buf->da;
220 
221 		ret = hfi_session_set_buffers(inst, &bd);
222 		if (ret) {
223 			dev_err(dev, "set session buffers failed\n");
224 			goto dma_free;
225 		}
226 
227 		list_add_tail(&buf->list, &inst->internalbufs);
228 	}
229 
230 	return 0;
231 
232 dma_free:
233 	dma_free_attrs(dev, buf->size, buf->va, buf->da, buf->attrs);
234 fail:
235 	kfree(buf);
236 	return ret;
237 }
238 
239 static int intbufs_unset_buffers(struct venus_inst *inst)
240 {
241 	struct hfi_buffer_desc bd = {0};
242 	struct intbuf *buf, *n;
243 	int ret = 0;
244 
245 	list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
246 		bd.buffer_size = buf->size;
247 		bd.buffer_type = buf->type;
248 		bd.num_buffers = 1;
249 		bd.device_addr = buf->da;
250 		bd.response_required = true;
251 
252 		ret = hfi_session_unset_buffers(inst, &bd);
253 
254 		list_del_init(&buf->list);
255 		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
256 			       buf->attrs);
257 		kfree(buf);
258 	}
259 
260 	return ret;
261 }
262 
263 static const unsigned int intbuf_types_1xx[] = {
264 	HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_1XX),
265 	HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_1XX),
266 	HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_1XX),
267 	HFI_BUFFER_INTERNAL_PERSIST,
268 	HFI_BUFFER_INTERNAL_PERSIST_1,
269 };
270 
271 static const unsigned int intbuf_types_4xx[] = {
272 	HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_4XX),
273 	HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_4XX),
274 	HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_4XX),
275 	HFI_BUFFER_INTERNAL_PERSIST,
276 	HFI_BUFFER_INTERNAL_PERSIST_1,
277 };
278 
279 int venus_helper_intbufs_alloc(struct venus_inst *inst)
280 {
281 	const unsigned int *intbuf;
282 	size_t arr_sz, i;
283 	int ret;
284 
285 	if (IS_V4(inst->core)) {
286 		arr_sz = ARRAY_SIZE(intbuf_types_4xx);
287 		intbuf = intbuf_types_4xx;
288 	} else {
289 		arr_sz = ARRAY_SIZE(intbuf_types_1xx);
290 		intbuf = intbuf_types_1xx;
291 	}
292 
293 	for (i = 0; i < arr_sz; i++) {
294 		ret = intbufs_set_buffer(inst, intbuf[i]);
295 		if (ret)
296 			goto error;
297 	}
298 
299 	return 0;
300 
301 error:
302 	intbufs_unset_buffers(inst);
303 	return ret;
304 }
305 EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc);
306 
307 int venus_helper_intbufs_free(struct venus_inst *inst)
308 {
309 	return intbufs_unset_buffers(inst);
310 }
311 EXPORT_SYMBOL_GPL(venus_helper_intbufs_free);
312 
313 int venus_helper_intbufs_realloc(struct venus_inst *inst)
314 {
315 	enum hfi_version ver = inst->core->res->hfi_version;
316 	struct hfi_buffer_desc bd;
317 	struct intbuf *buf, *n;
318 	int ret;
319 
320 	list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
321 		if (buf->type == HFI_BUFFER_INTERNAL_PERSIST ||
322 		    buf->type == HFI_BUFFER_INTERNAL_PERSIST_1)
323 			continue;
324 
325 		memset(&bd, 0, sizeof(bd));
326 		bd.buffer_size = buf->size;
327 		bd.buffer_type = buf->type;
328 		bd.num_buffers = 1;
329 		bd.device_addr = buf->da;
330 		bd.response_required = true;
331 
332 		ret = hfi_session_unset_buffers(inst, &bd);
333 
334 		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
335 			       buf->attrs);
336 
337 		list_del_init(&buf->list);
338 		kfree(buf);
339 	}
340 
341 	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH(ver));
342 	if (ret)
343 		goto err;
344 
345 	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_1(ver));
346 	if (ret)
347 		goto err;
348 
349 	ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_2(ver));
350 	if (ret)
351 		goto err;
352 
353 	return 0;
354 err:
355 	return ret;
356 }
357 EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
358 
359 static void fill_buffer_desc(const struct venus_buffer *buf,
360 			     struct hfi_buffer_desc *bd, bool response)
361 {
362 	memset(bd, 0, sizeof(*bd));
363 	bd->buffer_type = HFI_BUFFER_OUTPUT;
364 	bd->buffer_size = buf->size;
365 	bd->num_buffers = 1;
366 	bd->device_addr = buf->dma_addr;
367 	bd->response_required = response;
368 }
369 
370 static void return_buf_error(struct venus_inst *inst,
371 			     struct vb2_v4l2_buffer *vbuf)
372 {
373 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
374 
375 	if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
376 		v4l2_m2m_src_buf_remove_by_buf(m2m_ctx, vbuf);
377 	else
378 		v4l2_m2m_dst_buf_remove_by_buf(m2m_ctx, vbuf);
379 
380 	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
381 }
382 
383 static void
384 put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
385 {
386 	struct vb2_buffer *vb = &vbuf->vb2_buf;
387 	unsigned int i;
388 	int slot = -1;
389 	u64 ts_us = vb->timestamp;
390 
391 	for (i = 0; i < ARRAY_SIZE(inst->tss); i++) {
392 		if (!inst->tss[i].used) {
393 			slot = i;
394 			break;
395 		}
396 	}
397 
398 	if (slot == -1) {
399 		dev_dbg(inst->core->dev, "%s: no free slot\n", __func__);
400 		return;
401 	}
402 
403 	do_div(ts_us, NSEC_PER_USEC);
404 
405 	inst->tss[slot].used = true;
406 	inst->tss[slot].flags = vbuf->flags;
407 	inst->tss[slot].tc = vbuf->timecode;
408 	inst->tss[slot].ts_us = ts_us;
409 	inst->tss[slot].ts_ns = vb->timestamp;
410 }
411 
412 void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
413 				  struct vb2_v4l2_buffer *vbuf)
414 {
415 	struct vb2_buffer *vb = &vbuf->vb2_buf;
416 	unsigned int i;
417 
418 	for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) {
419 		if (!inst->tss[i].used)
420 			continue;
421 
422 		if (inst->tss[i].ts_us != timestamp_us)
423 			continue;
424 
425 		inst->tss[i].used = false;
426 		vbuf->flags |= inst->tss[i].flags;
427 		vbuf->timecode = inst->tss[i].tc;
428 		vb->timestamp = inst->tss[i].ts_ns;
429 		break;
430 	}
431 }
432 EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata);
433 
434 static int
435 session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
436 {
437 	struct venus_buffer *buf = to_venus_buffer(vbuf);
438 	struct vb2_buffer *vb = &vbuf->vb2_buf;
439 	unsigned int type = vb->type;
440 	struct hfi_frame_data fdata;
441 	int ret;
442 
443 	memset(&fdata, 0, sizeof(fdata));
444 	fdata.alloc_len = buf->size;
445 	fdata.device_addr = buf->dma_addr;
446 	fdata.timestamp = vb->timestamp;
447 	do_div(fdata.timestamp, NSEC_PER_USEC);
448 	fdata.flags = 0;
449 	fdata.clnt_data = vbuf->vb2_buf.index;
450 
451 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
452 		fdata.buffer_type = HFI_BUFFER_INPUT;
453 		fdata.filled_len = vb2_get_plane_payload(vb, 0);
454 		fdata.offset = vb->planes[0].data_offset;
455 
456 		if (vbuf->flags & V4L2_BUF_FLAG_LAST || !fdata.filled_len)
457 			fdata.flags |= HFI_BUFFERFLAG_EOS;
458 
459 		if (inst->session_type == VIDC_SESSION_TYPE_DEC)
460 			put_ts_metadata(inst, vbuf);
461 
462 		venus_pm_load_scale(inst);
463 	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
464 		if (inst->session_type == VIDC_SESSION_TYPE_ENC)
465 			fdata.buffer_type = HFI_BUFFER_OUTPUT;
466 		else
467 			fdata.buffer_type = inst->opb_buftype;
468 		fdata.filled_len = 0;
469 		fdata.offset = 0;
470 	}
471 
472 	ret = hfi_session_process_buf(inst, &fdata);
473 	if (ret)
474 		return ret;
475 
476 	return 0;
477 }
478 
479 static bool is_dynamic_bufmode(struct venus_inst *inst)
480 {
481 	struct venus_core *core = inst->core;
482 	struct venus_caps *caps;
483 
484 	/*
485 	 * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports
486 	 * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2.
487 	 */
488 	if (IS_V4(core))
489 		return true;
490 
491 	caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
492 	if (!caps)
493 		return false;
494 
495 	return caps->cap_bufs_mode_dynamic;
496 }
497 
498 int venus_helper_unregister_bufs(struct venus_inst *inst)
499 {
500 	struct venus_buffer *buf, *n;
501 	struct hfi_buffer_desc bd;
502 	int ret = 0;
503 
504 	if (is_dynamic_bufmode(inst))
505 		return 0;
506 
507 	list_for_each_entry_safe(buf, n, &inst->registeredbufs, reg_list) {
508 		fill_buffer_desc(buf, &bd, true);
509 		ret = hfi_session_unset_buffers(inst, &bd);
510 		list_del_init(&buf->reg_list);
511 	}
512 
513 	return ret;
514 }
515 EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs);
516 
517 static int session_register_bufs(struct venus_inst *inst)
518 {
519 	struct venus_core *core = inst->core;
520 	struct device *dev = core->dev;
521 	struct hfi_buffer_desc bd;
522 	struct venus_buffer *buf;
523 	int ret = 0;
524 
525 	if (is_dynamic_bufmode(inst))
526 		return 0;
527 
528 	list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
529 		fill_buffer_desc(buf, &bd, false);
530 		ret = hfi_session_set_buffers(inst, &bd);
531 		if (ret) {
532 			dev_err(dev, "%s: set buffer failed\n", __func__);
533 			break;
534 		}
535 	}
536 
537 	return ret;
538 }
539 
540 static u32 to_hfi_raw_fmt(u32 v4l2_fmt)
541 {
542 	switch (v4l2_fmt) {
543 	case V4L2_PIX_FMT_NV12:
544 		return HFI_COLOR_FORMAT_NV12;
545 	case V4L2_PIX_FMT_NV21:
546 		return HFI_COLOR_FORMAT_NV21;
547 	default:
548 		break;
549 	}
550 
551 	return 0;
552 }
553 
554 int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
555 			    struct hfi_buffer_requirements *req)
556 {
557 	u32 ptype = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
558 	union hfi_get_property hprop;
559 	unsigned int i;
560 	int ret;
561 
562 	if (req)
563 		memset(req, 0, sizeof(*req));
564 
565 	ret = hfi_session_get_property(inst, ptype, &hprop);
566 	if (ret)
567 		return ret;
568 
569 	ret = -EINVAL;
570 
571 	for (i = 0; i < HFI_BUFFER_TYPE_MAX; i++) {
572 		if (hprop.bufreq[i].type != type)
573 			continue;
574 
575 		if (req)
576 			memcpy(req, &hprop.bufreq[i], sizeof(*req));
577 		ret = 0;
578 		break;
579 	}
580 
581 	return ret;
582 }
583 EXPORT_SYMBOL_GPL(venus_helper_get_bufreq);
584 
585 static u32 get_framesize_raw_nv12(u32 width, u32 height)
586 {
587 	u32 y_stride, uv_stride, y_plane;
588 	u32 y_sclines, uv_sclines, uv_plane;
589 	u32 size;
590 
591 	y_stride = ALIGN(width, 128);
592 	uv_stride = ALIGN(width, 128);
593 	y_sclines = ALIGN(height, 32);
594 	uv_sclines = ALIGN(((height + 1) >> 1), 16);
595 
596 	y_plane = y_stride * y_sclines;
597 	uv_plane = uv_stride * uv_sclines + SZ_4K;
598 	size = y_plane + uv_plane + SZ_8K;
599 
600 	return ALIGN(size, SZ_4K);
601 }
602 
603 static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height)
604 {
605 	u32 y_meta_stride, y_meta_plane;
606 	u32 y_stride, y_plane;
607 	u32 uv_meta_stride, uv_meta_plane;
608 	u32 uv_stride, uv_plane;
609 	u32 extradata = SZ_16K;
610 
611 	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
612 	y_meta_plane = y_meta_stride * ALIGN(DIV_ROUND_UP(height, 8), 16);
613 	y_meta_plane = ALIGN(y_meta_plane, SZ_4K);
614 
615 	y_stride = ALIGN(width, 128);
616 	y_plane = ALIGN(y_stride * ALIGN(height, 32), SZ_4K);
617 
618 	uv_meta_stride = ALIGN(DIV_ROUND_UP(width / 2, 16), 64);
619 	uv_meta_plane = uv_meta_stride * ALIGN(DIV_ROUND_UP(height / 2, 8), 16);
620 	uv_meta_plane = ALIGN(uv_meta_plane, SZ_4K);
621 
622 	uv_stride = ALIGN(width, 128);
623 	uv_plane = ALIGN(uv_stride * ALIGN(height / 2, 32), SZ_4K);
624 
625 	return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane +
626 		     max(extradata, y_stride * 48), SZ_4K);
627 }
628 
629 static u32 get_framesize_raw_p010(u32 width, u32 height)
630 {
631 	u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
632 
633 	y_stride = ALIGN(width * 2, 256);
634 	uv_stride = ALIGN(width * 2, 256);
635 	y_sclines = ALIGN(height, 32);
636 	uv_sclines = ALIGN((height + 1) >> 1, 16);
637 	y_plane = y_stride * y_sclines;
638 	uv_plane = uv_stride * uv_sclines;
639 
640 	return ALIGN((y_plane + uv_plane), SZ_4K);
641 }
642 
643 static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height)
644 {
645 	u32 y_stride, uv_stride, y_sclines, uv_sclines;
646 	u32 y_ubwc_plane, uv_ubwc_plane;
647 	u32 y_meta_stride, y_meta_scanlines;
648 	u32 uv_meta_stride, uv_meta_scanlines;
649 	u32 y_meta_plane, uv_meta_plane;
650 	u32 size;
651 
652 	y_stride = ALIGN(width * 2, 256);
653 	uv_stride = ALIGN(width * 2, 256);
654 	y_sclines = ALIGN(height, 16);
655 	uv_sclines = ALIGN((height + 1) >> 1, 16);
656 
657 	y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
658 	uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
659 	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
660 	y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
661 	y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
662 	uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64);
663 	uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
664 	uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
665 
666 	size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
667 
668 	return ALIGN(size, SZ_4K);
669 }
670 
671 static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height)
672 {
673 	u32 y_stride, uv_stride, y_sclines, uv_sclines;
674 	u32 y_ubwc_plane, uv_ubwc_plane;
675 	u32 y_meta_stride, y_meta_scanlines;
676 	u32 uv_meta_stride, uv_meta_scanlines;
677 	u32 y_meta_plane, uv_meta_plane;
678 	u32 extradata = SZ_16K;
679 	u32 size;
680 
681 	y_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
682 	uv_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
683 	y_sclines = ALIGN(height, 16);
684 	uv_sclines = ALIGN((height + 1) >> 1, 16);
685 
686 	y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
687 	uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
688 	y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64);
689 	y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
690 	y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
691 	uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64);
692 	uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
693 	uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
694 
695 	size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
696 	size += max(extradata + SZ_8K, y_stride * 48);
697 
698 	return ALIGN(size, SZ_4K);
699 }
700 
701 u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
702 {
703 	switch (hfi_fmt) {
704 	case HFI_COLOR_FORMAT_NV12:
705 	case HFI_COLOR_FORMAT_NV21:
706 		return get_framesize_raw_nv12(width, height);
707 	case HFI_COLOR_FORMAT_NV12_UBWC:
708 		return get_framesize_raw_nv12_ubwc(width, height);
709 	case HFI_COLOR_FORMAT_P010:
710 		return get_framesize_raw_p010(width, height);
711 	case HFI_COLOR_FORMAT_P010_UBWC:
712 		return get_framesize_raw_p010_ubwc(width, height);
713 	case HFI_COLOR_FORMAT_YUV420_TP10_UBWC:
714 		return get_framesize_raw_yuv420_tp10_ubwc(width, height);
715 	default:
716 		return 0;
717 	}
718 }
719 EXPORT_SYMBOL_GPL(venus_helper_get_framesz_raw);
720 
721 u32 venus_helper_get_framesz(u32 v4l2_fmt, u32 width, u32 height)
722 {
723 	u32 hfi_fmt, sz;
724 	bool compressed;
725 
726 	switch (v4l2_fmt) {
727 	case V4L2_PIX_FMT_MPEG:
728 	case V4L2_PIX_FMT_H264:
729 	case V4L2_PIX_FMT_H264_NO_SC:
730 	case V4L2_PIX_FMT_H264_MVC:
731 	case V4L2_PIX_FMT_H263:
732 	case V4L2_PIX_FMT_MPEG1:
733 	case V4L2_PIX_FMT_MPEG2:
734 	case V4L2_PIX_FMT_MPEG4:
735 	case V4L2_PIX_FMT_XVID:
736 	case V4L2_PIX_FMT_VC1_ANNEX_G:
737 	case V4L2_PIX_FMT_VC1_ANNEX_L:
738 	case V4L2_PIX_FMT_VP8:
739 	case V4L2_PIX_FMT_VP9:
740 	case V4L2_PIX_FMT_HEVC:
741 		compressed = true;
742 		break;
743 	default:
744 		compressed = false;
745 		break;
746 	}
747 
748 	if (compressed) {
749 		sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2 / 2;
750 		return ALIGN(sz, SZ_4K);
751 	}
752 
753 	hfi_fmt = to_hfi_raw_fmt(v4l2_fmt);
754 	if (!hfi_fmt)
755 		return 0;
756 
757 	return venus_helper_get_framesz_raw(hfi_fmt, width, height);
758 }
759 EXPORT_SYMBOL_GPL(venus_helper_get_framesz);
760 
761 int venus_helper_set_input_resolution(struct venus_inst *inst,
762 				      unsigned int width, unsigned int height)
763 {
764 	u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
765 	struct hfi_framesize fs;
766 
767 	fs.buffer_type = HFI_BUFFER_INPUT;
768 	fs.width = width;
769 	fs.height = height;
770 
771 	return hfi_session_set_property(inst, ptype, &fs);
772 }
773 EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution);
774 
775 int venus_helper_set_output_resolution(struct venus_inst *inst,
776 				       unsigned int width, unsigned int height,
777 				       u32 buftype)
778 {
779 	u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
780 	struct hfi_framesize fs;
781 
782 	fs.buffer_type = buftype;
783 	fs.width = width;
784 	fs.height = height;
785 
786 	return hfi_session_set_property(inst, ptype, &fs);
787 }
788 EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution);
789 
790 int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode)
791 {
792 	const u32 ptype = HFI_PROPERTY_PARAM_WORK_MODE;
793 	struct hfi_video_work_mode wm;
794 
795 	if (!IS_V4(inst->core))
796 		return 0;
797 
798 	wm.video_work_mode = mode;
799 
800 	return hfi_session_set_property(inst, ptype, &wm);
801 }
802 EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
803 
804 int venus_helper_init_codec_freq_data(struct venus_inst *inst)
805 {
806 	const struct codec_freq_data *data;
807 	unsigned int i, data_size;
808 	u32 pixfmt;
809 	int ret = 0;
810 
811 	if (!IS_V4(inst->core))
812 		return 0;
813 
814 	data = inst->core->res->codec_freq_data;
815 	data_size = inst->core->res->codec_freq_data_size;
816 	pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ?
817 			inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
818 
819 	for (i = 0; i < data_size; i++) {
820 		if (data[i].pixfmt == pixfmt &&
821 		    data[i].session_type == inst->session_type) {
822 			inst->clk_data.codec_freq_data = &data[i];
823 			break;
824 		}
825 	}
826 
827 	if (!inst->clk_data.codec_freq_data)
828 		ret = -EINVAL;
829 
830 	return ret;
831 }
832 EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
833 
834 int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
835 			      unsigned int output_bufs,
836 			      unsigned int output2_bufs)
837 {
838 	u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
839 	struct hfi_buffer_count_actual buf_count;
840 	int ret;
841 
842 	buf_count.type = HFI_BUFFER_INPUT;
843 	buf_count.count_actual = input_bufs;
844 
845 	ret = hfi_session_set_property(inst, ptype, &buf_count);
846 	if (ret)
847 		return ret;
848 
849 	buf_count.type = HFI_BUFFER_OUTPUT;
850 	buf_count.count_actual = output_bufs;
851 
852 	ret = hfi_session_set_property(inst, ptype, &buf_count);
853 	if (ret)
854 		return ret;
855 
856 	if (output2_bufs) {
857 		buf_count.type = HFI_BUFFER_OUTPUT2;
858 		buf_count.count_actual = output2_bufs;
859 
860 		ret = hfi_session_set_property(inst, ptype, &buf_count);
861 	}
862 
863 	return ret;
864 }
865 EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs);
866 
867 int venus_helper_set_raw_format(struct venus_inst *inst, u32 hfi_format,
868 				u32 buftype)
869 {
870 	const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
871 	struct hfi_uncompressed_format_select fmt;
872 
873 	fmt.buffer_type = buftype;
874 	fmt.format = hfi_format;
875 
876 	return hfi_session_set_property(inst, ptype, &fmt);
877 }
878 EXPORT_SYMBOL_GPL(venus_helper_set_raw_format);
879 
880 int venus_helper_set_color_format(struct venus_inst *inst, u32 pixfmt)
881 {
882 	u32 hfi_format, buftype;
883 
884 	if (inst->session_type == VIDC_SESSION_TYPE_DEC)
885 		buftype = HFI_BUFFER_OUTPUT;
886 	else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
887 		buftype = HFI_BUFFER_INPUT;
888 	else
889 		return -EINVAL;
890 
891 	hfi_format = to_hfi_raw_fmt(pixfmt);
892 	if (!hfi_format)
893 		return -EINVAL;
894 
895 	return venus_helper_set_raw_format(inst, hfi_format, buftype);
896 }
897 EXPORT_SYMBOL_GPL(venus_helper_set_color_format);
898 
899 int venus_helper_set_multistream(struct venus_inst *inst, bool out_en,
900 				 bool out2_en)
901 {
902 	struct hfi_multi_stream multi = {0};
903 	u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
904 	int ret;
905 
906 	multi.buffer_type = HFI_BUFFER_OUTPUT;
907 	multi.enable = out_en;
908 
909 	ret = hfi_session_set_property(inst, ptype, &multi);
910 	if (ret)
911 		return ret;
912 
913 	multi.buffer_type = HFI_BUFFER_OUTPUT2;
914 	multi.enable = out2_en;
915 
916 	return hfi_session_set_property(inst, ptype, &multi);
917 }
918 EXPORT_SYMBOL_GPL(venus_helper_set_multistream);
919 
920 int venus_helper_set_dyn_bufmode(struct venus_inst *inst)
921 {
922 	const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
923 	struct hfi_buffer_alloc_mode mode;
924 	int ret;
925 
926 	if (!is_dynamic_bufmode(inst))
927 		return 0;
928 
929 	mode.type = HFI_BUFFER_OUTPUT;
930 	mode.mode = HFI_BUFFER_MODE_DYNAMIC;
931 
932 	ret = hfi_session_set_property(inst, ptype, &mode);
933 	if (ret)
934 		return ret;
935 
936 	mode.type = HFI_BUFFER_OUTPUT2;
937 
938 	return hfi_session_set_property(inst, ptype, &mode);
939 }
940 EXPORT_SYMBOL_GPL(venus_helper_set_dyn_bufmode);
941 
942 int venus_helper_set_bufsize(struct venus_inst *inst, u32 bufsize, u32 buftype)
943 {
944 	const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL;
945 	struct hfi_buffer_size_actual bufsz;
946 
947 	bufsz.type = buftype;
948 	bufsz.size = bufsize;
949 
950 	return hfi_session_set_property(inst, ptype, &bufsz);
951 }
952 EXPORT_SYMBOL_GPL(venus_helper_set_bufsize);
953 
954 unsigned int venus_helper_get_opb_size(struct venus_inst *inst)
955 {
956 	/* the encoder has only one output */
957 	if (inst->session_type == VIDC_SESSION_TYPE_ENC)
958 		return inst->output_buf_size;
959 
960 	if (inst->opb_buftype == HFI_BUFFER_OUTPUT)
961 		return inst->output_buf_size;
962 	else if (inst->opb_buftype == HFI_BUFFER_OUTPUT2)
963 		return inst->output2_buf_size;
964 
965 	return 0;
966 }
967 EXPORT_SYMBOL_GPL(venus_helper_get_opb_size);
968 
969 static void delayed_process_buf_func(struct work_struct *work)
970 {
971 	struct venus_buffer *buf, *n;
972 	struct venus_inst *inst;
973 	int ret;
974 
975 	inst = container_of(work, struct venus_inst, delayed_process_work);
976 
977 	mutex_lock(&inst->lock);
978 
979 	if (!(inst->streamon_out & inst->streamon_cap))
980 		goto unlock;
981 
982 	list_for_each_entry_safe(buf, n, &inst->delayed_process, ref_list) {
983 		if (buf->flags & HFI_BUFFERFLAG_READONLY)
984 			continue;
985 
986 		ret = session_process_buf(inst, &buf->vb);
987 		if (ret)
988 			return_buf_error(inst, &buf->vb);
989 
990 		list_del_init(&buf->ref_list);
991 	}
992 unlock:
993 	mutex_unlock(&inst->lock);
994 }
995 
996 void venus_helper_release_buf_ref(struct venus_inst *inst, unsigned int idx)
997 {
998 	struct venus_buffer *buf;
999 
1000 	list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
1001 		if (buf->vb.vb2_buf.index == idx) {
1002 			buf->flags &= ~HFI_BUFFERFLAG_READONLY;
1003 			schedule_work(&inst->delayed_process_work);
1004 			break;
1005 		}
1006 	}
1007 }
1008 EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref);
1009 
1010 void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer *vbuf)
1011 {
1012 	struct venus_buffer *buf = to_venus_buffer(vbuf);
1013 
1014 	buf->flags |= HFI_BUFFERFLAG_READONLY;
1015 }
1016 EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref);
1017 
1018 static int is_buf_refed(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
1019 {
1020 	struct venus_buffer *buf = to_venus_buffer(vbuf);
1021 
1022 	if (buf->flags & HFI_BUFFERFLAG_READONLY) {
1023 		list_add_tail(&buf->ref_list, &inst->delayed_process);
1024 		schedule_work(&inst->delayed_process_work);
1025 		return 1;
1026 	}
1027 
1028 	return 0;
1029 }
1030 
1031 struct vb2_v4l2_buffer *
1032 venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx)
1033 {
1034 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1035 
1036 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1037 		return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx);
1038 	else
1039 		return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx);
1040 }
1041 EXPORT_SYMBOL_GPL(venus_helper_find_buf);
1042 
1043 int venus_helper_vb2_buf_init(struct vb2_buffer *vb)
1044 {
1045 	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1046 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1047 	struct venus_buffer *buf = to_venus_buffer(vbuf);
1048 	struct sg_table *sgt;
1049 
1050 	sgt = vb2_dma_sg_plane_desc(vb, 0);
1051 	if (!sgt)
1052 		return -EFAULT;
1053 
1054 	buf->size = vb2_plane_size(vb, 0);
1055 	buf->dma_addr = sg_dma_address(sgt->sgl);
1056 
1057 	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1058 		list_add_tail(&buf->reg_list, &inst->registeredbufs);
1059 
1060 	return 0;
1061 }
1062 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init);
1063 
1064 int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb)
1065 {
1066 	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1067 	unsigned int out_buf_size = venus_helper_get_opb_size(inst);
1068 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1069 
1070 	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1071 		if (vbuf->field == V4L2_FIELD_ANY)
1072 			vbuf->field = V4L2_FIELD_NONE;
1073 		if (vbuf->field != V4L2_FIELD_NONE) {
1074 			dev_err(inst->core->dev, "%s field isn't supported\n",
1075 				__func__);
1076 			return -EINVAL;
1077 		}
1078 	}
1079 
1080 	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
1081 	    vb2_plane_size(vb, 0) < out_buf_size)
1082 		return -EINVAL;
1083 	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
1084 	    vb2_plane_size(vb, 0) < inst->input_buf_size)
1085 		return -EINVAL;
1086 
1087 	return 0;
1088 }
1089 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare);
1090 
1091 static void cache_payload(struct venus_inst *inst, struct vb2_buffer *vb)
1092 {
1093 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1094 	unsigned int idx = vbuf->vb2_buf.index;
1095 
1096 	if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1097 		inst->payloads[idx] = vb2_get_plane_payload(vb, 0);
1098 }
1099 
1100 void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
1101 {
1102 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1103 	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1104 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1105 	int ret;
1106 
1107 	mutex_lock(&inst->lock);
1108 
1109 	v4l2_m2m_buf_queue(m2m_ctx, vbuf);
1110 
1111 	cache_payload(inst, vb);
1112 
1113 	if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
1114 	    !(inst->streamon_out && inst->streamon_cap))
1115 		goto unlock;
1116 
1117 	if (vb2_start_streaming_called(vb->vb2_queue)) {
1118 		ret = is_buf_refed(inst, vbuf);
1119 		if (ret)
1120 			goto unlock;
1121 
1122 		ret = session_process_buf(inst, vbuf);
1123 		if (ret)
1124 			return_buf_error(inst, vbuf);
1125 	}
1126 
1127 unlock:
1128 	mutex_unlock(&inst->lock);
1129 }
1130 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue);
1131 
1132 void venus_helper_buffers_done(struct venus_inst *inst,
1133 			       enum vb2_buffer_state state)
1134 {
1135 	struct vb2_v4l2_buffer *buf;
1136 
1137 	while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx)))
1138 		v4l2_m2m_buf_done(buf, state);
1139 	while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
1140 		v4l2_m2m_buf_done(buf, state);
1141 }
1142 EXPORT_SYMBOL_GPL(venus_helper_buffers_done);
1143 
1144 void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
1145 {
1146 	struct venus_inst *inst = vb2_get_drv_priv(q);
1147 	struct venus_core *core = inst->core;
1148 	int ret;
1149 
1150 	mutex_lock(&inst->lock);
1151 
1152 	if (inst->streamon_out & inst->streamon_cap) {
1153 		ret = hfi_session_stop(inst);
1154 		ret |= hfi_session_unload_res(inst);
1155 		ret |= venus_helper_unregister_bufs(inst);
1156 		ret |= venus_helper_intbufs_free(inst);
1157 		ret |= hfi_session_deinit(inst);
1158 
1159 		if (inst->session_error || core->sys_error)
1160 			ret = -EIO;
1161 
1162 		if (ret)
1163 			hfi_session_abort(inst);
1164 
1165 		venus_helper_free_dpb_bufs(inst);
1166 
1167 		venus_pm_load_scale(inst);
1168 		INIT_LIST_HEAD(&inst->registeredbufs);
1169 	}
1170 
1171 	venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR);
1172 
1173 	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1174 		inst->streamon_out = 0;
1175 	else
1176 		inst->streamon_cap = 0;
1177 
1178 	venus_pm_release_core(inst);
1179 
1180 	mutex_unlock(&inst->lock);
1181 }
1182 EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
1183 
1184 int venus_helper_process_initial_cap_bufs(struct venus_inst *inst)
1185 {
1186 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1187 	struct v4l2_m2m_buffer *buf, *n;
1188 	int ret;
1189 
1190 	v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1191 		ret = session_process_buf(inst, &buf->vb);
1192 		if (ret) {
1193 			return_buf_error(inst, &buf->vb);
1194 			return ret;
1195 		}
1196 	}
1197 
1198 	return 0;
1199 }
1200 EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
1201 
1202 int venus_helper_process_initial_out_bufs(struct venus_inst *inst)
1203 {
1204 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1205 	struct v4l2_m2m_buffer *buf, *n;
1206 	int ret;
1207 
1208 	v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1209 		ret = session_process_buf(inst, &buf->vb);
1210 		if (ret) {
1211 			return_buf_error(inst, &buf->vb);
1212 			return ret;
1213 		}
1214 	}
1215 
1216 	return 0;
1217 }
1218 EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
1219 
1220 int venus_helper_vb2_start_streaming(struct venus_inst *inst)
1221 {
1222 	int ret;
1223 
1224 	ret = venus_helper_intbufs_alloc(inst);
1225 	if (ret)
1226 		return ret;
1227 
1228 	ret = session_register_bufs(inst);
1229 	if (ret)
1230 		goto err_bufs_free;
1231 
1232 	venus_pm_load_scale(inst);
1233 
1234 	ret = hfi_session_load_res(inst);
1235 	if (ret)
1236 		goto err_unreg_bufs;
1237 
1238 	ret = hfi_session_start(inst);
1239 	if (ret)
1240 		goto err_unload_res;
1241 
1242 	return 0;
1243 
1244 err_unload_res:
1245 	hfi_session_unload_res(inst);
1246 err_unreg_bufs:
1247 	venus_helper_unregister_bufs(inst);
1248 err_bufs_free:
1249 	venus_helper_intbufs_free(inst);
1250 	return ret;
1251 }
1252 EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
1253 
1254 void venus_helper_m2m_device_run(void *priv)
1255 {
1256 	struct venus_inst *inst = priv;
1257 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1258 	struct v4l2_m2m_buffer *buf, *n;
1259 	int ret;
1260 
1261 	mutex_lock(&inst->lock);
1262 
1263 	v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1264 		ret = session_process_buf(inst, &buf->vb);
1265 		if (ret)
1266 			return_buf_error(inst, &buf->vb);
1267 	}
1268 
1269 	v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1270 		ret = session_process_buf(inst, &buf->vb);
1271 		if (ret)
1272 			return_buf_error(inst, &buf->vb);
1273 	}
1274 
1275 	mutex_unlock(&inst->lock);
1276 }
1277 EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run);
1278 
1279 void venus_helper_m2m_job_abort(void *priv)
1280 {
1281 	struct venus_inst *inst = priv;
1282 
1283 	v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
1284 }
1285 EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
1286 
1287 void venus_helper_init_instance(struct venus_inst *inst)
1288 {
1289 	if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1290 		INIT_LIST_HEAD(&inst->delayed_process);
1291 		INIT_WORK(&inst->delayed_process_work,
1292 			  delayed_process_buf_func);
1293 	}
1294 }
1295 EXPORT_SYMBOL_GPL(venus_helper_init_instance);
1296 
1297 static bool find_fmt_from_caps(struct venus_caps *caps, u32 buftype, u32 fmt)
1298 {
1299 	unsigned int i;
1300 
1301 	for (i = 0; i < caps->num_fmts; i++) {
1302 		if (caps->fmts[i].buftype == buftype &&
1303 		    caps->fmts[i].fmt == fmt)
1304 			return true;
1305 	}
1306 
1307 	return false;
1308 }
1309 
1310 int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
1311 			      u32 *out_fmt, u32 *out2_fmt, bool ubwc)
1312 {
1313 	struct venus_core *core = inst->core;
1314 	struct venus_caps *caps;
1315 	u32 ubwc_fmt, fmt = to_hfi_raw_fmt(v4l2_fmt);
1316 	bool found, found_ubwc;
1317 
1318 	*out_fmt = *out2_fmt = 0;
1319 
1320 	if (!fmt)
1321 		return -EINVAL;
1322 
1323 	caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
1324 	if (!caps)
1325 		return -EINVAL;
1326 
1327 	if (inst->bit_depth == VIDC_BITDEPTH_10 &&
1328 	    inst->session_type == VIDC_SESSION_TYPE_DEC) {
1329 		found_ubwc =
1330 			find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1331 					   HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
1332 		found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
1333 					   HFI_COLOR_FORMAT_NV12);
1334 		if (found_ubwc && found) {
1335 			/*
1336 			 * Hard-code DPB buffers to be 10bit UBWC and decoder
1337 			 * output buffers in 8bit NV12 until V4L2 is able to
1338 			 * expose compressed/tiled formats to applications.
1339 			 */
1340 			*out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
1341 			*out2_fmt = HFI_COLOR_FORMAT_NV12;
1342 			return 0;
1343 		}
1344 
1345 		return -EINVAL;
1346 	}
1347 
1348 	if (ubwc) {
1349 		ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
1350 		found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1351 						ubwc_fmt);
1352 		found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1353 
1354 		if (found_ubwc && found) {
1355 			*out_fmt = ubwc_fmt;
1356 			*out2_fmt = fmt;
1357 			return 0;
1358 		}
1359 	}
1360 
1361 	found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt);
1362 	if (found) {
1363 		*out_fmt = fmt;
1364 		*out2_fmt = 0;
1365 		return 0;
1366 	}
1367 
1368 	found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1369 	if (found) {
1370 		*out_fmt = 0;
1371 		*out2_fmt = fmt;
1372 		return 0;
1373 	}
1374 
1375 	return -EINVAL;
1376 }
1377 EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
1378