2 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
3 * Copyright (C) 2017 Linaro Ltd.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/clk.h>
16 #include <linux/list.h>
17 #include <linux/mutex.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/slab.h>
20 #include <media/videobuf2-dma-sg.h>
21 #include <media/v4l2-mem2mem.h>
22 #include <asm/div64.h>
26 #include "hfi_helper.h"
29 struct list_head list
;
37 bool venus_helper_check_codec(struct venus_inst
*inst
, u32 v4l2_pixfmt
)
39 struct venus_core
*core
= inst
->core
;
40 u32 session_type
= inst
->session_type
;
43 switch (v4l2_pixfmt
) {
44 case V4L2_PIX_FMT_H264
:
45 codec
= HFI_VIDEO_CODEC_H264
;
47 case V4L2_PIX_FMT_H263
:
48 codec
= HFI_VIDEO_CODEC_H263
;
50 case V4L2_PIX_FMT_MPEG1
:
51 codec
= HFI_VIDEO_CODEC_MPEG1
;
53 case V4L2_PIX_FMT_MPEG2
:
54 codec
= HFI_VIDEO_CODEC_MPEG2
;
56 case V4L2_PIX_FMT_MPEG4
:
57 codec
= HFI_VIDEO_CODEC_MPEG4
;
59 case V4L2_PIX_FMT_VC1_ANNEX_G
:
60 case V4L2_PIX_FMT_VC1_ANNEX_L
:
61 codec
= HFI_VIDEO_CODEC_VC1
;
63 case V4L2_PIX_FMT_VP8
:
64 codec
= HFI_VIDEO_CODEC_VP8
;
66 case V4L2_PIX_FMT_VP9
:
67 codec
= HFI_VIDEO_CODEC_VP9
;
69 case V4L2_PIX_FMT_XVID
:
70 codec
= HFI_VIDEO_CODEC_DIVX
;
76 if (session_type
== VIDC_SESSION_TYPE_ENC
&& core
->enc_codecs
& codec
)
79 if (session_type
== VIDC_SESSION_TYPE_DEC
&& core
->dec_codecs
& codec
)
84 EXPORT_SYMBOL_GPL(venus_helper_check_codec
);
86 static int intbufs_set_buffer(struct venus_inst
*inst
, u32 type
)
88 struct venus_core
*core
= inst
->core
;
89 struct device
*dev
= core
->dev
;
90 struct hfi_buffer_requirements bufreq
;
91 struct hfi_buffer_desc bd
;
96 ret
= venus_helper_get_bufreq(inst
, type
, &bufreq
);
103 for (i
= 0; i
< bufreq
.count_actual
; i
++) {
104 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
);
110 buf
->type
= bufreq
.type
;
111 buf
->size
= bufreq
.size
;
112 buf
->attrs
= DMA_ATTR_WRITE_COMBINE
|
113 DMA_ATTR_NO_KERNEL_MAPPING
;
114 buf
->va
= dma_alloc_attrs(dev
, buf
->size
, &buf
->da
, GFP_KERNEL
,
121 memset(&bd
, 0, sizeof(bd
));
122 bd
.buffer_size
= buf
->size
;
123 bd
.buffer_type
= buf
->type
;
125 bd
.device_addr
= buf
->da
;
127 ret
= hfi_session_set_buffers(inst
, &bd
);
129 dev_err(dev
, "set session buffers failed\n");
133 list_add_tail(&buf
->list
, &inst
->internalbufs
);
139 dma_free_attrs(dev
, buf
->size
, buf
->va
, buf
->da
, buf
->attrs
);
145 static int intbufs_unset_buffers(struct venus_inst
*inst
)
147 struct hfi_buffer_desc bd
= {0};
148 struct intbuf
*buf
, *n
;
151 list_for_each_entry_safe(buf
, n
, &inst
->internalbufs
, list
) {
152 bd
.buffer_size
= buf
->size
;
153 bd
.buffer_type
= buf
->type
;
155 bd
.device_addr
= buf
->da
;
156 bd
.response_required
= true;
158 ret
= hfi_session_unset_buffers(inst
, &bd
);
160 list_del_init(&buf
->list
);
161 dma_free_attrs(inst
->core
->dev
, buf
->size
, buf
->va
, buf
->da
,
169 static const unsigned int intbuf_types
[] = {
170 HFI_BUFFER_INTERNAL_SCRATCH
,
171 HFI_BUFFER_INTERNAL_SCRATCH_1
,
172 HFI_BUFFER_INTERNAL_SCRATCH_2
,
173 HFI_BUFFER_INTERNAL_PERSIST
,
174 HFI_BUFFER_INTERNAL_PERSIST_1
,
177 static int intbufs_alloc(struct venus_inst
*inst
)
182 for (i
= 0; i
< ARRAY_SIZE(intbuf_types
); i
++) {
183 ret
= intbufs_set_buffer(inst
, intbuf_types
[i
]);
191 intbufs_unset_buffers(inst
);
195 static int intbufs_free(struct venus_inst
*inst
)
197 return intbufs_unset_buffers(inst
);
200 static u32
load_per_instance(struct venus_inst
*inst
)
204 if (!inst
|| !(inst
->state
>= INST_INIT
&& inst
->state
< INST_STOP
))
207 mbs
= (ALIGN(inst
->width
, 16) / 16) * (ALIGN(inst
->height
, 16) / 16);
209 return mbs
* inst
->fps
;
212 static u32
load_per_type(struct venus_core
*core
, u32 session_type
)
214 struct venus_inst
*inst
= NULL
;
217 mutex_lock(&core
->lock
);
218 list_for_each_entry(inst
, &core
->instances
, list
) {
219 if (inst
->session_type
!= session_type
)
222 mbs_per_sec
+= load_per_instance(inst
);
224 mutex_unlock(&core
->lock
);
229 static int load_scale_clocks(struct venus_core
*core
)
231 const struct freq_tbl
*table
= core
->res
->freq_tbl
;
232 unsigned int num_rows
= core
->res
->freq_tbl_size
;
233 unsigned long freq
= table
[0].freq
;
234 struct clk
*clk
= core
->clks
[0];
235 struct device
*dev
= core
->dev
;
240 mbs_per_sec
= load_per_type(core
, VIDC_SESSION_TYPE_ENC
) +
241 load_per_type(core
, VIDC_SESSION_TYPE_DEC
);
243 if (mbs_per_sec
> core
->res
->max_load
)
244 dev_warn(dev
, "HW is overloaded, needed: %d max: %d\n",
245 mbs_per_sec
, core
->res
->max_load
);
247 if (!mbs_per_sec
&& num_rows
> 1) {
248 freq
= table
[num_rows
- 1].freq
;
252 for (i
= 0; i
< num_rows
; i
++) {
253 if (mbs_per_sec
> table
[i
].load
)
255 freq
= table
[i
].freq
;
260 if (core
->res
->hfi_version
== HFI_VERSION_3XX
) {
261 ret
= clk_set_rate(clk
, freq
);
262 ret
|= clk_set_rate(core
->core0_clk
, freq
);
263 ret
|= clk_set_rate(core
->core1_clk
, freq
);
265 ret
= clk_set_rate(clk
, freq
);
269 dev_err(dev
, "failed to set clock rate %lu (%d)\n", freq
, ret
);
276 static void fill_buffer_desc(const struct venus_buffer
*buf
,
277 struct hfi_buffer_desc
*bd
, bool response
)
279 memset(bd
, 0, sizeof(*bd
));
280 bd
->buffer_type
= HFI_BUFFER_OUTPUT
;
281 bd
->buffer_size
= buf
->size
;
283 bd
->device_addr
= buf
->dma_addr
;
284 bd
->response_required
= response
;
287 static void return_buf_error(struct venus_inst
*inst
,
288 struct vb2_v4l2_buffer
*vbuf
)
290 struct v4l2_m2m_ctx
*m2m_ctx
= inst
->m2m_ctx
;
292 if (vbuf
->vb2_buf
.type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
293 v4l2_m2m_src_buf_remove_by_buf(m2m_ctx
, vbuf
);
295 v4l2_m2m_dst_buf_remove_by_buf(m2m_ctx
, vbuf
);
297 v4l2_m2m_buf_done(vbuf
, VB2_BUF_STATE_ERROR
);
301 session_process_buf(struct venus_inst
*inst
, struct vb2_v4l2_buffer
*vbuf
)
303 struct venus_buffer
*buf
= to_venus_buffer(vbuf
);
304 struct vb2_buffer
*vb
= &vbuf
->vb2_buf
;
305 unsigned int type
= vb
->type
;
306 struct hfi_frame_data fdata
;
309 memset(&fdata
, 0, sizeof(fdata
));
310 fdata
.alloc_len
= buf
->size
;
311 fdata
.device_addr
= buf
->dma_addr
;
312 fdata
.timestamp
= vb
->timestamp
;
313 do_div(fdata
.timestamp
, NSEC_PER_USEC
);
315 fdata
.clnt_data
= vbuf
->vb2_buf
.index
;
317 if (!fdata
.timestamp
)
318 fdata
.flags
|= HFI_BUFFERFLAG_TIMESTAMPINVALID
;
320 if (type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) {
321 fdata
.buffer_type
= HFI_BUFFER_INPUT
;
322 fdata
.filled_len
= vb2_get_plane_payload(vb
, 0);
323 fdata
.offset
= vb
->planes
[0].data_offset
;
325 if (vbuf
->flags
& V4L2_BUF_FLAG_LAST
|| !fdata
.filled_len
)
326 fdata
.flags
|= HFI_BUFFERFLAG_EOS
;
327 } else if (type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
) {
328 fdata
.buffer_type
= HFI_BUFFER_OUTPUT
;
329 fdata
.filled_len
= 0;
333 ret
= hfi_session_process_buf(inst
, &fdata
);
340 static inline int is_reg_unreg_needed(struct venus_inst
*inst
)
342 if (inst
->session_type
== VIDC_SESSION_TYPE_DEC
&&
343 inst
->core
->res
->hfi_version
== HFI_VERSION_3XX
)
346 if (inst
->session_type
== VIDC_SESSION_TYPE_DEC
&&
347 inst
->cap_bufs_mode_dynamic
&&
348 inst
->core
->res
->hfi_version
== HFI_VERSION_1XX
)
354 static int session_unregister_bufs(struct venus_inst
*inst
)
356 struct venus_buffer
*buf
, *n
;
357 struct hfi_buffer_desc bd
;
360 if (!is_reg_unreg_needed(inst
))
363 list_for_each_entry_safe(buf
, n
, &inst
->registeredbufs
, reg_list
) {
364 fill_buffer_desc(buf
, &bd
, true);
365 ret
= hfi_session_unset_buffers(inst
, &bd
);
366 list_del_init(&buf
->reg_list
);
372 static int session_register_bufs(struct venus_inst
*inst
)
374 struct venus_core
*core
= inst
->core
;
375 struct device
*dev
= core
->dev
;
376 struct hfi_buffer_desc bd
;
377 struct venus_buffer
*buf
;
380 if (!is_reg_unreg_needed(inst
))
383 list_for_each_entry(buf
, &inst
->registeredbufs
, reg_list
) {
384 fill_buffer_desc(buf
, &bd
, false);
385 ret
= hfi_session_set_buffers(inst
, &bd
);
387 dev_err(dev
, "%s: set buffer failed\n", __func__
);
395 int venus_helper_get_bufreq(struct venus_inst
*inst
, u32 type
,
396 struct hfi_buffer_requirements
*req
)
398 u32 ptype
= HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS
;
399 union hfi_get_property hprop
;
404 memset(req
, 0, sizeof(*req
));
406 ret
= hfi_session_get_property(inst
, ptype
, &hprop
);
412 for (i
= 0; i
< HFI_BUFFER_TYPE_MAX
; i
++) {
413 if (hprop
.bufreq
[i
].type
!= type
)
417 memcpy(req
, &hprop
.bufreq
[i
], sizeof(*req
));
424 EXPORT_SYMBOL_GPL(venus_helper_get_bufreq
);
426 int venus_helper_set_input_resolution(struct venus_inst
*inst
,
427 unsigned int width
, unsigned int height
)
429 u32 ptype
= HFI_PROPERTY_PARAM_FRAME_SIZE
;
430 struct hfi_framesize fs
;
432 fs
.buffer_type
= HFI_BUFFER_INPUT
;
436 return hfi_session_set_property(inst
, ptype
, &fs
);
438 EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution
);
440 int venus_helper_set_output_resolution(struct venus_inst
*inst
,
441 unsigned int width
, unsigned int height
)
443 u32 ptype
= HFI_PROPERTY_PARAM_FRAME_SIZE
;
444 struct hfi_framesize fs
;
446 fs
.buffer_type
= HFI_BUFFER_OUTPUT
;
450 return hfi_session_set_property(inst
, ptype
, &fs
);
452 EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution
);
454 int venus_helper_set_num_bufs(struct venus_inst
*inst
, unsigned int input_bufs
,
455 unsigned int output_bufs
)
457 u32 ptype
= HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL
;
458 struct hfi_buffer_count_actual buf_count
;
461 buf_count
.type
= HFI_BUFFER_INPUT
;
462 buf_count
.count_actual
= input_bufs
;
464 ret
= hfi_session_set_property(inst
, ptype
, &buf_count
);
468 buf_count
.type
= HFI_BUFFER_OUTPUT
;
469 buf_count
.count_actual
= output_bufs
;
471 return hfi_session_set_property(inst
, ptype
, &buf_count
);
473 EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs
);
475 int venus_helper_set_color_format(struct venus_inst
*inst
, u32 pixfmt
)
477 struct hfi_uncompressed_format_select fmt
;
478 u32 ptype
= HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT
;
481 if (inst
->session_type
== VIDC_SESSION_TYPE_DEC
)
482 fmt
.buffer_type
= HFI_BUFFER_OUTPUT
;
483 else if (inst
->session_type
== VIDC_SESSION_TYPE_ENC
)
484 fmt
.buffer_type
= HFI_BUFFER_INPUT
;
489 case V4L2_PIX_FMT_NV12
:
490 fmt
.format
= HFI_COLOR_FORMAT_NV12
;
492 case V4L2_PIX_FMT_NV21
:
493 fmt
.format
= HFI_COLOR_FORMAT_NV21
;
499 ret
= hfi_session_set_property(inst
, ptype
, &fmt
);
505 EXPORT_SYMBOL_GPL(venus_helper_set_color_format
);
507 static void delayed_process_buf_func(struct work_struct
*work
)
509 struct venus_buffer
*buf
, *n
;
510 struct venus_inst
*inst
;
513 inst
= container_of(work
, struct venus_inst
, delayed_process_work
);
515 mutex_lock(&inst
->lock
);
517 if (!(inst
->streamon_out
& inst
->streamon_cap
))
520 list_for_each_entry_safe(buf
, n
, &inst
->delayed_process
, ref_list
) {
521 if (buf
->flags
& HFI_BUFFERFLAG_READONLY
)
524 ret
= session_process_buf(inst
, &buf
->vb
);
526 return_buf_error(inst
, &buf
->vb
);
528 list_del_init(&buf
->ref_list
);
531 mutex_unlock(&inst
->lock
);
534 void venus_helper_release_buf_ref(struct venus_inst
*inst
, unsigned int idx
)
536 struct venus_buffer
*buf
;
538 list_for_each_entry(buf
, &inst
->registeredbufs
, reg_list
) {
539 if (buf
->vb
.vb2_buf
.index
== idx
) {
540 buf
->flags
&= ~HFI_BUFFERFLAG_READONLY
;
541 schedule_work(&inst
->delayed_process_work
);
546 EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref
);
548 void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer
*vbuf
)
550 struct venus_buffer
*buf
= to_venus_buffer(vbuf
);
552 buf
->flags
|= HFI_BUFFERFLAG_READONLY
;
554 EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref
);
556 static int is_buf_refed(struct venus_inst
*inst
, struct vb2_v4l2_buffer
*vbuf
)
558 struct venus_buffer
*buf
= to_venus_buffer(vbuf
);
560 if (buf
->flags
& HFI_BUFFERFLAG_READONLY
) {
561 list_add_tail(&buf
->ref_list
, &inst
->delayed_process
);
562 schedule_work(&inst
->delayed_process_work
);
569 struct vb2_v4l2_buffer
*
570 venus_helper_find_buf(struct venus_inst
*inst
, unsigned int type
, u32 idx
)
572 struct v4l2_m2m_ctx
*m2m_ctx
= inst
->m2m_ctx
;
574 if (type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
575 return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx
, idx
);
577 return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx
, idx
);
579 EXPORT_SYMBOL_GPL(venus_helper_find_buf
);
581 int venus_helper_vb2_buf_init(struct vb2_buffer
*vb
)
583 struct venus_inst
*inst
= vb2_get_drv_priv(vb
->vb2_queue
);
584 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
585 struct venus_buffer
*buf
= to_venus_buffer(vbuf
);
586 struct sg_table
*sgt
;
588 sgt
= vb2_dma_sg_plane_desc(vb
, 0);
592 buf
->size
= vb2_plane_size(vb
, 0);
593 buf
->dma_addr
= sg_dma_address(sgt
->sgl
);
595 if (vb
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
596 list_add_tail(&buf
->reg_list
, &inst
->registeredbufs
);
600 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init
);
602 int venus_helper_vb2_buf_prepare(struct vb2_buffer
*vb
)
604 struct venus_inst
*inst
= vb2_get_drv_priv(vb
->vb2_queue
);
606 if (vb
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
&&
607 vb2_plane_size(vb
, 0) < inst
->output_buf_size
)
609 if (vb
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
&&
610 vb2_plane_size(vb
, 0) < inst
->input_buf_size
)
615 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare
);
617 void venus_helper_vb2_buf_queue(struct vb2_buffer
*vb
)
619 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
620 struct venus_inst
*inst
= vb2_get_drv_priv(vb
->vb2_queue
);
621 struct v4l2_m2m_ctx
*m2m_ctx
= inst
->m2m_ctx
;
624 mutex_lock(&inst
->lock
);
626 v4l2_m2m_buf_queue(m2m_ctx
, vbuf
);
628 if (!(inst
->streamon_out
& inst
->streamon_cap
))
631 ret
= is_buf_refed(inst
, vbuf
);
635 ret
= session_process_buf(inst
, vbuf
);
637 return_buf_error(inst
, vbuf
);
640 mutex_unlock(&inst
->lock
);
642 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue
);
644 void venus_helper_buffers_done(struct venus_inst
*inst
,
645 enum vb2_buffer_state state
)
647 struct vb2_v4l2_buffer
*buf
;
649 while ((buf
= v4l2_m2m_src_buf_remove(inst
->m2m_ctx
)))
650 v4l2_m2m_buf_done(buf
, state
);
651 while ((buf
= v4l2_m2m_dst_buf_remove(inst
->m2m_ctx
)))
652 v4l2_m2m_buf_done(buf
, state
);
654 EXPORT_SYMBOL_GPL(venus_helper_buffers_done
);
656 void venus_helper_vb2_stop_streaming(struct vb2_queue
*q
)
658 struct venus_inst
*inst
= vb2_get_drv_priv(q
);
659 struct venus_core
*core
= inst
->core
;
662 mutex_lock(&inst
->lock
);
664 if (inst
->streamon_out
& inst
->streamon_cap
) {
665 ret
= hfi_session_stop(inst
);
666 ret
|= hfi_session_unload_res(inst
);
667 ret
|= session_unregister_bufs(inst
);
668 ret
|= intbufs_free(inst
);
669 ret
|= hfi_session_deinit(inst
);
671 if (inst
->session_error
|| core
->sys_error
)
675 hfi_session_abort(inst
);
677 load_scale_clocks(core
);
678 INIT_LIST_HEAD(&inst
->registeredbufs
);
681 venus_helper_buffers_done(inst
, VB2_BUF_STATE_ERROR
);
683 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
684 inst
->streamon_out
= 0;
686 inst
->streamon_cap
= 0;
688 mutex_unlock(&inst
->lock
);
690 EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming
);
692 int venus_helper_vb2_start_streaming(struct venus_inst
*inst
)
694 struct venus_core
*core
= inst
->core
;
697 ret
= intbufs_alloc(inst
);
701 ret
= session_register_bufs(inst
);
705 load_scale_clocks(core
);
707 ret
= hfi_session_load_res(inst
);
711 ret
= hfi_session_start(inst
);
718 hfi_session_unload_res(inst
);
720 session_unregister_bufs(inst
);
725 EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming
);
727 void venus_helper_m2m_device_run(void *priv
)
729 struct venus_inst
*inst
= priv
;
730 struct v4l2_m2m_ctx
*m2m_ctx
= inst
->m2m_ctx
;
731 struct v4l2_m2m_buffer
*buf
, *n
;
734 mutex_lock(&inst
->lock
);
736 v4l2_m2m_for_each_dst_buf_safe(m2m_ctx
, buf
, n
) {
737 ret
= session_process_buf(inst
, &buf
->vb
);
739 return_buf_error(inst
, &buf
->vb
);
742 v4l2_m2m_for_each_src_buf_safe(m2m_ctx
, buf
, n
) {
743 ret
= session_process_buf(inst
, &buf
->vb
);
745 return_buf_error(inst
, &buf
->vb
);
748 mutex_unlock(&inst
->lock
);
750 EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run
);
752 void venus_helper_m2m_job_abort(void *priv
)
754 struct venus_inst
*inst
= priv
;
756 v4l2_m2m_job_finish(inst
->m2m_dev
, inst
->m2m_ctx
);
758 EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort
);
760 void venus_helper_init_instance(struct venus_inst
*inst
)
762 if (inst
->session_type
== VIDC_SESSION_TYPE_DEC
) {
763 INIT_LIST_HEAD(&inst
->delayed_process
);
764 INIT_WORK(&inst
->delayed_process_work
,
765 delayed_process_buf_func
);
768 EXPORT_SYMBOL_GPL(venus_helper_init_instance
);