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
19 struct 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
venus_helper_check_codec(struct venus_inst * inst,u32 v4l2_pixfmt)28 bool 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 }
78 EXPORT_SYMBOL_GPL(venus_helper_check_codec);
79
venus_helper_queue_dpb_bufs(struct venus_inst * inst)80 int 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
98 fail:
99 return ret;
100 }
101 EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs);
102
venus_helper_free_dpb_bufs(struct venus_inst * inst)103 int 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 }
118 EXPORT_SYMBOL_GPL(venus_helper_free_dpb_bufs);
119
venus_helper_alloc_dpb_bufs(struct venus_inst * inst)120 int 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
175 fail:
176 venus_helper_free_dpb_bufs(inst);
177 return ret;
178 }
179 EXPORT_SYMBOL_GPL(venus_helper_alloc_dpb_bufs);
180
intbufs_set_buffer(struct venus_inst * inst,u32 type)181 static 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
233 dma_free:
234 dma_free_attrs(dev, buf->size, buf->va, buf->da, buf->attrs);
235 fail:
236 kfree(buf);
237 return ret;
238 }
239
intbufs_unset_buffers(struct venus_inst * inst)240 static 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
264 static 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
272 static 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
venus_helper_intbufs_alloc(struct venus_inst * inst)280 int 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
302 error:
303 intbufs_unset_buffers(inst);
304 return ret;
305 }
306 EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc);
307
venus_helper_intbufs_free(struct venus_inst * inst)308 int venus_helper_intbufs_free(struct venus_inst *inst)
309 {
310 return intbufs_unset_buffers(inst);
311 }
312 EXPORT_SYMBOL_GPL(venus_helper_intbufs_free);
313
venus_helper_intbufs_realloc(struct venus_inst * inst)314 int 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;
355 err:
356 return ret;
357 }
358 EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
359
fill_buffer_desc(const struct venus_buffer * buf,struct hfi_buffer_desc * bd,bool response)360 static 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
return_buf_error(struct venus_inst * inst,struct vb2_v4l2_buffer * vbuf)371 static 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
384 static void
put_ts_metadata(struct venus_inst * inst,struct vb2_v4l2_buffer * vbuf)385 put_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
venus_helper_get_ts_metadata(struct venus_inst * inst,u64 timestamp_us,struct vb2_v4l2_buffer * vbuf)413 void 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 }
433 EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata);
434
435 static int
session_process_buf(struct venus_inst * inst,struct vb2_v4l2_buffer * vbuf)436 session_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
is_dynamic_bufmode(struct venus_inst * inst)480 static 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
venus_helper_unregister_bufs(struct venus_inst * inst)499 int 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 }
516 EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs);
517
session_register_bufs(struct venus_inst * inst)518 static 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
to_hfi_raw_fmt(u32 v4l2_fmt)541 static 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
venus_helper_get_bufreq(struct venus_inst * inst,u32 type,struct hfi_buffer_requirements * req)555 int 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 }
584 EXPORT_SYMBOL_GPL(venus_helper_get_bufreq);
585
586 struct id_mapping {
587 u32 hfi_id;
588 u32 v4l2_id;
589 };
590
591 static 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
596 static 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
606 static 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
614 static 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
621 static 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
631 static 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
651 static 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
657 static 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
673 static 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
680 static 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
685 static 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
find_v4l2_id(u32 hfi_id,const struct id_mapping * array,unsigned int array_sz)700 static 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
find_hfi_id(u32 v4l2_id,const struct id_mapping * array,unsigned int array_sz)714 static 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
728 static void
v4l2_id_profile_level(u32 hfi_codec,struct hfi_profile_level * pl,u32 * profile,u32 * level)729 v4l2_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
764 static void
hfi_id_profile_level(u32 hfi_codec,u32 v4l2_pf,u32 v4l2_lvl,struct hfi_profile_level * pl)765 hfi_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
venus_helper_get_profile_level(struct venus_inst * inst,u32 * profile,u32 * level)797 int 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 }
811 EXPORT_SYMBOL_GPL(venus_helper_get_profile_level);
812
venus_helper_set_profile_level(struct venus_inst * inst,u32 profile,u32 level)813 int 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 }
822 EXPORT_SYMBOL_GPL(venus_helper_set_profile_level);
823
get_framesize_raw_nv12(u32 width,u32 height)824 static 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
get_framesize_raw_nv12_ubwc(u32 width,u32 height)842 static 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
get_framesize_raw_p010(u32 width,u32 height)868 static 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
get_framesize_raw_p010_ubwc(u32 width,u32 height)882 static 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
get_framesize_raw_yuv420_tp10_ubwc(u32 width,u32 height)910 static 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
venus_helper_get_framesz_raw(u32 hfi_fmt,u32 width,u32 height)940 u32 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 }
958 EXPORT_SYMBOL_GPL(venus_helper_get_framesz_raw);
959
venus_helper_get_framesz(u32 v4l2_fmt,u32 width,u32 height)960 u32 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 }
998 EXPORT_SYMBOL_GPL(venus_helper_get_framesz);
999
venus_helper_set_input_resolution(struct venus_inst * inst,unsigned int width,unsigned int height)1000 int 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 }
1012 EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution);
1013
venus_helper_set_output_resolution(struct venus_inst * inst,unsigned int width,unsigned int height,u32 buftype)1014 int 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 }
1027 EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution);
1028
venus_helper_set_work_mode(struct venus_inst * inst,u32 mode)1029 int 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 }
1041 EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
1042
venus_helper_init_codec_freq_data(struct venus_inst * inst)1043 int 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 }
1071 EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
1072
venus_helper_set_num_bufs(struct venus_inst * inst,unsigned int input_bufs,unsigned int output_bufs,unsigned int output2_bufs)1073 int 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 }
1104 EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs);
1105
venus_helper_set_raw_format(struct venus_inst * inst,u32 hfi_format,u32 buftype)1106 int 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 }
1117 EXPORT_SYMBOL_GPL(venus_helper_set_raw_format);
1118
venus_helper_set_color_format(struct venus_inst * inst,u32 pixfmt)1119 int 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 }
1136 EXPORT_SYMBOL_GPL(venus_helper_set_color_format);
1137
venus_helper_set_multistream(struct venus_inst * inst,bool out_en,bool out2_en)1138 int 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 }
1157 EXPORT_SYMBOL_GPL(venus_helper_set_multistream);
1158
venus_helper_set_dyn_bufmode(struct venus_inst * inst)1159 int 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 }
1179 EXPORT_SYMBOL_GPL(venus_helper_set_dyn_bufmode);
1180
venus_helper_set_bufsize(struct venus_inst * inst,u32 bufsize,u32 buftype)1181 int 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 }
1191 EXPORT_SYMBOL_GPL(venus_helper_set_bufsize);
1192
venus_helper_get_opb_size(struct venus_inst * inst)1193 unsigned 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 }
1206 EXPORT_SYMBOL_GPL(venus_helper_get_opb_size);
1207
delayed_process_buf_func(struct work_struct * work)1208 static 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 }
1231 unlock:
1232 mutex_unlock(&inst->lock);
1233 }
1234
venus_helper_release_buf_ref(struct venus_inst * inst,unsigned int idx)1235 void 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 }
1247 EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref);
1248
venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer * vbuf)1249 void 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 }
1255 EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref);
1256
is_buf_refed(struct venus_inst * inst,struct vb2_v4l2_buffer * vbuf)1257 static 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
1270 struct vb2_v4l2_buffer *
venus_helper_find_buf(struct venus_inst * inst,unsigned int type,u32 idx)1271 venus_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 }
1280 EXPORT_SYMBOL_GPL(venus_helper_find_buf);
1281
venus_helper_vb2_buf_init(struct vb2_buffer * vb)1282 int 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 }
1301 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init);
1302
venus_helper_vb2_buf_prepare(struct vb2_buffer * vb)1303 int 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 }
1328 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare);
1329
cache_payload(struct venus_inst * inst,struct vb2_buffer * vb)1330 static 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
venus_helper_vb2_buf_queue(struct vb2_buffer * vb)1339 void 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
1372 unlock:
1373 mutex_unlock(&inst->lock);
1374 }
1375 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue);
1376
venus_helper_buffers_done(struct venus_inst * inst,unsigned int type,enum vb2_buffer_state state)1377 void 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 }
1390 EXPORT_SYMBOL_GPL(venus_helper_buffers_done);
1391
venus_helper_vb2_stop_streaming(struct vb2_queue * q)1392 void 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 }
1433 EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
1434
venus_helper_process_initial_cap_bufs(struct venus_inst * inst)1435 int 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 }
1451 EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
1452
venus_helper_process_initial_out_bufs(struct venus_inst * inst)1453 int 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 }
1469 EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
1470
venus_helper_vb2_start_streaming(struct venus_inst * inst)1471 int 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
1495 err_unload_res:
1496 hfi_session_unload_res(inst);
1497 err_unreg_bufs:
1498 venus_helper_unregister_bufs(inst);
1499 err_bufs_free:
1500 venus_helper_intbufs_free(inst);
1501 return ret;
1502 }
1503 EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
1504
venus_helper_m2m_device_run(void * priv)1505 void 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 }
1528 EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run);
1529
venus_helper_m2m_job_abort(void * priv)1530 void 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 }
1536 EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
1537
venus_helper_init_instance(struct venus_inst * inst)1538 void 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 }
1546 EXPORT_SYMBOL_GPL(venus_helper_init_instance);
1547
find_fmt_from_caps(struct venus_caps * caps,u32 buftype,u32 fmt)1548 static 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
venus_helper_get_out_fmts(struct venus_inst * inst,u32 v4l2_fmt,u32 * out_fmt,u32 * out2_fmt,bool ubwc)1561 int 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 }
1628 EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
1629