Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] vcodec: mediatek: Add Mediatek VP8 Video Encoder Driver

Add vp8 encoder driver for MT8173

Signed-off-by: PoChun Lin <pochun.lin@mediatek.com>
Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Tiffany Lin and committed by
Mauro Carvalho Chehab
27a274db 4e855a6e

+790 -2
+5 -1
drivers/media/platform/mtk-vcodec/Makefile
··· 1 1 2 + 2 3 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o 3 4 4 5 5 6 6 - mtk-vcodec-enc-y := mtk_vcodec_enc.o \ 7 + mtk-vcodec-enc-y := venc/venc_vp8_if.o \ 8 + venc/venc_h264_if.o \ 9 + mtk_vcodec_enc.o \ 7 10 mtk_vcodec_enc_drv.o \ 8 11 mtk_vcodec_enc_pm.o \ 9 12 venc_drv_if.o \ 13 + venc_vpu_if.o \ 10 14 11 15 mtk-vcodec-common-y := mtk_vcodec_intr.o \ 12 16 mtk_vcodec_util.o\
+481
drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> 4 + * PoChun Lin <pochun.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 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. 15 + */ 16 + 17 + #include <linux/interrupt.h> 18 + #include <linux/kernel.h> 19 + #include <linux/slab.h> 20 + 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" 29 + #include "mtk_vpu.h" 30 + 31 + #define VENC_BITSTREAM_FRAME_SIZE 0x0098 32 + #define VENC_BITSTREAM_HEADER_LEN 0x00e8 33 + 34 + /* This ac_tag is vp8 frame tag. */ 35 + #define MAX_AC_TAG_SIZE 10 36 + 37 + /** 38 + * enum venc_vp8_vpu_work_buf - vp8 encoder buffer index 39 + */ 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, 55 + }; 56 + 57 + /* 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 63 + * size. 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. 72 + */ 73 + struct venc_vp8_vpu_config { 74 + u32 input_fourcc; 75 + u32 bitrate; 76 + u32 pic_w; 77 + u32 pic_h; 78 + u32 buf_w; 79 + u32 buf_h; 80 + u32 gop_size; 81 + u32 framerate; 82 + u32 ts_mode; 83 + }; 84 + 85 + /* 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) 91 + */ 92 + struct venc_vp8_vpu_buf { 93 + u32 align; 94 + u32 iova; 95 + u32 vpua; 96 + u32 size; 97 + }; 98 + 99 + /* 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. 110 + */ 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]; 114 + }; 115 + 116 + /* 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 129 + */ 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; 139 + }; 140 + 141 + static inline void vp8_enc_write_reg(struct venc_vp8_inst *inst, u32 addr, 142 + u32 val) 143 + { 144 + writel(val, inst->hw_base + addr); 145 + } 146 + 147 + static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr) 148 + { 149 + return readl(inst->hw_base + addr); 150 + } 151 + 152 + static void vp8_enc_free_work_buf(struct venc_vp8_inst *inst) 153 + { 154 + int i; 155 + 156 + mtk_vcodec_debug_enter(inst); 157 + 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)) 161 + continue; 162 + mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]); 163 + } 164 + 165 + mtk_vcodec_debug_leave(inst); 166 + } 167 + 168 + static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst) 169 + { 170 + int i; 171 + int ret = 0; 172 + struct venc_vp8_vpu_buf *wb = inst->vsi->work_bufs; 173 + 174 + mtk_vcodec_debug_enter(inst); 175 + 176 + for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) { 177 + if ((wb[i].size == 0)) 178 + continue; 179 + /* 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. 188 + */ 189 + inst->work_bufs[i].size = wb[i].size; 190 + ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->work_bufs[i]); 191 + if (ret) { 192 + mtk_vcodec_err(inst, 193 + "cannot alloc work_bufs[%d]", i); 194 + goto err_alloc; 195 + } 196 + /* 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. 200 + */ 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) { 204 + void *tmp_va; 205 + 206 + tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev, 207 + wb[i].vpua); 208 + memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size); 209 + } 210 + wb[i].iova = inst->work_bufs[i].dma_addr; 211 + 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); 217 + } 218 + 219 + mtk_vcodec_debug_leave(inst); 220 + 221 + return ret; 222 + 223 + err_alloc: 224 + vp8_enc_free_work_buf(inst); 225 + 226 + return ret; 227 + } 228 + 229 + static unsigned int vp8_enc_wait_venc_done(struct venc_vp8_inst *inst) 230 + { 231 + unsigned int irq_status = 0; 232 + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx; 233 + 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); 238 + } 239 + return irq_status; 240 + } 241 + 242 + /* 243 + * Compose ac_tag, bitstream header and bitstream payload into 244 + * one bitstream buffer. 245 + */ 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) 249 + { 250 + unsigned int not_key; 251 + u32 bs_frm_size; 252 + u32 bs_hdr_len; 253 + unsigned int ac_tag_size; 254 + u8 ac_tag[MAX_AC_TAG_SIZE]; 255 + 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); 258 + 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); 262 + /* key frame */ 263 + if (not_key == 0) { 264 + ac_tag_size = MAX_AC_TAG_SIZE; 265 + ac_tag[3] = 0x9d; 266 + ac_tag[4] = 0x01; 267 + ac_tag[5] = 0x2a; 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; 272 + } else { 273 + ac_tag_size = 3; 274 + } 275 + 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)", 278 + bs_buf->size); 279 + return -EINVAL; 280 + } 281 + 282 + /* 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. 288 + */ 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, 293 + bs_hdr_len); 294 + memcpy(bs_buf->va, ac_tag, ac_tag_size); 295 + *bs_size = bs_frm_size + bs_hdr_len + ac_tag_size; 296 + 297 + return 0; 298 + } 299 + 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) 304 + { 305 + int ret = 0; 306 + unsigned int irq_status; 307 + 308 + mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt); 309 + 310 + ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size); 311 + if (ret) 312 + return ret; 313 + 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); 317 + return -EIO; 318 + } 319 + 320 + if (vp8_enc_compose_one_frame(inst, bs_buf, bs_size)) { 321 + mtk_vcodec_err(inst, "vp8_enc_compose_one_frame failed"); 322 + return -EINVAL; 323 + } 324 + 325 + inst->frm_cnt++; 326 + mtk_vcodec_debug(inst, "<-size=%d key_frm=%d", *bs_size, 327 + inst->vpu_inst.is_key_frm); 328 + 329 + return ret; 330 + } 331 + 332 + static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) 333 + { 334 + int ret = 0; 335 + struct venc_vp8_inst *inst; 336 + 337 + inst = kzalloc(sizeof(*inst), GFP_KERNEL); 338 + if (!inst) 339 + return -ENOMEM; 340 + 341 + inst->ctx = ctx; 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); 346 + 347 + mtk_vcodec_debug_enter(inst); 348 + 349 + ret = vpu_enc_init(&inst->vpu_inst); 350 + 351 + inst->vsi = (struct venc_vp8_vsi *)inst->vpu_inst.vsi; 352 + 353 + mtk_vcodec_debug_leave(inst); 354 + 355 + if (ret) 356 + kfree(inst); 357 + else 358 + (*handle) = (unsigned long)inst; 359 + 360 + return ret; 361 + } 362 + 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) 368 + { 369 + int ret = 0; 370 + struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle; 371 + struct mtk_vcodec_ctx *ctx = inst->ctx; 372 + 373 + mtk_vcodec_debug_enter(inst); 374 + 375 + enable_irq(ctx->dev->enc_lt_irq); 376 + 377 + switch (opt) { 378 + case VENC_START_OPT_ENCODE_FRAME: 379 + ret = vp8_enc_encode_frame(inst, frm_buf, bs_buf, 380 + &result->bs_size); 381 + if (ret) 382 + goto encode_err; 383 + result->is_key_frm = inst->vpu_inst.is_key_frm; 384 + break; 385 + 386 + default: 387 + mtk_vcodec_err(inst, "opt not support:%d", opt); 388 + ret = -EINVAL; 389 + break; 390 + } 391 + 392 + encode_err: 393 + 394 + disable_irq(ctx->dev->enc_lt_irq); 395 + mtk_vcodec_debug_leave(inst); 396 + 397 + return ret; 398 + } 399 + 400 + static int vp8_enc_set_param(unsigned long handle, 401 + enum venc_set_param_type type, 402 + struct venc_enc_param *enc_prm) 403 + { 404 + int ret = 0; 405 + struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle; 406 + 407 + mtk_vcodec_debug(inst, "->type=%d", type); 408 + 409 + switch (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); 421 + if (ret) 422 + break; 423 + if (inst->work_buf_allocated) { 424 + vp8_enc_free_work_buf(inst); 425 + inst->work_buf_allocated = false; 426 + } 427 + ret = vp8_enc_alloc_work_buf(inst); 428 + if (ret) 429 + break; 430 + inst->work_buf_allocated = true; 431 + break; 432 + 433 + /* 434 + * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC 435 + */ 436 + case VENC_SET_PARAM_TS_MODE: 437 + inst->ts_mode = 1; 438 + mtk_vcodec_debug(inst, "set ts_mode"); 439 + break; 440 + 441 + default: 442 + ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm); 443 + break; 444 + } 445 + 446 + mtk_vcodec_debug_leave(inst); 447 + 448 + return ret; 449 + } 450 + 451 + static int vp8_enc_deinit(unsigned long handle) 452 + { 453 + int ret = 0; 454 + struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle; 455 + 456 + mtk_vcodec_debug_enter(inst); 457 + 458 + ret = vpu_enc_deinit(&inst->vpu_inst); 459 + 460 + if (inst->work_buf_allocated) 461 + vp8_enc_free_work_buf(inst); 462 + 463 + mtk_vcodec_debug_leave(inst); 464 + kfree(inst); 465 + 466 + return ret; 467 + } 468 + 469 + static struct venc_common_if venc_vp8_if = { 470 + vp8_enc_init, 471 + vp8_enc_encode, 472 + vp8_enc_set_param, 473 + vp8_enc_deinit, 474 + }; 475 + 476 + struct venc_common_if *get_vp8_enc_comm_if(void); 477 + 478 + struct venc_common_if *get_vp8_enc_comm_if(void) 479 + { 480 + return &venc_vp8_if; 481 + }
+6 -1
drivers/media/platform/mtk-vcodec/venc_drv_if.c
··· 19 19 #include <linux/kernel.h> 20 20 #include <linux/slab.h> 21 21 22 + #include "venc_drv_base.h" 22 23 #include "venc_drv_if.h" 24 + 23 25 #include "mtk_vcodec_enc.h" 24 26 #include "mtk_vcodec_enc_pm.h" 25 27 #include "mtk_vpu.h" 26 28 27 - #include "venc_drv_base.h" 29 + 30 + struct venc_common_if *get_vp8_enc_comm_if(void); 28 31 29 32 int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) 30 33 { ··· 35 32 36 33 switch (fourcc) { 37 34 case V4L2_PIX_FMT_VP8: 35 + ctx->enc_if = get_vp8_enc_comm_if(); 36 + break; 38 37 case V4L2_PIX_FMT_H264: 39 38 default: 40 39 return -EINVAL;
+237
drivers/media/platform/mtk-vcodec/venc_vpu_if.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PoChun Lin <pochun.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include "mtk_vpu.h" 17 + #include "venc_ipi_msg.h" 18 + #include "venc_vpu_if.h" 19 + 20 + static void handle_enc_init_msg(struct venc_vpu_inst *vpu, void *data) 21 + { 22 + struct venc_vpu_ipi_msg_init *msg = data; 23 + 24 + vpu->inst_addr = msg->vpu_inst_addr; 25 + vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr); 26 + } 27 + 28 + static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data) 29 + { 30 + struct venc_vpu_ipi_msg_enc *msg = data; 31 + 32 + vpu->state = msg->state; 33 + vpu->bs_size = msg->bs_size; 34 + vpu->is_key_frm = msg->is_key_frm; 35 + } 36 + 37 + static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv) 38 + { 39 + struct venc_vpu_ipi_msg_common *msg = data; 40 + struct venc_vpu_inst *vpu = (struct venc_vpu_inst *)msg->venc_inst; 41 + 42 + mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d", 43 + msg->msg_id, vpu, msg->status); 44 + 45 + switch (msg->msg_id) { 46 + case VPU_IPIMSG_ENC_INIT_DONE: 47 + handle_enc_init_msg(vpu, data); 48 + break; 49 + case VPU_IPIMSG_ENC_SET_PARAM_DONE: 50 + break; 51 + case VPU_IPIMSG_ENC_ENCODE_DONE: 52 + handle_enc_encode_msg(vpu, data); 53 + break; 54 + case VPU_IPIMSG_ENC_DEINIT_DONE: 55 + break; 56 + default: 57 + mtk_vcodec_err(vpu, "unknown msg id %x", msg->msg_id); 58 + break; 59 + } 60 + 61 + vpu->signaled = 1; 62 + vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK); 63 + 64 + mtk_vcodec_debug_leave(vpu); 65 + } 66 + 67 + static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg, 68 + int len) 69 + { 70 + int status; 71 + 72 + mtk_vcodec_debug_enter(vpu); 73 + 74 + if (!vpu->dev) { 75 + mtk_vcodec_err(vpu, "inst dev is NULL"); 76 + return -EINVAL; 77 + } 78 + 79 + status = vpu_ipi_send(vpu->dev, vpu->id, msg, len); 80 + if (status) { 81 + uint32_t msg_id = *(uint32_t *)msg; 82 + 83 + mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d", 84 + msg_id, len, status); 85 + return -EINVAL; 86 + } 87 + if (vpu->failure) 88 + return -EINVAL; 89 + 90 + mtk_vcodec_debug_leave(vpu); 91 + 92 + return 0; 93 + } 94 + 95 + int vpu_enc_init(struct venc_vpu_inst *vpu) 96 + { 97 + int status; 98 + struct venc_ap_ipi_msg_init out; 99 + 100 + mtk_vcodec_debug_enter(vpu); 101 + 102 + init_waitqueue_head(&vpu->wq_hd); 103 + vpu->signaled = 0; 104 + vpu->failure = 0; 105 + 106 + status = vpu_ipi_register(vpu->dev, vpu->id, vpu_enc_ipi_handler, 107 + NULL, NULL); 108 + if (status) { 109 + mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status); 110 + return -EINVAL; 111 + } 112 + 113 + memset(&out, 0, sizeof(out)); 114 + out.msg_id = AP_IPIMSG_ENC_INIT; 115 + out.venc_inst = (unsigned long)vpu; 116 + if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { 117 + mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail"); 118 + return -EINVAL; 119 + } 120 + 121 + mtk_vcodec_debug_leave(vpu); 122 + 123 + return 0; 124 + } 125 + 126 + int vpu_enc_set_param(struct venc_vpu_inst *vpu, 127 + enum venc_set_param_type id, 128 + struct venc_enc_param *enc_param) 129 + { 130 + struct venc_ap_ipi_msg_set_param out; 131 + 132 + mtk_vcodec_debug(vpu, "id %d ->", id); 133 + 134 + memset(&out, 0, sizeof(out)); 135 + out.msg_id = AP_IPIMSG_ENC_SET_PARAM; 136 + out.vpu_inst_addr = vpu->inst_addr; 137 + out.param_id = id; 138 + switch (id) { 139 + case VENC_SET_PARAM_ENC: 140 + out.data_item = 0; 141 + break; 142 + case VENC_SET_PARAM_FORCE_INTRA: 143 + out.data_item = 0; 144 + break; 145 + case VENC_SET_PARAM_ADJUST_BITRATE: 146 + out.data_item = 1; 147 + out.data[0] = enc_param->bitrate; 148 + break; 149 + case VENC_SET_PARAM_ADJUST_FRAMERATE: 150 + out.data_item = 1; 151 + out.data[0] = enc_param->frm_rate; 152 + break; 153 + case VENC_SET_PARAM_GOP_SIZE: 154 + out.data_item = 1; 155 + out.data[0] = enc_param->gop_size; 156 + break; 157 + case VENC_SET_PARAM_INTRA_PERIOD: 158 + out.data_item = 1; 159 + out.data[0] = enc_param->intra_period; 160 + break; 161 + case VENC_SET_PARAM_SKIP_FRAME: 162 + out.data_item = 0; 163 + break; 164 + default: 165 + mtk_vcodec_err(vpu, "id %d not supported", id); 166 + return -EINVAL; 167 + } 168 + if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { 169 + mtk_vcodec_err(vpu, 170 + "AP_IPIMSG_ENC_SET_PARAM %d fail", id); 171 + return -EINVAL; 172 + } 173 + 174 + mtk_vcodec_debug(vpu, "id %d <-", id); 175 + 176 + return 0; 177 + } 178 + 179 + int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, 180 + struct venc_frm_buf *frm_buf, 181 + struct mtk_vcodec_mem *bs_buf, 182 + unsigned int *bs_size) 183 + { 184 + struct venc_ap_ipi_msg_enc out; 185 + 186 + mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode); 187 + 188 + memset(&out, 0, sizeof(out)); 189 + out.msg_id = AP_IPIMSG_ENC_ENCODE; 190 + out.vpu_inst_addr = vpu->inst_addr; 191 + out.bs_mode = bs_mode; 192 + if (frm_buf) { 193 + if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) && 194 + (frm_buf->fb_addr[1].dma_addr % 16 == 0) && 195 + (frm_buf->fb_addr[2].dma_addr % 16 == 0)) { 196 + out.input_addr[0] = frm_buf->fb_addr[0].dma_addr; 197 + out.input_addr[1] = frm_buf->fb_addr[1].dma_addr; 198 + out.input_addr[2] = frm_buf->fb_addr[2].dma_addr; 199 + } else { 200 + mtk_vcodec_err(vpu, "dma_addr not align to 16"); 201 + return -EINVAL; 202 + } 203 + } 204 + if (bs_buf) { 205 + out.bs_addr = bs_buf->dma_addr; 206 + out.bs_size = bs_buf->size; 207 + } 208 + if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { 209 + mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail", 210 + bs_mode); 211 + return -EINVAL; 212 + } 213 + 214 + mtk_vcodec_debug(vpu, "bs_mode %d state %d size %d key_frm %d <-", 215 + bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm); 216 + 217 + return 0; 218 + } 219 + 220 + int vpu_enc_deinit(struct venc_vpu_inst *vpu) 221 + { 222 + struct venc_ap_ipi_msg_deinit out; 223 + 224 + mtk_vcodec_debug_enter(vpu); 225 + 226 + memset(&out, 0, sizeof(out)); 227 + out.msg_id = AP_IPIMSG_ENC_DEINIT; 228 + out.vpu_inst_addr = vpu->inst_addr; 229 + if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { 230 + mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_DEINIT fail"); 231 + return -EINVAL; 232 + } 233 + 234 + mtk_vcodec_debug_leave(vpu); 235 + 236 + return 0; 237 + }
+61
drivers/media/platform/mtk-vcodec/venc_vpu_if.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PoChun Lin <pochun.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef _VENC_VPU_IF_H_ 17 + #define _VENC_VPU_IF_H_ 18 + 19 + #include "mtk_vpu.h" 20 + #include "venc_drv_if.h" 21 + 22 + /* 23 + * struct venc_vpu_inst - encoder VPU driver instance 24 + * @wq_hd: wait queue used for vpu cmd trigger then wait vpu interrupt done 25 + * @signaled: flag used for checking vpu interrupt done 26 + * @failure: flag to show vpu cmd succeeds or not 27 + * @state: enum venc_ipi_msg_enc_state 28 + * @bs_size: bitstream size for skip frame case usage 29 + * @is_key_frm: key frame flag 30 + * @inst_addr: VPU instance addr 31 + * @vsi: driver structure allocated by VPU side and shared to AP side for 32 + * control and info share 33 + * @id: the id of inter-processor interrupt 34 + * @ctx: context for v4l2 layer integration 35 + * @dev: device for v4l2 layer integration 36 + */ 37 + struct venc_vpu_inst { 38 + wait_queue_head_t wq_hd; 39 + int signaled; 40 + int failure; 41 + int state; 42 + int bs_size; 43 + int is_key_frm; 44 + unsigned int inst_addr; 45 + void *vsi; 46 + enum ipi_id id; 47 + struct mtk_vcodec_ctx *ctx; 48 + struct platform_device *dev; 49 + }; 50 + 51 + int vpu_enc_init(struct venc_vpu_inst *vpu); 52 + int vpu_enc_set_param(struct venc_vpu_inst *vpu, 53 + enum venc_set_param_type id, 54 + struct venc_enc_param *param); 55 + int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, 56 + struct venc_frm_buf *frm_buf, 57 + struct mtk_vcodec_mem *bs_buf, 58 + unsigned int *bs_size); 59 + int vpu_enc_deinit(struct venc_vpu_inst *vpu); 60 + 61 + #endif