Dual core mode encoding need more venc working buffers, it will break the compatibility if we just add venc_vsi in AP-Kernel but not in firmware, so add more struct definition for it. Signed-off-by: Irui Wang <irui.wang@xxxxxxxxxxxx> --- .../platform/mtk-vcodec/mtk_vcodec_drv.h | 1 + .../platform/mtk-vcodec/mtk_vcodec_util.c | 19 ++ .../platform/mtk-vcodec/mtk_vcodec_util.h | 4 + .../platform/mtk-vcodec/venc/venc_h264_if.c | 178 +++++++++++++++--- 4 files changed, 177 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 9e4e4290a69a..dc036279c42f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -452,6 +452,7 @@ struct mtk_vcodec_enc_pdata { }; #define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext) +#define MTK_ENC_CORE_MODE(ctx) ((ctx)->dev->venc_pdata->core_mode) /** * struct mtk_vcodec_dev - driver data diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index ace78c4b5b9e..059f665afa96 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -11,6 +11,7 @@ #include "mtk_vcodec_dec_hw.h" #include "mtk_vcodec_drv.h" +#include "mtk_vcodec_enc_core.h" #include "mtk_vcodec_util.h" void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, @@ -26,6 +27,24 @@ void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, } EXPORT_SYMBOL(mtk_vcodec_get_reg_addr); +void __iomem *mtk_venc_get_core_reg_addr(struct mtk_vcodec_ctx *ctx, + unsigned int core_id) +{ + struct mtk_venc_core_dev *core; + + if (core_id >= MTK_VENC_CORE_MAX) { + mtk_v4l2_err("Invalid core_id = %d", core_id); + return NULL; + } + + core = (struct mtk_venc_core_dev *)ctx->dev->enc_core_dev[core_id]; + if (!core) + return NULL; + + return core->reg_base; +} +EXPORT_SYMBOL(mtk_venc_get_core_reg_addr); + int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, struct mtk_vcodec_mem *mem) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index 71956627a0e2..de9e18688842 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h @@ -50,6 +50,10 @@ struct mtk_vcodec_dev; void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, unsigned int reg_idx); + +void __iomem *mtk_venc_get_core_reg_addr(struct mtk_vcodec_ctx *data, + unsigned int core_id); + int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, struct mtk_vcodec_mem *mem); void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 4d9b8798dffe..023b6eb8b20c 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -50,6 +50,24 @@ enum venc_h264_vpu_work_buf { VENC_H264_VPU_WORK_BUF_MAX, }; +/* + * enum venc_dual_core_work_buf - h264 dual core encoder buffer index + */ +enum venc_dual_core_work_buf { + VENC_DUAL_CORE_WORK_BUF_RC_INFO_CORE0, + VENC_DUAL_CORE_WORK_BUF_RC_CODE, + VENC_DUAL_CORE_WORK_BUF_REC_LUMA, + VENC_DUAL_CORE_WORK_BUF_REC_CHROMA, + VENC_DUAL_CORE_WORK_BUF_REF_LUMA, + VENC_DUAL_CORE_WORK_BUF_REF_CHROMA, + VENC_DUAL_CORE_WORK_BUF_MV_INFO_1, + VENC_DUAL_CORE_WORK_BUF_MV_INFO_2, + VENC_DUAL_CORE_WORK_BUF_SKIP_FRAME, + VENC_DUAL_CORE_WORK_BUF_RC_INFO_CORE1, + VENC_DUAL_CORE_WORK_BUF_FR_RC_INFO, + VENC_DUAL_CORE_WORK_BUF_MAX, +}; + /* * enum venc_h264_bs_mode - for bs_mode argument in h264_enc_vpu_encode */ @@ -94,6 +112,24 @@ struct venc_h264_vpu_config { u32 wfd; }; +struct venc_dual_core_config { + u32 input_fourcc; + u32 bitrate; + u32 pic_w; + u32 pic_h; + u32 buf_w; + u32 buf_h; + u32 gop_size; + u32 intra_period; + u32 framerate; + u32 profile; + u32 level; + u32 wfd; + u32 max_qp; + u32 min_qp; + u32 reserved[8]; +}; + /* * struct venc_h264_vpu_buf - Structure for buffer information * AP-W/R : AP is writer/reader on this item @@ -127,6 +163,11 @@ struct venc_h264_vsi { struct venc_h264_vpu_buf work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; }; +struct venc_dual_core_vsi { + struct venc_dual_core_config config; + struct venc_h264_vpu_buf work_bufs[VENC_DUAL_CORE_WORK_BUF_MAX]; +}; + /* * struct venc_h264_inst - h264 encoder AP driver instance * @hw_base: h264 encoder hardware register base @@ -143,8 +184,8 @@ struct venc_h264_vsi { * @ctx: context for v4l2 layer integration */ struct venc_h264_inst { - void __iomem *hw_base; - struct mtk_vcodec_mem work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; + void __iomem *hw_base[MTK_VENC_CORE_MAX]; + struct mtk_vcodec_mem work_bufs[VENC_DUAL_CORE_WORK_BUF_MAX]; struct mtk_vcodec_mem pps_buf; bool work_buf_allocated; unsigned int frm_cnt; @@ -152,12 +193,13 @@ struct venc_h264_inst { unsigned int prepend_hdr; struct venc_vpu_inst vpu_inst; struct venc_h264_vsi *vsi; + struct venc_dual_core_vsi *core_vsi; struct mtk_vcodec_ctx *ctx; }; static inline u32 h264_read_reg(struct venc_h264_inst *inst, u32 addr) { - return readl(inst->hw_base + addr); + return readl(inst->hw_base[MTK_VENC_CORE0] + addr); } static unsigned int h264_get_profile(struct venc_h264_inst *inst, @@ -228,13 +270,21 @@ static unsigned int h264_get_level(struct venc_h264_inst *inst, static void h264_enc_free_work_buf(struct venc_h264_inst *inst) { int i; + struct mtk_vcodec_ctx *ctx = inst->ctx; + int max_work_buf; + bool is_dual_core = (MTK_ENC_CORE_MODE(ctx) == VENC_DUAL_CORE_MODE); mtk_vcodec_debug_enter(inst); + if (is_dual_core) + max_work_buf = VENC_DUAL_CORE_WORK_BUF_MAX; + else + max_work_buf = VENC_H264_VPU_WORK_BUF_MAX; + /* Except the SKIP_FRAME buffers, * other buffers need to be freed by AP. */ - for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) { + for (i = 0; i < max_work_buf; i++) { if (i != VENC_H264_VPU_WORK_BUF_SKIP_FRAME) mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]); } @@ -248,11 +298,22 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) { int i; int ret = 0; - struct venc_h264_vpu_buf *wb = inst->vsi->work_bufs; + struct mtk_vcodec_ctx *ctx = inst->ctx; + struct venc_h264_vpu_buf *wb; + int max_work_buf; + bool is_dual_core = (MTK_ENC_CORE_MODE(ctx) == VENC_DUAL_CORE_MODE); mtk_vcodec_debug_enter(inst); - for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) { + if (is_dual_core) { + wb = inst->core_vsi->work_bufs; + max_work_buf = VENC_DUAL_CORE_WORK_BUF_MAX; + } else { + wb = inst->vsi->work_bufs; + max_work_buf = VENC_H264_VPU_WORK_BUF_MAX; + } + + for (i = 0; i < max_work_buf; i++) { /* * This 'wb' structure is set by VPU side and shared to AP for * buffer allocation and IO virtual addr mapping. For most of @@ -358,6 +419,26 @@ static int h264_frame_type(struct venc_h264_inst *inst) return VENC_H264_P_FRM; /* Note: B frames are not supported */ } } + +static int h264_core_frame_type(struct venc_h264_inst *inst) +{ + struct venc_dual_core_vsi *vsi = inst->core_vsi; + + if ((vsi->config.gop_size != 0 && + (inst->frm_cnt % vsi->config.gop_size) == 0) || + (inst->frm_cnt == 0 && vsi->config.gop_size == 0)) { + /* IDR frame */ + return VENC_H264_IDR_FRM; + } else if ((vsi->config.intra_period != 0 && + (inst->frm_cnt % vsi->config.intra_period) == 0) || + (inst->frm_cnt == 0 && vsi->config.intra_period == 0)) { + /* I frame */ + return VENC_H264_I_FRM; + } else { + return VENC_H264_P_FRM; /* Note: B frames are not supported */ + } +} + static int h264_encode_sps(struct venc_h264_inst *inst, struct mtk_vcodec_mem *bs_buf, unsigned int *bs_size) @@ -440,12 +521,18 @@ static int h264_encode_frame(struct venc_h264_inst *inst, int ret = 0; unsigned int irq_status; struct venc_frame_info frame_info; + struct mtk_vcodec_ctx *ctx = inst->ctx; + bool is_dual_core = (MTK_ENC_CORE_MODE(ctx) == VENC_DUAL_CORE_MODE); mtk_vcodec_debug_enter(inst); mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt); frame_info.frm_count = inst->frm_cnt; frame_info.skip_frm_count = inst->skip_frm_cnt; - frame_info.frm_type = h264_frame_type(inst); + if (is_dual_core) + frame_info.frm_type = h264_core_frame_type(inst); + else + frame_info.frm_type = h264_frame_type(inst); + mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n", frame_info.frm_count, frame_info.skip_frm_count, frame_info.frm_type); @@ -501,7 +588,8 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, static int h264_enc_init(struct mtk_vcodec_ctx *ctx) { const bool is_ext = MTK_ENC_CTX_IS_EXT(ctx); - int ret = 0; + bool is_dual_core = (MTK_ENC_CORE_MODE(ctx) == VENC_DUAL_CORE_MODE); + int ret, i = 0; struct venc_h264_inst *inst; inst = kzalloc(sizeof(*inst), GFP_KERNEL); @@ -511,13 +599,22 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu_inst.ctx = ctx; inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264; - inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS); mtk_vcodec_debug_enter(inst); ret = vpu_enc_init(&inst->vpu_inst); - inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi; + if (is_dual_core) { + inst->core_vsi = + (struct venc_dual_core_vsi *)inst->vpu_inst.vsi; + for (i = 0; i < MTK_VENC_CORE_MAX; i++) + inst->hw_base[i] = + mtk_venc_get_core_reg_addr(inst->ctx, i); + + } else { + inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi; + inst->hw_base[0] = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS); + } mtk_vcodec_debug_leave(inst); @@ -624,31 +721,62 @@ static int h264_enc_encode(void *handle, return ret; } +static void h264_enc_set_configs(struct venc_h264_inst *inst, + struct venc_enc_param *enc_prm) +{ + inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt; + inst->vsi->config.bitrate = enc_prm->bitrate; + inst->vsi->config.pic_w = enc_prm->width; + inst->vsi->config.pic_h = enc_prm->height; + inst->vsi->config.buf_w = enc_prm->buf_width; + inst->vsi->config.buf_h = enc_prm->buf_height; + inst->vsi->config.gop_size = enc_prm->gop_size; + inst->vsi->config.framerate = enc_prm->frm_rate; + inst->vsi->config.intra_period = enc_prm->intra_period; + inst->vsi->config.profile = + h264_get_profile(inst, enc_prm->h264_profile); + inst->vsi->config.level = + h264_get_level(inst, enc_prm->h264_level); + inst->vsi->config.wfd = 0; +} + +static void h264_enc_set_core_configs(struct venc_h264_inst *inst, + struct venc_enc_param *enc_prm) +{ + inst->core_vsi->config.input_fourcc = enc_prm->input_yuv_fmt; + inst->core_vsi->config.bitrate = enc_prm->bitrate; + inst->core_vsi->config.pic_w = enc_prm->width; + inst->core_vsi->config.pic_h = enc_prm->height; + inst->core_vsi->config.buf_w = enc_prm->buf_width; + inst->core_vsi->config.buf_h = enc_prm->buf_height; + inst->core_vsi->config.gop_size = enc_prm->gop_size; + inst->core_vsi->config.framerate = enc_prm->frm_rate; + inst->core_vsi->config.intra_period = enc_prm->intra_period; + inst->core_vsi->config.profile = + h264_get_profile(inst, enc_prm->h264_profile); + inst->core_vsi->config.level = + h264_get_level(inst, enc_prm->h264_level); + inst->core_vsi->config.wfd = 0; +} + static int h264_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { int ret = 0; struct venc_h264_inst *inst = (struct venc_h264_inst *)handle; + struct mtk_vcodec_ctx *ctx = inst->ctx; + bool is_dual_core = (MTK_ENC_CORE_MODE(ctx) == VENC_DUAL_CORE_MODE); - mtk_vcodec_debug(inst, "->type=%d", type); + mtk_vcodec_debug(inst, "->type=%d, dual_core=%d", type, is_dual_core); switch (type) { case VENC_SET_PARAM_ENC: - inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt; - inst->vsi->config.bitrate = enc_prm->bitrate; - inst->vsi->config.pic_w = enc_prm->width; - inst->vsi->config.pic_h = enc_prm->height; - inst->vsi->config.buf_w = enc_prm->buf_width; - inst->vsi->config.buf_h = enc_prm->buf_height; - inst->vsi->config.gop_size = enc_prm->gop_size; - inst->vsi->config.framerate = enc_prm->frm_rate; - inst->vsi->config.intra_period = enc_prm->intra_period; - inst->vsi->config.profile = - h264_get_profile(inst, enc_prm->h264_profile); - inst->vsi->config.level = - h264_get_level(inst, enc_prm->h264_level); - inst->vsi->config.wfd = 0; + if (is_dual_core) + h264_enc_set_core_configs(inst, enc_prm); + else + h264_enc_set_configs(inst, enc_prm); + ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm); if (ret) break; -- 2.18.0