// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2020-2021 NXP */ #include #include #include #include #include #include #include #include #include #include #include "vpu.h" #include "vpu_rpc.h" #include "vpu_defs.h" #include "vpu_helpers.h" #include "vpu_cmds.h" #include "vpu_v4l2.h" #include "vpu_imx8q.h" #include "vpu_windsor.h" #define CMD_SIZE 2560 #define MSG_SIZE 25600 #define WINDSOR_USER_DATA_WORDS 16 #define WINDSOR_MAX_SRC_FRAMES 0x6 #define WINDSOR_MAX_REF_FRAMES 0x3 #define WINDSOR_BITRATE_UNIT 1024 #define WINDSOR_H264_EXTENDED_SAR 255 enum { GTB_ENC_CMD_NOOP = 0x0, GTB_ENC_CMD_STREAM_START, GTB_ENC_CMD_FRAME_ENCODE, GTB_ENC_CMD_FRAME_SKIP, GTB_ENC_CMD_STREAM_STOP, GTB_ENC_CMD_PARAMETER_UPD, GTB_ENC_CMD_TERMINATE, GTB_ENC_CMD_SNAPSHOT, GTB_ENC_CMD_ROLL_SNAPSHOT, GTB_ENC_CMD_LOCK_SCHEDULER, GTB_ENC_CMD_UNLOCK_SCHEDULER, GTB_ENC_CMD_CONFIGURE_CODEC, GTB_ENC_CMD_DEAD_MARK, GTB_ENC_CMD_FIRM_RESET, GTB_ENC_CMD_FW_STATUS, GTB_ENC_CMD_RESERVED }; enum { VID_API_EVENT_UNDEFINED = 0x0, VID_API_ENC_EVENT_RESET_DONE = 0x1, VID_API_ENC_EVENT_START_DONE, VID_API_ENC_EVENT_STOP_DONE, VID_API_ENC_EVENT_TERMINATE_DONE, VID_API_ENC_EVENT_FRAME_INPUT_DONE, VID_API_ENC_EVENT_FRAME_DONE, VID_API_ENC_EVENT_FRAME_RELEASE, VID_API_ENC_EVENT_PARA_UPD_DONE, VID_API_ENC_EVENT_MEM_REQUEST, VID_API_ENC_EVENT_FIRMWARE_XCPT, VID_API_ENC_EVENT_RESERVED }; enum { MEDIAIP_ENC_PIC_TYPE_B_FRAME = 0, MEDIAIP_ENC_PIC_TYPE_P_FRAME, MEDIAIP_ENC_PIC_TYPE_I_FRAME, MEDIAIP_ENC_PIC_TYPE_IDR_FRAME, MEDIAIP_ENC_PIC_TYPE_BI_FRAME }; struct windsor_iface { u32 exec_base_addr; u32 exec_area_size; struct vpu_rpc_buffer_desc cmd_buffer_desc; struct vpu_rpc_buffer_desc msg_buffer_desc; u32 cmd_int_enable[VID_API_NUM_STREAMS]; u32 fw_version; u32 mvd_fw_offset; u32 max_streams; u32 ctrl_iface[VID_API_NUM_STREAMS]; struct vpu_rpc_system_config system_config; u32 api_version; struct vpu_rpc_buffer_desc log_buffer_desc; }; struct windsor_ctrl_iface { u32 enc_yuv_buffer_desc; u32 enc_stream_buffer_desc; u32 enc_expert_mode_param; u32 enc_param; u32 enc_mem_pool; u32 enc_encoding_status; u32 enc_dsa_status; }; struct vpu_enc_yuv_desc { u32 frame_id; u32 luma_base; u32 chroma_base; u32 param_idx; u32 key_frame; }; struct vpu_enc_calib_params { u32 use_ame; u32 cme_mvx_max; u32 cme_mvy_max; u32 ame_prefresh_y0; u32 ame_prefresh_y1; u32 fme_min_sad; u32 cme_min_sad; u32 fme_pred_int_weight; u32 fme_pred_hp_weight; u32 fme_pred_qp_weight; u32 fme_cost_weight; u32 fme_act_thold; u32 fme_sad_thold; u32 fme_zero_sad_thold; u32 fme_lrg_mvx_lmt; u32 fme_lrg_mvy_lmt; u32 fme_force_mode; u32 fme_force4mvcost; u32 fme_force2mvcost; u32 h264_inter_thrd; u32 i16x16_mode_cost; u32 i4x4_mode_lambda; u32 i8x8_mode_lambda; u32 inter_mod_mult; u32 inter_sel_mult; u32 inter_bid_cost; u32 inter_bwd_cost; u32 inter_4mv_cost; s32 one_mv_i16_cost; s32 one_mv_i4x4_cost; s32 one_mv_i8x8_cost; s32 two_mv_i16_cost; s32 two_mv_i4x4_cost; s32 two_mv_i8x8_cost; s32 four_mv_i16_cost; s32 four_mv_i4x4_cost; s32 four_mv_i8x8_cost; u32 intra_pred_enab; u32 intra_chr_pred; u32 intra16_pred; u32 intra4x4_pred; u32 intra8x8_pred; u32 cb_base; u32 cb_size; u32 cb_head_room; u32 mem_page_width; u32 mem_page_height; u32 mem_total_size; u32 mem_chunk_phys_addr; u32 mem_chunk_virt_addr; u32 mem_chunk_size; u32 mem_y_stride; u32 mem_uv_stride; u32 split_wr_enab; u32 split_wr_req_size; u32 split_rd_enab; u32 split_rd_req_size; }; struct vpu_enc_config_params { u32 param_change; u32 start_frame; u32 end_frame; u32 userdata_enable; u32 userdata_id[4]; u32 userdata_message[WINDSOR_USER_DATA_WORDS]; u32 userdata_length; u32 h264_profile_idc; u32 h264_level_idc; u32 h264_au_delimiter; u32 h264_seq_end_code; u32 h264_recovery_points; u32 h264_vui_parameters; u32 h264_aspect_ratio_present; u32 h264_aspect_ratio_sar_width; u32 h264_aspect_ratio_sar_height; u32 h264_overscan_present; u32 h264_video_type_present; u32 h264_video_format; u32 h264_video_full_range; u32 h264_video_colour_descriptor; u32 h264_video_colour_primaries; u32 h264_video_transfer_char; u32 h264_video_matrix_coeff; u32 h264_chroma_loc_info_present; u32 h264_chroma_loc_type_top; u32 h264_chroma_loc_type_bot; u32 h264_timing_info_present; u32 h264_buffering_period_present; u32 h264_low_delay_hrd_flag; u32 aspect_ratio; u32 test_mode; // Automated firmware test mode u32 dsa_test_mode; // Automated test mode for the DSA. u32 fme_test_mode; // Automated test mode for the fme u32 cbr_row_mode; //0: FW mode; 1: HW mode u32 windsor_mode; //0: normal mode; 1: intra only mode; 2: intra+0MV mode u32 encode_mode; // H264, VC1, MPEG2, DIVX u32 frame_width; // display width u32 frame_height; // display height u32 enc_frame_width; // encoding width, should be 16-pix align u32 enc_frame_height; // encoding height, should be 16-pix aligned u32 frame_rate_num; u32 frame_rate_den; u32 vi_field_source; u32 vi_frame_width; u32 vi_frame_height; u32 crop_frame_width; u32 crop_frame_height; u32 crop_x_start_posn; u32 crop_y_start_posn; u32 mode422; u32 mode_yuy2; u32 dsa_luma_en; u32 dsa_chroma_en; u32 dsa_ext_hfilt_en; u32 dsa_di_en; u32 dsa_di_top_ref; u32 dsa_vertf_disable; u32 dsa_disable_pwb; u32 dsa_hor_phase; u32 dsa_ver_phase; u32 dsa_iac_enable; u32 iac_sc_threshold; u32 iac_vm_threshold; u32 iac_skip_mode; u32 iac_grp_width; u32 iac_grp_height; u32 rate_control_mode; u32 rate_control_resolution; u32 buffer_size; u32 buffer_level_init; u32 buffer_I_bit_budget; u32 top_field_first; u32 intra_lum_qoffset; u32 intra_chr_qoffset; u32 inter_lum_qoffset; u32 inter_chr_qoffset; u32 use_def_scaling_mtx; u32 inter_8x8_enab; u32 inter_4x4_enab; u32 fme_enable_qpel; u32 fme_enable_hpel; u32 fme_nozeromv; u32 fme_predmv_en; u32 fme_pred_2mv4mv; u32 fme_smallsadthresh; u32 ame_en_lmvc; u32 ame_x_mult; u32 cme_enable_4mv; u32 cme_enable_1mv; u32 hme_enable_16x8mv; u32 hme_enable_8x16mv; u32 cme_mv_weight; u32 cme_mv_cost; u32 ame_mult_mv; u32 ame_shift_mv; u32 hme_forceto1mv_en; u32 hme_2mv_cost; u32 hme_pred_mode; u32 hme_sc_rnge; u32 hme_sw_rnge; u32 output_format; u32 timestamp_enab; u32 initial_pts_enab; u32 initial_pts; }; struct vpu_enc_static_params { u32 param_change; u32 gop_length; u32 rate_control_bitrate; u32 rate_control_bitrate_min; u32 rate_control_bitrate_max; u32 rate_control_content_models; u32 rate_control_iframe_maxsize; u32 rate_control_qp_init; u32 rate_control_islice_qp; u32 rate_control_pslice_qp; u32 rate_control_bslice_qp; u32 adaptive_quantization; u32 aq_variance; u32 cost_optimization; u32 fdlp_mode; u32 enable_isegbframes; u32 enable_adaptive_keyratio; u32 keyratio_imin; u32 keyratio_imax; u32 keyratio_pmin; u32 keyratio_pmax; u32 keyratio_bmin; u32 keyratio_bmax; s32 keyratio_istep; s32 keyratio_pstep; s32 keyratio_bstep; u32 enable_paff; u32 enable_b_frame_ref; u32 enable_adaptive_gop; u32 enable_closed_gop; u32 open_gop_refresh_freq; u32 enable_adaptive_sc; u32 enable_fade_detection; s32 fade_detection_threshold; u32 enable_repeat_b; u32 enable_low_delay_b; }; struct vpu_enc_dynamic_params { u32 param_change; u32 rows_per_slice; u32 mbaff_enable; u32 dbf_enable; u32 field_source; u32 gop_b_length; u32 mb_group_size; u32 cbr_rows_per_group; u32 skip_enable; u32 pts_bits_0_to_31; u32 pts_bit_32; u32 rm_expsv_cff; u32 const_ipred; s32 chr_qp_offset; u32 intra_mb_qp_offset; u32 h264_cabac_init_method; u32 h264_cabac_init_idc; u32 h264_cabac_enable; s32 alpha_c0_offset_div2; s32 beta_offset_div2; u32 intra_prefresh_y0; u32 intra_prefresh_y1; u32 dbg_dump_rec_src; }; struct vpu_enc_expert_mode_param { struct vpu_enc_calib_params calib_param; struct vpu_enc_config_params config_param; struct vpu_enc_static_params static_param; struct vpu_enc_dynamic_params dynamic_param; }; enum MEDIAIP_ENC_FMT { MEDIAIP_ENC_FMT_H264 = 0, MEDIAIP_ENC_FMT_VC1, MEDIAIP_ENC_FMT_MPEG2, MEDIAIP_ENC_FMT_MPEG4SP, MEDIAIP_ENC_FMT_H263, MEDIAIP_ENC_FMT_MPEG1, MEDIAIP_ENC_FMT_SHORT_HEADER, MEDIAIP_ENC_FMT_NULL }; enum MEDIAIP_ENC_PROFILE { MEDIAIP_ENC_PROF_MPEG2_SP = 0, MEDIAIP_ENC_PROF_MPEG2_MP, MEDIAIP_ENC_PROF_MPEG2_HP, MEDIAIP_ENC_PROF_H264_BP, MEDIAIP_ENC_PROF_H264_MP, MEDIAIP_ENC_PROF_H264_HP, MEDIAIP_ENC_PROF_MPEG4_SP, MEDIAIP_ENC_PROF_MPEG4_ASP, MEDIAIP_ENC_PROF_VC1_SP, MEDIAIP_ENC_PROF_VC1_MP, MEDIAIP_ENC_PROF_VC1_AP }; enum MEDIAIP_ENC_BITRATE_MODE { MEDIAIP_ENC_BITRATE_MODE_VBR = 0x00000001, MEDIAIP_ENC_BITRATE_MODE_CBR = 0x00000002, MEDIAIP_ENC_BITRATE_MODE_CONSTANT_QP = 0x00000004 }; struct vpu_enc_memory_resource { u32 phys; u32 virt; u32 size; }; struct vpu_enc_param { enum MEDIAIP_ENC_FMT codec_mode; enum MEDIAIP_ENC_PROFILE profile; u32 level; struct vpu_enc_memory_resource enc_mem_desc; u32 frame_rate; u32 src_stride; u32 src_width; u32 src_height; u32 src_offset_x; u32 src_offset_y; u32 src_crop_width; u32 src_crop_height; u32 out_width; u32 out_height; u32 iframe_interval; u32 bframes; u32 low_latency_mode; enum MEDIAIP_ENC_BITRATE_MODE bitrate_mode; u32 target_bitrate; u32 max_bitrate; u32 min_bitrate; u32 init_slice_qp; }; struct vpu_enc_mem_pool { struct vpu_enc_memory_resource enc_frames[WINDSOR_MAX_SRC_FRAMES]; struct vpu_enc_memory_resource ref_frames[WINDSOR_MAX_REF_FRAMES]; struct vpu_enc_memory_resource act_frame; }; struct vpu_enc_encoding_status { u32 frame_id; u32 error_flag; //Error type u32 mb_y; u32 mb_x; u32 reserved[12]; }; struct vpu_enc_dsa_status { u32 frame_id; u32 dsa_cyle; u32 mb_y; u32 mb_x; u32 reserved[4]; }; struct vpu_enc_ctrl { struct vpu_enc_yuv_desc *yuv_desc; struct vpu_rpc_buffer_desc *stream_desc; struct vpu_enc_expert_mode_param *expert; struct vpu_enc_param *param; struct vpu_enc_mem_pool *pool; struct vpu_enc_encoding_status *status; struct vpu_enc_dsa_status *dsa; }; struct vpu_enc_host_ctrls { struct vpu_enc_ctrl ctrls[VID_API_NUM_STREAMS]; }; struct windsor_pic_info { u32 frame_id; u32 pic_encod_done; u32 pic_type; u32 skipped_frame; u32 error_flag; u32 psnr; u32 flush_done; u32 mb_y; u32 mb_x; u32 frame_size; u32 frame_enc_ttl_cycles; u32 frame_enc_ttl_frm_cycles; u32 frame_enc_ttl_slc_cycles; u32 frame_enc_ttl_enc_cycles; u32 frame_enc_ttl_hme_cycles; u32 frame_enc_ttl_dsa_cycles; u32 frame_enc_fw_cycles; u32 frame_crc; u32 num_interrupts_1; u32 num_interrupts_2; u32 poc; u32 ref_info; u32 pic_num; u32 pic_activity; u32 scene_change; u32 mb_stats; u32 enc_cache_count0; u32 enc_cache_count1; u32 mtl_wr_strb_cnt; u32 mtl_rd_strb_cnt; u32 str_buff_wptr; u32 diagnosticEvents; u32 proc_iacc_tot_rd_cnt; u32 proc_dacc_tot_rd_cnt; u32 proc_dacc_tot_wr_cnt; u32 proc_dacc_reg_rd_cnt; u32 proc_dacc_reg_wr_cnt; u32 proc_dacc_rng_rd_cnt; u32 proc_dacc_rng_wr_cnt; s32 tv_s; u32 tv_ns; }; u32 vpu_windsor_get_data_size(void) { return sizeof(struct vpu_enc_host_ctrls); } static struct vpu_enc_yuv_desc *get_yuv_desc(struct vpu_shared_addr *shared, u32 instance) { struct vpu_enc_host_ctrls *hcs = shared->priv; return hcs->ctrls[instance].yuv_desc; } static struct vpu_enc_mem_pool *get_mem_pool(struct vpu_shared_addr *shared, u32 instance) { struct vpu_enc_host_ctrls *hcs = shared->priv; return hcs->ctrls[instance].pool; } static struct vpu_rpc_buffer_desc *get_stream_buf_desc(struct vpu_shared_addr *shared, u32 instance) { struct vpu_enc_host_ctrls *hcs = shared->priv; return hcs->ctrls[instance].stream_desc; } static struct vpu_enc_expert_mode_param *get_expert_param(struct vpu_shared_addr *shared, u32 instance) { struct vpu_enc_host_ctrls *hcs = shared->priv; return hcs->ctrls[instance].expert; } static struct vpu_enc_param *get_enc_param(struct vpu_shared_addr *shared, u32 instance) { struct vpu_enc_host_ctrls *hcs = shared->priv; return hcs->ctrls[instance].param; } static u32 get_ptr(u32 ptr) { return (ptr | 0x80000000); } void vpu_windsor_init_rpc(struct vpu_shared_addr *shared, struct vpu_buffer *rpc, dma_addr_t boot_addr) { unsigned long base_phy_addr; unsigned long phy_addr; unsigned long offset; struct windsor_iface *iface; struct windsor_ctrl_iface *ctrl; struct vpu_enc_host_ctrls *hcs; unsigned int i; if (rpc->phys < boot_addr) return; base_phy_addr = rpc->phys - boot_addr; iface = rpc->virt; shared->iface = iface; shared->boot_addr = boot_addr; hcs = shared->priv; iface->exec_base_addr = base_phy_addr; iface->exec_area_size = rpc->length; offset = sizeof(struct windsor_iface); phy_addr = base_phy_addr + offset; shared->cmd_desc = &iface->cmd_buffer_desc; shared->cmd_mem_vir = rpc->virt + offset; iface->cmd_buffer_desc.start = iface->cmd_buffer_desc.rptr = iface->cmd_buffer_desc.wptr = phy_addr; iface->cmd_buffer_desc.end = iface->cmd_buffer_desc.start + CMD_SIZE; offset += CMD_SIZE; phy_addr = base_phy_addr + offset; shared->msg_desc = &iface->msg_buffer_desc; shared->msg_mem_vir = rpc->virt + offset; iface->msg_buffer_desc.start = iface->msg_buffer_desc.wptr = iface->msg_buffer_desc.rptr = phy_addr; iface->msg_buffer_desc.end = iface->msg_buffer_desc.start + MSG_SIZE; offset += MSG_SIZE; for (i = 0; i < ARRAY_SIZE(iface->ctrl_iface); i++) { iface->ctrl_iface[i] = base_phy_addr + offset; offset += sizeof(struct windsor_ctrl_iface); } for (i = 0; i < ARRAY_SIZE(iface->ctrl_iface); i++) { ctrl = rpc->virt + (iface->ctrl_iface[i] - base_phy_addr); ctrl->enc_yuv_buffer_desc = base_phy_addr + offset; hcs->ctrls[i].yuv_desc = rpc->virt + offset; offset += sizeof(struct vpu_enc_yuv_desc); ctrl->enc_stream_buffer_desc = base_phy_addr + offset; hcs->ctrls[i].stream_desc = rpc->virt + offset; offset += sizeof(struct vpu_rpc_buffer_desc); ctrl->enc_expert_mode_param = base_phy_addr + offset; hcs->ctrls[i].expert = rpc->virt + offset; offset += sizeof(struct vpu_enc_expert_mode_param); ctrl->enc_param = base_phy_addr + offset; hcs->ctrls[i].param = rpc->virt + offset; offset += sizeof(struct vpu_enc_param); ctrl->enc_mem_pool = base_phy_addr + offset; hcs->ctrls[i].pool = rpc->virt + offset; offset += sizeof(struct vpu_enc_mem_pool); ctrl->enc_encoding_status = base_phy_addr + offset; hcs->ctrls[i].status = rpc->virt + offset; offset += sizeof(struct vpu_enc_encoding_status); ctrl->enc_dsa_status = base_phy_addr + offset; hcs->ctrls[i].dsa = rpc->virt + offset; offset += sizeof(struct vpu_enc_dsa_status); } rpc->bytesused = offset; } void vpu_windsor_set_log_buf(struct vpu_shared_addr *shared, struct vpu_buffer *log) { struct windsor_iface *iface = shared->iface; iface->log_buffer_desc.start = iface->log_buffer_desc.wptr = iface->log_buffer_desc.rptr = log->phys - shared->boot_addr; iface->log_buffer_desc.end = iface->log_buffer_desc.start + log->length; } void vpu_windsor_set_system_cfg(struct vpu_shared_addr *shared, u32 regs_base, void __iomem *regs, u32 core_id) { struct windsor_iface *iface = shared->iface; struct vpu_rpc_system_config *config = &iface->system_config; vpu_imx8q_set_system_cfg_common(config, regs_base, core_id); } int vpu_windsor_get_stream_buffer_size(struct vpu_shared_addr *shared) { return 0x300000; } static struct vpu_pair windsor_cmds[] = { {VPU_CMD_ID_NOOP, GTB_ENC_CMD_NOOP}, {VPU_CMD_ID_CONFIGURE_CODEC, GTB_ENC_CMD_CONFIGURE_CODEC}, {VPU_CMD_ID_START, GTB_ENC_CMD_STREAM_START}, {VPU_CMD_ID_STOP, GTB_ENC_CMD_STREAM_STOP}, {VPU_CMD_ID_FRAME_ENCODE, GTB_ENC_CMD_FRAME_ENCODE}, {VPU_CMD_ID_SNAPSHOT, GTB_ENC_CMD_SNAPSHOT}, {VPU_CMD_ID_FIRM_RESET, GTB_ENC_CMD_FIRM_RESET}, {VPU_CMD_ID_UPDATE_PARAMETER, GTB_ENC_CMD_PARAMETER_UPD}, {VPU_CMD_ID_DEBUG, GTB_ENC_CMD_FW_STATUS} }; static struct vpu_pair windsor_msgs[] = { {VPU_MSG_ID_RESET_DONE, VID_API_ENC_EVENT_RESET_DONE}, {VPU_MSG_ID_START_DONE, VID_API_ENC_EVENT_START_DONE}, {VPU_MSG_ID_STOP_DONE, VID_API_ENC_EVENT_STOP_DONE}, {VPU_MSG_ID_FRAME_INPUT_DONE, VID_API_ENC_EVENT_FRAME_INPUT_DONE}, {VPU_MSG_ID_ENC_DONE, VID_API_ENC_EVENT_FRAME_DONE}, {VPU_MSG_ID_FRAME_RELEASE, VID_API_ENC_EVENT_FRAME_RELEASE}, {VPU_MSG_ID_MEM_REQUEST, VID_API_ENC_EVENT_MEM_REQUEST}, {VPU_MSG_ID_PARAM_UPD_DONE, VID_API_ENC_EVENT_PARA_UPD_DONE}, {VPU_MSG_ID_FIRMWARE_XCPT, VID_API_ENC_EVENT_FIRMWARE_XCPT}, }; int vpu_windsor_pack_cmd(struct vpu_rpc_event *pkt, u32 index, u32 id, void *data) { int ret; ret = vpu_find_dst_by_src(windsor_cmds, ARRAY_SIZE(windsor_cmds), id); if (ret < 0) return ret; pkt->hdr.id = ret; pkt->hdr.num = 0; pkt->hdr.index = index; if (id == VPU_CMD_ID_FRAME_ENCODE) { s64 timestamp = *(s64 *)data; struct timespec64 ts = ns_to_timespec64(timestamp); pkt->hdr.num = 2; pkt->data[0] = ts.tv_sec; pkt->data[1] = ts.tv_nsec; } return 0; } int vpu_windsor_convert_msg_id(u32 id) { return vpu_find_src_by_dst(windsor_msgs, ARRAY_SIZE(windsor_msgs), id); } static void vpu_windsor_unpack_pic_info(struct vpu_rpc_event *pkt, void *data) { struct vpu_enc_pic_info *info = data; struct windsor_pic_info *windsor = (struct windsor_pic_info *)pkt->data; struct timespec64 ts = { windsor->tv_s, windsor->tv_ns }; info->frame_id = windsor->frame_id; switch (windsor->pic_type) { case MEDIAIP_ENC_PIC_TYPE_I_FRAME: case MEDIAIP_ENC_PIC_TYPE_IDR_FRAME: info->pic_type = V4L2_BUF_FLAG_KEYFRAME; break; case MEDIAIP_ENC_PIC_TYPE_P_FRAME: info->pic_type = V4L2_BUF_FLAG_PFRAME; break; case MEDIAIP_ENC_PIC_TYPE_B_FRAME: info->pic_type = V4L2_BUF_FLAG_BFRAME; break; default: break; } info->skipped_frame = windsor->skipped_frame; info->error_flag = windsor->error_flag; info->psnr = windsor->psnr; info->frame_size = windsor->frame_size; info->wptr = get_ptr(windsor->str_buff_wptr); info->crc = windsor->frame_crc; info->timestamp = timespec64_to_ns(&ts); } static void vpu_windsor_unpack_mem_req(struct vpu_rpc_event *pkt, void *data) { struct vpu_pkt_mem_req_data *req_data = data; req_data->enc_frame_size = pkt->data[0]; req_data->enc_frame_num = pkt->data[1]; req_data->ref_frame_size = pkt->data[2]; req_data->ref_frame_num = pkt->data[3]; req_data->act_buf_size = pkt->data[4]; req_data->act_buf_num = 1; } int vpu_windsor_unpack_msg_data(struct vpu_rpc_event *pkt, void *data) { if (!pkt || !data) return -EINVAL; switch (pkt->hdr.id) { case VID_API_ENC_EVENT_FRAME_DONE: vpu_windsor_unpack_pic_info(pkt, data); break; case VID_API_ENC_EVENT_MEM_REQUEST: vpu_windsor_unpack_mem_req(pkt, data); break; case VID_API_ENC_EVENT_FRAME_RELEASE: *(u32 *)data = pkt->data[0]; break; default: break; } return 0; } static int vpu_windsor_fill_yuv_frame(struct vpu_shared_addr *shared, u32 instance, struct vb2_buffer *vb) { struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); struct vpu_format *out_fmt; struct vpu_enc_yuv_desc *desc; struct vb2_v4l2_buffer *vbuf; if (instance >= VID_API_NUM_STREAMS) return -EINVAL; desc = get_yuv_desc(shared, instance); out_fmt = vpu_get_format(inst, vb->type); vbuf = to_vb2_v4l2_buffer(vb); desc->frame_id = vbuf->sequence; if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME) desc->key_frame = 1; else desc->key_frame = 0; desc->luma_base = vpu_get_vb_phy_addr(vb, 0); if (vb->num_planes > 1) desc->chroma_base = vpu_get_vb_phy_addr(vb, 1); else desc->chroma_base = desc->luma_base + out_fmt->sizeimage[0]; return 0; } int vpu_windsor_input_frame(struct vpu_shared_addr *shared, struct vpu_inst *inst, struct vb2_buffer *vb) { vpu_windsor_fill_yuv_frame(shared, inst->id, vb); return vpu_session_encode_frame(inst, vb->timestamp); } int vpu_windsor_config_memory_resource(struct vpu_shared_addr *shared, u32 instance, u32 type, u32 index, struct vpu_buffer *buf) { struct vpu_enc_mem_pool *pool; struct vpu_enc_memory_resource *res; if (instance >= VID_API_NUM_STREAMS) return -EINVAL; pool = get_mem_pool(shared, instance); switch (type) { case MEM_RES_ENC: if (index >= ARRAY_SIZE(pool->enc_frames)) return -EINVAL; res = &pool->enc_frames[index]; break; case MEM_RES_REF: if (index >= ARRAY_SIZE(pool->ref_frames)) return -EINVAL; res = &pool->ref_frames[index]; break; case MEM_RES_ACT: if (index) return -EINVAL; res = &pool->act_frame; break; default: return -EINVAL; } res->phys = buf->phys; res->virt = buf->phys - shared->boot_addr; res->size = buf->length; return 0; } int vpu_windsor_config_stream_buffer(struct vpu_shared_addr *shared, u32 instance, struct vpu_buffer *buf) { struct vpu_rpc_buffer_desc *desc; struct vpu_enc_expert_mode_param *expert; desc = get_stream_buf_desc(shared, instance); expert = get_expert_param(shared, instance); desc->start = buf->phys; desc->wptr = buf->phys; desc->rptr = buf->phys; desc->end = buf->phys + buf->length; expert->calib_param.mem_chunk_phys_addr = 0; expert->calib_param.mem_chunk_virt_addr = 0; expert->calib_param.mem_chunk_size = 0; expert->calib_param.cb_base = buf->phys; expert->calib_param.cb_size = buf->length; return 0; } int vpu_windsor_update_stream_buffer(struct vpu_shared_addr *shared, u32 instance, u32 ptr, bool write) { struct vpu_rpc_buffer_desc *desc; desc = get_stream_buf_desc(shared, instance); /*update wptr/rptr after data is written or read*/ mb(); if (write) desc->wptr = ptr; else desc->rptr = ptr; return 0; } int vpu_windsor_get_stream_buffer_desc(struct vpu_shared_addr *shared, u32 instance, struct vpu_rpc_buffer_desc *desc) { struct vpu_rpc_buffer_desc *rpc_desc; rpc_desc = get_stream_buf_desc(shared, instance); if (desc) { desc->wptr = get_ptr(rpc_desc->wptr); desc->rptr = get_ptr(rpc_desc->rptr); desc->start = get_ptr(rpc_desc->start); desc->end = get_ptr(rpc_desc->end); } return 0; } u32 vpu_windsor_get_version(struct vpu_shared_addr *shared) { struct windsor_iface *iface = shared->iface; return iface->fw_version; } static int vpu_windsor_set_frame_rate(struct vpu_enc_expert_mode_param *expert, struct vpu_encode_params *params) { expert->config_param.frame_rate_num = params->frame_rate.numerator; expert->config_param.frame_rate_den = params->frame_rate.denominator; return 0; } static int vpu_windsor_set_format(struct vpu_enc_param *param, u32 pixelformat) { switch (pixelformat) { case V4L2_PIX_FMT_H264: param->codec_mode = MEDIAIP_ENC_FMT_H264; break; default: return -EINVAL; } return 0; } static int vpu_windsor_set_profile(struct vpu_enc_param *param, u32 profile) { switch (profile) { case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: param->profile = MEDIAIP_ENC_PROF_H264_BP; break; case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: param->profile = MEDIAIP_ENC_PROF_H264_MP; break; case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: param->profile = MEDIAIP_ENC_PROF_H264_HP; break; default: return -EINVAL; } return 0; } static const u32 h264_level[] = { [V4L2_MPEG_VIDEO_H264_LEVEL_1_0] = 10, [V4L2_MPEG_VIDEO_H264_LEVEL_1B] = 14, [V4L2_MPEG_VIDEO_H264_LEVEL_1_1] = 11, [V4L2_MPEG_VIDEO_H264_LEVEL_1_2] = 12, [V4L2_MPEG_VIDEO_H264_LEVEL_1_3] = 13, [V4L2_MPEG_VIDEO_H264_LEVEL_2_0] = 20, [V4L2_MPEG_VIDEO_H264_LEVEL_2_1] = 21, [V4L2_MPEG_VIDEO_H264_LEVEL_2_2] = 22, [V4L2_MPEG_VIDEO_H264_LEVEL_3_0] = 30, [V4L2_MPEG_VIDEO_H264_LEVEL_3_1] = 31, [V4L2_MPEG_VIDEO_H264_LEVEL_3_2] = 32, [V4L2_MPEG_VIDEO_H264_LEVEL_4_0] = 40, [V4L2_MPEG_VIDEO_H264_LEVEL_4_1] = 41, [V4L2_MPEG_VIDEO_H264_LEVEL_4_2] = 42, [V4L2_MPEG_VIDEO_H264_LEVEL_5_0] = 50, [V4L2_MPEG_VIDEO_H264_LEVEL_5_1] = 51 }; static int vpu_windsor_set_level(struct vpu_enc_param *param, u32 level) { if (level >= ARRAY_SIZE(h264_level)) return -EINVAL; param->level = h264_level[level]; return 0; } static int vpu_windsor_set_size(struct vpu_enc_param *windsor, struct vpu_encode_params *params) { windsor->src_stride = params->src_stride; windsor->src_width = params->src_width; windsor->src_height = params->src_height; windsor->src_offset_x = params->crop.left; windsor->src_offset_y = params->crop.top; windsor->src_crop_width = params->crop.width; windsor->src_crop_height = params->crop.height; windsor->out_width = params->out_width; windsor->out_height = params->out_height; return 0; } static int vpu_windsor_set_gop(struct vpu_enc_param *param, u32 gop) { param->iframe_interval = gop; return 0; } static int vpu_windsor_set_bframes(struct vpu_enc_param *param, u32 bframes) { if (bframes) { param->low_latency_mode = 0; param->bframes = bframes; } else { param->low_latency_mode = 1; param->bframes = 0; } return 0; } static int vpu_windsor_set_bitrate_mode(struct vpu_enc_param *param, u32 rc_enable, u32 mode) { if (!rc_enable) param->bitrate_mode = MEDIAIP_ENC_BITRATE_MODE_CONSTANT_QP; else if (mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) param->bitrate_mode = MEDIAIP_ENC_BITRATE_MODE_VBR; else param->bitrate_mode = MEDIAIP_ENC_BITRATE_MODE_CBR; return 0; } static u32 vpu_windsor_bitrate(u32 bitrate) { return DIV_ROUND_CLOSEST(bitrate, WINDSOR_BITRATE_UNIT); } static int vpu_windsor_set_bitrate(struct vpu_enc_param *windsor, struct vpu_encode_params *params) { windsor->target_bitrate = vpu_windsor_bitrate(params->bitrate); windsor->min_bitrate = vpu_windsor_bitrate(params->bitrate_min); windsor->max_bitrate = vpu_windsor_bitrate(params->bitrate_max); return 0; } static int vpu_windsor_set_qp(struct vpu_enc_expert_mode_param *expert, struct vpu_encode_params *params) { expert->static_param.rate_control_islice_qp = params->i_frame_qp; expert->static_param.rate_control_pslice_qp = params->p_frame_qp; expert->static_param.rate_control_bslice_qp = params->b_frame_qp; return 0; } static int vpu_windsor_set_sar(struct vpu_enc_expert_mode_param *expert, struct vpu_encode_params *params) { expert->config_param.h264_aspect_ratio_present = params->sar.enable; if (params->sar.idc == V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED) expert->config_param.aspect_ratio = WINDSOR_H264_EXTENDED_SAR; else expert->config_param.aspect_ratio = params->sar.idc; expert->config_param.h264_aspect_ratio_sar_width = params->sar.width; expert->config_param.h264_aspect_ratio_sar_height = params->sar.height; return 0; } static int vpu_windsor_set_color(struct vpu_enc_expert_mode_param *expert, struct vpu_encode_params *params) { expert->config_param.h264_video_type_present = 1; expert->config_param.h264_video_format = 5; expert->config_param.h264_video_colour_descriptor = 1; expert->config_param.h264_video_colour_primaries = vpu_color_cvrt_primaries_v2i(params->color.primaries); expert->config_param.h264_video_transfer_char = vpu_color_cvrt_transfers_v2i(params->color.transfer); expert->config_param.h264_video_matrix_coeff = vpu_color_cvrt_matrix_v2i(params->color.matrix); expert->config_param.h264_video_full_range = vpu_color_cvrt_full_range_v2i(params->color.full_range); return 0; } static int vpu_windsor_update_bitrate(struct vpu_shared_addr *shared, u32 instance, struct vpu_encode_params *params) { struct vpu_enc_param *windsor; struct vpu_enc_expert_mode_param *expert; windsor = get_enc_param(shared, instance); expert = get_expert_param(shared, instance); if (windsor->bitrate_mode != MEDIAIP_ENC_BITRATE_MODE_CBR) return 0; if (!params->rc_enable) return 0; if (vpu_windsor_bitrate(params->bitrate) == windsor->target_bitrate) return 0; vpu_windsor_set_bitrate(windsor, params); expert->static_param.rate_control_bitrate = windsor->target_bitrate; expert->static_param.rate_control_bitrate_min = windsor->min_bitrate; expert->static_param.rate_control_bitrate_max = windsor->max_bitrate; return 0; } static int vpu_windsor_set_params(struct vpu_shared_addr *shared, u32 instance, struct vpu_encode_params *params) { struct vpu_enc_param *windsor; int ret; windsor = get_enc_param(shared, instance); if (params->input_format != V4L2_PIX_FMT_NV12 && params->input_format != V4L2_PIX_FMT_NV12M) return -EINVAL; ret = vpu_windsor_set_format(windsor, params->codec_format); if (ret) return ret; vpu_windsor_set_profile(windsor, params->profile); vpu_windsor_set_level(windsor, params->level); vpu_windsor_set_size(windsor, params); vpu_windsor_set_gop(windsor, params->gop_length); vpu_windsor_set_bframes(windsor, params->bframes); vpu_windsor_set_bitrate_mode(windsor, params->rc_enable, params->rc_mode); vpu_windsor_set_bitrate(windsor, params); windsor->init_slice_qp = params->i_frame_qp; if (!params->frame_rate.numerator) return -EINVAL; windsor->frame_rate = params->frame_rate.denominator / params->frame_rate.numerator; return 0; } static int vpu_windsor_update_params(struct vpu_shared_addr *shared, u32 instance, struct vpu_encode_params *params) { struct vpu_enc_expert_mode_param *expert; expert = get_expert_param(shared, instance); vpu_windsor_set_frame_rate(expert, params); vpu_windsor_set_qp(expert, params); vpu_windsor_set_sar(expert, params); vpu_windsor_set_color(expert, params); vpu_windsor_update_bitrate(shared, instance, params); /*expert->config_param.iac_sc_threshold = 0;*/ return 0; } int vpu_windsor_set_encode_params(struct vpu_shared_addr *shared, u32 instance, struct vpu_encode_params *params, u32 update) { if (!params) return -EINVAL; if (!update) return vpu_windsor_set_params(shared, instance, params); else return vpu_windsor_update_params(shared, instance, params); } u32 vpu_windsor_get_max_instance_count(struct vpu_shared_addr *shared) { struct windsor_iface *iface = shared->iface; return iface->max_streams; }