// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2021 MediaTek Inc. * Author: George Sun */ #include #include #include #include #include "../mtk_vcodec_dec.h" #include "../../common/mtk_vcodec_intr.h" #include "../vdec_drv_base.h" #include "../vdec_drv_if.h" #include "../vdec_vpu_if.h" /* reset_frame_context defined in VP9 spec */ #define VP9_RESET_FRAME_CONTEXT_NONE0 0 #define VP9_RESET_FRAME_CONTEXT_NONE1 1 #define VP9_RESET_FRAME_CONTEXT_SPEC 2 #define VP9_RESET_FRAME_CONTEXT_ALL 3 #define VP9_TILE_BUF_SIZE 4096 #define VP9_PROB_BUF_SIZE 2560 #define VP9_COUNTS_BUF_SIZE 16384 #define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x)) #define LF_FLAG(x) (!!((lf)->flags & V4L2_VP9_LOOP_FILTER_FLAG_##x)) #define SEG_FLAG(x) (!!((seg)->flags & V4L2_VP9_SEGMENTATION_FLAG_##x)) #define VP9_BAND_6(band) ((band) == 0 ? 3 : 6) /* * struct vdec_vp9_slice_frame_ctx - vp9 prob tables footprint */ struct vdec_vp9_slice_frame_ctx { struct { u8 probs[6][3]; u8 padding[2]; } coef_probs[4][2][2][6]; u8 y_mode_prob[4][16]; u8 switch_interp_prob[4][16]; u8 seg[32]; /* ignore */ u8 comp_inter_prob[16]; u8 comp_ref_prob[16]; u8 single_ref_prob[5][2]; u8 single_ref_prob_padding[6]; u8 joint[3]; u8 joint_padding[13]; struct { u8 sign; u8 classes[10]; u8 padding[5]; } sign_classes[2]; struct { u8 class0[1]; u8 bits[10]; u8 padding[5]; } class0_bits[2]; struct { u8 class0_fp[2][3]; u8 fp[3]; u8 class0_hp; u8 hp; u8 padding[5]; } class0_fp_hp[2]; u8 uv_mode_prob[10][16]; u8 uv_mode_prob_padding[2][16]; u8 partition_prob[16][4]; u8 inter_mode_probs[7][4]; u8 skip_probs[4]; u8 tx_p8x8[2][4]; u8 tx_p16x16[2][4]; u8 tx_p32x32[2][4]; u8 intra_inter_prob[8]; }; /* * struct vdec_vp9_slice_frame_counts - vp9 counts tables footprint */ struct vdec_vp9_slice_frame_counts { union { struct { u32 band_0[3]; u32 padding0[1]; u32 band_1_5[5][6]; u32 padding1[2]; } eob_branch[4][2][2]; u32 eob_branch_space[256 * 4]; }; struct { u32 band_0[3][4]; u32 band_1_5[5][6][4]; } coef_probs[4][2][2]; u32 intra_inter[4][2]; u32 comp_inter[5][2]; u32 comp_inter_padding[2]; u32 comp_ref[5][2]; u32 comp_ref_padding[2]; u32 single_ref[5][2][2]; u32 inter_mode[7][4]; u32 y_mode[4][12]; u32 uv_mode[10][10]; u32 partition[16][4]; u32 switchable_interp[4][4]; u32 tx_p8x8[2][2]; u32 tx_p16x16[2][4]; u32 tx_p32x32[2][4]; u32 skip[3][4]; u32 joint[4]; struct { u32 sign[2]; u32 class0[2]; u32 classes[12]; u32 bits[10][2]; u32 padding[4]; u32 class0_fp[2][4]; u32 fp[4]; u32 class0_hp[2]; u32 hp[2]; } mvcomp[2]; u32 reserved[126][4]; }; /** * struct vdec_vp9_slice_counts_map - vp9 counts tables to map * v4l2_vp9_frame_symbol_counts * @skip: skip counts. * @y_mode: Y prediction mode counts. * @filter: interpolation filter counts. * @sign: motion vector sign counts. * @classes: motion vector class counts. * @class0: motion vector class0 bit counts. * @bits: motion vector bits counts. * @class0_fp: motion vector class0 fractional bit counts. * @fp: motion vector fractional bit counts. * @class0_hp: motion vector class0 high precision fractional bit counts. * @hp: motion vector high precision fractional bit counts. */ struct vdec_vp9_slice_counts_map { u32 skip[3][2]; u32 y_mode[4][10]; u32 filter[4][3]; u32 sign[2][2]; u32 classes[2][11]; u32 class0[2][2]; u32 bits[2][10][2]; u32 class0_fp[2][2][4]; u32 fp[2][4]; u32 class0_hp[2][2]; u32 hp[2][2]; }; /* * struct vdec_vp9_slice_uncompressed_header - vp9 uncompressed header syntax * used for decoding */ struct vdec_vp9_slice_uncompressed_header { u8 profile; u8 last_frame_type; u8 frame_type; u8 last_show_frame; u8 show_frame; u8 error_resilient_mode; u8 bit_depth; u8 padding0[1]; u16 last_frame_width; u16 last_frame_height; u16 frame_width; u16 frame_height; u8 intra_only; u8 reset_frame_context; u8 ref_frame_sign_bias[4]; u8 allow_high_precision_mv; u8 interpolation_filter; u8 refresh_frame_context; u8 frame_parallel_decoding_mode; u8 frame_context_idx; /* loop_filter_params */ u8 loop_filter_level; u8 loop_filter_sharpness; u8 loop_filter_delta_enabled; s8 loop_filter_ref_deltas[4]; s8 loop_filter_mode_deltas[2]; /* quantization_params */ u8 base_q_idx; s8 delta_q_y_dc; s8 delta_q_uv_dc; s8 delta_q_uv_ac; /* segmentation_params */ u8 segmentation_enabled; u8 segmentation_update_map; u8 segmentation_tree_probs[7]; u8 padding1[1]; u8 segmentation_temporal_udpate; u8 segmentation_pred_prob[3]; u8 segmentation_update_data; u8 segmentation_abs_or_delta_update; u8 feature_enabled[8]; s16 feature_value[8][4]; /* tile_info */ u8 tile_cols_log2; u8 tile_rows_log2; u8 padding2[2]; u16 uncompressed_header_size; u16 header_size_in_bytes; /* LAT OUT, CORE IN */ u32 dequant[8][4]; }; /* * struct vdec_vp9_slice_compressed_header - vp9 compressed header syntax * used for decoding. */ struct vdec_vp9_slice_compressed_header { u8 tx_mode; u8 ref_mode; u8 comp_fixed_ref; u8 comp_var_ref[2]; u8 padding[3]; }; /* * struct vdec_vp9_slice_tiles - vp9 tile syntax */ struct vdec_vp9_slice_tiles { u32 size[4][64]; u32 mi_rows[4]; u32 mi_cols[64]; u8 actual_rows; u8 padding[7]; }; /* * struct vdec_vp9_slice_reference - vp9 reference frame information */ struct vdec_vp9_slice_reference { u16 frame_width; u16 frame_height; u8 bit_depth; u8 subsampling_x; u8 subsampling_y; u8 padding; }; /* * struct vdec_vp9_slice_frame - vp9 syntax used for decoding */ struct vdec_vp9_slice_frame { struct vdec_vp9_slice_uncompressed_header uh; struct vdec_vp9_slice_compressed_header ch; struct vdec_vp9_slice_tiles tiles; struct vdec_vp9_slice_reference ref[3]; }; /* * struct vdec_vp9_slice_init_vsi - VSI used to initialize instance */ struct vdec_vp9_slice_init_vsi { unsigned int architecture; unsigned int reserved; u64 core_vsi; /* default frame context's position in MicroP */ u64 default_frame_ctx; }; /* * struct vdec_vp9_slice_mem - memory address and size */ struct vdec_vp9_slice_mem { union { u64 buf; dma_addr_t dma_addr; }; union { size_t size; dma_addr_t dma_addr_end; u64 padding; }; }; /* * struct vdec_vp9_slice_bs - input buffer for decoding */ struct vdec_vp9_slice_bs { struct vdec_vp9_slice_mem buf; struct vdec_vp9_slice_mem frame; }; /* * struct vdec_vp9_slice_fb - frame buffer for decoding */ struct vdec_vp9_slice_fb { struct vdec_vp9_slice_mem y; struct vdec_vp9_slice_mem c; }; /* * struct vdec_vp9_slice_state - decoding state */ struct vdec_vp9_slice_state { int err; unsigned int full; unsigned int timeout; unsigned int perf; unsigned int crc[12]; }; /** * struct vdec_vp9_slice_vsi - exchange decoding information * between Main CPU and MicroP * * @bs: input buffer * @fb: output buffer * @ref: 3 reference buffers * @mv: mv working buffer * @seg: segmentation working buffer * @tile: tile buffer * @prob: prob table buffer, used to set/update prob table * @counts: counts table buffer, used to update prob table * @ube: general buffer * @trans: trans buffer position in general buffer * @err_map: error buffer * @row_info: row info buffer * @frame: decoding syntax * @state: decoding state */ struct vdec_vp9_slice_vsi { /* used in LAT stage */ struct vdec_vp9_slice_bs bs; /* used in Core stage */ struct vdec_vp9_slice_fb fb; struct vdec_vp9_slice_fb ref[3]; struct vdec_vp9_slice_mem mv[2]; struct vdec_vp9_slice_mem seg[2]; struct vdec_vp9_slice_mem tile; struct vdec_vp9_slice_mem prob; struct vdec_vp9_slice_mem counts; /* LAT stage's output, Core stage's input */ struct vdec_vp9_slice_mem ube; struct vdec_vp9_slice_mem trans; struct vdec_vp9_slice_mem err_map; struct vdec_vp9_slice_mem row_info; /* decoding parameters */ struct vdec_vp9_slice_frame frame; struct vdec_vp9_slice_state state; }; /** * struct vdec_vp9_slice_pfc - per-frame context that contains a local vsi. * pass it from lat to core * * @vsi: local vsi. copy to/from remote vsi before/after decoding * @ref_idx: reference buffer index * @seq: picture sequence * @state: decoding state */ struct vdec_vp9_slice_pfc { struct vdec_vp9_slice_vsi vsi; u64 ref_idx[3]; int seq; /* LAT/Core CRC */ struct vdec_vp9_slice_state state[2]; }; /* * enum vdec_vp9_slice_resolution_level */ enum vdec_vp9_slice_resolution_level { VP9_RES_NONE, VP9_RES_FHD, VP9_RES_4K, VP9_RES_8K, }; /* * struct vdec_vp9_slice_ref - picture's width & height should kept * for later decoding as reference picture */ struct vdec_vp9_slice_ref { unsigned int width; unsigned int height; }; /** * struct vdec_vp9_slice_instance - represent one vp9 instance * * @ctx: pointer to codec's context * @vpu: VPU instance * @seq: global picture sequence * @level: level of current resolution * @width: width of last picture * @height: height of last picture * @frame_type: frame_type of last picture * @irq: irq to Main CPU or MicroP * @show_frame: show_frame of last picture * @dpb: picture information (width/height) for reference * @mv: mv working buffer * @seg: segmentation working buffer * @tile: tile buffer * @prob: prob table buffer, used to set/update prob table * @counts: counts table buffer, used to update prob table * @frame_ctx: 4 frame context according to VP9 Spec * @frame_ctx_helper: 4 frame context according to newest kernel spec * @dirty: state of each frame context * @init_vsi: vsi used for initialized VP9 instance * @vsi: vsi used for decoding/flush ... * @core_vsi: vsi used for Core stage * * @sc_pfc: per frame context single core * @counts_map: used map to counts_helper * @counts_helper: counts table according to newest kernel spec */ struct vdec_vp9_slice_instance { struct mtk_vcodec_dec_ctx *ctx; struct vdec_vpu_inst vpu; int seq; enum vdec_vp9_slice_resolution_level level; /* for resolution change and get_pic_info */ unsigned int width; unsigned int height; /* for last_frame_type */ unsigned int frame_type; unsigned int irq; unsigned int show_frame; /* maintain vp9 reference frame state */ struct vdec_vp9_slice_ref dpb[VB2_MAX_FRAME]; /* * normal working buffers * mv[0]/seg[0]/tile/prob/counts is used for LAT * mv[1]/seg[1] is used for CORE */ struct mtk_vcodec_mem mv[2]; struct mtk_vcodec_mem seg[2]; struct mtk_vcodec_mem tile; struct mtk_vcodec_mem prob; struct mtk_vcodec_mem counts; /* 4 prob tables */ struct vdec_vp9_slice_frame_ctx frame_ctx[4]; /*4 helper tables */ struct v4l2_vp9_frame_context frame_ctx_helper; unsigned char dirty[4]; /* MicroP vsi */ union { struct vdec_vp9_slice_init_vsi *init_vsi; struct vdec_vp9_slice_vsi *vsi; }; struct vdec_vp9_slice_vsi *core_vsi; struct vdec_vp9_slice_pfc sc_pfc; struct vdec_vp9_slice_counts_map counts_map; struct v4l2_vp9_frame_symbol_counts counts_helper; }; /* * all VP9 instances could share this default frame context. */ static struct vdec_vp9_slice_frame_ctx *vdec_vp9_slice_default_frame_ctx; static DEFINE_MUTEX(vdec_vp9_slice_frame_ctx_lock); static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf); static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance *instance) { struct vdec_vp9_slice_frame_ctx *remote_frame_ctx; struct vdec_vp9_slice_frame_ctx *frame_ctx; struct mtk_vcodec_dec_ctx *ctx; struct vdec_vp9_slice_init_vsi *vsi; int ret = 0; ctx = instance->ctx; vsi = instance->vpu.vsi; if (!ctx || !vsi) return -EINVAL; remote_frame_ctx = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, (u32)vsi->default_frame_ctx); if (!remote_frame_ctx) { mtk_vdec_err(ctx, "failed to map default frame ctx\n"); return -EINVAL; } mutex_lock(&vdec_vp9_slice_frame_ctx_lock); if (vdec_vp9_slice_default_frame_ctx) goto out; frame_ctx = kmemdup(remote_frame_ctx, sizeof(*frame_ctx), GFP_KERNEL); if (!frame_ctx) { ret = -ENOMEM; goto out; } vdec_vp9_slice_default_frame_ctx = frame_ctx; out: mutex_unlock(&vdec_vp9_slice_frame_ctx_lock); return ret; } static int vdec_vp9_slice_alloc_working_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi) { struct mtk_vcodec_dec_ctx *ctx = instance->ctx; enum vdec_vp9_slice_resolution_level level; /* super blocks */ unsigned int max_sb_w; unsigned int max_sb_h; unsigned int max_w; unsigned int max_h; unsigned int w; unsigned int h; size_t size; int ret; int i; w = vsi->frame.uh.frame_width; h = vsi->frame.uh.frame_height; if (w > VCODEC_DEC_4K_CODED_WIDTH || h > VCODEC_DEC_4K_CODED_HEIGHT) { return -EINVAL; } else if (w > MTK_VDEC_MAX_W || h > MTK_VDEC_MAX_H) { /* 4K */ level = VP9_RES_4K; max_w = VCODEC_DEC_4K_CODED_WIDTH; max_h = VCODEC_DEC_4K_CODED_HEIGHT; } else { /* FHD */ level = VP9_RES_FHD; max_w = MTK_VDEC_MAX_W; max_h = MTK_VDEC_MAX_H; } if (level == instance->level) return 0; mtk_vdec_debug(ctx, "resolution level changed, from %u to %u, %ux%u", instance->level, level, w, h); max_sb_w = DIV_ROUND_UP(max_w, 64); max_sb_h = DIV_ROUND_UP(max_h, 64); ret = -ENOMEM; /* * Lat-flush must wait core idle, otherwise core will * use released buffers */ size = (max_sb_w * max_sb_h + 2) * 576; for (i = 0; i < 2; i++) { if (instance->mv[i].va) mtk_vcodec_mem_free(ctx, &instance->mv[i]); instance->mv[i].size = size; if (mtk_vcodec_mem_alloc(ctx, &instance->mv[i])) goto err; } size = (max_sb_w * max_sb_h * 32) + 256; for (i = 0; i < 2; i++) { if (instance->seg[i].va) mtk_vcodec_mem_free(ctx, &instance->seg[i]); instance->seg[i].size = size; if (mtk_vcodec_mem_alloc(ctx, &instance->seg[i])) goto err; } if (!instance->tile.va) { instance->tile.size = VP9_TILE_BUF_SIZE; if (mtk_vcodec_mem_alloc(ctx, &instance->tile)) goto err; } if (!instance->prob.va) { instance->prob.size = VP9_PROB_BUF_SIZE; if (mtk_vcodec_mem_alloc(ctx, &instance->prob)) goto err; } if (!instance->counts.va) { instance->counts.size = VP9_COUNTS_BUF_SIZE; if (mtk_vcodec_mem_alloc(ctx, &instance->counts)) goto err; } instance->level = level; return 0; err: instance->level = VP9_RES_NONE; return ret; } static void vdec_vp9_slice_free_working_buffer(struct vdec_vp9_slice_instance *instance) { struct mtk_vcodec_dec_ctx *ctx = instance->ctx; int i; for (i = 0; i < ARRAY_SIZE(instance->mv); i++) { if (instance->mv[i].va) mtk_vcodec_mem_free(ctx, &instance->mv[i]); } for (i = 0; i < ARRAY_SIZE(instance->seg); i++) { if (instance->seg[i].va) mtk_vcodec_mem_free(ctx, &instance->seg[i]); } if (instance->tile.va) mtk_vcodec_mem_free(ctx, &instance->tile); if (instance->prob.va) mtk_vcodec_mem_free(ctx, &instance->prob); if (instance->counts.va) mtk_vcodec_mem_free(ctx, &instance->counts); instance->level = VP9_RES_NONE; } static void vdec_vp9_slice_vsi_from_remote(struct vdec_vp9_slice_vsi *vsi, struct vdec_vp9_slice_vsi *remote_vsi, int skip) { struct vdec_vp9_slice_frame *rf; struct vdec_vp9_slice_frame *f; /* * compressed header * dequant * buffer position * decode state */ if (!skip) { rf = &remote_vsi->frame; f = &vsi->frame; memcpy(&f->ch, &rf->ch, sizeof(f->ch)); memcpy(&f->uh.dequant, &rf->uh.dequant, sizeof(f->uh.dequant)); memcpy(&vsi->trans, &remote_vsi->trans, sizeof(vsi->trans)); } memcpy(&vsi->state, &remote_vsi->state, sizeof(vsi->state)); } static void vdec_vp9_slice_vsi_to_remote(struct vdec_vp9_slice_vsi *vsi, struct vdec_vp9_slice_vsi *remote_vsi) { memcpy(remote_vsi, vsi, sizeof(*vsi)); } static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2) { int sbs = (mi_num + 7) >> 3; int offset = ((idx * sbs) >> tile_log2) << 3; return min(offset, mi_num); } static int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance) { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); if (!src) return -EINVAL; dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); if (!dst) return -EINVAL; v4l2_m2m_buf_copy_metadata(src, dst, true); return 0; } static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf) { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); if (!src) return -EINVAL; lat_buf->src_buf_req = src->vb2_buf.req_obj.req; dst = &lat_buf->ts_info; v4l2_m2m_buf_copy_metadata(src, dst, true); return 0; } static void vdec_vp9_slice_setup_hdr(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_uncompressed_header *uh, struct v4l2_ctrl_vp9_frame *hdr) { int i; uh->profile = hdr->profile; uh->last_frame_type = instance->frame_type; uh->frame_type = !HDR_FLAG(KEY_FRAME); uh->last_show_frame = instance->show_frame; uh->show_frame = HDR_FLAG(SHOW_FRAME); uh->error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); uh->bit_depth = hdr->bit_depth; uh->last_frame_width = instance->width; uh->last_frame_height = instance->height; uh->frame_width = hdr->frame_width_minus_1 + 1; uh->frame_height = hdr->frame_height_minus_1 + 1; uh->intra_only = HDR_FLAG(INTRA_ONLY); /* map v4l2 enum to values defined in VP9 spec for firmware */ switch (hdr->reset_frame_context) { case V4L2_VP9_RESET_FRAME_CTX_NONE: uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; break; case V4L2_VP9_RESET_FRAME_CTX_SPEC: uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_SPEC; break; case V4L2_VP9_RESET_FRAME_CTX_ALL: uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_ALL; break; default: uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; break; } /* * ref_frame_sign_bias specifies the intended direction * of the motion vector in time for each reference frame. * - INTRA_FRAME = 0, * - LAST_FRAME = 1, * - GOLDEN_FRAME = 2, * - ALTREF_FRAME = 3, * ref_frame_sign_bias[INTRA_FRAME] is always 0 * and VDA only passes another 3 directions */ uh->ref_frame_sign_bias[0] = 0; for (i = 0; i < 3; i++) uh->ref_frame_sign_bias[i + 1] = !!(hdr->ref_frame_sign_bias & (1 << i)); uh->allow_high_precision_mv = HDR_FLAG(ALLOW_HIGH_PREC_MV); uh->interpolation_filter = hdr->interpolation_filter; uh->refresh_frame_context = HDR_FLAG(REFRESH_FRAME_CTX); uh->frame_parallel_decoding_mode = HDR_FLAG(PARALLEL_DEC_MODE); uh->frame_context_idx = hdr->frame_context_idx; /* tile info */ uh->tile_cols_log2 = hdr->tile_cols_log2; uh->tile_rows_log2 = hdr->tile_rows_log2; uh->uncompressed_header_size = hdr->uncompressed_header_size; uh->header_size_in_bytes = hdr->compressed_header_size; } static void vdec_vp9_slice_setup_frame_ctx(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_uncompressed_header *uh, struct v4l2_ctrl_vp9_frame *hdr) { int error_resilient_mode; int reset_frame_context; int key_frame; int intra_only; int i; key_frame = HDR_FLAG(KEY_FRAME); intra_only = HDR_FLAG(INTRA_ONLY); error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); reset_frame_context = uh->reset_frame_context; /* * according to "6.2 Uncompressed header syntax" in * "VP9 Bitstream & Decoding Process Specification", * reset @frame_context_idx when (FrameIsIntra || error_resilient_mode) */ if (key_frame || intra_only || error_resilient_mode) { /* * @reset_frame_context specifies * whether the frame context should be * reset to default values: * 0 or 1 means do not reset any frame context * 2 resets just the context specified in the frame header * 3 resets all contexts */ if (key_frame || error_resilient_mode || reset_frame_context == 3) { /* use default table */ for (i = 0; i < 4; i++) instance->dirty[i] = 0; } else if (reset_frame_context == 2) { instance->dirty[uh->frame_context_idx] = 0; } uh->frame_context_idx = 0; } } static void vdec_vp9_slice_setup_loop_filter(struct vdec_vp9_slice_uncompressed_header *uh, struct v4l2_vp9_loop_filter *lf) { int i; uh->loop_filter_level = lf->level; uh->loop_filter_sharpness = lf->sharpness; uh->loop_filter_delta_enabled = LF_FLAG(DELTA_ENABLED); for (i = 0; i < 4; i++) uh->loop_filter_ref_deltas[i] = lf->ref_deltas[i]; for (i = 0; i < 2; i++) uh->loop_filter_mode_deltas[i] = lf->mode_deltas[i]; } static void vdec_vp9_slice_setup_quantization(struct vdec_vp9_slice_uncompressed_header *uh, struct v4l2_vp9_quantization *quant) { uh->base_q_idx = quant->base_q_idx; uh->delta_q_y_dc = quant->delta_q_y_dc; uh->delta_q_uv_dc = quant->delta_q_uv_dc; uh->delta_q_uv_ac = quant->delta_q_uv_ac; } static void vdec_vp9_slice_setup_segmentation(struct vdec_vp9_slice_uncompressed_header *uh, struct v4l2_vp9_segmentation *seg) { int i; int j; uh->segmentation_enabled = SEG_FLAG(ENABLED); uh->segmentation_update_map = SEG_FLAG(UPDATE_MAP); for (i = 0; i < 7; i++) uh->segmentation_tree_probs[i] = seg->tree_probs[i]; uh->segmentation_temporal_udpate = SEG_FLAG(TEMPORAL_UPDATE); for (i = 0; i < 3; i++) uh->segmentation_pred_prob[i] = seg->pred_probs[i]; uh->segmentation_update_data = SEG_FLAG(UPDATE_DATA); uh->segmentation_abs_or_delta_update = SEG_FLAG(ABS_OR_DELTA_UPDATE); for (i = 0; i < 8; i++) { uh->feature_enabled[i] = seg->feature_enabled[i]; for (j = 0; j < 4; j++) uh->feature_value[i][j] = seg->feature_data[i][j]; } } static int vdec_vp9_slice_setup_tile(struct vdec_vp9_slice_vsi *vsi, struct v4l2_ctrl_vp9_frame *hdr) { unsigned int rows_log2; unsigned int cols_log2; unsigned int rows; unsigned int cols; unsigned int mi_rows; unsigned int mi_cols; struct vdec_vp9_slice_tiles *tiles; int offset; int start; int end; int i; rows_log2 = hdr->tile_rows_log2; cols_log2 = hdr->tile_cols_log2; rows = 1 << rows_log2; cols = 1 << cols_log2; tiles = &vsi->frame.tiles; tiles->actual_rows = 0; if (rows > 4 || cols > 64) return -EINVAL; /* setup mi rows/cols information */ mi_rows = (hdr->frame_height_minus_1 + 1 + 7) >> 3; mi_cols = (hdr->frame_width_minus_1 + 1 + 7) >> 3; for (i = 0; i < rows; i++) { start = vdec_vp9_slice_tile_offset(i, mi_rows, rows_log2); end = vdec_vp9_slice_tile_offset(i + 1, mi_rows, rows_log2); offset = end - start; tiles->mi_rows[i] = (offset + 7) >> 3; if (tiles->mi_rows[i]) tiles->actual_rows++; } for (i = 0; i < cols; i++) { start = vdec_vp9_slice_tile_offset(i, mi_cols, cols_log2); end = vdec_vp9_slice_tile_offset(i + 1, mi_cols, cols_log2); offset = end - start; tiles->mi_cols[i] = (offset + 7) >> 3; } return 0; } static void vdec_vp9_slice_setup_state(struct vdec_vp9_slice_vsi *vsi) { memset(&vsi->state, 0, sizeof(vsi->state)); } static void vdec_vp9_slice_setup_ref_idx(struct vdec_vp9_slice_pfc *pfc, struct v4l2_ctrl_vp9_frame *hdr) { pfc->ref_idx[0] = hdr->last_frame_ts; pfc->ref_idx[1] = hdr->golden_frame_ts; pfc->ref_idx[2] = hdr->alt_frame_ts; } static int vdec_vp9_slice_setup_pfc(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_pfc *pfc) { struct v4l2_ctrl_vp9_frame *hdr; struct vdec_vp9_slice_uncompressed_header *uh; struct v4l2_ctrl *hdr_ctrl; struct vdec_vp9_slice_vsi *vsi; int ret; /* frame header */ hdr_ctrl = v4l2_ctrl_find(&instance->ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_FRAME); if (!hdr_ctrl || !hdr_ctrl->p_cur.p) return -EINVAL; hdr = hdr_ctrl->p_cur.p; vsi = &pfc->vsi; uh = &vsi->frame.uh; /* setup vsi information */ vdec_vp9_slice_setup_hdr(instance, uh, hdr); vdec_vp9_slice_setup_frame_ctx(instance, uh, hdr); vdec_vp9_slice_setup_loop_filter(uh, &hdr->lf); vdec_vp9_slice_setup_quantization(uh, &hdr->quant); vdec_vp9_slice_setup_segmentation(uh, &hdr->seg); ret = vdec_vp9_slice_setup_tile(vsi, hdr); if (ret) return ret; vdec_vp9_slice_setup_state(vsi); /* core stage needs buffer index to get ref y/c ... */ vdec_vp9_slice_setup_ref_idx(pfc, hdr); pfc->seq = instance->seq; instance->seq++; return 0; } static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi, struct mtk_vcodec_mem *bs, struct vdec_lat_buf *lat_buf) { int i; vsi->bs.buf.dma_addr = bs->dma_addr; vsi->bs.buf.size = bs->size; vsi->bs.frame.dma_addr = bs->dma_addr; vsi->bs.frame.size = bs->size; for (i = 0; i < 2; i++) { vsi->mv[i].dma_addr = instance->mv[i].dma_addr; vsi->mv[i].size = instance->mv[i].size; } for (i = 0; i < 2; i++) { vsi->seg[i].dma_addr = instance->seg[i].dma_addr; vsi->seg[i].size = instance->seg[i].size; } vsi->tile.dma_addr = instance->tile.dma_addr; vsi->tile.size = instance->tile.size; vsi->prob.dma_addr = instance->prob.dma_addr; vsi->prob.size = instance->prob.size; vsi->counts.dma_addr = instance->counts.dma_addr; vsi->counts.size = instance->counts.size; vsi->ube.dma_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; vsi->ube.size = lat_buf->ctx->msg_queue.wdma_addr.size; vsi->trans.dma_addr = lat_buf->ctx->msg_queue.wdma_wptr_addr; /* used to store trans end */ vsi->trans.dma_addr_end = lat_buf->ctx->msg_queue.wdma_rptr_addr; vsi->err_map.dma_addr = lat_buf->wdma_err_addr.dma_addr; vsi->err_map.size = lat_buf->wdma_err_addr.size; vsi->row_info.buf = 0; vsi->row_info.size = 0; return 0; } static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi) { struct vdec_vp9_slice_frame_ctx *frame_ctx; struct vdec_vp9_slice_uncompressed_header *uh; uh = &vsi->frame.uh; mtk_vdec_debug(instance->ctx, "ctx dirty %u idx %d\n", instance->dirty[uh->frame_context_idx], uh->frame_context_idx); if (instance->dirty[uh->frame_context_idx]) frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; else frame_ctx = vdec_vp9_slice_default_frame_ctx; memcpy(instance->prob.va, frame_ctx, sizeof(*frame_ctx)); return 0; } static void vdec_vp9_slice_setup_seg_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi, struct mtk_vcodec_mem *buf) { struct vdec_vp9_slice_uncompressed_header *uh; /* reset segment buffer */ uh = &vsi->frame.uh; if (uh->frame_type == 0 || uh->intra_only || uh->error_resilient_mode || uh->frame_width != instance->width || uh->frame_height != instance->height) { mtk_vdec_debug(instance->ctx, "reset seg\n"); memset(buf->va, 0, buf->size); } } /* * parse tiles according to `6.4 Decode tiles syntax` * in "vp9-bitstream-specification" * * frame contains uncompress header, compressed header and several tiles. * this function parses tiles' position and size, stores them to tile buffer * for decoding. */ static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi, struct mtk_vcodec_mem *bs) { struct vdec_vp9_slice_uncompressed_header *uh; unsigned int rows_log2; unsigned int cols_log2; unsigned int rows; unsigned int cols; unsigned int mi_row; unsigned int mi_col; unsigned int offset; dma_addr_t pa; unsigned int size; struct vdec_vp9_slice_tiles *tiles; unsigned char *pos; unsigned char *end; unsigned char *va; unsigned int *tb; int i; int j; uh = &vsi->frame.uh; rows_log2 = uh->tile_rows_log2; cols_log2 = uh->tile_cols_log2; rows = 1 << rows_log2; cols = 1 << cols_log2; if (rows > 4 || cols > 64) { mtk_vdec_err(instance->ctx, "tile_rows %u tile_cols %u\n", rows, cols); return -EINVAL; } offset = uh->uncompressed_header_size + uh->header_size_in_bytes; if (bs->size <= offset) { mtk_vdec_err(instance->ctx, "bs size %zu tile offset %u\n", bs->size, offset); return -EINVAL; } tiles = &vsi->frame.tiles; /* setup tile buffer */ va = (unsigned char *)bs->va; pos = va + offset; end = va + bs->size; /* truncated */ pa = bs->dma_addr + offset; tb = instance->tile.va; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { if (i == rows - 1 && j == cols - 1) { size = (unsigned int)(end - pos); } else { if (end - pos < 4) return -EINVAL; size = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3]; pos += 4; pa += 4; offset += 4; if (end - pos < size) return -EINVAL; } tiles->size[i][j] = size; if (tiles->mi_rows[i]) { *tb++ = (size << 3) + ((offset << 3) & 0x7f); *tb++ = pa & ~0xf; *tb++ = (pa << 3) & 0x7f; mi_row = (tiles->mi_rows[i] - 1) & 0x1ff; mi_col = (tiles->mi_cols[j] - 1) & 0x3f; *tb++ = (mi_row << 6) + mi_col; } pos += size; pa += size; offset += size; } } return 0; } static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, struct mtk_vcodec_mem *bs, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; int ret; ret = vdec_vp9_slice_setup_lat_from_src_buf(instance, lat_buf); if (ret) goto err; ret = vdec_vp9_slice_setup_pfc(instance, pfc); if (ret) goto err; ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); if (ret) goto err; ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); if (ret) goto err; vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); /* setup prob/tile buffers for LAT */ ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); if (ret) goto err; ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) goto err; return 0; err: return ret; } static void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k, struct vdec_vp9_slice_frame_counts *counts, struct v4l2_vp9_frame_symbol_counts *counts_helper) { u32 l = 0, m; /* * helper eo -> mtk eo * helpre e1 -> mtk c3 * helper c0 -> c0 * helper c1 -> c1 * helper c2 -> c2 */ for (m = 0; m < 3; m++) { counts_helper->coeff[i][j][k][l][m] = (u32 (*)[3]) & counts->coef_probs[i][j][k].band_0[m]; counts_helper->eob[i][j][k][l][m][0] = &counts->eob_branch[i][j][k].band_0[m]; counts_helper->eob[i][j][k][l][m][1] = &counts->coef_probs[i][j][k].band_0[m][3]; } for (l = 1; l < 6; l++) { for (m = 0; m < 6; m++) { counts_helper->coeff[i][j][k][l][m] = (u32 (*)[3]) & counts->coef_probs[i][j][k].band_1_5[l - 1][m]; counts_helper->eob[i][j][k][l][m][0] = &counts->eob_branch[i][j][k].band_1_5[l - 1][m]; counts_helper->eob[i][j][k][l][m][1] = &counts->coef_probs[i][j][k].band_1_5[l - 1][m][3]; } } } static void vdec_vp9_slice_counts_map_helper(struct vdec_vp9_slice_counts_map *counts_map, struct vdec_vp9_slice_frame_counts *counts, struct v4l2_vp9_frame_symbol_counts *counts_helper) { int i, j, k; counts_helper->partition = &counts->partition; counts_helper->intra_inter = &counts->intra_inter; counts_helper->tx32p = &counts->tx_p32x32; counts_helper->tx16p = &counts->tx_p16x16; counts_helper->tx8p = &counts->tx_p8x8; counts_helper->uv_mode = &counts->uv_mode; counts_helper->comp = &counts->comp_inter; counts_helper->comp_ref = &counts->comp_ref; counts_helper->single_ref = &counts->single_ref; counts_helper->mv_mode = &counts->inter_mode; counts_helper->mv_joint = &counts->joint; for (i = 0; i < ARRAY_SIZE(counts_map->skip); i++) memcpy(counts_map->skip[i], counts->skip[i], sizeof(counts_map->skip[0])); counts_helper->skip = &counts_map->skip; for (i = 0; i < ARRAY_SIZE(counts_map->y_mode); i++) memcpy(counts_map->y_mode[i], counts->y_mode[i], sizeof(counts_map->y_mode[0])); counts_helper->y_mode = &counts_map->y_mode; for (i = 0; i < ARRAY_SIZE(counts_map->filter); i++) memcpy(counts_map->filter[i], counts->switchable_interp[i], sizeof(counts_map->filter[0])); counts_helper->filter = &counts_map->filter; for (i = 0; i < ARRAY_SIZE(counts_map->sign); i++) memcpy(counts_map->sign[i], counts->mvcomp[i].sign, sizeof(counts_map->sign[0])); counts_helper->sign = &counts_map->sign; for (i = 0; i < ARRAY_SIZE(counts_map->classes); i++) memcpy(counts_map->classes[i], counts->mvcomp[i].classes, sizeof(counts_map->classes[0])); counts_helper->classes = &counts_map->classes; for (i = 0; i < ARRAY_SIZE(counts_map->class0); i++) memcpy(counts_map->class0[i], counts->mvcomp[i].class0, sizeof(counts_map->class0[0])); counts_helper->class0 = &counts_map->class0; for (i = 0; i < ARRAY_SIZE(counts_map->bits); i++) for (j = 0; j < ARRAY_SIZE(counts_map->bits[0]); j++) memcpy(counts_map->bits[i][j], counts->mvcomp[i].bits[j], sizeof(counts_map->bits[0][0])); counts_helper->bits = &counts_map->bits; for (i = 0; i < ARRAY_SIZE(counts_map->class0_fp); i++) for (j = 0; j < ARRAY_SIZE(counts_map->class0_fp[0]); j++) memcpy(counts_map->class0_fp[i][j], counts->mvcomp[i].class0_fp[j], sizeof(counts_map->class0_fp[0][0])); counts_helper->class0_fp = &counts_map->class0_fp; for (i = 0; i < ARRAY_SIZE(counts_map->fp); i++) memcpy(counts_map->fp[i], counts->mvcomp[i].fp, sizeof(counts_map->fp[0])); counts_helper->fp = &counts_map->fp; for (i = 0; i < ARRAY_SIZE(counts_map->class0_hp); i++) memcpy(counts_map->class0_hp[i], counts->mvcomp[i].class0_hp, sizeof(counts_map->class0_hp[0])); counts_helper->class0_hp = &counts_map->class0_hp; for (i = 0; i < ARRAY_SIZE(counts_map->hp); i++) memcpy(counts_map->hp[i], counts->mvcomp[i].hp, sizeof(counts_map->hp[0])); counts_helper->hp = &counts_map->hp; for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) vdec_vp9_slice_map_counts_eob_coef(i, j, k, counts, counts_helper); } static void vdec_vp9_slice_map_to_coef(unsigned int i, unsigned int j, unsigned int k, struct vdec_vp9_slice_frame_ctx *frame_ctx, struct v4l2_vp9_frame_context *frame_ctx_helper) { u32 l, m; for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { for (m = 0; m < VP9_BAND_6(l); m++) { memcpy(frame_ctx_helper->coef[i][j][k][l][m], frame_ctx->coef_probs[i][j][k][l].probs[m], sizeof(frame_ctx_helper->coef[i][j][k][l][0])); } } } static void vdec_vp9_slice_map_from_coef(unsigned int i, unsigned int j, unsigned int k, struct vdec_vp9_slice_frame_ctx *frame_ctx, struct v4l2_vp9_frame_context *frame_ctx_helper) { u32 l, m; for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { for (m = 0; m < VP9_BAND_6(l); m++) { memcpy(frame_ctx->coef_probs[i][j][k][l].probs[m], frame_ctx_helper->coef[i][j][k][l][m], sizeof(frame_ctx_helper->coef[i][j][k][l][0])); } } } static void vdec_vp9_slice_framectx_map_helper(bool frame_is_intra, struct vdec_vp9_slice_frame_ctx *pre_frame_ctx, struct vdec_vp9_slice_frame_ctx *frame_ctx, struct v4l2_vp9_frame_context *frame_ctx_helper) { struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; u32 i, j, k; for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) vdec_vp9_slice_map_to_coef(i, j, k, pre_frame_ctx, frame_ctx_helper); /* * use previous prob when frame is not intra or * we should use the prob updated by the compressed header parse */ if (!frame_is_intra) frame_ctx = pre_frame_ctx; for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) memcpy(frame_ctx_helper->tx8[i], frame_ctx->tx_p8x8[i], sizeof(frame_ctx_helper->tx8[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) memcpy(frame_ctx_helper->tx16[i], frame_ctx->tx_p16x16[i], sizeof(frame_ctx_helper->tx16[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) memcpy(frame_ctx_helper->tx32[i], frame_ctx->tx_p32x32[i], sizeof(frame_ctx_helper->tx32[0])); memcpy(frame_ctx_helper->skip, frame_ctx->skip_probs, sizeof(frame_ctx_helper->skip)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) memcpy(frame_ctx_helper->inter_mode[i], frame_ctx->inter_mode_probs[i], sizeof(frame_ctx_helper->inter_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) memcpy(frame_ctx_helper->interp_filter[i], frame_ctx->switch_interp_prob[i], sizeof(frame_ctx_helper->interp_filter[0])); memcpy(frame_ctx_helper->is_inter, frame_ctx->intra_inter_prob, sizeof(frame_ctx_helper->is_inter)); memcpy(frame_ctx_helper->comp_mode, frame_ctx->comp_inter_prob, sizeof(frame_ctx_helper->comp_mode)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) memcpy(frame_ctx_helper->single_ref[i], frame_ctx->single_ref_prob[i], sizeof(frame_ctx_helper->single_ref[0])); memcpy(frame_ctx_helper->comp_ref, frame_ctx->comp_ref_prob, sizeof(frame_ctx_helper->comp_ref)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) memcpy(frame_ctx_helper->y_mode[i], frame_ctx->y_mode_prob[i], sizeof(frame_ctx_helper->y_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) memcpy(frame_ctx_helper->uv_mode[i], frame_ctx->uv_mode_prob[i], sizeof(frame_ctx_helper->uv_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) memcpy(frame_ctx_helper->partition[i], frame_ctx->partition_prob[i], sizeof(frame_ctx_helper->partition[0])); memcpy(mv->joint, frame_ctx->joint, sizeof(mv->joint)); for (i = 0; i < ARRAY_SIZE(mv->sign); i++) mv->sign[i] = frame_ctx->sign_classes[i].sign; for (i = 0; i < ARRAY_SIZE(mv->classes); i++) memcpy(mv->classes[i], frame_ctx->sign_classes[i].classes, sizeof(mv->classes[i])); for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) mv->class0_bit[i] = frame_ctx->class0_bits[i].class0[0]; for (i = 0; i < ARRAY_SIZE(mv->bits); i++) memcpy(mv->bits[i], frame_ctx->class0_bits[i].bits, sizeof(mv->bits[0])); for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) memcpy(mv->class0_fr[i][j], frame_ctx->class0_fp_hp[i].class0_fp[j], sizeof(mv->class0_fr[0][0])); for (i = 0; i < ARRAY_SIZE(mv->fr); i++) memcpy(mv->fr[i], frame_ctx->class0_fp_hp[i].fp, sizeof(mv->fr[0])); for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) mv->class0_hp[i] = frame_ctx->class0_fp_hp[i].class0_hp; for (i = 0; i < ARRAY_SIZE(mv->hp); i++) mv->hp[i] = frame_ctx->class0_fp_hp[i].hp; } static void vdec_vp9_slice_helper_map_framectx(struct v4l2_vp9_frame_context *frame_ctx_helper, struct vdec_vp9_slice_frame_ctx *frame_ctx) { struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; u32 i, j, k; for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) memcpy(frame_ctx->tx_p8x8[i], frame_ctx_helper->tx8[i], sizeof(frame_ctx_helper->tx8[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) memcpy(frame_ctx->tx_p16x16[i], frame_ctx_helper->tx16[i], sizeof(frame_ctx_helper->tx16[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) memcpy(frame_ctx->tx_p32x32[i], frame_ctx_helper->tx32[i], sizeof(frame_ctx_helper->tx32[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) vdec_vp9_slice_map_from_coef(i, j, k, frame_ctx, frame_ctx_helper); memcpy(frame_ctx->skip_probs, frame_ctx_helper->skip, sizeof(frame_ctx_helper->skip)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) memcpy(frame_ctx->inter_mode_probs[i], frame_ctx_helper->inter_mode[i], sizeof(frame_ctx_helper->inter_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) memcpy(frame_ctx->switch_interp_prob[i], frame_ctx_helper->interp_filter[i], sizeof(frame_ctx_helper->interp_filter[0])); memcpy(frame_ctx->intra_inter_prob, frame_ctx_helper->is_inter, sizeof(frame_ctx_helper->is_inter)); memcpy(frame_ctx->comp_inter_prob, frame_ctx_helper->comp_mode, sizeof(frame_ctx_helper->comp_mode)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) memcpy(frame_ctx->single_ref_prob[i], frame_ctx_helper->single_ref[i], sizeof(frame_ctx_helper->single_ref[0])); memcpy(frame_ctx->comp_ref_prob, frame_ctx_helper->comp_ref, sizeof(frame_ctx_helper->comp_ref)); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) memcpy(frame_ctx->y_mode_prob[i], frame_ctx_helper->y_mode[i], sizeof(frame_ctx_helper->y_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) memcpy(frame_ctx->uv_mode_prob[i], frame_ctx_helper->uv_mode[i], sizeof(frame_ctx_helper->uv_mode[0])); for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) memcpy(frame_ctx->partition_prob[i], frame_ctx_helper->partition[i], sizeof(frame_ctx_helper->partition[0])); memcpy(frame_ctx->joint, mv->joint, sizeof(mv->joint)); for (i = 0; i < ARRAY_SIZE(mv->sign); i++) frame_ctx->sign_classes[i].sign = mv->sign[i]; for (i = 0; i < ARRAY_SIZE(mv->classes); i++) memcpy(frame_ctx->sign_classes[i].classes, mv->classes[i], sizeof(mv->classes[i])); for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) frame_ctx->class0_bits[i].class0[0] = mv->class0_bit[i]; for (i = 0; i < ARRAY_SIZE(mv->bits); i++) memcpy(frame_ctx->class0_bits[i].bits, mv->bits[i], sizeof(mv->bits[0])); for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) memcpy(frame_ctx->class0_fp_hp[i].class0_fp[j], mv->class0_fr[i][j], sizeof(mv->class0_fr[0][0])); for (i = 0; i < ARRAY_SIZE(mv->fr); i++) memcpy(frame_ctx->class0_fp_hp[i].fp, mv->fr[i], sizeof(mv->fr[0])); for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) frame_ctx->class0_fp_hp[i].class0_hp = mv->class0_hp[i]; for (i = 0; i < ARRAY_SIZE(mv->hp); i++) frame_ctx->class0_fp_hp[i].hp = mv->hp[i]; } static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_vsi *vsi) { struct vdec_vp9_slice_frame_ctx *pre_frame_ctx; struct v4l2_vp9_frame_context *pre_frame_ctx_helper; struct vdec_vp9_slice_frame_ctx *frame_ctx; struct vdec_vp9_slice_frame_counts *counts; struct v4l2_vp9_frame_symbol_counts *counts_helper; struct vdec_vp9_slice_uncompressed_header *uh; bool frame_is_intra; bool use_128; uh = &vsi->frame.uh; pre_frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; pre_frame_ctx_helper = &instance->frame_ctx_helper; frame_ctx = (struct vdec_vp9_slice_frame_ctx *)instance->prob.va; counts = (struct vdec_vp9_slice_frame_counts *)instance->counts.va; counts_helper = &instance->counts_helper; if (!uh->refresh_frame_context) return 0; if (!uh->frame_parallel_decoding_mode) { vdec_vp9_slice_counts_map_helper(&instance->counts_map, counts, counts_helper); frame_is_intra = !vsi->frame.uh.frame_type || vsi->frame.uh.intra_only; /* check default prob */ if (!instance->dirty[uh->frame_context_idx]) vdec_vp9_slice_framectx_map_helper(frame_is_intra, vdec_vp9_slice_default_frame_ctx, frame_ctx, pre_frame_ctx_helper); else vdec_vp9_slice_framectx_map_helper(frame_is_intra, pre_frame_ctx, frame_ctx, pre_frame_ctx_helper); use_128 = !frame_is_intra && !vsi->frame.uh.last_frame_type; v4l2_vp9_adapt_coef_probs(pre_frame_ctx_helper, counts_helper, use_128, frame_is_intra); if (!frame_is_intra) v4l2_vp9_adapt_noncoef_probs(pre_frame_ctx_helper, counts_helper, V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, vsi->frame.uh.interpolation_filter, vsi->frame.ch.tx_mode, vsi->frame.uh.allow_high_precision_mv ? V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV : 0); vdec_vp9_slice_helper_map_framectx(pre_frame_ctx_helper, pre_frame_ctx); } else { memcpy(pre_frame_ctx, frame_ctx, sizeof(*frame_ctx)); } instance->dirty[uh->frame_context_idx] = 1; return 0; } static int vdec_vp9_slice_update_single(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi; vsi = &pfc->vsi; memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); mtk_vdec_debug(instance->ctx, "Frame %u Y_CRC %08x %08x %08x %08x\n", pfc->seq, vsi->state.crc[0], vsi->state.crc[1], vsi->state.crc[2], vsi->state.crc[3]); mtk_vdec_debug(instance->ctx, "Frame %u C_CRC %08x %08x %08x %08x\n", pfc->seq, vsi->state.crc[4], vsi->state.crc[5], vsi->state.crc[6], vsi->state.crc[7]); vdec_vp9_slice_update_prob(instance, vsi); instance->width = vsi->frame.uh.frame_width; instance->height = vsi->frame.uh.frame_height; instance->frame_type = vsi->frame.uh.frame_type; instance->show_frame = vsi->frame.uh.show_frame; return 0; } static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi; vsi = &pfc->vsi; memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); mtk_vdec_debug(instance->ctx, "Frame %u LAT CRC 0x%08x %lx %lx\n", pfc->seq, vsi->state.crc[0], (unsigned long)vsi->trans.dma_addr, (unsigned long)vsi->trans.dma_addr_end); /* buffer full, need to re-decode */ if (vsi->state.full) { /* buffer not enough */ if (vsi->trans.dma_addr_end - vsi->trans.dma_addr == vsi->ube.size) return -ENOMEM; return -EAGAIN; } vdec_vp9_slice_update_prob(instance, vsi); instance->width = vsi->frame.uh.frame_width; instance->height = vsi->frame.uh.frame_height; instance->frame_type = vsi->frame.uh.frame_type; instance->show_frame = vsi->frame.uh.show_frame; return 0; } static int vdec_vp9_slice_setup_core_to_dst_buf(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf) { struct vb2_v4l2_buffer *dst; dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); if (!dst) return -EINVAL; v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst, true); return 0; } static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_pfc *pfc, struct vdec_vp9_slice_vsi *vsi, struct vdec_fb *fb, struct vdec_lat_buf *lat_buf) { struct vb2_buffer *vb; struct vb2_queue *vq; struct vdec_vp9_slice_reference *ref; int plane; int size; int w; int h; int i; plane = instance->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; w = vsi->frame.uh.frame_width; h = vsi->frame.uh.frame_height; size = ALIGN(w, 64) * ALIGN(h, 64); /* frame buffer */ vsi->fb.y.dma_addr = fb->base_y.dma_addr; if (plane == 1) vsi->fb.c.dma_addr = fb->base_y.dma_addr + size; else vsi->fb.c.dma_addr = fb->base_c.dma_addr; /* reference buffers */ vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (!vq) return -EINVAL; /* get current output buffer */ vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; if (!vb) return -EINVAL; /* update internal buffer's width/height */ instance->dpb[vb->index].width = w; instance->dpb[vb->index].height = h; /* * get buffer's width/height from instance * get buffer address from vb2buf */ for (i = 0; i < 3; i++) { ref = &vsi->frame.ref[i]; vb = vb2_find_buffer(vq, pfc->ref_idx[i]); if (!vb) { ref->frame_width = w; ref->frame_height = h; memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); } else { int idx = vb->index; ref->frame_width = instance->dpb[idx].width; ref->frame_height = instance->dpb[idx].height; vsi->ref[i].y.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (plane == 1) vsi->ref[i].c.dma_addr = vsi->ref[i].y.dma_addr + size; else vsi->ref[i].c.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 1); } } return 0; } static void vdec_vp9_slice_setup_single_buffer(struct vdec_vp9_slice_instance *instance, struct vdec_vp9_slice_pfc *pfc, struct vdec_vp9_slice_vsi *vsi, struct mtk_vcodec_mem *bs, struct vdec_fb *fb) { int i; vsi->bs.buf.dma_addr = bs->dma_addr; vsi->bs.buf.size = bs->size; vsi->bs.frame.dma_addr = bs->dma_addr; vsi->bs.frame.size = bs->size; for (i = 0; i < 2; i++) { vsi->mv[i].dma_addr = instance->mv[i].dma_addr; vsi->mv[i].size = instance->mv[i].size; } for (i = 0; i < 2; i++) { vsi->seg[i].dma_addr = instance->seg[i].dma_addr; vsi->seg[i].size = instance->seg[i].size; } vsi->tile.dma_addr = instance->tile.dma_addr; vsi->tile.size = instance->tile.size; vsi->prob.dma_addr = instance->prob.dma_addr; vsi->prob.size = instance->prob.size; vsi->counts.dma_addr = instance->counts.dma_addr; vsi->counts.size = instance->counts.size; vsi->row_info.buf = 0; vsi->row_info.size = 0; vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, NULL); } static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance, struct vdec_fb *fb, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; int ret; vdec_vp9_slice_setup_state(vsi); ret = vdec_vp9_slice_setup_core_to_dst_buf(instance, lat_buf); if (ret) goto err; ret = vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, lat_buf); if (ret) goto err; vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[1]); return 0; err: return ret; } static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; int ret; ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance); if (ret) goto err; ret = vdec_vp9_slice_setup_pfc(instance, pfc); if (ret) goto err; ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); if (ret) goto err; vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb); vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); if (ret) goto err; ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) goto err; return 0; err: return ret; } static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) { struct vdec_vp9_slice_vsi *vsi; vsi = &pfc->vsi; memcpy(&pfc->state[1], &vsi->state, sizeof(vsi->state)); mtk_vdec_debug(instance->ctx, "Frame %u Y_CRC %08x %08x %08x %08x\n", pfc->seq, vsi->state.crc[0], vsi->state.crc[1], vsi->state.crc[2], vsi->state.crc[3]); mtk_vdec_debug(instance->ctx, "Frame %u C_CRC %08x %08x %08x %08x\n", pfc->seq, vsi->state.crc[4], vsi->state.crc[5], vsi->state.crc[6], vsi->state.crc[7]); return 0; } static int vdec_vp9_slice_init(struct mtk_vcodec_dec_ctx *ctx) { struct vdec_vp9_slice_instance *instance; struct vdec_vp9_slice_init_vsi *vsi; int ret; instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) return -ENOMEM; instance->ctx = ctx; instance->vpu.id = SCP_IPI_VDEC_LAT; instance->vpu.core_id = SCP_IPI_VDEC_CORE; instance->vpu.ctx = ctx; instance->vpu.codec_type = ctx->current_codec; ret = vpu_dec_init(&instance->vpu); if (ret) { mtk_vdec_err(ctx, "failed to init vpu dec, ret %d\n", ret); goto error_vpu_init; } /* init vsi and global flags */ vsi = instance->vpu.vsi; if (!vsi) { mtk_vdec_err(ctx, "failed to get VP9 vsi\n"); ret = -EINVAL; goto error_vsi; } instance->init_vsi = vsi; instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, (u32)vsi->core_vsi); if (!instance->core_vsi) { mtk_vdec_err(ctx, "failed to get VP9 core vsi\n"); ret = -EINVAL; goto error_vsi; } instance->irq = 1; ret = vdec_vp9_slice_init_default_frame_ctx(instance); if (ret) goto error_default_frame_ctx; ctx->drv_handle = instance; return 0; error_default_frame_ctx: error_vsi: vpu_dec_deinit(&instance->vpu); error_vpu_init: kfree(instance); return ret; } static void vdec_vp9_slice_deinit(void *h_vdec) { struct vdec_vp9_slice_instance *instance = h_vdec; if (!instance) return; vpu_dec_deinit(&instance->vpu); vdec_vp9_slice_free_working_buffer(instance); vdec_msg_queue_deinit(&instance->ctx->msg_queue, instance->ctx); kfree(instance); } static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp9_slice_instance *instance = h_vdec; mtk_vdec_debug(instance->ctx, "flush ...\n"); if (instance->ctx->dev->vdec_pdata->hw_arch != MTK_VDEC_PURE_SINGLE_CORE) vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); return vpu_dec_reset(&instance->vpu); } static void vdec_vp9_slice_get_pic_info(struct vdec_vp9_slice_instance *instance) { struct mtk_vcodec_dec_ctx *ctx = instance->ctx; unsigned int data[3]; mtk_vdec_debug(instance->ctx, "w %u h %u\n", ctx->picinfo.pic_w, ctx->picinfo.pic_h); data[0] = ctx->picinfo.pic_w; data[1] = ctx->picinfo.pic_h; data[2] = ctx->capture_fourcc; vpu_dec_get_param(&instance->vpu, data, 3, GET_PARAM_PIC_INFO); ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); ctx->picinfo.fb_sz[0] = instance->vpu.fb_sz[0]; ctx->picinfo.fb_sz[1] = instance->vpu.fb_sz[1]; } static void vdec_vp9_slice_get_dpb_size(struct vdec_vp9_slice_instance *instance, unsigned int *dpb_sz) { /* refer VP9 specification */ *dpb_sz = 9; } static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) { struct vdec_vp9_slice_instance *instance = h_vdec; switch (type) { case GET_PARAM_PIC_INFO: vdec_vp9_slice_get_pic_info(instance); break; case GET_PARAM_DPB_SIZE: vdec_vp9_slice_get_dpb_size(instance, out); break; case GET_PARAM_CROP_INFO: mtk_vdec_debug(instance->ctx, "No need to get vp9 crop information."); break; default: mtk_vdec_err(instance->ctx, "invalid get parameter type=%d\n", type); return -EINVAL; } return 0; } static int vdec_vp9_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp9_slice_instance *instance = h_vdec; struct vdec_vp9_slice_pfc *pfc = &instance->sc_pfc; struct vdec_vp9_slice_vsi *vsi; struct mtk_vcodec_dec_ctx *ctx; int ret; if (!instance || !instance->ctx) return -EINVAL; ctx = instance->ctx; /* bs NULL means flush decoder */ if (!bs) return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); if (!fb) return -EBUSY; vsi = &pfc->vsi; ret = vdec_vp9_slice_setup_single(instance, bs, fb, pfc); if (ret) { mtk_vdec_err(ctx, "Failed to setup VP9 single ret %d\n", ret); return ret; } vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); ret = vpu_dec_start(&instance->vpu, NULL, 0); if (ret) { mtk_vdec_err(ctx, "Failed to dec VP9 ret %d\n", ret); return ret; } ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); /* update remote vsi if decode timeout */ if (ret) { mtk_vdec_err(ctx, "VP9 decode timeout %d\n", ret); WRITE_ONCE(instance->vsi->state.timeout, 1); } vpu_dec_end(&instance->vpu); vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); ret = vdec_vp9_slice_update_single(instance, pfc); if (ret) { mtk_vdec_err(ctx, "VP9 decode error: %d\n", ret); return ret; } instance->ctx->decoded_frame_cnt++; return 0; } static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp9_slice_instance *instance = h_vdec; struct vdec_lat_buf *lat_buf; struct vdec_vp9_slice_pfc *pfc; struct vdec_vp9_slice_vsi *vsi; struct mtk_vcodec_dec_ctx *ctx; int ret; if (!instance || !instance->ctx) return -EINVAL; ctx = instance->ctx; /* init msgQ for the first time */ if (vdec_msg_queue_init(&ctx->msg_queue, ctx, vdec_vp9_slice_core_decode, sizeof(*pfc))) return -ENOMEM; /* bs NULL means flush decoder */ if (!bs) return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); lat_buf = vdec_msg_queue_dqbuf(&instance->ctx->msg_queue.lat_ctx); if (!lat_buf) { mtk_vdec_debug(ctx, "Failed to get VP9 lat buf\n"); return -EAGAIN; } pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; if (!pfc) { ret = -EINVAL; goto err_free_fb_out; } vsi = &pfc->vsi; ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); if (ret) { mtk_vdec_err(ctx, "Failed to setup VP9 lat ret %d\n", ret); goto err_free_fb_out; } vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); ret = vpu_dec_start(&instance->vpu, NULL, 0); if (ret) { mtk_vdec_err(ctx, "Failed to dec VP9 ret %d\n", ret); goto err_free_fb_out; } if (instance->irq) { ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); /* update remote vsi if decode timeout */ if (ret) { mtk_vdec_err(ctx, "VP9 decode timeout %d pic %d\n", ret, pfc->seq); WRITE_ONCE(instance->vsi->state.timeout, 1); } vpu_dec_end(&instance->vpu); } vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); ret = vdec_vp9_slice_update_lat(instance, lat_buf, pfc); /* LAT trans full, no more UBE or decode timeout */ if (ret) { mtk_vdec_err(ctx, "VP9 decode error: %d\n", ret); goto err_free_fb_out; } mtk_vdec_debug(ctx, "lat dma addr: 0x%lx 0x%lx\n", (unsigned long)pfc->vsi.trans.dma_addr, (unsigned long)pfc->vsi.trans.dma_addr_end); vdec_msg_queue_update_ube_wptr(&ctx->msg_queue, vsi->trans.dma_addr_end + ctx->msg_queue.wdma_addr.dma_addr); vdec_msg_queue_qbuf(&ctx->msg_queue.core_ctx, lat_buf); return 0; err_free_fb_out: vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf); return ret; } static int vdec_vp9_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp9_slice_instance *instance = h_vdec; int ret; if (instance->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE) ret = vdec_vp9_slice_single_decode(h_vdec, bs, fb, res_chg); else ret = vdec_vp9_slice_lat_decode(h_vdec, bs, fb, res_chg); return ret; } static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf) { struct vdec_vp9_slice_instance *instance; struct vdec_vp9_slice_pfc *pfc; struct mtk_vcodec_dec_ctx *ctx = NULL; struct vdec_fb *fb = NULL; int ret = -EINVAL; if (!lat_buf) goto err; pfc = lat_buf->private_data; ctx = lat_buf->ctx; if (!pfc || !ctx) goto err; instance = ctx->drv_handle; if (!instance) goto err; fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); if (!fb) { ret = -EBUSY; goto err; } ret = vdec_vp9_slice_setup_core(instance, fb, lat_buf, pfc); if (ret) { mtk_vdec_err(ctx, "vdec_vp9_slice_setup_core\n"); goto err; } vdec_vp9_slice_vsi_to_remote(&pfc->vsi, instance->core_vsi); ret = vpu_dec_core(&instance->vpu); if (ret) { mtk_vdec_err(ctx, "vpu_dec_core\n"); goto err; } if (instance->irq) { ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); /* update remote vsi if decode timeout */ if (ret) { mtk_vdec_err(ctx, "VP9 core timeout pic %d\n", pfc->seq); WRITE_ONCE(instance->core_vsi->state.timeout, 1); } vpu_dec_core_end(&instance->vpu); } vdec_vp9_slice_vsi_from_remote(&pfc->vsi, instance->core_vsi, 1); ret = vdec_vp9_slice_update_core(instance, lat_buf, pfc); if (ret) { mtk_vdec_err(ctx, "vdec_vp9_slice_update_core\n"); goto err; } pfc->vsi.trans.dma_addr_end += ctx->msg_queue.wdma_addr.dma_addr; mtk_vdec_debug(ctx, "core dma_addr_end 0x%lx\n", (unsigned long)pfc->vsi.trans.dma_addr_end); vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); ctx->dev->vdec_pdata->cap_to_disp(ctx, 0, lat_buf->src_buf_req); return 0; err: if (ctx && pfc) { /* always update read pointer */ vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); if (fb) ctx->dev->vdec_pdata->cap_to_disp(ctx, 1, lat_buf->src_buf_req); } return ret; } const struct vdec_common_if vdec_vp9_slice_lat_if = { .init = vdec_vp9_slice_init, .decode = vdec_vp9_slice_decode, .get_param = vdec_vp9_slice_get_param, .deinit = vdec_vp9_slice_deinit, };