382 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2016 MediaTek Inc.4 * Author: PoChun Lin <pochun.lin@mediatek.com>5 */6 7#include "mtk_vcodec_enc_drv.h"8#include "venc_ipi_msg.h"9#include "venc_vpu_if.h"10 11static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)12{13 const struct venc_vpu_ipi_msg_init *msg = data;14 15 vpu->inst_addr = msg->vpu_inst_addr;16 vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,17 msg->vpu_inst_addr);18 19 /* Firmware version field value is unspecified on MT8173. */20 if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU)21 return;22 23 /* Check firmware version. */24 mtk_venc_debug(vpu->ctx, "firmware version: 0x%x\n", msg->venc_abi_version);25 switch (msg->venc_abi_version) {26 case 1:27 break;28 default:29 mtk_venc_err(vpu->ctx, "unhandled firmware version 0x%x\n",30 msg->venc_abi_version);31 vpu->failure = 1;32 break;33 }34}35 36static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)37{38 const struct venc_vpu_ipi_msg_enc *msg = data;39 40 vpu->state = msg->state;41 vpu->bs_size = msg->bs_size;42 vpu->is_key_frm = msg->is_key_frm;43}44 45static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu)46{47 struct mtk_vcodec_enc_ctx *ctx;48 int ret = false;49 50 mutex_lock(&enc_dev->dev_ctx_lock);51 list_for_each_entry(ctx, &enc_dev->ctx_list, list) {52 if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) {53 ret = true;54 break;55 }56 }57 mutex_unlock(&enc_dev->dev_ctx_lock);58 59 return ret;60}61 62static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)63{64 struct mtk_vcodec_enc_dev *enc_dev;65 const struct venc_vpu_ipi_msg_common *msg = data;66 struct venc_vpu_inst *vpu;67 68 enc_dev = (struct mtk_vcodec_enc_dev *)priv;69 vpu = (struct venc_vpu_inst *)(unsigned long)msg->venc_inst;70 if (!priv || !vpu) {71 pr_err(MTK_DBG_V4L2_STR "venc_inst is NULL, did the SCP hang or crash?");72 return;73 }74 75 mtk_venc_debug(vpu->ctx, "msg_id %x inst %p status %d", msg->msg_id, vpu, msg->status);76 if (!vpu_enc_check_ap_inst(enc_dev, vpu) || msg->msg_id < VPU_IPIMSG_ENC_INIT_DONE ||77 msg->msg_id > VPU_IPIMSG_ENC_DEINIT_DONE) {78 mtk_v4l2_venc_err(vpu->ctx, "venc msg id not correctly => 0x%x", msg->msg_id);79 vpu->failure = -EINVAL;80 goto error;81 }82 83 vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);84 if (vpu->failure) {85 mtk_venc_err(vpu->ctx, "vpu enc status failure %d", vpu->failure);86 goto error;87 }88 89 switch (msg->msg_id) {90 case VPU_IPIMSG_ENC_INIT_DONE:91 handle_enc_init_msg(vpu, data);92 break;93 case VPU_IPIMSG_ENC_SET_PARAM_DONE:94 break;95 case VPU_IPIMSG_ENC_ENCODE_DONE:96 handle_enc_encode_msg(vpu, data);97 break;98 case VPU_IPIMSG_ENC_DEINIT_DONE:99 break;100 default:101 mtk_venc_err(vpu->ctx, "unknown msg id %x", msg->msg_id);102 break;103 }104 105error:106 vpu->signaled = 1;107}108 109static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,110 int len)111{112 int status;113 114 if (!vpu->ctx->dev->fw_handler) {115 mtk_venc_err(vpu->ctx, "inst dev is NULL");116 return -EINVAL;117 }118 119 status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,120 len, 2000);121 if (status) {122 mtk_venc_err(vpu->ctx, "vpu_ipi_send msg_id %x len %d fail %d",123 *(uint32_t *)msg, len, status);124 return -EINVAL;125 }126 if (vpu->failure)127 return -EINVAL;128 129 return 0;130}131 132int vpu_enc_init(struct venc_vpu_inst *vpu)133{134 int status;135 struct venc_ap_ipi_msg_init out;136 137 init_waitqueue_head(&vpu->wq_hd);138 vpu->signaled = 0;139 vpu->failure = 0;140 vpu->ctx->vpu_inst = vpu;141 142 status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,143 vpu_enc_ipi_handler, "venc",144 vpu->ctx->dev);145 146 if (status) {147 mtk_venc_err(vpu->ctx, "vpu_ipi_register fail %d", status);148 return -EINVAL;149 }150 151 memset(&out, 0, sizeof(out));152 out.msg_id = AP_IPIMSG_ENC_INIT;153 out.venc_inst = (unsigned long)vpu;154 if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {155 mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_INIT fail");156 return -EINVAL;157 }158 159 if (IS_ERR_OR_NULL(vpu->vsi)) {160 mtk_venc_err(vpu->ctx, "invalid venc vsi");161 return -EINVAL;162 }163 164 return 0;165}166 167static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,168 struct venc_enc_param *enc_prm)169{170 unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;171 172 return img_crop_right % 16;173}174 175static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm)176{177 return round_up(enc_prm->height, 16) - enc_prm->height;178}179 180static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm)181{182 return DIV_ROUND_UP(enc_prm->width, 16) *183 DIV_ROUND_UP(enc_prm->height, 16);184}185 186int vpu_enc_set_param(struct venc_vpu_inst *vpu,187 enum venc_set_param_type id,188 struct venc_enc_param *enc_param)189{190 const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);191 size_t msg_size = is_ext ?192 sizeof(struct venc_ap_ipi_msg_set_param_ext) :193 sizeof(struct venc_ap_ipi_msg_set_param);194 struct venc_ap_ipi_msg_set_param_ext out;195 196 mtk_venc_debug(vpu->ctx, "id %d ->", id);197 198 memset(&out, 0, sizeof(out));199 out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;200 out.base.vpu_inst_addr = vpu->inst_addr;201 out.base.param_id = id;202 switch (id) {203 case VENC_SET_PARAM_ENC:204 if (is_ext) {205 out.base.data_item = 3;206 out.base.data[0] =207 venc_enc_param_crop_right(vpu, enc_param);208 out.base.data[1] =209 venc_enc_param_crop_bottom(enc_param);210 out.base.data[2] = venc_enc_param_num_mb(enc_param);211 } else {212 out.base.data_item = 0;213 }214 break;215 case VENC_SET_PARAM_FORCE_INTRA:216 out.base.data_item = 0;217 break;218 case VENC_SET_PARAM_ADJUST_BITRATE:219 out.base.data_item = 1;220 out.base.data[0] = enc_param->bitrate;221 break;222 case VENC_SET_PARAM_ADJUST_FRAMERATE:223 out.base.data_item = 1;224 out.base.data[0] = enc_param->frm_rate;225 break;226 case VENC_SET_PARAM_GOP_SIZE:227 out.base.data_item = 1;228 out.base.data[0] = enc_param->gop_size;229 break;230 case VENC_SET_PARAM_INTRA_PERIOD:231 out.base.data_item = 1;232 out.base.data[0] = enc_param->intra_period;233 break;234 case VENC_SET_PARAM_SKIP_FRAME:235 out.base.data_item = 0;236 break;237 default:238 mtk_venc_err(vpu->ctx, "id %d not supported", id);239 return -EINVAL;240 }241 if (vpu_enc_send_msg(vpu, &out, msg_size)) {242 mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_SET_PARAM %d fail", id);243 return -EINVAL;244 }245 246 mtk_venc_debug(vpu->ctx, "id %d <-", id);247 248 return 0;249}250 251static int vpu_enc_encode_32bits(struct venc_vpu_inst *vpu,252 unsigned int bs_mode,253 struct venc_frm_buf *frm_buf,254 struct mtk_vcodec_mem *bs_buf,255 struct venc_frame_info *frame_info)256{257 const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);258 size_t msg_size = is_ext ?259 sizeof(struct venc_ap_ipi_msg_enc_ext) :260 sizeof(struct venc_ap_ipi_msg_enc);261 struct venc_ap_ipi_msg_enc_ext out;262 263 mtk_venc_debug(vpu->ctx, "bs_mode %d ->", bs_mode);264 265 memset(&out, 0, sizeof(out));266 out.base.msg_id = AP_IPIMSG_ENC_ENCODE;267 out.base.vpu_inst_addr = vpu->inst_addr;268 out.base.bs_mode = bs_mode;269 if (frm_buf) {270 if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&271 (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&272 (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {273 out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;274 out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;275 out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;276 } else {277 mtk_venc_err(vpu->ctx, "dma_addr not align to 16");278 return -EINVAL;279 }280 }281 if (bs_buf) {282 out.base.bs_addr = bs_buf->dma_addr;283 out.base.bs_size = bs_buf->size;284 }285 if (is_ext && frame_info) {286 out.data_item = 3;287 out.data[0] = frame_info->frm_count;288 out.data[1] = frame_info->skip_frm_count;289 out.data[2] = frame_info->frm_type;290 }291 if (vpu_enc_send_msg(vpu, &out, msg_size)) {292 mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_ENCODE %d fail", bs_mode);293 return -EINVAL;294 }295 296 return 0;297}298 299static int vpu_enc_encode_34bits(struct venc_vpu_inst *vpu,300 unsigned int bs_mode,301 struct venc_frm_buf *frm_buf,302 struct mtk_vcodec_mem *bs_buf,303 struct venc_frame_info *frame_info)304{305 struct venc_ap_ipi_msg_enc_ext_34 out;306 size_t msg_size = sizeof(struct venc_ap_ipi_msg_enc_ext_34);307 308 mtk_venc_debug(vpu->ctx, "bs_mode %d ->", bs_mode);309 310 memset(&out, 0, sizeof(out));311 out.msg_id = AP_IPIMSG_ENC_ENCODE;312 out.vpu_inst_addr = vpu->inst_addr;313 out.bs_mode = bs_mode;314 315 if (frm_buf) {316 if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&317 (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&318 (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {319 out.input_addr[0] = frm_buf->fb_addr[0].dma_addr;320 out.input_addr[1] = frm_buf->fb_addr[1].dma_addr;321 out.input_addr[2] = frm_buf->fb_addr[2].dma_addr;322 } else {323 mtk_venc_err(vpu->ctx, "dma_addr not align to 16");324 return -EINVAL;325 }326 }327 if (bs_buf) {328 out.bs_addr = bs_buf->dma_addr;329 out.bs_size = bs_buf->size;330 }331 if (frame_info) {332 out.data_item = 3;333 out.data[0] = frame_info->frm_count;334 out.data[1] = frame_info->skip_frm_count;335 out.data[2] = frame_info->frm_type;336 }337 if (vpu_enc_send_msg(vpu, &out, msg_size)) {338 mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_ENCODE %d fail", bs_mode);339 return -EINVAL;340 }341 342 return 0;343}344 345int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,346 struct venc_frm_buf *frm_buf,347 struct mtk_vcodec_mem *bs_buf,348 struct venc_frame_info *frame_info)349{350 int ret;351 352 if (MTK_ENC_IOVA_IS_34BIT(vpu->ctx))353 ret = vpu_enc_encode_34bits(vpu, bs_mode,354 frm_buf, bs_buf, frame_info);355 else356 ret = vpu_enc_encode_32bits(vpu, bs_mode,357 frm_buf, bs_buf, frame_info);358 359 if (ret)360 return ret;361 362 mtk_venc_debug(vpu->ctx, "bs_mode %d state %d size %d key_frm %d <-",363 bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm);364 365 return 0;366}367 368int vpu_enc_deinit(struct venc_vpu_inst *vpu)369{370 struct venc_ap_ipi_msg_deinit out;371 372 memset(&out, 0, sizeof(out));373 out.msg_id = AP_IPIMSG_ENC_DEINIT;374 out.vpu_inst_addr = vpu->inst_addr;375 if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {376 mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_DEINIT fail");377 return -EINVAL;378 }379 380 return 0;381}382