linux/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
<<
>>
Prefs
   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 */
  31enum 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 */
  66struct 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 */
  86struct 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 */
 106struct 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 */
 125struct 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
 136static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr)
 137{
 138        return readl(inst->hw_base + addr);
 139}
 140
 141static 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
 157static 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
 212err_alloc:
 213        vp8_enc_free_work_buf(inst);
 214
 215        return ret;
 216}
 217
 218static 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 */
 235static 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
 294static 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
 326static 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
 357static 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
 386encode_err:
 387
 388        disable_irq(ctx->dev->enc_lt_irq);
 389        mtk_vcodec_debug_leave(inst);
 390
 391        return ret;
 392}
 393
 394static 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
 445static 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
 463const 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};
 469