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