| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright 2020-2021 NXP |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/interconnect.h> |
| #include <linux/ioctl.h> |
| #include <linux/list.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/of_device.h> |
| #include <linux/of_address.h> |
| #include <linux/platform_device.h> |
| #include <linux/time64.h> |
| #include <media/videobuf2-v4l2.h> |
| #include <media/videobuf2-dma-contig.h> |
| #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_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_enc_yuv_desc *desc; |
| struct vb2_v4l2_buffer *vbuf; |
| |
| if (instance >= VID_API_NUM_STREAMS) |
| return -EINVAL; |
| |
| desc = get_yuv_desc(shared, instance); |
| |
| 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); |
| desc->chroma_base = vpu_get_vb_phy_addr(vb, 1); |
| |
| 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; |
| } |