root/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vp8_enc_read_reg
  2. vp8_enc_free_work_buf
  3. vp8_enc_alloc_work_buf
  4. vp8_enc_wait_venc_done
  5. vp8_enc_compose_one_frame
  6. vp8_enc_encode_frame
  7. vp8_enc_init
  8. vp8_enc_encode
  9. vp8_enc_set_param
  10. vp8_enc_deinit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2016 MediaTek Inc.
   4  * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
   5  *         PoChun Lin <pochun.lin@mediatek.com>
   6  */
   7 
   8 #include <linux/interrupt.h>
   9 #include <linux/kernel.h>
  10 #include <linux/slab.h>
  11 
  12 #include "../mtk_vcodec_drv.h"
  13 #include "../mtk_vcodec_util.h"
  14 #include "../mtk_vcodec_intr.h"
  15 #include "../mtk_vcodec_enc.h"
  16 #include "../mtk_vcodec_enc_pm.h"
  17 #include "../venc_drv_base.h"
  18 #include "../venc_ipi_msg.h"
  19 #include "../venc_vpu_if.h"
  20 #include "mtk_vpu.h"
  21 
  22 #define VENC_BITSTREAM_FRAME_SIZE 0x0098
  23 #define VENC_BITSTREAM_HEADER_LEN 0x00e8
  24 
  25 /* This ac_tag is vp8 frame tag. */
  26 #define MAX_AC_TAG_SIZE 10
  27 
  28 /*
  29  * enum venc_vp8_vpu_work_buf - vp8 encoder buffer index
  30  */
  31 enum venc_vp8_vpu_work_buf {
  32         VENC_VP8_VPU_WORK_BUF_LUMA,
  33         VENC_VP8_VPU_WORK_BUF_LUMA2,
  34         VENC_VP8_VPU_WORK_BUF_LUMA3,
  35         VENC_VP8_VPU_WORK_BUF_CHROMA,
  36         VENC_VP8_VPU_WORK_BUF_CHROMA2,
  37         VENC_VP8_VPU_WORK_BUF_CHROMA3,
  38         VENC_VP8_VPU_WORK_BUF_MV_INFO,
  39         VENC_VP8_VPU_WORK_BUF_BS_HEADER,
  40         VENC_VP8_VPU_WORK_BUF_PROB_BUF,
  41         VENC_VP8_VPU_WORK_BUF_RC_INFO,
  42         VENC_VP8_VPU_WORK_BUF_RC_CODE,
  43         VENC_VP8_VPU_WORK_BUF_RC_CODE2,
  44         VENC_VP8_VPU_WORK_BUF_RC_CODE3,
  45         VENC_VP8_VPU_WORK_BUF_MAX,
  46 };
  47 
  48 /*
  49  * struct venc_vp8_vpu_config - Structure for vp8 encoder configuration
  50  *                              AP-W/R : AP is writer/reader on this item
  51  *                              VPU-W/R: VPU is write/reader on this item
  52  * @input_fourcc: input fourcc
  53  * @bitrate: target bitrate (in bps)
  54  * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
  55  *         to be used for display purposes; must be smaller or equal to buffer
  56  *         size.
  57  * @pic_h: picture height
  58  * @buf_w: buffer width (with 16 alignment). Buffer size is stream resolution
  59  *         in pixels aligned to hardware requirements.
  60  * @buf_h: buffer height (with 16 alignment)
  61  * @gop_size: group of picture size (key frame)
  62  * @framerate: frame rate in fps
  63  * @ts_mode: temporal scalability mode (0: disable, 1: enable)
  64  *           support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
  65  */
  66 struct venc_vp8_vpu_config {
  67         u32 input_fourcc;
  68         u32 bitrate;
  69         u32 pic_w;
  70         u32 pic_h;
  71         u32 buf_w;
  72         u32 buf_h;
  73         u32 gop_size;
  74         u32 framerate;
  75         u32 ts_mode;
  76 };
  77 
  78 /*
  79  * struct venc_vp8_vpu_buf - Structure for buffer information
  80  *                           AP-W/R : AP is writer/reader on this item
  81  *                           VPU-W/R: VPU is write/reader on this item
  82  * @iova: IO virtual address
  83  * @vpua: VPU side memory addr which is used by RC_CODE
  84  * @size: buffer size (in bytes)
  85  */
  86 struct venc_vp8_vpu_buf {
  87         u32 iova;
  88         u32 vpua;
  89         u32 size;
  90 };
  91 
  92 /*
  93  * struct venc_vp8_vsi - Structure for VPU driver control and info share
  94  *                       AP-W/R : AP is writer/reader on this item
  95  *                       VPU-W/R: VPU is write/reader on this item
  96  * This structure is allocated in VPU side and shared to AP side.
  97  * @config: vp8 encoder configuration
  98  * @work_bufs: working buffer information in VPU side
  99  * The work_bufs here is for storing the 'size' info shared to AP side.
 100  * The similar item in struct venc_vp8_inst is for memory allocation
 101  * in AP side. The AP driver will copy the 'size' from here to the one in
 102  * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
 103  * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
 104  * register setting in VPU side.
 105  */
 106 struct venc_vp8_vsi {
 107         struct venc_vp8_vpu_config config;
 108         struct venc_vp8_vpu_buf work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
 109 };
 110 
 111 /*
 112  * struct venc_vp8_inst - vp8 encoder AP driver instance
 113  * @hw_base: vp8 encoder hardware register base
 114  * @work_bufs: working buffer
 115  * @work_buf_allocated: working buffer allocated flag
 116  * @frm_cnt: encoded frame count, it's used for I-frame judgement and
 117  *           reset when force intra cmd received.
 118  * @ts_mode: temporal scalability mode (0: disable, 1: enable)
 119  *           support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
 120  * @vpu_inst: VPU instance to exchange information between AP and VPU
 121  * @vsi: driver structure allocated by VPU side and shared to AP side for
 122  *       control and info share
 123  * @ctx: context for v4l2 layer integration
 124  */
 125 struct venc_vp8_inst {
 126         void __iomem *hw_base;
 127         struct mtk_vcodec_mem work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
 128         bool work_buf_allocated;
 129         unsigned int frm_cnt;
 130         unsigned int ts_mode;
 131         struct venc_vpu_inst vpu_inst;
 132         struct venc_vp8_vsi *vsi;
 133         struct mtk_vcodec_ctx *ctx;
 134 };
 135 
 136 static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr)
 137 {
 138         return readl(inst->hw_base + addr);
 139 }
 140 
 141 static void vp8_enc_free_work_buf(struct venc_vp8_inst *inst)
 142 {
 143         int i;
 144 
 145         mtk_vcodec_debug_enter(inst);
 146 
 147         /* Buffers need to be freed by AP. */
 148         for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
 149                 if (inst->work_bufs[i].size == 0)
 150                         continue;
 151                 mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]);
 152         }
 153 
 154         mtk_vcodec_debug_leave(inst);
 155 }
 156 
 157 static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
 158 {
 159         int i;
 160         int ret = 0;
 161         struct venc_vp8_vpu_buf *wb = inst->vsi->work_bufs;
 162 
 163         mtk_vcodec_debug_enter(inst);
 164 
 165         for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
 166                 if (wb[i].size == 0)
 167                         continue;
 168                 /*
 169                  * This 'wb' structure is set by VPU side and shared to AP for
 170                  * buffer allocation and IO virtual addr mapping. For most of
 171                  * the buffers, AP will allocate the buffer according to 'size'
 172                  * field and store the IO virtual addr in 'iova' field. For the
 173                  * RC_CODEx buffers, they are pre-allocated in the VPU side
 174                  * because they are inside VPU SRAM, and save the VPU addr in
 175                  * the 'vpua' field. The AP will translate the VPU addr to the
 176                  * corresponding IO virtual addr and store in 'iova' field.
 177                  */
 178                 inst->work_bufs[i].size = wb[i].size;
 179                 ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->work_bufs[i]);
 180                 if (ret) {
 181                         mtk_vcodec_err(inst,
 182                                        "cannot alloc work_bufs[%d]", i);
 183                         goto err_alloc;
 184                 }
 185                 /*
 186                  * This RC_CODEx is pre-allocated by VPU and saved in VPU addr.
 187                  * So we need use memcpy to copy RC_CODEx from VPU addr into IO
 188                  * virtual addr in 'iova' field for reg setting in VPU side.
 189                  */
 190                 if (i == VENC_VP8_VPU_WORK_BUF_RC_CODE ||
 191                     i == VENC_VP8_VPU_WORK_BUF_RC_CODE2 ||
 192                     i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) {
 193                         void *tmp_va;
 194 
 195                         tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev,
 196                                                      wb[i].vpua);
 197                         memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size);
 198                 }
 199                 wb[i].iova = inst->work_bufs[i].dma_addr;
 200 
 201                 mtk_vcodec_debug(inst,
 202                                  "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
 203                                  i, inst->work_bufs[i].va,
 204                                  &inst->work_bufs[i].dma_addr,
 205                                  inst->work_bufs[i].size);
 206         }
 207 
 208         mtk_vcodec_debug_leave(inst);
 209 
 210         return ret;
 211 
 212 err_alloc:
 213         vp8_enc_free_work_buf(inst);
 214 
 215         return ret;
 216 }
 217 
 218 static unsigned int vp8_enc_wait_venc_done(struct venc_vp8_inst *inst)
 219 {
 220         unsigned int irq_status = 0;
 221         struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx;
 222 
 223         if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
 224                                           WAIT_INTR_TIMEOUT_MS)) {
 225                 irq_status = ctx->irq_status;
 226                 mtk_vcodec_debug(inst, "isr return %x", irq_status);
 227         }
 228         return irq_status;
 229 }
 230 
 231 /*
 232  * Compose ac_tag, bitstream header and bitstream payload into
 233  * one bitstream buffer.
 234  */
 235 static int vp8_enc_compose_one_frame(struct venc_vp8_inst *inst,
 236                                      struct mtk_vcodec_mem *bs_buf,
 237                                      unsigned int *bs_size)
 238 {
 239         unsigned int not_key;
 240         u32 bs_frm_size;
 241         u32 bs_hdr_len;
 242         unsigned int ac_tag_size;
 243         u8 ac_tag[MAX_AC_TAG_SIZE];
 244         u32 tag;
 245 
 246         bs_frm_size = vp8_enc_read_reg(inst, VENC_BITSTREAM_FRAME_SIZE);
 247         bs_hdr_len = vp8_enc_read_reg(inst, VENC_BITSTREAM_HEADER_LEN);
 248 
 249         /* if a frame is key frame, not_key is 0 */
 250         not_key = !inst->vpu_inst.is_key_frm;
 251         tag = (bs_hdr_len << 5) | 0x10 | not_key;
 252         ac_tag[0] = tag & 0xff;
 253         ac_tag[1] = (tag >> 8) & 0xff;
 254         ac_tag[2] = (tag >> 16) & 0xff;
 255 
 256         /* key frame */
 257         if (not_key == 0) {
 258                 ac_tag_size = MAX_AC_TAG_SIZE;
 259                 ac_tag[3] = 0x9d;
 260                 ac_tag[4] = 0x01;
 261                 ac_tag[5] = 0x2a;
 262                 ac_tag[6] = inst->vsi->config.pic_w;
 263                 ac_tag[7] = inst->vsi->config.pic_w >> 8;
 264                 ac_tag[8] = inst->vsi->config.pic_h;
 265                 ac_tag[9] = inst->vsi->config.pic_h >> 8;
 266         } else {
 267                 ac_tag_size = 3;
 268         }
 269 
 270         if (bs_buf->size < bs_hdr_len + bs_frm_size + ac_tag_size) {
 271                 mtk_vcodec_err(inst, "bitstream buf size is too small(%zu)",
 272                                bs_buf->size);
 273                 return -EINVAL;
 274         }
 275 
 276         /*
 277         * (1) The vp8 bitstream header and body are generated by the HW vp8
 278         * encoder separately at the same time. We cannot know the bitstream
 279         * header length in advance.
 280         * (2) From the vp8 spec, there is no stuffing byte allowed between the
 281         * ac tag, bitstream header and bitstream body.
 282         */
 283         memmove(bs_buf->va + bs_hdr_len + ac_tag_size,
 284                 bs_buf->va, bs_frm_size);
 285         memcpy(bs_buf->va + ac_tag_size,
 286                inst->work_bufs[VENC_VP8_VPU_WORK_BUF_BS_HEADER].va,
 287                bs_hdr_len);
 288         memcpy(bs_buf->va, ac_tag, ac_tag_size);
 289         *bs_size = bs_frm_size + bs_hdr_len + ac_tag_size;
 290 
 291         return 0;
 292 }
 293 
 294 static int vp8_enc_encode_frame(struct venc_vp8_inst *inst,
 295                                 struct venc_frm_buf *frm_buf,
 296                                 struct mtk_vcodec_mem *bs_buf,
 297                                 unsigned int *bs_size)
 298 {
 299         int ret = 0;
 300         unsigned int irq_status;
 301 
 302         mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt);
 303 
 304         ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size);
 305         if (ret)
 306                 return ret;
 307 
 308         irq_status = vp8_enc_wait_venc_done(inst);
 309         if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
 310                 mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
 311                 return -EIO;
 312         }
 313 
 314         if (vp8_enc_compose_one_frame(inst, bs_buf, bs_size)) {
 315                 mtk_vcodec_err(inst, "vp8_enc_compose_one_frame failed");
 316                 return -EINVAL;
 317         }
 318 
 319         inst->frm_cnt++;
 320         mtk_vcodec_debug(inst, "<-size=%d key_frm=%d", *bs_size,
 321                          inst->vpu_inst.is_key_frm);
 322 
 323         return ret;
 324 }
 325 
 326 static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
 327 {
 328         int ret = 0;
 329         struct venc_vp8_inst *inst;
 330 
 331         inst = kzalloc(sizeof(*inst), GFP_KERNEL);
 332         if (!inst)
 333                 return -ENOMEM;
 334 
 335         inst->ctx = ctx;
 336         inst->vpu_inst.ctx = ctx;
 337         inst->vpu_inst.dev = ctx->dev->vpu_plat_dev;
 338         inst->vpu_inst.id = IPI_VENC_VP8;
 339         inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS);
 340 
 341         mtk_vcodec_debug_enter(inst);
 342 
 343         ret = vpu_enc_init(&inst->vpu_inst);
 344 
 345         inst->vsi = (struct venc_vp8_vsi *)inst->vpu_inst.vsi;
 346 
 347         mtk_vcodec_debug_leave(inst);
 348 
 349         if (ret)
 350                 kfree(inst);
 351         else
 352                 ctx->drv_handle = inst;
 353 
 354         return ret;
 355 }
 356 
 357 static int vp8_enc_encode(void *handle,
 358                           enum venc_start_opt opt,
 359                           struct venc_frm_buf *frm_buf,
 360                           struct mtk_vcodec_mem *bs_buf,
 361                           struct venc_done_result *result)
 362 {
 363         int ret = 0;
 364         struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
 365         struct mtk_vcodec_ctx *ctx = inst->ctx;
 366 
 367         mtk_vcodec_debug_enter(inst);
 368 
 369         enable_irq(ctx->dev->enc_lt_irq);
 370 
 371         switch (opt) {
 372         case VENC_START_OPT_ENCODE_FRAME:
 373                 ret = vp8_enc_encode_frame(inst, frm_buf, bs_buf,
 374                                            &result->bs_size);
 375                 if (ret)
 376                         goto encode_err;
 377                 result->is_key_frm = inst->vpu_inst.is_key_frm;
 378                 break;
 379 
 380         default:
 381                 mtk_vcodec_err(inst, "opt not support:%d", opt);
 382                 ret = -EINVAL;
 383                 break;
 384         }
 385 
 386 encode_err:
 387 
 388         disable_irq(ctx->dev->enc_lt_irq);
 389         mtk_vcodec_debug_leave(inst);
 390 
 391         return ret;
 392 }
 393 
 394 static int vp8_enc_set_param(void *handle,
 395                              enum venc_set_param_type type,
 396                              struct venc_enc_param *enc_prm)
 397 {
 398         int ret = 0;
 399         struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
 400 
 401         mtk_vcodec_debug(inst, "->type=%d", type);
 402 
 403         switch (type) {
 404         case VENC_SET_PARAM_ENC:
 405                 inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
 406                 inst->vsi->config.bitrate = enc_prm->bitrate;
 407                 inst->vsi->config.pic_w = enc_prm->width;
 408                 inst->vsi->config.pic_h = enc_prm->height;
 409                 inst->vsi->config.buf_w = enc_prm->buf_width;
 410                 inst->vsi->config.buf_h = enc_prm->buf_height;
 411                 inst->vsi->config.gop_size = enc_prm->gop_size;
 412                 inst->vsi->config.framerate = enc_prm->frm_rate;
 413                 inst->vsi->config.ts_mode = inst->ts_mode;
 414                 ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
 415                 if (ret)
 416                         break;
 417                 if (inst->work_buf_allocated) {
 418                         vp8_enc_free_work_buf(inst);
 419                         inst->work_buf_allocated = false;
 420                 }
 421                 ret = vp8_enc_alloc_work_buf(inst);
 422                 if (ret)
 423                         break;
 424                 inst->work_buf_allocated = true;
 425                 break;
 426 
 427         /*
 428          * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC
 429          */
 430         case VENC_SET_PARAM_TS_MODE:
 431                 inst->ts_mode = 1;
 432                 mtk_vcodec_debug(inst, "set ts_mode");
 433                 break;
 434 
 435         default:
 436                 ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
 437                 break;
 438         }
 439 
 440         mtk_vcodec_debug_leave(inst);
 441 
 442         return ret;
 443 }
 444 
 445 static int vp8_enc_deinit(void *handle)
 446 {
 447         int ret = 0;
 448         struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
 449 
 450         mtk_vcodec_debug_enter(inst);
 451 
 452         ret = vpu_enc_deinit(&inst->vpu_inst);
 453 
 454         if (inst->work_buf_allocated)
 455                 vp8_enc_free_work_buf(inst);
 456 
 457         mtk_vcodec_debug_leave(inst);
 458         kfree(inst);
 459 
 460         return ret;
 461 }
 462 
 463 const struct venc_common_if venc_vp8_if = {
 464         .init = vp8_enc_init,
 465         .encode = vp8_enc_encode,
 466         .set_param = vp8_enc_set_param,
 467         .deinit = vp8_enc_deinit,
 468 };

/* [<][>][^][v][top][bottom][index][help] */