1
2
3
4
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
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
487
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(ALIGN(width, 192) * 4 / 3, 256);
921 uv_stride = ALIGN(ALIGN(width, 192) * 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
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 cache_payload(inst, vb);
1351
1352 if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
1353 !(inst->streamon_out && inst->streamon_cap))
1354 goto unlock;
1355
1356 if (vb2_start_streaming_called(vb->vb2_queue)) {
1357 ret = is_buf_refed(inst, vbuf);
1358 if (ret)
1359 goto unlock;
1360
1361 ret = session_process_buf(inst, vbuf);
1362 if (ret)
1363 return_buf_error(inst, vbuf);
1364 }
1365
1366unlock:
1367 mutex_unlock(&inst->lock);
1368}
1369EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue);
1370
1371void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type,
1372 enum vb2_buffer_state state)
1373{
1374 struct vb2_v4l2_buffer *buf;
1375
1376 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
1377 while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx)))
1378 v4l2_m2m_buf_done(buf, state);
1379 } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
1380 while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
1381 v4l2_m2m_buf_done(buf, state);
1382 }
1383}
1384EXPORT_SYMBOL_GPL(venus_helper_buffers_done);
1385
1386void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
1387{
1388 struct venus_inst *inst = vb2_get_drv_priv(q);
1389 struct venus_core *core = inst->core;
1390 int ret;
1391
1392 mutex_lock(&inst->lock);
1393
1394 if (inst->streamon_out & inst->streamon_cap) {
1395 ret = hfi_session_stop(inst);
1396 ret |= hfi_session_unload_res(inst);
1397 ret |= venus_helper_unregister_bufs(inst);
1398 ret |= venus_helper_intbufs_free(inst);
1399 ret |= hfi_session_deinit(inst);
1400
1401 if (inst->session_error || core->sys_error)
1402 ret = -EIO;
1403
1404 if (ret)
1405 hfi_session_abort(inst);
1406
1407 venus_helper_free_dpb_bufs(inst);
1408
1409 venus_pm_load_scale(inst);
1410 INIT_LIST_HEAD(&inst->registeredbufs);
1411 }
1412
1413 venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
1414 VB2_BUF_STATE_ERROR);
1415 venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
1416 VB2_BUF_STATE_ERROR);
1417
1418 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1419 inst->streamon_out = 0;
1420 else
1421 inst->streamon_cap = 0;
1422
1423 venus_pm_release_core(inst);
1424
1425 mutex_unlock(&inst->lock);
1426}
1427EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
1428
1429int venus_helper_process_initial_cap_bufs(struct venus_inst *inst)
1430{
1431 struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1432 struct v4l2_m2m_buffer *buf, *n;
1433 int ret;
1434
1435 v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1436 ret = session_process_buf(inst, &buf->vb);
1437 if (ret) {
1438 return_buf_error(inst, &buf->vb);
1439 return ret;
1440 }
1441 }
1442
1443 return 0;
1444}
1445EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
1446
1447int venus_helper_process_initial_out_bufs(struct venus_inst *inst)
1448{
1449 struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1450 struct v4l2_m2m_buffer *buf, *n;
1451 int ret;
1452
1453 v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1454 ret = session_process_buf(inst, &buf->vb);
1455 if (ret) {
1456 return_buf_error(inst, &buf->vb);
1457 return ret;
1458 }
1459 }
1460
1461 return 0;
1462}
1463EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
1464
1465int venus_helper_vb2_start_streaming(struct venus_inst *inst)
1466{
1467 int ret;
1468
1469 ret = venus_helper_intbufs_alloc(inst);
1470 if (ret)
1471 return ret;
1472
1473 ret = session_register_bufs(inst);
1474 if (ret)
1475 goto err_bufs_free;
1476
1477 venus_pm_load_scale(inst);
1478
1479 ret = hfi_session_load_res(inst);
1480 if (ret)
1481 goto err_unreg_bufs;
1482
1483 ret = hfi_session_start(inst);
1484 if (ret)
1485 goto err_unload_res;
1486
1487 return 0;
1488
1489err_unload_res:
1490 hfi_session_unload_res(inst);
1491err_unreg_bufs:
1492 venus_helper_unregister_bufs(inst);
1493err_bufs_free:
1494 venus_helper_intbufs_free(inst);
1495 return ret;
1496}
1497EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
1498
1499void venus_helper_m2m_device_run(void *priv)
1500{
1501 struct venus_inst *inst = priv;
1502 struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1503 struct v4l2_m2m_buffer *buf, *n;
1504 int ret;
1505
1506 mutex_lock(&inst->lock);
1507
1508 v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1509 ret = session_process_buf(inst, &buf->vb);
1510 if (ret)
1511 return_buf_error(inst, &buf->vb);
1512 }
1513
1514 v4l2_m2m_for_each_src_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 mutex_unlock(&inst->lock);
1521}
1522EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run);
1523
1524void venus_helper_m2m_job_abort(void *priv)
1525{
1526 struct venus_inst *inst = priv;
1527
1528 v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
1529}
1530EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
1531
1532void venus_helper_init_instance(struct venus_inst *inst)
1533{
1534 if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1535 INIT_LIST_HEAD(&inst->delayed_process);
1536 INIT_WORK(&inst->delayed_process_work,
1537 delayed_process_buf_func);
1538 }
1539}
1540EXPORT_SYMBOL_GPL(venus_helper_init_instance);
1541
1542static bool find_fmt_from_caps(struct venus_caps *caps, u32 buftype, u32 fmt)
1543{
1544 unsigned int i;
1545
1546 for (i = 0; i < caps->num_fmts; i++) {
1547 if (caps->fmts[i].buftype == buftype &&
1548 caps->fmts[i].fmt == fmt)
1549 return true;
1550 }
1551
1552 return false;
1553}
1554
1555int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
1556 u32 *out_fmt, u32 *out2_fmt, bool ubwc)
1557{
1558 struct venus_core *core = inst->core;
1559 struct venus_caps *caps;
1560 u32 ubwc_fmt, fmt = to_hfi_raw_fmt(v4l2_fmt);
1561 bool found, found_ubwc;
1562
1563 *out_fmt = *out2_fmt = 0;
1564
1565 if (!fmt)
1566 return -EINVAL;
1567
1568 caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
1569 if (!caps)
1570 return -EINVAL;
1571
1572 if (inst->bit_depth == VIDC_BITDEPTH_10 &&
1573 inst->session_type == VIDC_SESSION_TYPE_DEC) {
1574 found_ubwc =
1575 find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1576 HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
1577 found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
1578 HFI_COLOR_FORMAT_NV12);
1579 if (found_ubwc && found) {
1580
1581
1582
1583
1584
1585 *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
1586 *out2_fmt = HFI_COLOR_FORMAT_NV12;
1587 return 0;
1588 }
1589
1590 return -EINVAL;
1591 }
1592
1593 if (ubwc) {
1594 ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
1595 found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1596 ubwc_fmt);
1597 found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1598
1599 if (found_ubwc && found) {
1600 *out_fmt = ubwc_fmt;
1601 *out2_fmt = fmt;
1602 return 0;
1603 }
1604 }
1605
1606 found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt);
1607 if (found) {
1608 *out_fmt = fmt;
1609 *out2_fmt = 0;
1610 return 0;
1611 }
1612
1613 found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1614 if (found) {
1615 *out_fmt = 0;
1616 *out2_fmt = fmt;
1617 return 0;
1618 }
1619
1620 return -EINVAL;
1621}
1622EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
1623