/* * Copyright 2022 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "hal_jpege_v540c" #include #include #include #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_soc.h" #include "mpp_common.h" #include "mpp_frame_impl.h" #include "hal_jpege_debug.h" #include "jpege_syntax.h" #include "hal_bufs.h" #include "rkv_enc_def.h" #include "vepu5xx_common.h" #include "vepu540c_common.h" #include "hal_jpege_vepu540c.h" #include "hal_jpege_vepu540c_reg.h" #include "hal_jpege_hdr.h" typedef struct jpegeV540cHalContext_t { MppEncHalApi api; MppDev dev; void *regs; void *reg_out; void *dump_files; RK_S32 frame_type; RK_S32 last_frame_type; /* @frame_cnt starts from ZERO */ RK_U32 frame_cnt; void *roi_data; MppEncCfgSet *cfg; RK_U32 enc_mode; RK_U32 frame_size; RK_S32 max_buf_cnt; RK_S32 hdr_status; void *input_fmt; RK_U8 *src_buf; RK_U8 *dst_buf; RK_S32 buf_size; RK_U32 frame_num; RK_S32 fbc_header_len; RK_U32 title_num; JpegeBits bits; JpegeSyntax syntax; HalJpegeRc hal_rc; } jpegeV540cHalContext; MPP_RET hal_jpege_v540c_init(void *hal, MppEncHalCfg *cfg) { MPP_RET ret = MPP_OK; jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; mpp_env_get_u32("hal_jpege_debug", &hal_jpege_debug, 0); hal_jpege_enter(); ctx->reg_out = mpp_calloc(JpegV540cStatus, 1); ctx->regs = mpp_calloc(JpegV540cRegSet, 1); ctx->input_fmt = mpp_calloc(VepuFmtCfg, 1); ctx->cfg = cfg->cfg; ctx->frame_cnt = 0; ctx->enc_mode = 1; cfg->type = VPU_CLIENT_RKVENC; ret = mpp_dev_init(&cfg->dev, cfg->type); if (ret) { mpp_err_f("mpp_dev_init failed. ret: %d\n", ret); return ret; } ctx->dev = cfg->dev; jpege_bits_init(&ctx->bits); mpp_assert(ctx->bits); hal_jpege_rc_init(&ctx->hal_rc); hal_jpege_leave(); return ret; } MPP_RET hal_jpege_v540c_deinit(void *hal) { jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; hal_jpege_enter(); jpege_bits_deinit(ctx->bits); MPP_FREE(ctx->regs); MPP_FREE(ctx->reg_out); MPP_FREE(ctx->input_fmt); if (ctx->dev) { mpp_dev_deinit(ctx->dev); ctx->dev = NULL; } hal_jpege_leave(); return MPP_OK; } static MPP_RET hal_jpege_vepu540c_prepare(void *hal) { jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; hal_jpege_dbg_func("enter %p\n", hal); VepuFmtCfg *fmt = (VepuFmtCfg *)ctx->input_fmt; vepu5xx_set_fmt(fmt, ctx->cfg->prep.format); hal_jpege_dbg_func("leave %p\n", hal); return MPP_OK; } MPP_RET hal_jpege_v540c_gen_regs(void *hal, HalEncTask *task) { jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; JpegV540cRegSet *regs = ctx->regs; jpeg_vepu540c_control_cfg *reg_ctl = ®s->reg_ctl; jpeg_vepu540c_base *reg_base = ®s->reg_base; JpegeBits bits = ctx->bits; size_t length = mpp_packet_get_length(task->packet); RK_U8 *buf = mpp_buffer_get_ptr(task->output); size_t size = mpp_buffer_get_size(task->output); JpegeSyntax *syntax = &ctx->syntax; Vepu540cJpegCfg cfg; RK_S32 bitpos; hal_jpege_enter(); cfg.enc_task = task; cfg.jpeg_reg_base = ®_base->jpegReg; cfg.dev = ctx->dev; cfg.input_fmt = ctx->input_fmt; memset(regs, 0, sizeof(JpegV540cRegSet)); if (syntax->q_mode == JPEG_QFACTOR) { syntax->q_factor = 100 - task->rc_task->info.quality_target; hal_jpege_rc_update(&ctx->hal_rc, syntax); } /* write header to output buffer */ jpege_bits_setup(bits, buf, (RK_U32)size); /* seek length bytes data */ jpege_seek_bits(bits, length << 3); /* NOTE: write header will update qtable */ write_jpeg_header(bits, syntax, &ctx->hal_rc); bitpos = jpege_bits_get_bitpos(bits); task->length = (bitpos + 7) >> 3; mpp_buffer_sync_partial_end(task->output, 0, task->length); mpp_packet_set_length(task->packet, task->length); reg_ctl->reg0004_enc_strt.lkt_num = 0; reg_ctl->reg0004_enc_strt.vepu_cmd = ctx->enc_mode; reg_ctl->reg0005_enc_clr.safe_clr = 0x0; reg_ctl->reg0005_enc_clr.force_clr = 0x0; reg_ctl->reg0008_int_en.enc_done_en = 1; reg_ctl->reg0008_int_en.lkt_node_done_en = 1; reg_ctl->reg0008_int_en.sclr_done_en = 1; reg_ctl->reg0008_int_en.slc_done_en = 1; reg_ctl->reg0008_int_en.bsf_oflw_en = 1; reg_ctl->reg0008_int_en.brsp_otsd_en = 1; reg_ctl->reg0008_int_en.wbus_err_en = 1; reg_ctl->reg0008_int_en.rbus_err_en = 1; reg_ctl->reg0008_int_en.wdg_en = 1; reg_ctl->reg0008_int_en.lkt_err_int_en = 0; reg_ctl->reg0012_dtrns_map.jpeg_bus_edin = 0x7; reg_ctl->reg0012_dtrns_map.src_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.meiw_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.bsw_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.lktr_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.roir_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.lktw_bus_edin = 0x0; reg_ctl->reg0012_dtrns_map.rec_nfbc_bus_edin = 0x0; reg_base->reg0192_enc_pic.enc_stnd = 2; // disable h264 or hevc reg_ctl->reg0013_dtrns_cfg.axi_brsp_cke = 0x0; reg_ctl->reg0014_enc_wdg.vs_load_thd = 0x1fffff; reg_ctl->reg0014_enc_wdg.rfp_load_thd = 0; vepu540c_set_jpeg_reg(&cfg); { RK_U16 *tbl = ®s->jpeg_table.qua_tab0[0]; RK_U32 i, j; for ( i = 0; i < 8; i++) { for ( j = 0; j < 8; j++) { tbl[i * 8 + j] = 0x8000 / ctx->hal_rc.qtables[0][j * 8 + i]; } } tbl += 64; for ( i = 0; i < 8; i++) { for ( j = 0; j < 8; j++) { tbl[i * 8 + j] = 0x8000 / ctx->hal_rc.qtables[1][j * 8 + i]; } } tbl += 64; for ( i = 0; i < 8; i++) { for ( j = 0; j < 8; j++) { tbl[i * 8 + j] = 0x8000 / ctx->hal_rc.qtables[1][j * 8 + i]; } } } ctx->frame_num++; hal_jpege_leave(); return MPP_OK; } MPP_RET hal_jpege_v540c_start(void *hal, HalEncTask *enc_task) { MPP_RET ret = MPP_OK; jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; JpegV540cRegSet *hw_regs = ctx->regs; JpegV540cStatus *reg_out = ctx->reg_out; MppDevRegWrCfg cfg; MppDevRegRdCfg cfg1; hal_jpege_enter(); if (enc_task->flags.err) { mpp_err_f("enc_task->flags.err %08x, return e arly", enc_task->flags.err); return MPP_NOK; } cfg.reg = (RK_U32*)&hw_regs->reg_ctl; cfg.size = sizeof(jpeg_vepu540c_control_cfg); cfg.offset = VEPU540C_CTL_OFFSET; ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_REG_WR, &cfg); if (ret) { mpp_err_f("set register write failed %d\n", ret); return ret; } cfg.reg = &hw_regs->jpeg_table; cfg.size = sizeof(vepu540c_jpeg_tab); cfg.offset = VEPU540C_JPEGTAB_OFFSET; ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_REG_WR, &cfg); if (ret) { mpp_err_f("set register write failed %d\n", ret); return ret; } cfg.reg = &hw_regs->reg_base; cfg.size = sizeof(jpeg_vepu540c_base); cfg.offset = VEPU540C_BASE_OFFSET; ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_REG_WR, &cfg); if (ret) { mpp_err_f("set register write failed %d\n", ret); return ret; } cfg1.reg = ®_out->hw_status; cfg1.size = sizeof(RK_U32); cfg1.offset = VEPU540C_REG_BASE_HW_STATUS; ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_REG_RD, &cfg1); if (ret) { mpp_err_f("set register read failed %d\n", ret); return ret; } cfg1.reg = ®_out->st; cfg1.size = sizeof(JpegV540cStatus) - 4; cfg1.offset = VEPU540C_STATUS_OFFSET; ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_REG_RD, &cfg1); if (ret) { mpp_err_f("set register read failed %d\n", ret); return ret; } ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_CMD_SEND, NULL); if (ret) { mpp_err_f("send cmd failed %d\n", ret); } hal_jpege_leave(); return ret; } //#define DUMP_DATA static MPP_RET hal_jpege_vepu540c_status_check(void *hal) { jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; JpegV540cStatus *elem = (JpegV540cStatus *)ctx->reg_out; vepu540c_hw_status hw_status = elem->hw_status; hal_jpege_dbg_detail("hw_status: 0x%08x", hw_status.val); if (hw_status.int_sta.enc_done_sta) hal_jpege_dbg_detail("RKV_ENC_INT_ENC_DONE"); if (hw_status.int_sta.wdg_sta) mpp_err_f("RKV_ENC_INT_WDG_TIMEOUT"); if (hw_status.int_sta.jslc_done_sta) hal_jpege_dbg_detail("RKV_ENC_INT_JSL_DONE"); if (hw_status.int_sta.jbsf_oflw_sta) mpp_err_f("RKV_ENC_INT_JBSF_OFLOW"); return MPP_OK; } MPP_RET hal_jpege_v540c_wait(void *hal, HalEncTask *task) { MPP_RET ret = MPP_OK; jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; HalEncTask *enc_task = task; JpegV540cStatus *elem = (JpegV540cStatus *)ctx->reg_out; hal_jpege_enter(); if (enc_task->flags.err) { mpp_err_f("enc_task->flags.err %08x, return early", enc_task->flags.err); return MPP_NOK; } ret = mpp_dev_ioctl(ctx->dev, MPP_DEV_CMD_POLL, NULL); if (ret) { mpp_err_f("poll cmd failed %d\n", ret); ret = MPP_ERR_VPUHW; } else { hal_jpege_vepu540c_status_check(hal); task->hw_length += elem->st.jpeg_head_bits_l32; } hal_jpege_leave(); return ret; } MPP_RET hal_jpege_v540c_get_task(void *hal, HalEncTask *task) { jpegeV540cHalContext *ctx = (jpegeV540cHalContext *)hal; MppFrame frame = task->frame; EncFrmStatus *frm_status = &task->rc_task->frm; JpegeSyntax *syntax = (JpegeSyntax *)task->syntax.data; hal_jpege_enter(); memcpy(&ctx->syntax, syntax, sizeof(ctx->syntax)); ctx->last_frame_type = ctx->frame_type; if (!frm_status->reencode && mpp_frame_has_meta(task->frame)) { MppMeta meta = mpp_frame_get_meta(frame); mpp_meta_get_ptr(meta, KEY_ROI_DATA, (void **)&ctx->roi_data); } if (ctx->cfg->jpeg.update) { hal_jpege_rc_update(&ctx->hal_rc, syntax); ctx->cfg->jpeg.update = 0; } task->rc_task->frm.is_intra = 1; hal_jpege_leave(); return MPP_OK; } MPP_RET hal_jpege_v540c_ret_task(void *hal, HalEncTask *task) { (void)hal; EncRcTaskInfo *rc_info = &task->rc_task->info; hal_jpege_enter(); task->length += task->hw_length; // setup bit length for rate control rc_info->bit_real = task->hw_length * 8; rc_info->quality_real = rc_info->quality_target; hal_jpege_leave(); return MPP_OK; } const MppEncHalApi hal_jpege_vepu540c = { "hal_jpege_v540c", MPP_VIDEO_CodingMJPEG, sizeof(jpegeV540cHalContext), 0, hal_jpege_v540c_init, hal_jpege_v540c_deinit, hal_jpege_vepu540c_prepare, hal_jpege_v540c_get_task, hal_jpege_v540c_gen_regs, hal_jpege_v540c_start, hal_jpege_v540c_wait, NULL, NULL, hal_jpege_v540c_ret_task, };