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=%pad,size=%zu",
214 i
, inst
->work_bufs
[i
].va
,
215 &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
];
257 bs_frm_size
= vp8_enc_read_reg(inst
, VENC_BITSTREAM_FRAME_SIZE
);
258 bs_hdr_len
= vp8_enc_read_reg(inst
, VENC_BITSTREAM_HEADER_LEN
);
260 /* if a frame is key frame, not_key is 0 */
261 not_key
= !inst
->vpu_inst
.is_key_frm
;
262 tag
= (bs_hdr_len
<< 5) | 0x10 | not_key
;
263 ac_tag
[0] = tag
& 0xff;
264 ac_tag
[1] = (tag
>> 8) & 0xff;
265 ac_tag
[2] = (tag
>> 16) & 0xff;
269 ac_tag_size
= MAX_AC_TAG_SIZE
;
273 ac_tag
[6] = inst
->vsi
->config
.pic_w
;
274 ac_tag
[7] = inst
->vsi
->config
.pic_w
>> 8;
275 ac_tag
[8] = inst
->vsi
->config
.pic_h
;
276 ac_tag
[9] = inst
->vsi
->config
.pic_h
>> 8;
281 if (bs_buf
->size
< bs_hdr_len
+ bs_frm_size
+ ac_tag_size
) {
282 mtk_vcodec_err(inst
, "bitstream buf size is too small(%zu)",
288 * (1) The vp8 bitstream header and body are generated by the HW vp8
289 * encoder separately at the same time. We cannot know the bitstream
290 * header length in advance.
291 * (2) From the vp8 spec, there is no stuffing byte allowed between the
292 * ac tag, bitstream header and bitstream body.
294 memmove(bs_buf
->va
+ bs_hdr_len
+ ac_tag_size
,
295 bs_buf
->va
, bs_frm_size
);
296 memcpy(bs_buf
->va
+ ac_tag_size
,
297 inst
->work_bufs
[VENC_VP8_VPU_WORK_BUF_BS_HEADER
].va
,
299 memcpy(bs_buf
->va
, ac_tag
, ac_tag_size
);
300 *bs_size
= bs_frm_size
+ bs_hdr_len
+ ac_tag_size
;
305 static int vp8_enc_encode_frame(struct venc_vp8_inst
*inst
,
306 struct venc_frm_buf
*frm_buf
,
307 struct mtk_vcodec_mem
*bs_buf
,
308 unsigned int *bs_size
)
311 unsigned int irq_status
;
313 mtk_vcodec_debug(inst
, "->frm_cnt=%d", inst
->frm_cnt
);
315 ret
= vpu_enc_encode(&inst
->vpu_inst
, 0, frm_buf
, bs_buf
, bs_size
);
319 irq_status
= vp8_enc_wait_venc_done(inst
);
320 if (irq_status
!= MTK_VENC_IRQ_STATUS_FRM
) {
321 mtk_vcodec_err(inst
, "irq_status=%d failed", irq_status
);
325 if (vp8_enc_compose_one_frame(inst
, bs_buf
, bs_size
)) {
326 mtk_vcodec_err(inst
, "vp8_enc_compose_one_frame failed");
331 mtk_vcodec_debug(inst
, "<-size=%d key_frm=%d", *bs_size
,
332 inst
->vpu_inst
.is_key_frm
);
337 static int vp8_enc_init(struct mtk_vcodec_ctx
*ctx
, unsigned long *handle
)
340 struct venc_vp8_inst
*inst
;
342 inst
= kzalloc(sizeof(*inst
), GFP_KERNEL
);
347 inst
->vpu_inst
.ctx
= ctx
;
348 inst
->vpu_inst
.dev
= ctx
->dev
->vpu_plat_dev
;
349 inst
->vpu_inst
.id
= IPI_VENC_VP8
;
350 inst
->hw_base
= mtk_vcodec_get_reg_addr(inst
->ctx
, VENC_LT_SYS
);
352 mtk_vcodec_debug_enter(inst
);
354 ret
= vpu_enc_init(&inst
->vpu_inst
);
356 inst
->vsi
= (struct venc_vp8_vsi
*)inst
->vpu_inst
.vsi
;
358 mtk_vcodec_debug_leave(inst
);
363 (*handle
) = (unsigned long)inst
;
368 static int vp8_enc_encode(unsigned long handle
,
369 enum venc_start_opt opt
,
370 struct venc_frm_buf
*frm_buf
,
371 struct mtk_vcodec_mem
*bs_buf
,
372 struct venc_done_result
*result
)
375 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
376 struct mtk_vcodec_ctx
*ctx
= inst
->ctx
;
378 mtk_vcodec_debug_enter(inst
);
380 enable_irq(ctx
->dev
->enc_lt_irq
);
383 case VENC_START_OPT_ENCODE_FRAME
:
384 ret
= vp8_enc_encode_frame(inst
, frm_buf
, bs_buf
,
388 result
->is_key_frm
= inst
->vpu_inst
.is_key_frm
;
392 mtk_vcodec_err(inst
, "opt not support:%d", opt
);
399 disable_irq(ctx
->dev
->enc_lt_irq
);
400 mtk_vcodec_debug_leave(inst
);
405 static int vp8_enc_set_param(unsigned long handle
,
406 enum venc_set_param_type type
,
407 struct venc_enc_param
*enc_prm
)
410 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
412 mtk_vcodec_debug(inst
, "->type=%d", type
);
415 case VENC_SET_PARAM_ENC
:
416 inst
->vsi
->config
.input_fourcc
= enc_prm
->input_yuv_fmt
;
417 inst
->vsi
->config
.bitrate
= enc_prm
->bitrate
;
418 inst
->vsi
->config
.pic_w
= enc_prm
->width
;
419 inst
->vsi
->config
.pic_h
= enc_prm
->height
;
420 inst
->vsi
->config
.buf_w
= enc_prm
->buf_width
;
421 inst
->vsi
->config
.buf_h
= enc_prm
->buf_height
;
422 inst
->vsi
->config
.gop_size
= enc_prm
->gop_size
;
423 inst
->vsi
->config
.framerate
= enc_prm
->frm_rate
;
424 inst
->vsi
->config
.ts_mode
= inst
->ts_mode
;
425 ret
= vpu_enc_set_param(&inst
->vpu_inst
, type
, enc_prm
);
428 if (inst
->work_buf_allocated
) {
429 vp8_enc_free_work_buf(inst
);
430 inst
->work_buf_allocated
= false;
432 ret
= vp8_enc_alloc_work_buf(inst
);
435 inst
->work_buf_allocated
= true;
439 * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC
441 case VENC_SET_PARAM_TS_MODE
:
443 mtk_vcodec_debug(inst
, "set ts_mode");
447 ret
= vpu_enc_set_param(&inst
->vpu_inst
, type
, enc_prm
);
451 mtk_vcodec_debug_leave(inst
);
456 static int vp8_enc_deinit(unsigned long handle
)
459 struct venc_vp8_inst
*inst
= (struct venc_vp8_inst
*)handle
;
461 mtk_vcodec_debug_enter(inst
);
463 ret
= vpu_enc_deinit(&inst
->vpu_inst
);
465 if (inst
->work_buf_allocated
)
466 vp8_enc_free_work_buf(inst
);
468 mtk_vcodec_debug_leave(inst
);
474 static struct venc_common_if venc_vp8_if
= {
481 struct venc_common_if
*get_vp8_enc_comm_if(void);
483 struct venc_common_if
*get_vp8_enc_comm_if(void)