2 * Copyright (c) 2016 MediaTek Inc.
3 * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
4 * PoChun Lin <pochun.lin@mediatek.com>
6 * This program is free software; you can redistribute it and/or
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/interrupt.h>
18 #include <linux/kernel.h>
19 #include <linux/slab.h>
21 #include "../mtk_vcodec_drv.h"
22 #include "../mtk_vcodec_util.h"
23 #include "../mtk_vcodec_intr.h"
24 #include "../mtk_vcodec_enc.h"
25 #include "../mtk_vcodec_enc_pm.h"
26 #include "../venc_drv_base.h"
27 #include "../venc_ipi_msg.h"
28 #include "../venc_vpu_if.h"
31 #define VENC_BITSTREAM_FRAME_SIZE 0x0098
32 #define VENC_BITSTREAM_HEADER_LEN 0x00e8
34 /* This ac_tag is vp8 frame tag. */
35 #define MAX_AC_TAG_SIZE 10
38 * enum venc_vp8_vpu_work_buf - vp8 encoder buffer index
40 enum venc_vp8_vpu_work_buf
{
41 VENC_VP8_VPU_WORK_BUF_LUMA
,
42 VENC_VP8_VPU_WORK_BUF_LUMA2
,
43 VENC_VP8_VPU_WORK_BUF_LUMA3
,
44 VENC_VP8_VPU_WORK_BUF_CHROMA
,
45 VENC_VP8_VPU_WORK_BUF_CHROMA2
,
46 VENC_VP8_VPU_WORK_BUF_CHROMA3
,
47 VENC_VP8_VPU_WORK_BUF_MV_INFO
,
48 VENC_VP8_VPU_WORK_BUF_BS_HEADER
,
49 VENC_VP8_VPU_WORK_BUF_PROB_BUF
,
50 VENC_VP8_VPU_WORK_BUF_RC_INFO
,
51 VENC_VP8_VPU_WORK_BUF_RC_CODE
,
52 VENC_VP8_VPU_WORK_BUF_RC_CODE2
,
53 VENC_VP8_VPU_WORK_BUF_RC_CODE3
,
54 VENC_VP8_VPU_WORK_BUF_MAX
,
58 * struct venc_vp8_vpu_config - Structure for vp8 encoder configuration
59 * @input_fourcc: input fourcc
60 * @bitrate: target bitrate (in bps)
61 * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
62 * to be used for display purposes; must be smaller or equal to buffer
64 * @pic_h: picture height
65 * @buf_w: buffer width (with 16 alignment). Buffer size is stream resolution
66 * in pixels aligned to hardware requirements.
67 * @buf_h: buffer height (with 16 alignment)
68 * @gop_size: group of picture size (key frame)
69 * @framerate: frame rate in fps
70 * @ts_mode: temporal scalability mode (0: disable, 1: enable)
71 * support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
73 struct venc_vp8_vpu_config
{
86 * struct venc_vp8_vpu_buf -Structure for buffer information
87 * @align: buffer alignment (in bytes)
88 * @iova: IO virtual address
89 * @vpua: VPU side memory addr which is used by RC_CODE
90 * @size: buffer size (in bytes)
92 struct venc_vp8_vpu_buf
{
100 * struct venc_vp8_vsi - Structure for VPU driver control and info share
101 * This structure is allocated in VPU side and shared to AP side.
102 * @config: vp8 encoder configuration
103 * @work_bufs: working buffer information in VPU side
104 * The work_bufs here is for storing the 'size' info shared to AP side.
105 * The similar item in struct venc_vp8_inst is for memory allocation
106 * in AP side. The AP driver will copy the 'size' from here to the one in
107 * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
108 * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
109 * register setting in VPU side.
111 struct venc_vp8_vsi
{
112 struct venc_vp8_vpu_config config
;
113 struct venc_vp8_vpu_buf work_bufs
[VENC_VP8_VPU_WORK_BUF_MAX
];
117 * struct venc_vp8_inst - vp8 encoder AP driver instance
118 * @hw_base: vp8 encoder hardware register base
119 * @work_bufs: working buffer
120 * @work_buf_allocated: working buffer allocated flag
121 * @frm_cnt: encoded frame count, it's used for I-frame judgement and
122 * reset when force intra cmd received.
123 * @ts_mode: temporal scalability mode (0: disable, 1: enable)
124 * support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
125 * @vpu_inst: VPU instance to exchange information between AP and VPU
126 * @vsi: driver structure allocated by VPU side and shared to AP side for
127 * control and info share
128 * @ctx: context for v4l2 layer integration
130 struct venc_vp8_inst
{
131 void __iomem
*hw_base
;
132 struct mtk_vcodec_mem work_bufs
[VENC_VP8_VPU_WORK_BUF_MAX
];
133 bool work_buf_allocated
;
134 unsigned int frm_cnt
;
135 unsigned int ts_mode
;
136 struct venc_vpu_inst vpu_inst
;
137 struct venc_vp8_vsi
*vsi
;
138 struct mtk_vcodec_ctx
*ctx
;
141 static inline void vp8_enc_write_reg(struct venc_vp8_inst
*inst
, u32 addr
,
144 writel(val
, inst
->hw_base
+ addr
);
147 static inline u32
vp8_enc_read_reg(struct venc_vp8_inst
*inst
, u32 addr
)
149 return readl(inst
->hw_base
+ addr
);
152 static void vp8_enc_free_work_buf(struct venc_vp8_inst
*inst
)
156 mtk_vcodec_debug_enter(inst
);
158 /* Buffers need to be freed by AP. */
159 for (i
= 0; i
< VENC_VP8_VPU_WORK_BUF_MAX
; i
++) {
160 if ((inst
->work_bufs
[i
].size
== 0))
162 mtk_vcodec_mem_free(inst
->ctx
, &inst
->work_bufs
[i
]);
165 mtk_vcodec_debug_leave(inst
);
168 static int vp8_enc_alloc_work_buf(struct venc_vp8_inst
*inst
)
172 struct venc_vp8_vpu_buf
*wb
= inst
->vsi
->work_bufs
;
174 mtk_vcodec_debug_enter(inst
);
176 for (i
= 0; i
< VENC_VP8_VPU_WORK_BUF_MAX
; i
++) {
177 if ((wb
[i
].size
== 0))
180 * This 'wb' structure is set by VPU side and shared to AP for
181 * buffer allocation and IO virtual addr mapping. For most of
182 * the buffers, AP will allocate the buffer according to 'size'
183 * field and store the IO virtual addr in 'iova' field. For the
184 * RC_CODEx buffers, they are pre-allocated in the VPU side
185 * because they are inside VPU SRAM, and save the VPU addr in
186 * the 'vpua' field. The AP will translate the VPU addr to the
187 * corresponding IO virtual addr and store in 'iova' field.
189 inst
->work_bufs
[i
].size
= wb
[i
].size
;
190 ret
= mtk_vcodec_mem_alloc(inst
->ctx
, &inst
->work_bufs
[i
]);
193 "cannot alloc work_bufs[%d]", i
);
197 * This RC_CODEx is pre-allocated by VPU and saved in VPU addr.
198 * So we need use memcpy to copy RC_CODEx from VPU addr into IO
199 * virtual addr in 'iova' field for reg setting in VPU side.
201 if (i
== VENC_VP8_VPU_WORK_BUF_RC_CODE
||
202 i
== VENC_VP8_VPU_WORK_BUF_RC_CODE2
||
203 i
== VENC_VP8_VPU_WORK_BUF_RC_CODE3
) {
206 tmp_va
= vpu_mapping_dm_addr(inst
->vpu_inst
.dev
,
208 memcpy(inst
->work_bufs
[i
].va
, tmp_va
, wb
[i
].size
);
210 wb
[i
].iova
= inst
->work_bufs
[i
].dma_addr
;
212 mtk_vcodec_debug(inst
,
213 "work_bufs[%d] va=0x%p,iova=0x%p,size=%zu",
214 i
, inst
->work_bufs
[i
].va
,
215 (void *)inst
->work_bufs
[i
].dma_addr
,
216 inst
->work_bufs
[i
].size
);
219 mtk_vcodec_debug_leave(inst
);
224 vp8_enc_free_work_buf(inst
);
229 static unsigned int vp8_enc_wait_venc_done(struct venc_vp8_inst
*inst
)
231 unsigned int irq_status
= 0;
232 struct mtk_vcodec_ctx
*ctx
= (struct mtk_vcodec_ctx
*)inst
->ctx
;
234 if (!mtk_vcodec_wait_for_done_ctx(ctx
, MTK_INST_IRQ_RECEIVED
,
235 WAIT_INTR_TIMEOUT_MS
)) {
236 irq_status
= ctx
->irq_status
;
237 mtk_vcodec_debug(inst
, "isr return %x", irq_status
);
243 * Compose ac_tag, bitstream header and bitstream payload into
244 * one bitstream buffer.
246 static int vp8_enc_compose_one_frame(struct venc_vp8_inst
*inst
,
247 struct mtk_vcodec_mem
*bs_buf
,
248 unsigned int *bs_size
)
250 unsigned int not_key
;
253 unsigned int ac_tag_size
;
254 u8 ac_tag
[MAX_AC_TAG_SIZE
];
256 bs_frm_size
= vp8_enc_read_reg(inst
, VENC_BITSTREAM_FRAME_SIZE
);
257 bs_hdr_len
= vp8_enc_read_reg(inst
, VENC_BITSTREAM_HEADER_LEN
);
259 /* if a frame is key frame, not_key is 0 */
260 not_key
= !inst
->vpu_inst
.is_key_frm
;
261 *(u32
*)ac_tag
= __cpu_to_le32((bs_hdr_len
<< 5) | 0x10 | not_key
);
264 ac_tag_size
= MAX_AC_TAG_SIZE
;
268 ac_tag
[6] = inst
->vsi
->config
.pic_w
;
269 ac_tag
[7] = inst
->vsi
->config
.pic_w
>> 8;
270 ac_tag
[8] = inst
->vsi
->config
.pic_h
;
271 ac_tag
[9] = inst
->vsi
->config
.pic_h
>> 8;
276 if (bs_buf
->size
< bs_hdr_len
+ bs_frm_size
+ ac_tag_size
) {
277 mtk_vcodec_err(inst
, "bitstream buf size is too small(%zu)",
283 * (1) The vp8 bitstream header and body are generated by the HW vp8
284 * encoder separately at the same time. We cannot know the bitstream
285 * header length in advance.
286 * (2) From the vp8 spec, there is no stuffing byte allowed between the
287 * ac tag, bitstream header and bitstream body.
289 memmove(bs_buf
->va
+ bs_hdr_len
+ ac_tag_size
,
290 bs_buf
->va
, bs_frm_size
);
291 memcpy(bs_buf
->va
+ ac_tag_size
,
292 inst
->work_bufs
[VENC_VP8_VPU_WORK_BUF_BS_HEADER
].va
,
294 memcpy(bs_buf
->va
, ac_tag
, ac_tag_size
);
295 *bs_size
= bs_frm_size
+ bs_hdr_len
+ ac_tag_size
;
300 static int vp8_enc_encode_frame(struct venc_vp8_inst
*inst
,
301 struct venc_frm_buf
*frm_buf
,
302 struct mtk_vcodec_mem
*bs_buf
,
303 unsigned int *bs_size
)
306 unsigned int irq_status
;
308 mtk_vcodec_debug(inst
, "->frm_cnt=%d", inst
->frm_cnt
);
310 ret
= vpu_enc_encode(&inst
->vpu_inst
, 0, frm_buf
, bs_buf
, bs_size
);
314 irq_status
= vp8_enc_wait_venc_done(inst
);
315 if (irq_status
!= MTK_VENC_IRQ_STATUS_FRM
) {
316 mtk_vcodec_err(inst
, "irq_status=%d failed", irq_status
);
320 if (vp8_enc_compose_one_frame(inst
, bs_buf
, bs_size
)) {
321 mtk_vcodec_err(inst
, "vp8_enc_compose_one_frame failed");
326 mtk_vcodec_debug(inst
, "<-size=%d key_frm=%d", *bs_size
,
327 inst
->vpu_inst
.is_key_frm
);
332 static int vp8_enc_init(struct mtk_vcodec_ctx
*ctx
, unsigned long *handle
)
335 struct venc_vp8_inst
*inst
;
337 inst
= kzalloc(sizeof(*inst
), GFP_KERNEL
);
342 inst
->vpu_inst
.ctx
= ctx
;
343 inst
->vpu_inst
.dev
= ctx
->dev
->vpu_plat_dev
;
344 inst
->vpu_inst
.id
= IPI_VENC_VP8
;
345 inst
->hw_base
= mtk_vcodec_get_reg_addr(inst
->ctx
, VENC_LT_SYS
);
347 mtk_vcodec_debug_enter(inst
);
349 ret
= vpu_enc_init(&inst
->vpu_inst
);
351 inst
->vsi
= (struct venc_vp8_vsi
*)inst
->vpu_inst
.vsi
;
353 mtk_vcodec_debug_leave(inst
);
358 (*handle
) = (unsigned long)inst
;
363 static int vp8_enc_encode(unsigned long handle
,
364 enum venc_start_opt opt
,
365 struct venc_frm_buf
*frm_buf
,
366 struct mtk_vcodec_mem
*bs_buf
,
367 struct venc_done_result
*result
)
370 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
371 struct mtk_vcodec_ctx
*ctx
= inst
->ctx
;
373 mtk_vcodec_debug_enter(inst
);
375 enable_irq(ctx
->dev
->enc_lt_irq
);
378 case VENC_START_OPT_ENCODE_FRAME
:
379 ret
= vp8_enc_encode_frame(inst
, frm_buf
, bs_buf
,
383 result
->is_key_frm
= inst
->vpu_inst
.is_key_frm
;
387 mtk_vcodec_err(inst
, "opt not support:%d", opt
);
394 disable_irq(ctx
->dev
->enc_lt_irq
);
395 mtk_vcodec_debug_leave(inst
);
400 static int vp8_enc_set_param(unsigned long handle
,
401 enum venc_set_param_type type
,
402 struct venc_enc_param
*enc_prm
)
405 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
407 mtk_vcodec_debug(inst
, "->type=%d", type
);
410 case VENC_SET_PARAM_ENC
:
411 inst
->vsi
->config
.input_fourcc
= enc_prm
->input_yuv_fmt
;
412 inst
->vsi
->config
.bitrate
= enc_prm
->bitrate
;
413 inst
->vsi
->config
.pic_w
= enc_prm
->width
;
414 inst
->vsi
->config
.pic_h
= enc_prm
->height
;
415 inst
->vsi
->config
.buf_w
= enc_prm
->buf_width
;
416 inst
->vsi
->config
.buf_h
= enc_prm
->buf_height
;
417 inst
->vsi
->config
.gop_size
= enc_prm
->gop_size
;
418 inst
->vsi
->config
.framerate
= enc_prm
->frm_rate
;
419 inst
->vsi
->config
.ts_mode
= inst
->ts_mode
;
420 ret
= vpu_enc_set_param(&inst
->vpu_inst
, type
, enc_prm
);
423 if (inst
->work_buf_allocated
) {
424 vp8_enc_free_work_buf(inst
);
425 inst
->work_buf_allocated
= false;
427 ret
= vp8_enc_alloc_work_buf(inst
);
430 inst
->work_buf_allocated
= true;
434 * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC
436 case VENC_SET_PARAM_TS_MODE
:
438 mtk_vcodec_debug(inst
, "set ts_mode");
442 ret
= vpu_enc_set_param(&inst
->vpu_inst
, type
, enc_prm
);
446 mtk_vcodec_debug_leave(inst
);
451 static int vp8_enc_deinit(unsigned long handle
)
454 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
456 mtk_vcodec_debug_enter(inst
);
458 ret
= vpu_enc_deinit(&inst
->vpu_inst
);
460 if (inst
->work_buf_allocated
)
461 vp8_enc_free_work_buf(inst
);
463 mtk_vcodec_debug_leave(inst
);
469 static struct venc_common_if venc_vp8_if
= {
476 struct venc_common_if
*get_vp8_enc_comm_if(void);
478 struct venc_common_if
*get_vp8_enc_comm_if(void)