Message ID | 20220331024801.29229-17-yunfei.dong@mediatek.com |
---|---|
State | Superseded |
Headers | show |
Series | media: mtk-vcodec: support for M8192 decoder | expand |
Hi Nicolas, Thanks for you comments. Very sorry I forgot to update the build error in upstream patch when fix in chrome os. Will remove reviewed-by tag in next patch v9. Best Regards, Yunfei Dong On Thu, 2022-04-07 at 12:58 -0400, Nicolas Dufresne wrote: > Le jeudi 31 mars 2022 à 10:48 +0800, Yunfei Dong a écrit : > > Add support for VP9 decoding using the stateless API, > > as supported by MT8192. And the drivers is lat and core > > architecture. > > > > Signed-off-by: George Sun <george.sun@mediatek.com> > > Signed-off-by: Xiaoyong Lu <xiaoyong.lu@mediatek.com> > > Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com> > > Reviewed-by: AngeloGioacchino Del Regno < > > angelogioacchino.delregno@collabora.com> > > --- > > changed compare with v7: > > Using upstream interface to update vp9 prob tables. > > --- > > .../media/platform/mediatek/vcodec/Makefile | 1 + > > .../vcodec/mtk_vcodec_dec_stateless.c | 26 +- > > .../platform/mediatek/vcodec/mtk_vcodec_drv.h | 1 + > > .../vcodec/vdec/vdec_vp9_req_lat_if.c | 2072 > > +++++++++++++++++ > > .../platform/mediatek/vcodec/vdec_drv_if.c | 4 + > > .../platform/mediatek/vcodec/vdec_drv_if.h | 1 + > > 6 files changed, 2102 insertions(+), 3 deletions(-) > > create mode 100644 > > drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c > > > > diff --git a/drivers/media/platform/mediatek/vcodec/Makefile > > b/drivers/media/platform/mediatek/vcodec/Makefile > > index b457daf2d196..93e7a343b5b0 100644 > > --- a/drivers/media/platform/mediatek/vcodec/Makefile > > +++ b/drivers/media/platform/mediatek/vcodec/Makefile > > @@ -9,6 +9,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ > > vdec/vdec_vp8_if.o \ > > vdec/vdec_vp8_req_if.o \ > > vdec/vdec_vp9_if.o \ > > + vdec/vdec_vp9_req_lat_if.o \ > > vdec/vdec_h264_req_if.o \ > > vdec/vdec_h264_req_common.o \ > > vdec/vdec_h264_req_multi_if.o \ > > diff --git > > a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c > > b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c > > index 3208f834ff80..a4735e67d39e 100644 > > --- > > a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c > > +++ > > b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c > > @@ -91,13 +91,28 @@ static const struct mtk_stateless_control > > mtk_stateless_controls[] = { > > .max = V4L2_MPEG_VIDEO_VP8_PROFILE_3, > > }, > > .codec_type = V4L2_PIX_FMT_VP8_FRAME, > > - } > > + }, > > + { > > + .cfg = { > > + .id = V4L2_CID_STATELESS_VP9_FRAME, > > + }, > > + .codec_type = V4L2_PIX_FMT_VP9_FRAME, > > + }, > > + { > > + .cfg = { > > + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, > > + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, > > + .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, > > + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, > > + }, > > + .codec_type = V4L2_PIX_FMT_VP9_FRAME, > > + }, > > }; > > > > #define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) > > > > -static struct mtk_video_fmt mtk_video_formats[4]; > > -static struct mtk_codec_framesizes mtk_vdec_framesizes[2]; > > +static struct mtk_video_fmt mtk_video_formats[5]; > > +static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; > > > > static struct mtk_video_fmt default_out_format; > > static struct mtk_video_fmt default_cap_format; > > @@ -338,6 +353,7 @@ static void mtk_vcodec_add_formats(unsigned int > > fourcc, > > switch (fourcc) { > > case V4L2_PIX_FMT_H264_SLICE: > > case V4L2_PIX_FMT_VP8_FRAME: > > + case V4L2_PIX_FMT_VP9_FRAME: > > mtk_video_formats[count_formats].fourcc = fourcc; > > mtk_video_formats[count_formats].type = MTK_FMT_DEC; > > mtk_video_formats[count_formats].num_planes = 1; > > @@ -385,6 +401,10 @@ static void > > mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) > > mtk_vcodec_add_formats(V4L2_PIX_FMT_VP8_FRAME, ctx); > > out_format_count++; > > } > > + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP9_FRAME) { > > + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP9_FRAME, ctx); > > + out_format_count++; > > + } > > > > if (cap_format_count) > > default_cap_format = mtk_video_formats[cap_format_count > > - 1]; > > diff --git > > a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h > > b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h > > index 2ba1c19f07b6..a29041a0b7e0 100644 > > --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h > > +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h > > @@ -355,6 +355,7 @@ enum mtk_vdec_format_types { > > MTK_VDEC_FORMAT_MT21C = 0x40, > > MTK_VDEC_FORMAT_H264_SLICE = 0x100, > > MTK_VDEC_FORMAT_VP8_FRAME = 0x200, > > + MTK_VDEC_FORMAT_VP9_FRAME = 0x400, > > }; > > > > /** > > diff --git > > a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c > > b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c > > new file mode 100644 > > index 000000000000..d63399085b9b > > --- /dev/null > > +++ > > b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c > > @@ -0,0 +1,2072 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2021 MediaTek Inc. > > + * Author: George Sun <george.sun@mediatek.com> > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/slab.h> > > +#include <media/videobuf2-dma-contig.h> > > +#include <media/v4l2-vp9.h> > > + > > +#include "../mtk_vcodec_util.h" > > +#include "../mtk_vcodec_dec.h" > > +#include "../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. > > + * @mv_joint: motion vector joint 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 > > + * @counts_map: used map to counts_helper > > + * &counts_helper: counts table according to newest kernel spec > > Change & into @ to fix: > > drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c:492 > : warning: Function parameter or member 'counts_helper' not described > in 'vdec_vp9_slice_instance' > > > + */ > > +struct vdec_vp9_slice_instance { > > + struct mtk_vcodec_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_counts_map counts_map; > > + struct v4l2_vp9_frame_symbol_counts counts_helper; > > +}; > > From here .... > > > + > > +/* > > + * (2, (0, (1, 3))) > > + * max level = 2 > > + */ > > +static const signed char vdec_vp9_slice_inter_mode_tree[6] = { > > + -2, 2, 0, 4, -1, -3 > > +}; > > + > > +/* max level = 6 */ > > +static const signed char vdec_vp9_slice_intra_mode_tree[18] = { > > + 0, 2, -9, 4, -1, 6, 8, 12, -2, 10, -4, -5, -3, 14, -8, 16, -6, > > -7 > > +}; > > + > > +/* max level = 2 */ > > +static const signed char vdec_vp9_slice_partition_tree[6] = { > > + 0, 2, -1, 4, -2, -3 > > +}; > > + > > +/* max level = 1 */ > > +static const signed char vdec_vp9_slice_switchable_interp_tree[4] > > = { > > + 0, 2, -1, -2 > > +}; > > + > > +/* max level = 2 */ > > +static const signed char vdec_vp9_slice_mv_joint_tree[6] = { > > + 0, 2, -1, 4, -2, -3 > > +}; > > + > > +/* max level = 6 */ > > +static const signed char vdec_vp9_slice_mv_class_tree[20] = { > > + 0, 2, -1, 4, 6, 8, -2, -3, 10, 12, > > + -4, -5, -6, 14, 16, 18, -7, -8, -9, -10 > > +}; > > + > > +/* max level = 0 */ > > +static const signed char vdec_vp9_slice_mv_class0_tree[2] = { > > + 0, -1 > > +}; > > + > > +/* max level = 2 */ > > +static const signed char vdec_vp9_slice_mv_fp_tree[6] = { > > + 0, 2, -1, 4, -2, -3 > > +}; > > All these are unused. > > > + > > +/* > > + * 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_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_vcodec_err(instance, "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 = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); > > + if (!frame_ctx) { > > + ret = -ENOMEM; > > + goto out; > > + } > > + > > + memcpy_fromio(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); > > + 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_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_vcodec_debug(instance, "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_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_fromio(&f->ch, &rf->ch, sizeof(f->ch)); > > + memcpy_fromio(&f->uh.dequant, &rf->uh.dequant, > > sizeof(f->uh.dequant)); > > + memcpy_fromio(&vsi->trans, &remote_vsi->trans, > > sizeof(vsi->trans)); > > + } > > + > > + memcpy_fromio(&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_toio(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 offset < mi_num ? offset : mi_num; > > +} > > + > > +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_vcodec_debug(instance, "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_vcodec_debug(instance, "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; > > + unsigned int 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_vcodec_err(instance, "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_vcodec_err(instance, "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 = (unsigned int)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, m; > > + > > + /* > > + * helper eo -> mtk eo > > + * helpre e1 -> mtk c3 > > + * helper c0 -> c0 > > + * helper c1 -> c1 > > + * helper c2 -> c2 > > + */ > > + for (l = 0; l < 6; l++) { > > + for (m = 0; m < VP9_BAND_6(l); m++) { > > + if (l == 0) { > > + counts_helper->coeff[i][j][k][l][m] = > > + &counts- > > >coef_probs[i][j][k].band_0[m]; > > The missing a cast from (u32 (*)[4]) -> (u32 (*)[3]), the cast is > safe otherwise > as long as the forth item is just HW padding. If its used by the HW > for special > purpose, consider initializing it. > > > + 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]; > > + } else { > > + counts_helper->coeff[i][j][k][l][m] = > > + &counts- > > >coef_probs[i][j][k].band_1_5[l - 1][m]; > > Same here. > > > + 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, l, m; > > l and m are unused. > > > + > > + 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_he > > lper); > > + > > + /* > > + * 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_int > > ra, > > + vdec_vp9_sli > > ce_default_frame_ctx, > > + frame_ctx, > > + pre_frame_ct > > x_helper); > > + else > > + vdec_vp9_slice_framectx_map_helper(frame_is_int > > ra, > > + pre_frame_ct > > x, > > + frame_ctx, > > + pre_frame_ct > > x_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_help > > er, > > + 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_FLA > > G_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_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_vcodec_debug(instance, "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 idx; > > + 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 */ > > + for (i = 0; i < vq->num_buffers; i++) { > > + if (vb == vq->bufs[i]) { > > + instance->dpb[i].width = w; > > + instance->dpb[i].height = h; > > + break; > > + } > > + } > > + > > + /* > > + * get buffer's width/height from instance > > + * get buffer address from vb2buf > > + */ > > + for (i = 0; i < 3; i++) { > > + ref = &vsi->frame.ref[i]; > > + idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); > > + if (idx < 0) { > > + ref->frame_width = w; > > + ref->frame_height = h; > > + memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); > > + } else { > > + ref->frame_width = instance->dpb[idx].width; > > + ref->frame_height = instance->dpb[idx].height; > > + vb = vq->bufs[idx]; > > + 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(v > > b, 1); > > + } > > + } > > + > > + return 0; > > +} > > + > > +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_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_vcodec_debug(instance, "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_vcodec_debug(instance, "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_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_vcodec_err(instance, "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_vcodec_err(instance, "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_vcodec_err(instance, "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_vcodec_debug(instance, "flush ...\n"); > > + > > + 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_ctx *ctx = instance->ctx; > > + unsigned int data[3]; > > + > > + mtk_vcodec_debug(instance, "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_vcodec_debug(instance, "No need to get vp9 crop > > information."); > > + break; > > + default: > > + mtk_vcodec_err(instance, "invalid get parameter > > type=%d\n", > > + type); > > + return -EINVAL; > > + } > > + > > + 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_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_vcodec_err(instance, "Failed to get VP9 lat > > buf\n"); > > + return -EBUSY; > > + } > > + pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; > > + if (!pfc) > > + return -EINVAL; > > + vsi = &pfc->vsi; > > + > > + ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); > > + if (ret) { > > + mtk_vcodec_err(instance, "Failed to setup VP9 lat ret > > %d\n", ret); > > + return ret; > > + } > > + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); > > + > > + ret = vpu_dec_start(&instance->vpu, 0, 0); > > + if (ret) { > > + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", > > ret); > > + return ret; > > + } > > + > > + if (instance->irq) { > > + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IR > > Q_RECEIVED, > > + WAIT_INTR_TIMEOUT_MS > > , MTK_VDEC_LAT0); > > + /* update remote vsi if decode timeout */ > > + if (ret) { > > + mtk_vcodec_err(instance, "VP9 decode timeout %d > > pic %d\n", ret, pfc->seq); > > + writel(1, &instance->vsi->state.timeout); > > + } > > + 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_vcodec_err(instance, "VP9 decode error: %d\n", > > ret); > > + return ret; > > + } > > + > > + mtk_vcodec_debug(instance, "lat dma 1 0x%llx 0x%llx\n", > > + pfc->vsi.trans.dma_addr, 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->dev->msg_queue_core_ctx, lat_buf); > > + > > + return 0; > > +} > > + > > +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_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_vcodec_err(instance, > > "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_vcodec_err(instance, "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_vcodec_err(instance, "VP9 core timeout pic > > %d\n", pfc->seq); > > + writel(1, &instance->core_vsi->state.timeout); > > + } > > + 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_vcodec_err(instance, > > "vdec_vp9_slice_update_core\n"); > > + goto err; > > + } > > + > > + pfc->vsi.trans.dma_addr_end += ctx- > > >msg_queue.wdma_addr.dma_addr; > > + mtk_vcodec_debug(instance, "core dma_addr_end 0x%llx\n", 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) { > > + /* 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_lat_decode, > > + .get_param = vdec_vp9_slice_get_param, > > + .deinit = vdec_vp9_slice_deinit, > > +}; > > diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c > > b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c > > index b709c7bae197..27b4b35039cf 100644 > > --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c > > +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c > > @@ -45,6 +45,10 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, > > unsigned int fourcc) > > ctx->dec_if = &vdec_vp9_if; > > ctx->hw_id = MTK_VDEC_CORE; > > break; > > + case V4L2_PIX_FMT_VP9_FRAME: > > + ctx->dec_if = &vdec_vp9_slice_lat_if; > > + ctx->hw_id = MTK_VDEC_LAT0; > > + break; > > default: > > return -EINVAL; > > } > > diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h > > b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h > > index 97f6e324e623..076306ff2dd4 100644 > > --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h > > +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h > > @@ -60,6 +60,7 @@ extern const struct vdec_common_if > > vdec_h264_slice_multi_if; > > extern const struct vdec_common_if vdec_vp8_if; > > extern const struct vdec_common_if vdec_vp8_slice_if; > > extern const struct vdec_common_if vdec_vp9_if; > > +extern const struct vdec_common_if vdec_vp9_slice_lat_if; > > > > /** > > * vdec_if_init() - initialize decode driver > >
diff --git a/drivers/media/platform/mediatek/vcodec/Makefile b/drivers/media/platform/mediatek/vcodec/Makefile index b457daf2d196..93e7a343b5b0 100644 --- a/drivers/media/platform/mediatek/vcodec/Makefile +++ b/drivers/media/platform/mediatek/vcodec/Makefile @@ -9,6 +9,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ vdec/vdec_vp8_req_if.o \ vdec/vdec_vp9_if.o \ + vdec/vdec_vp9_req_lat_if.o \ vdec/vdec_h264_req_if.o \ vdec/vdec_h264_req_common.o \ vdec/vdec_h264_req_multi_if.o \ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c index 3208f834ff80..a4735e67d39e 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c @@ -91,13 +91,28 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { .max = V4L2_MPEG_VIDEO_VP8_PROFILE_3, }, .codec_type = V4L2_PIX_FMT_VP8_FRAME, - } + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_VP9_FRAME, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, + }, }; #define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) -static struct mtk_video_fmt mtk_video_formats[4]; -static struct mtk_codec_framesizes mtk_vdec_framesizes[2]; +static struct mtk_video_fmt mtk_video_formats[5]; +static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; static struct mtk_video_fmt default_out_format; static struct mtk_video_fmt default_cap_format; @@ -338,6 +353,7 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_VP9_FRAME: mtk_video_formats[count_formats].fourcc = fourcc; mtk_video_formats[count_formats].type = MTK_FMT_DEC; mtk_video_formats[count_formats].num_planes = 1; @@ -385,6 +401,10 @@ static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) mtk_vcodec_add_formats(V4L2_PIX_FMT_VP8_FRAME, ctx); out_format_count++; } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP9_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP9_FRAME, ctx); + out_format_count++; + } if (cap_format_count) default_cap_format = mtk_video_formats[cap_format_count - 1]; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index 2ba1c19f07b6..a29041a0b7e0 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -355,6 +355,7 @@ enum mtk_vdec_format_types { MTK_VDEC_FORMAT_MT21C = 0x40, MTK_VDEC_FORMAT_H264_SLICE = 0x100, MTK_VDEC_FORMAT_VP8_FRAME = 0x200, + MTK_VDEC_FORMAT_VP9_FRAME = 0x400, }; /** diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c new file mode 100644 index 000000000000..d63399085b9b --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c @@ -0,0 +1,2072 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: George Sun <george.sun@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/videobuf2-dma-contig.h> +#include <media/v4l2-vp9.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../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. + * @mv_joint: motion vector joint 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 + * @counts_map: used map to counts_helper + * &counts_helper: counts table according to newest kernel spec + */ +struct vdec_vp9_slice_instance { + struct mtk_vcodec_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_counts_map counts_map; + struct v4l2_vp9_frame_symbol_counts counts_helper; +}; + +/* + * (2, (0, (1, 3))) + * max level = 2 + */ +static const signed char vdec_vp9_slice_inter_mode_tree[6] = { + -2, 2, 0, 4, -1, -3 +}; + +/* max level = 6 */ +static const signed char vdec_vp9_slice_intra_mode_tree[18] = { + 0, 2, -9, 4, -1, 6, 8, 12, -2, 10, -4, -5, -3, 14, -8, 16, -6, -7 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_partition_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* max level = 1 */ +static const signed char vdec_vp9_slice_switchable_interp_tree[4] = { + 0, 2, -1, -2 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_mv_joint_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* max level = 6 */ +static const signed char vdec_vp9_slice_mv_class_tree[20] = { + 0, 2, -1, 4, 6, 8, -2, -3, 10, 12, + -4, -5, -6, 14, 16, 18, -7, -8, -9, -10 +}; + +/* max level = 0 */ +static const signed char vdec_vp9_slice_mv_class0_tree[2] = { + 0, -1 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_mv_fp_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* + * 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_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_vcodec_err(instance, "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 = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + if (!frame_ctx) { + ret = -ENOMEM; + goto out; + } + + memcpy_fromio(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); + 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_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_vcodec_debug(instance, "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_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_fromio(&f->ch, &rf->ch, sizeof(f->ch)); + memcpy_fromio(&f->uh.dequant, &rf->uh.dequant, sizeof(f->uh.dequant)); + memcpy_fromio(&vsi->trans, &remote_vsi->trans, sizeof(vsi->trans)); + } + + memcpy_fromio(&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_toio(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 offset < mi_num ? offset : mi_num; +} + +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_vcodec_debug(instance, "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_vcodec_debug(instance, "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; + unsigned int 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_vcodec_err(instance, "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_vcodec_err(instance, "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 = (unsigned int)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, m; + + /* + * helper eo -> mtk eo + * helpre e1 -> mtk c3 + * helper c0 -> c0 + * helper c1 -> c1 + * helper c2 -> c2 + */ + for (l = 0; l < 6; l++) { + for (m = 0; m < VP9_BAND_6(l); m++) { + if (l == 0) { + counts_helper->coeff[i][j][k][l][m] = + &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]; + } else { + counts_helper->coeff[i][j][k][l][m] = + &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, l, m; + + 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_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_vcodec_debug(instance, "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 idx; + 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 */ + for (i = 0; i < vq->num_buffers; i++) { + if (vb == vq->bufs[i]) { + instance->dpb[i].width = w; + instance->dpb[i].height = h; + break; + } + } + + /* + * get buffer's width/height from instance + * get buffer address from vb2buf + */ + for (i = 0; i < 3; i++) { + ref = &vsi->frame.ref[i]; + idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); + if (idx < 0) { + ref->frame_width = w; + ref->frame_height = h; + memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); + } else { + ref->frame_width = instance->dpb[idx].width; + ref->frame_height = instance->dpb[idx].height; + vb = vq->bufs[idx]; + 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 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_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_vcodec_debug(instance, "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_vcodec_debug(instance, "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_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_vcodec_err(instance, "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_vcodec_err(instance, "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_vcodec_err(instance, "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_vcodec_debug(instance, "flush ...\n"); + + 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_ctx *ctx = instance->ctx; + unsigned int data[3]; + + mtk_vcodec_debug(instance, "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_vcodec_debug(instance, "No need to get vp9 crop information."); + break; + default: + mtk_vcodec_err(instance, "invalid get parameter type=%d\n", + type); + return -EINVAL; + } + + 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_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_vcodec_err(instance, "Failed to get VP9 lat buf\n"); + return -EBUSY; + } + pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; + if (!pfc) + return -EINVAL; + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "Failed to setup VP9 lat ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, 0, 0); + if (ret) { + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + 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_vcodec_err(instance, "VP9 decode timeout %d pic %d\n", ret, pfc->seq); + writel(1, &instance->vsi->state.timeout); + } + 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_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + mtk_vcodec_debug(instance, "lat dma 1 0x%llx 0x%llx\n", + pfc->vsi.trans.dma_addr, 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->dev->msg_queue_core_ctx, lat_buf); + + return 0; +} + +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_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_vcodec_err(instance, "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_vcodec_err(instance, "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_vcodec_err(instance, "VP9 core timeout pic %d\n", pfc->seq); + writel(1, &instance->core_vsi->state.timeout); + } + 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_vcodec_err(instance, "vdec_vp9_slice_update_core\n"); + goto err; + } + + pfc->vsi.trans.dma_addr_end += ctx->msg_queue.wdma_addr.dma_addr; + mtk_vcodec_debug(instance, "core dma_addr_end 0x%llx\n", 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) { + /* 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_lat_decode, + .get_param = vdec_vp9_slice_get_param, + .deinit = vdec_vp9_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c index b709c7bae197..27b4b35039cf 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c @@ -45,6 +45,10 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) ctx->dec_if = &vdec_vp9_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP9_FRAME: + ctx->dec_if = &vdec_vp9_slice_lat_if; + ctx->hw_id = MTK_VDEC_LAT0; + break; default: return -EINVAL; } diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h index 97f6e324e623..076306ff2dd4 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h @@ -60,6 +60,7 @@ extern const struct vdec_common_if vdec_h264_slice_multi_if; extern const struct vdec_common_if vdec_vp8_if; extern const struct vdec_common_if vdec_vp8_slice_if; extern const struct vdec_common_if vdec_vp9_if; +extern const struct vdec_common_if vdec_vp9_slice_lat_if; /** * vdec_if_init() - initialize decode driver