Commit | Line | Data |
---|---|---|
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 | |
21 | struct 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 |
30 | bool 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 | } | |
80 | EXPORT_SYMBOL_GPL(venus_helper_check_codec); | |
81 | ||
f012b23d SV |
82 | static 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 | ||
100 | fail: | |
101 | return ret; | |
102 | } | |
103 | ||
104 | int 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 | } | |
119 | EXPORT_SYMBOL_GPL(venus_helper_free_dpb_bufs); | |
120 | ||
121 | int 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 | ||
176 | fail: | |
177 | venus_helper_free_dpb_bufs(inst); | |
178 | return ret; | |
179 | } | |
180 | EXPORT_SYMBOL_GPL(venus_helper_alloc_dpb_bufs); | |
181 | ||
af2c3834 SV |
182 | static 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 | ||
234 | dma_free: | |
235 | dma_free_attrs(dev, buf->size, buf->va, buf->da, buf->attrs); | |
236 | fail: | |
237 | kfree(buf); | |
238 | return ret; | |
239 | } | |
240 | ||
241 | static 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 |
265 | static 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 | ||
273 | static 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 | ||
281 | static 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 | ||
303 | error: | |
304 | intbufs_unset_buffers(inst); | |
305 | return ret; | |
306 | } | |
307 | ||
308 | static int intbufs_free(struct venus_inst *inst) | |
309 | { | |
310 | return intbufs_unset_buffers(inst); | |
311 | } | |
312 | ||
313 | static 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 | ||
325 | static 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 | ||
342 | static 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 | ||
371 | set_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 | |
387 | err: | |
388 | dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret); | |
389 | return ret; | |
af2c3834 SV |
390 | } |
391 | ||
392 | static 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 | ||
403 | static 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 | ||
416 | static int | |
417 | session_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 | 456 | static 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 | ||
468 | static 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 | ||
486 | static 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 |
509 | static 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 |
523 | int 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 | } | |
552 | EXPORT_SYMBOL_GPL(venus_helper_get_bufreq); | |
553 | ||
e1cb72de SV |
554 | static 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 | ||
572 | static 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 | ||
598 | u32 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 | } | |
610 | EXPORT_SYMBOL_GPL(venus_helper_get_framesz_raw); | |
611 | ||
612 | u32 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 | } | |
650 | EXPORT_SYMBOL_GPL(venus_helper_get_framesz); | |
651 | ||
af2c3834 SV |
652 | int 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 | } | |
664 | EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution); | |
665 | ||
666 | int 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 | } | |
679 | EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution); | |
680 | ||
01165b84 SV |
681 | int 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 | } | |
693 | EXPORT_SYMBOL_GPL(venus_helper_set_work_mode); | |
694 | ||
695 | int 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 | } | |
707 | EXPORT_SYMBOL_GPL(venus_helper_set_core_usage); | |
708 | ||
af2c3834 | 709 | int 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 | } |
740 | EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs); | |
741 | ||
ab97a3fb SV |
742 | int 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 | } | |
753 | EXPORT_SYMBOL_GPL(venus_helper_set_raw_format); | |
754 | ||
755 | int 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 | } |
772 | EXPORT_SYMBOL_GPL(venus_helper_set_color_format); | |
773 | ||
f012b23d SV |
774 | int 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 | } | |
793 | EXPORT_SYMBOL_GPL(venus_helper_set_multistream); | |
794 | ||
2b0a8517 SV |
795 | int 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 | } | |
815 | EXPORT_SYMBOL_GPL(venus_helper_set_dyn_bufmode); | |
816 | ||
d4a5b0a6 SV |
817 | int 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 | } | |
827 | EXPORT_SYMBOL_GPL(venus_helper_set_bufsize); | |
828 | ||
130c0117 SV |
829 | unsigned 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 | } | |
842 | EXPORT_SYMBOL_GPL(venus_helper_get_opb_size); | |
843 | ||
af2c3834 SV |
844 | static 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 | } | |
867 | unlock: | |
868 | mutex_unlock(&inst->lock); | |
869 | } | |
870 | ||
871 | void 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 | } | |
883 | EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref); | |
884 | ||
885 | void 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 | } | |
891 | EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref); | |
892 | ||
893 | static 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 | ||
906 | struct vb2_v4l2_buffer * | |
907 | venus_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 | } | |
916 | EXPORT_SYMBOL_GPL(venus_helper_find_buf); | |
917 | ||
918 | int 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 | } | |
937 | EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init); | |
938 | ||
939 | int 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 | } | |
953 | EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare); | |
954 | ||
955 | void 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 | ||
977 | unlock: | |
978 | mutex_unlock(&inst->lock); | |
979 | } | |
980 | EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue); | |
981 | ||
982 | void 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 | } | |
992 | EXPORT_SYMBOL_GPL(venus_helper_buffers_done); | |
993 | ||
994 | void 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 | } | |
1030 | EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); | |
1031 | ||
1032 | int 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 |
1061 | err_session_stop: |
1062 | hfi_session_stop(inst); | |
af2c3834 SV |
1063 | err_unload_res: |
1064 | hfi_session_unload_res(inst); | |
1065 | err_unreg_bufs: | |
1066 | session_unregister_bufs(inst); | |
1067 | err_bufs_free: | |
1068 | intbufs_free(inst); | |
1069 | return ret; | |
1070 | } | |
1071 | EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming); | |
1072 | ||
1073 | void 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 | } | |
1096 | EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run); | |
1097 | ||
1098 | void 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 | } | |
1104 | EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort); | |
1105 | ||
1106 | void 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 | } | |
1114 | EXPORT_SYMBOL_GPL(venus_helper_init_instance); | |
aa3a8414 | 1115 | |
f012b23d SV |
1116 | static 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 | ||
1129 | int 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 | } | |
1175 | EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts); | |
1176 | ||
aa3a8414 SV |
1177 | int 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 | } | |
1224 | EXPORT_SYMBOL_GPL(venus_helper_power_enable); |