blob: e6a47fd2fae2c27ce847a1e499217293ffe63767 [file] [log] [blame]
/*
* drivers/amlogic/amports/vvp9.c
*
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/kfifo.h>
#include <linux/kthread.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/utils/amstream.h>
#include <linux/amlogic/media/utils/vformat.h>
#include <linux/amlogic/media/frame_sync/ptsserv.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <linux/slab.h>
//#include <linux/amlogic/tee.h>
#include <uapi/linux/tee.h>
#include <linux/sched/clock.h>
#include "../../../stream_input/amports/amports_priv.h"
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include "../utils/decoder_mmu_box.h"
#include "../utils/decoder_bmmu_box.h"
#define MEM_NAME "codec_vp9"
#include <linux/amlogic/media/utils/vdec_reg.h>
#include "../utils/vdec.h"
#include "../utils/amvdec.h"
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
#include "../utils/vdec_profile.h"
#endif
#include <linux/amlogic/media/video_sink/video.h>
#include <linux/amlogic/media/codec_mm/configs.h>
#include "../utils/config_parser.h"
#include "../utils/firmware.h"
#include "../../../common/chips/decoder_cpu_ver_info.h"
#include "../utils/vdec_v4l2_buffer_ops.h"
#include <media/v4l2-mem2mem.h>
#include "../utils/vdec_feature.h"
#define MIX_STREAM_SUPPORT
#include "vvp9.h"
#define VP9_10B_MMU_DW
/*#define SUPPORT_FB_DECODING*/
/*#define FB_DECODING_TEST_SCHEDULE*/
#define CO_MV_COMPRESS
#define HW_MASK_FRONT 0x1
#define HW_MASK_BACK 0x2
#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0x3442
#define VP9D_MPP_REFINFO_DATA 0x3443
#define VP9D_MPP_REF_SCALE_ENBL 0x3441
#define HEVC_MPRED_CTRL4 0x324c
#define HEVC_CM_HEADER_START_ADDR 0x3628
#define HEVC_DBLK_CFGB 0x350b
#define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464
#define HEVC_SAO_MMU_VH1_ADDR 0x363b
#define HEVC_SAO_MMU_VH0_ADDR 0x363a
#define HEVC_SAO_MMU_VH0_ADDR2 0x364d
#define HEVC_SAO_MMU_VH1_ADDR2 0x364e
#define HEVC_MV_INFO 0x310d
#define HEVC_QP_INFO 0x3137
#define HEVC_SKIP_INFO 0x3136
#define HEVC_SAO_CTRL9 0x362d
#define HEVC_CM_HEADER_START_ADDR2 0x364a
#define HEVC_SAO_MMU_DMA_CTRL2 0x364c
#define HEVC_SAO_MMU_VH0_ADDR2 0x364d
#define HEVC_SAO_MMU_VH1_ADDR2 0x364e
#define HEVC_SAO_MMU_STATUS2 0x3650
#define HEVC_DW_VH0_ADDDR 0x365e
#define HEVC_DW_VH1_ADDDR 0x365f
#define VP9_10B_DEC_IDLE 0
#define VP9_10B_DEC_FRAME_HEADER 1
#define VP9_10B_DEC_SLICE_SEGMENT 2
#define VP9_10B_DECODE_SLICE 5
#define VP9_10B_DISCARD_NAL 6
#define VP9_DUMP_LMEM 7
#define HEVC_DECPIC_DATA_DONE 0xa
#define HEVC_DECPIC_DATA_ERROR 0xb
#define HEVC_NAL_DECODE_DONE 0xe
#define HEVC_DECODE_BUFEMPTY 0x20
#define HEVC_DECODE_TIMEOUT 0x21
#define HEVC_SEARCH_BUFEMPTY 0x22
#define HEVC_DECODE_OVER_SIZE 0x23
#define HEVC_S2_DECODING_DONE 0x50
#define VP9_HEAD_PARSER_DONE 0xf0
#define VP9_HEAD_SEARCH_DONE 0xf1
#define VP9_EOS 0xf2
#define HEVC_ACTION_DONE 0xff
#define VF_POOL_SIZE 32
#undef pr_info
#define pr_info printk
#define DECODE_MODE_SINGLE ((0x80 << 24) | 0)
#define DECODE_MODE_MULTI_STREAMBASE ((0x80 << 24) | 1)
#define DECODE_MODE_MULTI_FRAMEBASE ((0x80 << 24) | 2)
#define DECODE_MODE_SINGLE_LOW_LATENCY ((0x80 << 24) | 3)
#define DECODE_MODE_MULTI_FRAMEBASE_NOHEAD ((0x80 << 24) | 4)
#define VP9_TRIGGER_FRAME_DONE 0x100
#define VP9_TRIGGER_FRAME_ENABLE 0x200
#define MV_MEM_UNIT 0x240
/*---------------------------------------------------
* Include "parser_cmd.h"
*---------------------------------------------------
*/
#define PARSER_CMD_SKIP_CFG_0 0x0000090b
#define PARSER_CMD_SKIP_CFG_1 0x1b14140f
#define PARSER_CMD_SKIP_CFG_2 0x001b1910
#define PARSER_CMD_NUMBER 37
/*#define HEVC_PIC_STRUCT_SUPPORT*/
/* to remove, fix build error */
/*#define CODEC_MM_FLAGS_FOR_VDECODER 0*/
#define MULTI_INSTANCE_SUPPORT
#define SUPPORT_10BIT
/* #define ERROR_HANDLE_DEBUG */
#ifndef STAT_KTHREAD
#define STAT_KTHREAD 0x40
#endif
#ifdef MULTI_INSTANCE_SUPPORT
#define MAX_DECODE_INSTANCE_NUM 9
#define MULTI_DRIVER_NAME "ammvdec_vp9"
static unsigned int max_decode_instance_num
= MAX_DECODE_INSTANCE_NUM;
static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM];
static unsigned int display_frame_count[MAX_DECODE_INSTANCE_NUM];
static unsigned int max_process_time[MAX_DECODE_INSTANCE_NUM];
static unsigned int run_count[MAX_DECODE_INSTANCE_NUM];
static unsigned int input_empty[MAX_DECODE_INSTANCE_NUM];
static unsigned int not_run_ready[MAX_DECODE_INSTANCE_NUM];
static u32 decode_timeout_val = 200;
static int start_decode_buf_level = 0x8000;
static u32 work_buf_size;
static u32 force_pts_unstable;
static u32 mv_buf_margin;
static u32 mv_buf_dynamic_alloc;
/* DOUBLE_WRITE_MODE is enabled only when NV21 8 bit output is needed */
/* double_write_mode:
* 0, no double write;
* 1, 1:1 ratio;
* 2, (1/4):(1/4) ratio;
* 3, (1/4):(1/4) ratio, with both compressed frame included
* 4, (1/2):(1/2) ratio;
* 8, (1/8):(1/8) ratio;
* 0x10, double write only
* 0x100, if > 1080p,use mode 4,else use mode 1;
* 0x200, if > 1080p,use mode 2,else use mode 1;
* 0x300, if > 720p, use mode 4, else use mode 1;
*/
static u32 double_write_mode;
#define DRIVER_NAME "amvdec_vp9"
#define DRIVER_HEADER_NAME "amvdec_vp9_header"
#define PUT_INTERVAL (HZ/100)
#define ERROR_SYSTEM_RESET_COUNT 200
#define PTS_NORMAL 0
#define PTS_NONE_REF_USE_DURATION 1
#define PTS_MODE_SWITCHING_THRESHOLD 3
#define PTS_MODE_SWITCHING_RECOVERY_THREASHOLD 3
#define DUR2PTS(x) ((x)*90/96)
struct VP9Decoder_s;
static int vvp9_vf_states(struct vframe_states *states, void *);
static struct vframe_s *vvp9_vf_peek(void *);
static struct vframe_s *vvp9_vf_get(void *);
static void vvp9_vf_put(struct vframe_s *, void *);
static int vvp9_event_cb(int type, void *data, void *private_data);
static int vvp9_stop(struct VP9Decoder_s *pbi);
#ifdef MULTI_INSTANCE_SUPPORT
static s32 vvp9_init(struct vdec_s *vdec);
#else
static s32 vvp9_init(struct VP9Decoder_s *pbi);
#endif
static void vvp9_prot_init(struct VP9Decoder_s *pbi, u32 mask);
static int vvp9_local_init(struct VP9Decoder_s *pbi);
static void vvp9_put_timer_func(struct timer_list *timer);
static void dump_data(struct VP9Decoder_s *pbi, int size);
static unsigned char get_data_check_sum
(struct VP9Decoder_s *pbi, int size);
static void dump_pic_list(struct VP9Decoder_s *pbi);
static int vp9_alloc_mmu(
struct VP9Decoder_s *pbi,
int cur_buf_idx,
int pic_width,
int pic_height,
unsigned short bit_depth,
unsigned int *mmu_index_adr);
#ifdef VP9_10B_MMU_DW
int vp9_alloc_mmu_dw(
struct VP9Decoder_s *pbi,
int cur_buf_idx,
int pic_width,
int pic_height,
unsigned short bit_depth,
unsigned int *mmu_index_adr);
#endif
static const char vvp9_dec_id[] = "vvp9-dev";
#define PROVIDER_NAME "decoder.vp9"
#define MULTI_INSTANCE_PROVIDER_NAME "vdec.vp9"
static const struct vframe_operations_s vvp9_vf_provider = {
.peek = vvp9_vf_peek,
.get = vvp9_vf_get,
.put = vvp9_vf_put,
.event_cb = vvp9_event_cb,
.vf_states = vvp9_vf_states,
};
static struct vframe_provider_s vvp9_vf_prov;
static u32 bit_depth_luma;
static u32 bit_depth_chroma;
static u32 frame_width;
static u32 frame_height;
static u32 video_signal_type;
static u32 on_no_keyframe_skiped;
#define PROB_SIZE (496 * 2 * 4)
#define PROB_BUF_SIZE (0x5000)
#define COUNT_BUF_SIZE (0x300 * 4 * 4)
/*compute_losless_comp_body_size(4096, 2304, 1) = 18874368(0x1200000)*/
#define MAX_FRAME_4K_NUM 0x1200
#define MAX_FRAME_8K_NUM 0x4800
#define HEVC_ASSIST_MMU_MAP_ADDR 0x3009
// bit[31:20] -- fb_read_lcu_y
// READ only// bit[19:8] -- fb_read_lcu_x
// READ only// bit[7] -- fb_read_lcu_latch
// bit[6:5] -- reserved
// bit[4] -- fb_disable_wr_iqit_buf
// bit[3] -- fb_read_avs2_enable
// bit[2] -- fb_read_vp9_enable
// bit[1] -- fb_avs2_enable
// bit[0] -- fb_vp9_enable
#define HEVC_ASSIST_HED_FB_CTL 0x300c
// [31:16] height// [15:0] width
#define HEVC_ASSIST_PIC_SIZE_FB_READ 0x300d
#define HEVC_ASSIST_MMU_MAP_ADDR2 0x300e
#ifdef SUPPORT_FB_DECODING
/* register define */
#define HEVC_ASSIST_HED_FB_W_CTL 0x3006
#define HEVC_ASSIST_HED_FB_R_CTL 0x3007
#define HEVC_ASSIST_HED_FB_ADDR 0x3008
#define HEVC_ASSIST_FB_MMU_MAP_ADDR 0x300a
#define HEVC_ASSIST_FBD_MMU_MAP_ADDR 0x300b
#define MAX_STAGE_PAGE_NUM 0x1200
#define STAGE_MMU_MAP_SIZE (MAX_STAGE_PAGE_NUM * 4)
#endif
static inline int div_r32(int64_t m, int n)
{
/*
*return (int)(m/n)
*/
#ifndef CONFIG_ARM64
int64_t qu = 0;
qu = div_s64(m, n);
return (int)qu;
#else
return (int)(m/n);
#endif
}
/*USE_BUF_BLOCK*/
struct BUF_s {
int index;
unsigned int alloc_flag;
/*buffer */
unsigned int cma_page_count;
unsigned long alloc_addr;
unsigned long start_adr;
unsigned int size;
unsigned int free_start_adr;
ulong v4l_ref_buf_addr;
ulong header_addr;
u32 header_size;
u32 luma_size;
ulong chroma_addr;
u32 chroma_size;
} /*BUF_t */;
struct MVBUF_s {
unsigned long start_adr;
unsigned int size;
int used_flag;
} /*MVBUF_t */;
/* #undef BUFMGR_ONLY to enable hardware configuration */
/*#define TEST_WR_PTR_INC*/
/*#define WR_PTR_INC_NUM 128*/
#define WR_PTR_INC_NUM 1
#define SIMULATION
#define DOS_PROJECT
#undef MEMORY_MAP_IN_REAL_CHIP
/*#undef DOS_PROJECT*/
/*#define MEMORY_MAP_IN_REAL_CHIP*/
/*#define BUFFER_MGR_ONLY*/
/*#define CONFIG_HEVC_CLK_FORCED_ON*/
/*#define ENABLE_SWAP_TEST*/
#define MCRCC_ENABLE
#define VP9_LPF_LVL_UPDATE
/*#define DBG_LF_PRINT*/
#ifdef VP9_10B_NV21
#else
#define LOSLESS_COMPRESS_MODE
#endif
#define DOUBLE_WRITE_YSTART_TEMP 0x02000000
#define DOUBLE_WRITE_CSTART_TEMP 0x02900000
#define VP9_DEBUG_BUFMGR 0x01
#define VP9_DEBUG_BUFMGR_MORE 0x02
#define VP9_DEBUG_BUFMGR_DETAIL 0x04
#define VP9_DEBUG_OUT_PTS 0x10
#define VP9_DEBUG_SEND_PARAM_WITH_REG 0x100
#define VP9_DEBUG_MERGE 0x200
#define VP9_DEBUG_DBG_LF_PRINT 0x400
#define VP9_DEBUG_REG 0x800
#define VP9_DEBUG_2_STAGE 0x1000
#define VP9_DEBUG_2_STAGE_MORE 0x2000
#define VP9_DEBUG_QOS_INFO 0x4000
#define VP9_DEBUG_DIS_LOC_ERROR_PROC 0x10000
#define VP9_DEBUG_DIS_SYS_ERROR_PROC 0x20000
#define VP9_DEBUG_DUMP_PIC_LIST 0x40000
#define VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC 0x80000
#define VP9_DEBUG_NO_TRIGGER_FRAME 0x100000
#define VP9_DEBUG_LOAD_UCODE_FROM_FILE 0x200000
#define VP9_DEBUG_FORCE_SEND_AGAIN 0x400000
#define VP9_DEBUG_DUMP_DATA 0x800000
#define VP9_DEBUG_CACHE 0x1000000
#define VP9_DEBUG_CACHE_HIT_RATE 0x2000000
#define IGNORE_PARAM_FROM_CONFIG 0x8000000
#ifdef MULTI_INSTANCE_SUPPORT
#define PRINT_FLAG_ERROR 0x0
#define PRINT_FLAG_V4L_DETAIL 0x10000000
#define PRINT_FLAG_VDEC_STATUS 0x20000000
#define PRINT_FLAG_VDEC_DETAIL 0x40000000
#define PRINT_FLAG_VDEC_DATA 0x80000000
#endif
static u32 force_bufspec;
static u32 debug;
static bool is_reset;
/*for debug*/
/*
udebug_flag:
bit 0, enable ucode print
bit 1, enable ucode detail print
bit [31:16] not 0, pos to dump lmem
bit 2, pop bits to lmem
bit [11:8], pre-pop bits for alignment (when bit 2 is 1)
*/
static u32 udebug_flag;
/*
when udebug_flag[1:0] is not 0
udebug_pause_pos not 0,
pause position
*/
static u32 udebug_pause_pos;
/*
when udebug_flag[1:0] is not 0
and udebug_pause_pos is not 0,
pause only when DEBUG_REG2 is equal to this val
*/
static u32 udebug_pause_val;
static u32 udebug_pause_decode_idx;
static u32 without_display_mode;
static u32 v4l_bitstream_id_enable = 1;
/*
*[3:0] 0: default use config from omx.
* 1: force enable fence.
* 2: disable fence.
*[7:4] 0: fence use for driver.
* 1: fence fd use for app.
*/
static u32 force_config_fence;
#define DEBUG_REG
#ifdef DEBUG_REG
void WRITE_VREG_DBG2(unsigned int adr, unsigned int val)
{
if (debug & VP9_DEBUG_REG)
pr_info("%s(%x, %x)\n", __func__, adr, val);
if (adr != 0)
WRITE_VREG(adr, val);
}
#undef WRITE_VREG
#define WRITE_VREG WRITE_VREG_DBG2
#endif
#define FRAME_CNT_WINDOW_SIZE 59
#define RATE_CORRECTION_THRESHOLD 5
/**************************************************
VP9 buffer management start
***************************************************/
#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000
#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000
#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000
//#define MMU_COMPRESS_HEADER_SIZE 0x48000
//#define MMU_COMPRESS_HEADER_SIZE_DW 0x48000
//#define MMU_COMPRESS_8K_HEADER_SIZE (MMU_COMPRESS_HEADER_SIZE * 4)
#define MMU_COMPRESS_HEADER_SIZE 0x48000
#define MMU_COMPRESS_HEADER_SIZE_DW 0x48000
#define MMU_COMPRESS_8K_HEADER_SIZE (MMU_COMPRESS_HEADER_SIZE * 4)
#define MAX_SIZE_8K (8192 * 4608)
#define MAX_SIZE_4K (4096 * 2304)
#define MAX_SIZE_2K (1920 * 1088)
#define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K)
#define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088))
#define INVALID_IDX -1 /* Invalid buffer index.*/
#define RPM_BEGIN 0x200
#define RPM_END 0x280
union param_u {
struct {
unsigned short data[RPM_END - RPM_BEGIN];
} l;
struct {
/* from ucode lmem, do not change this struct */
unsigned short profile;
unsigned short show_existing_frame;
unsigned short frame_to_show_idx;
unsigned short frame_type; /*1 bit*/
unsigned short show_frame; /*1 bit*/
unsigned short error_resilient_mode; /*1 bit*/
unsigned short intra_only; /*1 bit*/
unsigned short display_size_present; /*1 bit*/
unsigned short reset_frame_context;
unsigned short refresh_frame_flags;
unsigned short width;
unsigned short height;
unsigned short display_width;
unsigned short display_height;
/*
*bit[11:8] - ref_frame_info_0 (ref(3-bits), ref_frame_sign_bias(1-bit))
*bit[7:4] - ref_frame_info_1 (ref(3-bits), ref_frame_sign_bias(1-bit))
*bit[3:0] - ref_frame_info_2 (ref(3-bits), ref_frame_sign_bias(1-bit))
*/
unsigned short ref_info;
/*
*bit[2]: same_frame_size0
*bit[1]: same_frame_size1
*bit[0]: same_frame_size2
*/
unsigned short same_frame_size;
unsigned short mode_ref_delta_enabled;
unsigned short ref_deltas[4];
unsigned short mode_deltas[2];
unsigned short filter_level;
unsigned short sharpness_level;
unsigned short bit_depth;
unsigned short seg_quant_info[8];
unsigned short seg_enabled;
unsigned short seg_abs_delta;
/* bit 15: feature enabled; bit 8, sign; bit[5:0], data */
unsigned short seg_lf_info[8];
} p;
};
struct vpx_codec_frame_buffer_s {
uint8_t *data; /**< Pointer to the data buffer */
size_t size; /**< Size of data in bytes */
void *priv; /**< Frame's private data */
};
enum vpx_color_space_t {
VPX_CS_UNKNOWN = 0, /**< Unknown */
VPX_CS_BT_601 = 1, /**< BT.601 */
VPX_CS_BT_709 = 2, /**< BT.709 */
VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */
VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */
VPX_CS_BT_2020 = 5, /**< BT.2020 */
VPX_CS_RESERVED = 6, /**< Reserved */
VPX_CS_SRGB = 7 /**< sRGB */
}; /**< alias for enum vpx_color_space */
enum vpx_bit_depth_t {
VPX_BITS_8 = 8, /**< 8 bits */
VPX_BITS_10 = 10, /**< 10 bits */
VPX_BITS_12 = 12, /**< 12 bits */
};
#define MAX_SLICE_NUM 1024
struct PIC_BUFFER_CONFIG_s {
int index;
int BUF_index;
int mv_buf_index;
int comp_body_size;
int buf_size;
int vf_ref;
int y_canvas_index;
int uv_canvas_index;
#ifdef MULTI_INSTANCE_SUPPORT
struct canvas_config_s canvas_config[2];
#endif
int decode_idx;
int slice_type;
int stream_offset;
u32 pts;
u64 pts64;
u64 timestamp;
uint8_t error_mark;
/**/
int slice_idx;
/*buffer*/
unsigned long header_adr;
#ifdef VP9_10B_MMU_DW
unsigned long header_dw_adr;
#endif
unsigned long mpred_mv_wr_start_addr;
int mv_size;
/*unsigned long mc_y_adr;
*unsigned long mc_u_v_adr;
*/
unsigned int dw_y_adr;
unsigned int dw_u_v_adr;
u32 luma_size;
u32 chroma_size;
int mc_canvas_y;
int mc_canvas_u_v;
int lcu_total;
/**/
int y_width;
int y_height;
int y_crop_width;
int y_crop_height;
int y_stride;
int uv_width;
int uv_height;
int uv_crop_width;
int uv_crop_height;
int uv_stride;
int alpha_width;
int alpha_height;
int alpha_stride;
uint8_t *y_buffer;
uint8_t *u_buffer;
uint8_t *v_buffer;
uint8_t *alpha_buffer;
uint8_t *buffer_alloc;
int buffer_alloc_sz;
int border;
int frame_size;
int subsampling_x;
int subsampling_y;
unsigned int bit_depth;
enum vpx_color_space_t color_space;
int corrupted;
int flags;
unsigned long cma_alloc_addr;
int double_write_mode;
/* picture qos infomation*/
int max_qp;
int avg_qp;
int min_qp;
int max_skip;
int avg_skip;
int min_skip;
int max_mv;
int min_mv;
int avg_mv;
u32 hw_decode_time;
u32 frame_size2; // For frame base mode
/* vdec sync. */
struct dma_fence *fence;
/* hdr10 plus data */
u32 hdr10p_data_size;
char *hdr10p_data_buf;
} PIC_BUFFER_CONFIG;
enum BITSTREAM_PROFILE {
PROFILE_0,
PROFILE_1,
PROFILE_2,
PROFILE_3,
MAX_PROFILES
};
enum FRAME_TYPE {
KEY_FRAME = 0,
INTER_FRAME = 1,
FRAME_TYPES,
};
enum REFERENCE_MODE {
SINGLE_REFERENCE = 0,
COMPOUND_REFERENCE = 1,
REFERENCE_MODE_SELECT = 2,
REFERENCE_MODES = 3,
};
#define NONE -1
#define INTRA_FRAME 0
#define LAST_FRAME 1
#define GOLDEN_FRAME 2
#define ALTREF_FRAME 3
#define MAX_REF_FRAMES 4
#define REFS_PER_FRAME 3
#define REF_FRAMES_LOG2 3
#define REF_FRAMES (1 << REF_FRAMES_LOG2)
#define REF_FRAMES_4K (6)
/*4 scratch frames for the new frames to support a maximum of 4 cores decoding
*in parallel, 3 for scaled references on the encoder.
*TODO(hkuang): Add ondemand frame buffers instead of hardcoding the number
* // of framebuffers.
*TODO(jkoleszar): These 3 extra references could probably come from the
*normal reference pool.
*/
#define FRAME_BUFFERS (REF_FRAMES + 16)
#define HEADER_FRAME_BUFFERS (FRAME_BUFFERS)
#define MAX_BUF_NUM (FRAME_BUFFERS)
#define MV_BUFFER_NUM FRAME_BUFFERS
#ifdef SUPPORT_FB_DECODING
#define STAGE_MAX_BUFFERS 16
#else
#define STAGE_MAX_BUFFERS 0
#endif
#define FRAME_CONTEXTS_LOG2 2
#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2)
/*buffer + header buffer + workspace*/
#ifdef MV_USE_FIXED_BUF
#define MAX_BMMU_BUFFER_NUM (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + 1)
#define VF_BUFFER_IDX(n) (n)
#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
#define WORK_SPACE_BUF_ID (FRAME_BUFFERS + HEADER_FRAME_BUFFERS)
#else
#define MAX_BMMU_BUFFER_NUM \
(FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM + 1)
#define VF_BUFFER_IDX(n) (n)
#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
#define MV_BUFFER_IDX(n) (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + n)
#define WORK_SPACE_BUF_ID \
(FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM)
#endif
struct RefCntBuffer_s {
int ref_count;
/*MV_REF *mvs;*/
int mi_rows;
int mi_cols;
struct vpx_codec_frame_buffer_s raw_frame_buffer;
struct PIC_BUFFER_CONFIG_s buf;
/*The Following variables will only be used in frame parallel decode.
*
*frame_worker_owner indicates which FrameWorker owns this buffer. NULL means
*that no FrameWorker owns, or is decoding, this buffer.
*VP9Worker *frame_worker_owner;
*
*row and col indicate which position frame has been decoded to in real
*pixel unit. They are reset to -1 when decoding begins and set to INT_MAX
*when the frame is fully decoded.
*/
int row;
int col;
int show_frame;
} RefCntBuffer;
struct RefBuffer_s {
/*TODO(dkovalev): idx is not really required and should be removed, now it
*is used in vp9_onyxd_if.c
*/
int idx;
struct PIC_BUFFER_CONFIG_s *buf;
/*struct scale_factors sf;*/
} RefBuffer;
struct InternalFrameBuffer_s {
uint8_t *data;
size_t size;
int in_use;
} InternalFrameBuffer;
struct InternalFrameBufferList_s {
int num_internal_frame_buffers;
struct InternalFrameBuffer_s *int_fb;
} InternalFrameBufferList;
struct BufferPool_s {
/*Protect BufferPool from being accessed by several FrameWorkers at
*the same time during frame parallel decode.
*TODO(hkuang): Try to use atomic variable instead of locking the whole pool.
*
*Private data associated with the frame buffer callbacks.
*void *cb_priv;
*
*vpx_get_frame_buffer_cb_fn_t get_fb_cb;
*vpx_release_frame_buffer_cb_fn_t release_fb_cb;
*/
struct RefCntBuffer_s frame_bufs[FRAME_BUFFERS];
/*Frame buffers allocated internally by the codec.*/
struct InternalFrameBufferList_s int_frame_buffers;
unsigned long flags;
spinlock_t lock;
} BufferPool;
#define lock_buffer_pool(pool, flags) \
spin_lock_irqsave(&pool->lock, flags)
#define unlock_buffer_pool(pool, flags) \
spin_unlock_irqrestore(&pool->lock, flags)
struct VP9_Common_s {
enum vpx_color_space_t color_space;
int width;
int height;
int display_width;
int display_height;
int last_width;
int last_height;
int subsampling_x;
int subsampling_y;
int use_highbitdepth;/*Marks if we need to use 16bit frame buffers.*/
struct PIC_BUFFER_CONFIG_s *frame_to_show;
struct RefCntBuffer_s *prev_frame;
/*TODO(hkuang): Combine this with cur_buf in macroblockd.*/
struct RefCntBuffer_s *cur_frame;
int ref_frame_map[REF_FRAMES]; /* maps fb_idx to reference slot */
/*Prepare ref_frame_map for the next frame.
*Only used in frame parallel decode.
*/
int next_ref_frame_map[REF_FRAMES];
/* TODO(jkoleszar): could expand active_ref_idx to 4,
*with 0 as intra, and roll new_fb_idx into it.
*/
/*Each frame can reference REFS_PER_FRAME buffers*/
struct RefBuffer_s frame_refs[REFS_PER_FRAME];
int prev_fb_idx;
int new_fb_idx;
int cur_fb_idx_mmu;
/*last frame's frame type for motion search*/
enum FRAME_TYPE last_frame_type;
enum FRAME_TYPE frame_type;
int show_frame;
int last_show_frame;
int show_existing_frame;
/*Flag signaling that the frame is encoded using only INTRA modes.*/
uint8_t intra_only;
uint8_t last_intra_only;
int allow_high_precision_mv;
/*Flag signaling that the frame context should be reset to default
*values. 0 or 1 implies don't reset, 2 reset just the context
*specified in the frame header, 3 reset all contexts.
*/
int reset_frame_context;
/*MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in
* MODE_INFO (8-pixel) units.
*/
int MBs;
int mb_rows, mi_rows;
int mb_cols, mi_cols;
int mi_stride;
/*Whether to use previous frame's motion vectors for prediction.*/
int use_prev_frame_mvs;
int refresh_frame_context; /* Two state 0 = NO, 1 = YES */
int ref_frame_sign_bias[MAX_REF_FRAMES]; /* Two state 0, 1 */
/*struct loopfilter lf;*/
/*struct segmentation seg;*/
/*TODO(hkuang):Remove this as it is the same as frame_parallel_decode*/
/* in pbi.*/
int frame_parallel_decode; /* frame-based threading.*/
/*Context probabilities for reference frame prediction*/
/*MV_REFERENCE_FRAME comp_fixed_ref;*/
/*MV_REFERENCE_FRAME comp_var_ref[2];*/
enum REFERENCE_MODE reference_mode;
/*FRAME_CONTEXT *fc; */ /* this frame entropy */
/*FRAME_CONTEXT *frame_contexts; */ /*FRAME_CONTEXTS*/
/*unsigned int frame_context_idx; *//* Context to use/update */
/*FRAME_COUNTS counts;*/
unsigned int current_video_frame;
enum BITSTREAM_PROFILE profile;
enum vpx_bit_depth_t bit_depth;
int error_resilient_mode;
int frame_parallel_decoding_mode;
int byte_alignment;
int skip_loop_filter;
/*External BufferPool passed from outside.*/
struct BufferPool_s *buffer_pool;
int above_context_alloc_cols;
};
static void set_canvas(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config);
static int prepare_display_buf(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config);
static void fill_frame_info(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *frame,
unsigned int framesize,
unsigned int pts);
static struct PIC_BUFFER_CONFIG_s *get_frame_new_buffer(struct VP9_Common_s *cm)
{
return &cm->buffer_pool->frame_bufs[cm->new_fb_idx].buf;
}
static void ref_cnt_fb(struct RefCntBuffer_s *bufs, int *idx, int new_idx)
{
const int ref_index = *idx;
if (ref_index >= 0 && bufs[ref_index].ref_count > 0) {
bufs[ref_index].ref_count--;
/*pr_info("[MMU DEBUG 2] dec ref_count[%d] : %d\r\n",
* ref_index, bufs[ref_index].ref_count);
*/
}
*idx = new_idx;
bufs[new_idx].ref_count++;
/*pr_info("[MMU DEBUG 3] inc ref_count[%d] : %d\r\n",
* new_idx, bufs[new_idx].ref_count);
*/
}
int vp9_release_frame_buffer(struct vpx_codec_frame_buffer_s *fb)
{
struct InternalFrameBuffer_s *const int_fb =
(struct InternalFrameBuffer_s *)fb->priv;
if (int_fb)
int_fb->in_use = 0;
return 0;
}
static int compute_losless_comp_body_size(int width, int height,
uint8_t is_bit_depth_10);
static void setup_display_size(struct VP9_Common_s *cm, union param_u *params,
int print_header_info)
{
cm->display_width = cm->width;
cm->display_height = cm->height;
if (params->p.display_size_present) {
if (print_header_info)
pr_info(" * 1-bit display_size_present read : 1\n");
cm->display_width = params->p.display_width;
cm->display_height = params->p.display_height;
/*vp9_read_frame_size(rb, &cm->display_width,
* &cm->display_height);
*/
} else {
if (print_header_info)
pr_info(" * 1-bit display_size_present read : 0\n");
}
}
uint8_t print_header_info = 0;
struct buff_s {
u32 buf_start;
u32 buf_size;
u32 buf_end;
} buff_t;
struct BuffInfo_s {
u32 max_width;
u32 max_height;
u32 start_adr;
u32 end_adr;
struct buff_s ipp;
struct buff_s sao_abv;
struct buff_s sao_vb;
struct buff_s short_term_rps;
struct buff_s vps;
struct buff_s sps;
struct buff_s pps;
struct buff_s sao_up;
struct buff_s swap_buf;
struct buff_s swap_buf2;
struct buff_s scalelut;
struct buff_s dblk_para;
struct buff_s dblk_data;
struct buff_s seg_map;
struct buff_s mmu_vbh;
struct buff_s cm_header;
#ifdef VP9_10B_MMU_DW
struct buff_s mmu_vbh_dw;
struct buff_s cm_header_dw;
#endif
struct buff_s mpred_above;
#ifdef MV_USE_FIXED_BUF
struct buff_s mpred_mv;
#endif
struct buff_s rpm;
struct buff_s lmem;
} BuffInfo_t;
#ifdef MULTI_INSTANCE_SUPPORT
#define DEC_RESULT_NONE 0
#define DEC_RESULT_DONE 1
#define DEC_RESULT_AGAIN 2
#define DEC_RESULT_CONFIG_PARAM 3
#define DEC_RESULT_ERROR 4
#define DEC_INIT_PICLIST 5
#define DEC_UNINIT_PICLIST 6
#define DEC_RESULT_GET_DATA 7
#define DEC_RESULT_GET_DATA_RETRY 8
#define DEC_RESULT_EOS 9
#define DEC_RESULT_FORCE_EXIT 10
#define DEC_RESULT_NEED_MORE_BUFFER 11
#define DEC_V4L2_CONTINUE_DECODING 18
#define DEC_S1_RESULT_NONE 0
#define DEC_S1_RESULT_DONE 1
#define DEC_S1_RESULT_FORCE_EXIT 2
#define DEC_S1_RESULT_TEST_TRIGGER_DONE 0xf0
#ifdef FB_DECODING_TEST_SCHEDULE
#define TEST_SET_NONE 0
#define TEST_SET_PIC_DONE 1
#define TEST_SET_S2_DONE 2
#endif
static void vp9_work(struct work_struct *work);
#endif
struct loop_filter_info_n;
struct loopfilter;
struct segmentation;
#ifdef SUPPORT_FB_DECODING
static void mpred_process(struct VP9Decoder_s *pbi);
static void vp9_s1_work(struct work_struct *work);
struct stage_buf_s {
int index;
unsigned short rpm[RPM_END - RPM_BEGIN];
};
static unsigned int not_run2_ready[MAX_DECODE_INSTANCE_NUM];
static unsigned int run2_count[MAX_DECODE_INSTANCE_NUM];
#ifdef FB_DECODING_TEST_SCHEDULE
u32 stage_buf_num; /* = 16;*/
#else
u32 stage_buf_num;
#endif
#endif
struct vp9_fence_vf_t {
u32 used_size;
struct vframe_s *fence_vf[VF_POOL_SIZE];
};
struct VP9Decoder_s {
#ifdef MULTI_INSTANCE_SUPPORT
unsigned char index;
struct device *cma_dev;
struct platform_device *platform_dev;
void (*vdec_cb)(struct vdec_s *, void *);
void *vdec_cb_arg;
struct vframe_chunk_s *chunk;
int dec_result;
struct work_struct work;
struct work_struct recycle_mmu_work;
struct work_struct set_clk_work;
u32 start_shift_bytes;
struct BuffInfo_s work_space_buf_store;
unsigned long buf_start;
u32 buf_size;
u32 cma_alloc_count;
unsigned long cma_alloc_addr;
uint8_t eos;
unsigned long int start_process_time;
unsigned last_lcu_idx;
int decode_timeout_count;
unsigned timeout_num;
int save_buffer_mode;
int double_write_mode;
#endif
long used_4k_num;
unsigned char m_ins_flag;
char *provider_name;
union param_u param;
int frame_count;
int pic_count;
u32 stat;
struct timer_list timer;
u32 frame_dur;
u32 frame_ar;
int fatal_error;
uint8_t init_flag;
uint8_t first_sc_checked;
uint8_t process_busy;
#define PROC_STATE_INIT 0
#define PROC_STATE_DECODESLICE 1
#define PROC_STATE_SENDAGAIN 2
uint8_t process_state;
u32 ucode_pause_pos;
int show_frame_num;
struct buff_s mc_buf_spec;
struct dec_sysinfo vvp9_amstream_dec_info;
void *rpm_addr;
void *lmem_addr;
dma_addr_t rpm_phy_addr;
dma_addr_t lmem_phy_addr;
unsigned short *lmem_ptr;
unsigned short *debug_ptr;
void *prob_buffer_addr;
void *count_buffer_addr;
dma_addr_t prob_buffer_phy_addr;
dma_addr_t count_buffer_phy_addr;
void *frame_mmu_map_addr;
dma_addr_t frame_mmu_map_phy_addr;
#ifdef VP9_10B_MMU_DW
void *frame_mmu_dw_map_addr;
dma_addr_t frame_mmu_dw_map_phy_addr;
#endif
unsigned int use_cma_flag;
struct BUF_s m_BUF[MAX_BUF_NUM];
struct MVBUF_s m_mv_BUF[MV_BUFFER_NUM];
u32 used_buf_num;
DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
DECLARE_KFIFO(pending_q, struct vframe_s *, VF_POOL_SIZE);
struct vframe_s vfpool[VF_POOL_SIZE];
u32 vf_pre_count;
u32 vf_get_count;
u32 vf_put_count;
int buf_num;
int pic_num;
int lcu_size_log2;
unsigned int losless_comp_body_size;
u32 video_signal_type;
int pts_mode;
int last_lookup_pts;
int last_pts;
u64 last_lookup_pts_us64;
u64 last_pts_us64;
u64 shift_byte_count;
u32 pts_unstable;
u32 frame_cnt_window;
u32 pts1, pts2;
u32 last_duration;
u32 duration_from_pts_done;
bool vp9_first_pts_ready;
u32 shift_byte_count_lo;
u32 shift_byte_count_hi;
int pts_mode_switching_count;
int pts_mode_recovery_count;
bool get_frame_dur;
u32 saved_resolution;
/**/
struct VP9_Common_s common;
struct RefCntBuffer_s *cur_buf;
int refresh_frame_flags;
uint8_t need_resync;
uint8_t hold_ref_buf;
uint8_t ready_for_new_data;
struct BufferPool_s vp9_buffer_pool;
struct BuffInfo_s *work_space_buf;
struct buff_s *mc_buf;
unsigned int frame_width;
unsigned int frame_height;
unsigned short *rpm_ptr;
int init_pic_w;
int init_pic_h;
int lcu_total;
int lcu_size;
int slice_type;
int skip_flag;
int decode_idx;
int slice_idx;
uint8_t has_keyframe;
uint8_t wait_buf;
uint8_t error_flag;
/* bit 0, for decoding; bit 1, for displaying */
uint8_t ignore_bufmgr_error;
int PB_skip_mode;
int PB_skip_count_after_decoding;
/*hw*/
/*lf*/
int default_filt_lvl;
struct loop_filter_info_n *lfi;
struct loopfilter *lf;
struct segmentation *seg_4lf;
/**/
struct vdec_info *gvs;
u32 pre_stream_offset;
unsigned int dec_status;
u32 last_put_idx;
int new_frame_displayed;
void *mmu_box;
void *bmmu_box;
int mmu_enable;
#ifdef VP9_10B_MMU_DW
void *mmu_box_dw;
int dw_mmu_enable;
#endif
struct vframe_master_display_colour_s vf_dp;
struct firmware_s *fw;
int max_pic_w;
int max_pic_h;
#ifdef SUPPORT_FB_DECODING
int dec_s1_result;
int s1_test_cmd;
struct work_struct s1_work;
int used_stage_buf_num;
int s1_pos;
int s2_pos;
void *stage_mmu_map_addr;
dma_addr_t stage_mmu_map_phy_addr;
struct stage_buf_s *s1_buf;
struct stage_buf_s *s2_buf;
struct stage_buf_s *stage_bufs
[STAGE_MAX_BUFFERS];
unsigned char run2_busy;
int s1_mv_buf_index;
int s1_mv_buf_index_pre;
int s1_mv_buf_index_pre_pre;
unsigned long s1_mpred_mv_wr_start_addr;
unsigned long s1_mpred_mv_wr_start_addr_pre;
unsigned short s1_intra_only;
unsigned short s1_frame_type;
unsigned short s1_width;
unsigned short s1_height;
unsigned short s1_last_show_frame;
union param_u s1_param;
u8 back_not_run_ready;
#endif
int need_cache_size;
u64 sc_start_time;
bool postproc_done;
int low_latency_flag;
bool no_head;
bool pic_list_init_done;
bool pic_list_init_done2;
bool is_used_v4l;
void *v4l2_ctx;
bool v4l_params_parsed;
int frameinfo_enable;
struct vframe_qos_s vframe_qos;
u32 mem_map_mode;
u32 dynamic_buf_num_margin;
struct vframe_s vframe_dummy;
u32 res_ch_flag;
/*struct VP9Decoder_s vp9_decoder;*/
union param_u vp9_param;
int sidebind_type;
int sidebind_channel_id;
bool enable_fence;
int fence_usage;
u32 frame_mode_pts_save[FRAME_BUFFERS];
u64 frame_mode_pts64_save[FRAME_BUFFERS];
int run_ready_min_buf_num;
int one_package_frame_cnt;
int buffer_wrap[FRAME_BUFFERS];
int last_width;
int last_height;
u32 error_frame_width;
u32 error_frame_height;
u32 endian;
ulong fb_token;
struct vp9_fence_vf_t fence_vf_s;
struct mutex fence_mutex;
dma_addr_t rdma_phy_adr;
unsigned *rdma_adr;
struct trace_decoder_name trace;
};
static int vp9_print(struct VP9Decoder_s *pbi,
int flag, const char *fmt, ...)
{
#define HEVC_PRINT_BUF 512
unsigned char buf[HEVC_PRINT_BUF];
int len = 0;
if (pbi == NULL ||
(flag == 0) ||
(debug & flag)) {
va_list args;
va_start(args, fmt);
if (pbi)
len = sprintf(buf, "[%d]", pbi->index);
vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
pr_debug("%s", buf);
va_end(args);
}
return 0;
}
static int is_oversize(int w, int h)
{
int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)?
MAX_SIZE_8K : MAX_SIZE_4K;
if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D)
max = MAX_SIZE_2K;
if (w <= 0 || h <= 0)
return true;
if (h != 0 && (w > max / h))
return true;
return false;
}
static int vvp9_mmu_compress_header_size(int w, int h)
{
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
IS_8K_SIZE(w, h))
return (MMU_COMPRESS_HEADER_SIZE_8K);
if (IS_4K_SIZE(w, h))
return (MMU_COMPRESS_HEADER_SIZE_4K);
return (MMU_COMPRESS_HEADER_SIZE_1080P);
}
/*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/
static int vvp9_frame_mmu_map_size(struct VP9Decoder_s *pbi)
{
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h))
return (MAX_FRAME_8K_NUM << 2);
return (MAX_FRAME_4K_NUM << 2);
}
static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic);
static void resize_context_buffers(struct VP9Decoder_s *pbi,
struct VP9_Common_s *cm, int width, int height)
{
if (cm->width != width || cm->height != height) {
/* to do ..*/
if (pbi != NULL) {
pbi->vp9_first_pts_ready = 0;
pbi->duration_from_pts_done = 0;
}
pr_info("%s (%d,%d)=>(%d,%d)\r\n", __func__,
cm->width, cm->height,
width, height);
cm->width = width;
cm->height = height;
}
/*
*if (cm->cur_frame->mvs == NULL ||
* cm->mi_rows > cm->cur_frame->mi_rows ||
* cm->mi_cols > cm->cur_frame->mi_cols) {
* resize_mv_buffer(cm);
*}
*/
}
static int valid_ref_frame_size(int ref_width, int ref_height,
int this_width, int this_height) {
return 2 * this_width >= ref_width &&
2 * this_height >= ref_height &&
this_width <= 16 * ref_width &&
this_height <= 16 * ref_height;
}
/*
*static int valid_ref_frame_img_fmt(enum vpx_bit_depth_t ref_bit_depth,
* int ref_xss, int ref_yss,
* enum vpx_bit_depth_t this_bit_depth,
* int this_xss, int this_yss) {
* return ref_bit_depth == this_bit_depth && ref_xss == this_xss &&
* ref_yss == this_yss;
*}
*/
static int setup_frame_size(
struct VP9Decoder_s *pbi,
struct VP9_Common_s *cm, union param_u *params,
unsigned int *mmu_index_adr,
unsigned int *mmu_dw_index_adr,
int print_header_info) {
int width, height;
struct BufferPool_s * const pool = cm->buffer_pool;
struct PIC_BUFFER_CONFIG_s *ybf;
int ret = 0;
width = params->p.width;
height = params->p.height;
if (is_oversize(width, height)) {
pbi->error_frame_width = width;
pbi->error_frame_height = height;
vp9_print(pbi, 0, "%s, Error: Invalid frame size\n", __func__);
return -1;
}
pbi->error_frame_width = 0;
pbi->error_frame_height = 0;
/*vp9_read_frame_size(rb, &width, &height);*/
if (print_header_info)
pr_info(" * 16-bits w read : %d (width : %d)\n", width, height);
if (print_header_info)
pr_info
(" * 16-bits h read : %d (height : %d)\n", width, height);
WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, (height << 16) | width);
#ifdef VP9_10B_HED_FB
WRITE_VREG(HEVC_ASSIST_PIC_SIZE_FB_READ, (height << 16) | width);
#endif
if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
ret = vp9_alloc_mmu(pbi,
cm->new_fb_idx,
params->p.width,
params->p.height,
params->p.bit_depth,
mmu_index_adr);
if (ret != 0) {
pr_err("can't alloc need mmu1,idx %d ret =%d\n",
cm->new_fb_idx,
ret);
return ret;
}
cm->cur_fb_idx_mmu = cm->new_fb_idx;
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable && (mmu_dw_index_adr != NULL)) {
ret = vp9_alloc_mmu_dw(pbi, cm->new_fb_idx,
params->p.width, params->p.height,
params->p.bit_depth, mmu_dw_index_adr);
if (ret != 0) {
pr_err("can't alloc need mmu1 dw,idx %d ret =%d\n",
cm->new_fb_idx,
ret);
return ret;
}
}
#endif
resize_context_buffers(pbi, cm, width, height);
setup_display_size(cm, params, print_header_info);
#if 0
lock_buffer_pool(pool);
if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_DEC_BORDER_IN_PIXELS,
cm->byte_alignment,
&pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer,
pool->get_fb_cb, pool->cb_priv)) {
unlock_buffer_pool(pool);
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffer");
}
unlock_buffer_pool(pool);
#else
/* porting */
ybf = get_frame_new_buffer(cm);
if (!ybf)
return -1;
ybf->y_crop_width = width;
ybf->y_crop_height = height;
ybf->bit_depth = params->p.bit_depth;
#endif
pool->frame_bufs[cm->new_fb_idx].buf.subsampling_x = cm->subsampling_x;
pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y;
pool->frame_bufs[cm->new_fb_idx].buf.bit_depth =
(unsigned int)cm->bit_depth;
pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space;
return ret;
}
static int setup_frame_size_with_refs(
struct VP9Decoder_s *pbi,
struct VP9_Common_s *cm,
union param_u *params,
unsigned int *mmu_index_adr,
unsigned int *mmu_dw_index_adr,
int print_header_info) {
int width, height;
int found = 0, i;
int has_valid_ref_frame = 0;
struct PIC_BUFFER_CONFIG_s *ybf;
struct BufferPool_s * const pool = cm->buffer_pool;
int ret = 0;
for (i = 0; i < REFS_PER_FRAME; ++i) {
if ((params->p.same_frame_size >>
(REFS_PER_FRAME - i - 1)) & 0x1) {
struct PIC_BUFFER_CONFIG_s *const buf =
cm->frame_refs[i].buf;
/*if (print_header_info)
* pr_info
* ("1-bit same_frame_size[%d] read : 1\n", i);
*/
width = buf->y_crop_width;
height = buf->y_crop_height;
/*if (print_header_info)
* pr_info
* (" - same_frame_size width : %d\n", width);
*/
/*if (print_header_info)
* pr_info
* (" - same_frame_size height : %d\n", height);
*/
found = 1;
break;
} else {
/*if (print_header_info)
* pr_info
* ("1-bit same_frame_size[%d] read : 0\n", i);
*/
}
}
if (!found) {
/*vp9_read_frame_size(rb, &width, &height);*/
width = params->p.width;
height = params->p.height;
/*if (print_header_info)
* pr_info
* (" * 16-bits w read : %d (width : %d)\n",
* width, height);
*if (print_header_info)
* pr_info
* (" * 16-bits h read : %d (height : %d)\n",
* width, height);
*/
}
if (is_oversize(width, height)) {
pbi->error_frame_width = width;
pbi->error_frame_height = height;
vp9_print(pbi, 0, "%s, Error: Invalid frame size\n", __func__);
return -1;
}
pbi->error_frame_width = 0;
pbi->error_frame_height = 0;
params->p.width = width;
params->p.height = height;
WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, (height << 16) | width);
if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
/*if(cm->prev_fb_idx >= 0) release_unused_4k(cm->prev_fb_idx);
*cm->prev_fb_idx = cm->new_fb_idx;
*/
/* pr_info
* ("[DEBUG DEBUG]Before alloc_mmu,
* prev_fb_idx : %d, new_fb_idx : %d\r\n",
* cm->prev_fb_idx, cm->new_fb_idx);
*/
ret = vp9_alloc_mmu(pbi, cm->new_fb_idx,
params->p.width, params->p.height,
params->p.bit_depth, mmu_index_adr);
if (ret != 0) {
pr_err("can't alloc need mmu,idx %d\r\n",
cm->new_fb_idx);
return ret;
}
cm->cur_fb_idx_mmu = cm->new_fb_idx;
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable && (mmu_dw_index_adr != NULL)) {
ret = vp9_alloc_mmu_dw(pbi, cm->new_fb_idx,
params->p.width, params->p.height,
params->p.bit_depth, mmu_dw_index_adr);
if (ret != 0) {
pr_err("can't alloc need mmu dw,idx %d\r\n",
cm->new_fb_idx);
return ret;
}
}
#endif
/*Check to make sure at least one of frames that this frame references
*has valid dimensions.
*/
for (i = 0; i < REFS_PER_FRAME; ++i) {
struct RefBuffer_s * const ref_frame = &cm->frame_refs[i];
has_valid_ref_frame |=
valid_ref_frame_size(ref_frame->buf->y_crop_width,
ref_frame->buf->y_crop_height,
width, height);
}
if (!has_valid_ref_frame) {
pr_err("Error: Referenced frame has invalid size\r\n");
return -1;
}
#if 0
for (i = 0; i < REFS_PER_FRAME; ++i) {
struct RefBuffer_s * const ref_frame =
&cm->frame_refs[i];
if (!valid_ref_frame_img_fmt(
ref_frame->buf->bit_depth,
ref_frame->buf->subsampling_x,
ref_frame->buf->subsampling_y,
cm->bit_depth,
cm->subsampling_x,
cm->subsampling_y))
pr_err
("Referenced frame incompatible color fmt\r\n");
return -1;
}
#endif
resize_context_buffers(pbi, cm, width, height);
setup_display_size(cm, params, print_header_info);
#if 0
lock_buffer_pool(pool);
if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_DEC_BORDER_IN_PIXELS,
cm->byte_alignment,
&pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer,
pool->get_fb_cb,
pool->cb_priv)) {
unlock_buffer_pool(pool);
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffer");
}
unlock_buffer_pool(pool);
#else
/* porting */
ybf = get_frame_new_buffer(cm);
if (!ybf)
return -1;
ybf->y_crop_width = width;
ybf->y_crop_height = height;
ybf->bit_depth = params->p.bit_depth;
#endif
pool->frame_bufs[cm->new_fb_idx].buf.subsampling_x = cm->subsampling_x;
pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y;
pool->frame_bufs[cm->new_fb_idx].buf.bit_depth =
(unsigned int)cm->bit_depth;
pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space;
return ret;
}
static inline bool close_to(int a, int b, int m)
{
return (abs(a - b) < m) ? true : false;
}
#ifdef MULTI_INSTANCE_SUPPORT
static int vp9_print_cont(struct VP9Decoder_s *pbi,
int flag, const char *fmt, ...)
{
unsigned char buf[HEVC_PRINT_BUF];
int len = 0;
if (pbi == NULL ||
(flag == 0) ||
(debug & flag)) {
va_list args;
va_start(args, fmt);
vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
pr_debug("%s", buf);
va_end(args);
}
return 0;
}
static void trigger_schedule(struct VP9Decoder_s *pbi)
{
if (pbi->is_used_v4l) {
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
if (ctx->param_sets_from_ucode &&
!pbi->v4l_params_parsed)
vdec_v4l_write_frame_sync(ctx);
}
if (pbi->vdec_cb)
pbi->vdec_cb(hw_to_vdec(pbi), pbi->vdec_cb_arg);
}
static void reset_process_time(struct VP9Decoder_s *pbi)
{
if (pbi->start_process_time) {
unsigned process_time =
1000 * (jiffies - pbi->start_process_time) / HZ;
pbi->start_process_time = 0;
if (process_time > max_process_time[pbi->index])
max_process_time[pbi->index] = process_time;
}
}
static void start_process_time(struct VP9Decoder_s *pbi)
{
pbi->start_process_time = jiffies;
pbi->decode_timeout_count = 0;
pbi->last_lcu_idx = 0;
}
static void timeout_process(struct VP9Decoder_s *pbi)
{
pbi->timeout_num++;
amhevc_stop();
vp9_print(pbi,
0, "%s decoder timeout\n", __func__);
pbi->dec_result = DEC_RESULT_DONE;
reset_process_time(pbi);
vdec_schedule_work(&pbi->work);
}
static u32 get_valid_double_write_mode(struct VP9Decoder_s *pbi)
{
u32 dw = ((double_write_mode & 0x80000000) == 0) ?
pbi->double_write_mode :
(double_write_mode & 0x7fffffff);
if (dw & 0x20) {
if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T3)
&& ((dw & 0xf) == 2 || (dw & 0xf) == 3)) {
pr_info("MMU doueble write 1:4 not supported !!!\n");
dw = 0;
}
}
return dw;
}
static int get_double_write_mode(struct VP9Decoder_s *pbi)
{
u32 valid_dw_mode = get_valid_double_write_mode(pbi);
u32 dw;
int w, h;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *cur_pic_config;
if (pbi->is_used_v4l) {
unsigned int out;
vdec_v4l_get_dw_mode(pbi->v4l2_ctx, &out);
dw = out;
return dw;
}
/* mask for supporting double write value bigger than 0x100 */
if (valid_dw_mode & 0xffffff00) {
if (!cm->cur_frame)
return 1;/*no valid frame,*/
cur_pic_config = &cm->cur_frame->buf;
w = cur_pic_config->y_crop_width;
h = cur_pic_config->y_crop_height;
dw = 0x1; /*1:1*/
switch (valid_dw_mode) {
case 0x100:
if (w > 1920 && h > 1088)
dw = 0x4; /*1:2*/
break;
case 0x200:
if (w > 1920 && h > 1088)
dw = 0x2; /*1:4*/
break;
case 0x300:
if (w > 1280 && h > 720)
dw = 0x4; /*1:2*/
break;
default:
break;
}
return dw;
}
return valid_dw_mode;
}
/* for double write buf alloc */
static int get_double_write_mode_init(struct VP9Decoder_s *pbi)
{
u32 valid_dw_mode = get_valid_double_write_mode(pbi);
u32 dw;
int w = pbi->init_pic_w;
int h = pbi->init_pic_h;
dw = 0x1; /*1:1*/
switch (valid_dw_mode) {
case 0x100:
if (w > 1920 && h > 1088)
dw = 0x4; /*1:2*/
break;
case 0x200:
if (w > 1920 && h > 1088)
dw = 0x2; /*1:4*/
break;
case 0x300:
if (w > 1280 && h > 720)
dw = 0x4; /*1:2*/
break;
default:
dw = valid_dw_mode;
break;
}
return dw;
}
#endif
//#define MAX_4K_NUM 0x1200
/* return page number */
static int vp9_mmu_page_num(struct VP9Decoder_s *pbi,
int w, int h, int save_mode)
{
int picture_size;
int cur_mmu_4k_number, max_frame_num;
picture_size = compute_losless_comp_body_size(w, h, save_mode);
cur_mmu_4k_number = ((picture_size + (PAGE_SIZE - 1)) >> PAGE_SHIFT);
max_frame_num = (vvp9_frame_mmu_map_size(pbi) >> 2);
if (cur_mmu_4k_number > max_frame_num) {
pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n",
cur_mmu_4k_number, w, h);
return -1;
}
return cur_mmu_4k_number;
}
static struct internal_comp_buf* v4lfb_to_icomp_buf(
struct VP9Decoder_s *pbi,
struct vdec_v4l2_buffer *fb)
{
struct aml_video_dec_buf *aml_fb = NULL;
struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer);
return &v4l2_ctx->comp_bufs[aml_fb->internal_index];
}
static struct internal_comp_buf* index_to_icomp_buf(
struct VP9Decoder_s *pbi, int index)
{
struct aml_video_dec_buf *aml_fb = NULL;
struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
struct vdec_v4l2_buffer *fb = NULL;
fb = (struct vdec_v4l2_buffer *)
pbi->m_BUF[index].v4l_ref_buf_addr;
aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer);
return &v4l2_ctx->comp_bufs[aml_fb->internal_index];
}
int vp9_alloc_mmu(
struct VP9Decoder_s *pbi,
int cur_buf_idx,
int pic_width,
int pic_height,
unsigned short bit_depth,
unsigned int *mmu_index_adr)
{
int ret;
int bit_depth_10 = (bit_depth == VPX_BITS_10);
int cur_mmu_4k_number;
if (get_double_write_mode(pbi) == 0x10)
return 0;
if (bit_depth >= VPX_BITS_12) {
pbi->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW;
pr_err("fatal_error, un support bit depth 12!\n\n");
return -1;
}
cur_mmu_4k_number = vp9_mmu_page_num(pbi,
pic_width,
pic_height,
bit_depth_10);
if (cur_mmu_4k_number < 0)
return -1;
if (pbi->is_used_v4l) {
struct internal_comp_buf *ibuf =
index_to_icomp_buf(pbi, cur_buf_idx);
ret = decoder_mmu_box_alloc_idx(
ibuf->mmu_box,
ibuf->index,
ibuf->frame_buffer_size,
mmu_index_adr);
} else {
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START);
ret = decoder_mmu_box_alloc_idx(
pbi->mmu_box,
cur_buf_idx,
cur_mmu_4k_number,
mmu_index_adr);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END);
}
return ret;
}
#ifdef VP9_10B_MMU_DW
int vp9_alloc_mmu_dw(
struct VP9Decoder_s *pbi,
int cur_buf_idx,
int pic_width,
int pic_height,
unsigned short bit_depth,
unsigned int *mmu_index_adr)
{
int ret;
int bit_depth_10 = (bit_depth == VPX_BITS_10);
int cur_mmu_4k_number;
if (pbi->is_used_v4l)
return -1;
if (get_double_write_mode(pbi) == 0x10)
return 0;
if (bit_depth >= VPX_BITS_12) {
pbi->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW;
pr_err("fatal_error, un support bit depth 12!\n\n");
return -1;
}
cur_mmu_4k_number = vp9_mmu_page_num(pbi,
pic_width,
pic_height,
bit_depth_10);
if (cur_mmu_4k_number < 0)
return -1;
ret = decoder_mmu_box_alloc_idx(
pbi->mmu_box_dw,
cur_buf_idx,
cur_mmu_4k_number,
mmu_index_adr);
return ret;
}
#endif
#ifndef MV_USE_FIXED_BUF
static void dealloc_mv_bufs(struct VP9Decoder_s *pbi)
{
int i;
for (i = 0; i < MV_BUFFER_NUM; i++) {
if (pbi->m_mv_BUF[i].start_adr) {
if (debug)
pr_info(
"dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
i, pbi->m_mv_BUF[i].start_adr,
pbi->m_mv_BUF[i].size,
pbi->m_mv_BUF[i].used_flag);
decoder_bmmu_box_free_idx(
pbi->bmmu_box,
MV_BUFFER_IDX(i));
pbi->m_mv_BUF[i].start_adr = 0;
pbi->m_mv_BUF[i].size = 0;
pbi->m_mv_BUF[i].used_flag = 0;
}
}
}
static int alloc_mv_buf(struct VP9Decoder_s *pbi,
int i, int size)
{
int ret = 0;
if (pbi->m_mv_BUF[i].start_adr &&
size > pbi->m_mv_BUF[i].size) {
dealloc_mv_bufs(pbi);
} else if (pbi->m_mv_BUF[i].start_adr)
return 0;
if (decoder_bmmu_box_alloc_buf_phy
(pbi->bmmu_box,
MV_BUFFER_IDX(i), size,
DRIVER_NAME,
&pbi->m_mv_BUF[i].start_adr) < 0) {
pbi->m_mv_BUF[i].start_adr = 0;
ret = -1;
} else {
pbi->m_mv_BUF[i].size = size;
pbi->m_mv_BUF[i].used_flag = 0;
ret = 0;
if (debug) {
pr_info(
"MV Buffer %d: start_adr %px size %x\n",
i,
(void *)pbi->m_mv_BUF[i].start_adr,
pbi->m_mv_BUF[i].size);
}
}
return ret;
}
static int cal_mv_buf_size(struct VP9Decoder_s *pbi, int pic_width, int pic_height)
{
int lcu_size = 64; /*fixed 64*/
int pic_width_64 = (pic_width + 63) & (~0x3f);
int pic_height_32 = (pic_height + 31) & (~0x1f);
int pic_width_lcu = (pic_width_64 % lcu_size) ?
pic_width_64 / lcu_size + 1
: pic_width_64 / lcu_size;
int pic_height_lcu = (pic_height_32 % lcu_size) ?
pic_height_32 / lcu_size + 1
: pic_height_32 / lcu_size;
int lcu_total = pic_width_lcu * pic_height_lcu;
int size_a = lcu_total * 36 * 16;
int size_b = pic_width_lcu * 16 *
((pic_height_lcu >> 3) + (pic_height_lcu & 0x7));
int size = (size_a + size_b + 0xffff) &
(~0xffff);
return size;
}
static int init_mv_buf_list(struct VP9Decoder_s *pbi)
{
int i;
int ret = 0;
int count = MV_BUFFER_NUM;
int pic_width = pbi->init_pic_w;
int pic_height = pbi->init_pic_h;
int size = cal_mv_buf_size(pbi, pic_width, pic_height);
if (mv_buf_dynamic_alloc)
return 0;
if (mv_buf_margin > 0)
count = REF_FRAMES + mv_buf_margin;
if (pbi->init_pic_w > 2048 && pbi->init_pic_h > 1088)
count = REF_FRAMES_4K + mv_buf_margin;
if (debug) {
pr_info("%s w:%d, h:%d, count: %d\n",
__func__, pbi->init_pic_w, pbi->init_pic_h, count);
}
for (i = 0;
i < count && i < MV_BUFFER_NUM; i++) {
if (alloc_mv_buf(pbi, i, size) < 0) {
ret = -1;
break;
}
}
return ret;
}
static int get_mv_buf(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config)
{
int i;
int ret = -1;
if (mv_buf_dynamic_alloc) {
union param_u *params = &pbi->vp9_param;
int size = cal_mv_buf_size(pbi,
params->p.width, params->p.height);
for (i = 0; i < MV_BUFFER_NUM; i++) {
if (pbi->m_mv_BUF[i].start_adr == 0) {
ret = i;
break;
}
}
if (i == MV_BUFFER_NUM) {
pr_info(
"%s: Error, mv buf MV_BUFFER_NUM is not enough\n",
__func__);
return ret;
}
if (alloc_mv_buf(pbi, ret, size) >= 0) {
pic_config->mv_buf_index = ret;
pic_config->mpred_mv_wr_start_addr =
(pbi->m_mv_BUF[ret].start_adr + 0xffff) &
(~0xffff);
pic_config->mv_size = size;
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info(
"%s alloc => %d (%ld) size 0x%x\n",
__func__, ret,
pic_config->mpred_mv_wr_start_addr,
pic_config->mv_size);
} else {
pr_info(
"%s: Error, mv buf alloc fail\n",
__func__);
}
return ret;
}
for (i = 0; i < MV_BUFFER_NUM; i++) {
if (pbi->m_mv_BUF[i].start_adr &&
pbi->m_mv_BUF[i].used_flag == 0) {
pbi->m_mv_BUF[i].used_flag = 1;
ret = i;
break;
}
}
if (ret >= 0) {
pic_config->mv_buf_index = ret;
pic_config->mpred_mv_wr_start_addr =
(pbi->m_mv_BUF[ret].start_adr + 0xffff) &
(~0xffff);
pic_config->mv_size = pbi->m_mv_BUF[ret].size;
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info(
"%s => %d (%lx) size 0x%x\n",
__func__, ret,
pic_config->mpred_mv_wr_start_addr,
pic_config->mv_size);
} else {
pr_info(
"%s: Error, mv buf is not enough\n",
__func__);
}
return ret;
}
static void put_mv_buf(struct VP9Decoder_s *pbi,
int *mv_buf_index)
{
int i = *mv_buf_index;
if (i >= MV_BUFFER_NUM) {
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info(
"%s: index %d beyond range\n",
__func__, i);
return;
}
if (mv_buf_dynamic_alloc) {
if (pbi->m_mv_BUF[i].start_adr) {
if (debug)
pr_info(
"dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
i, pbi->m_mv_BUF[i].start_adr,
pbi->m_mv_BUF[i].size,
pbi->m_mv_BUF[i].used_flag);
decoder_bmmu_box_free_idx(
pbi->bmmu_box,
MV_BUFFER_IDX(i));
pbi->m_mv_BUF[i].start_adr = 0;
pbi->m_mv_BUF[i].size = 0;
pbi->m_mv_BUF[i].used_flag = 0;
}
*mv_buf_index = -1;
return;
}
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info(
"%s(%d): used_flag(%d)\n",
__func__, i,
pbi->m_mv_BUF[i].used_flag);
*mv_buf_index = -1;
if (pbi->m_mv_BUF[i].start_adr &&
pbi->m_mv_BUF[i].used_flag)
pbi->m_mv_BUF[i].used_flag = 0;
}
static void put_un_used_mv_bufs(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
int i;
for (i = 0; i < pbi->used_buf_num; ++i) {
#if 0
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.index != -1) &&
(frame_bufs[i].buf.mv_buf_index >= 0)
)
#else
if ((&frame_bufs[i] != cm->prev_frame) &&
(frame_bufs[i].buf.index != -1) &&
(frame_bufs[i].buf.mv_buf_index >= 0)
)
#endif
put_mv_buf(pbi, &frame_bufs[i].buf.mv_buf_index);
}
}
#ifdef SUPPORT_FB_DECODING
static bool mv_buf_available(struct VP9Decoder_s *pbi)
{
int i;
bool ret = 0;
for (i = 0; i < MV_BUFFER_NUM; i++) {
if (pbi->m_mv_BUF[i].start_adr &&
pbi->m_mv_BUF[i].used_flag == 0) {
ret = 1;
break;
}
}
return ret;
}
#endif
#endif
#ifdef SUPPORT_FB_DECODING
static void init_stage_buf(struct VP9Decoder_s *pbi)
{
uint i;
for (i = 0; i < STAGE_MAX_BUFFERS
&& i < stage_buf_num; i++) {
pbi->stage_bufs[i] =
vmalloc(sizeof(struct stage_buf_s));
if (pbi->stage_bufs[i] == NULL) {
vp9_print(pbi,
0, "%s vmalloc fail\n", __func__);
break;
}
pbi->stage_bufs[i]->index = i;
}
pbi->used_stage_buf_num = i;
pbi->s1_pos = 0;
pbi->s2_pos = 0;
pbi->s1_buf = NULL;
pbi->s2_buf = NULL;
pbi->s1_mv_buf_index = FRAME_BUFFERS;
pbi->s1_mv_buf_index_pre = FRAME_BUFFERS;
pbi->s1_mv_buf_index_pre_pre = FRAME_BUFFERS;
if (pbi->used_stage_buf_num > 0)
vp9_print(pbi,
0, "%s 2 stage decoding buf %d\n",
__func__,
pbi->used_stage_buf_num);
}
static void uninit_stage_buf(struct VP9Decoder_s *pbi)
{
int i;
for (i = 0; i < pbi->used_stage_buf_num; i++) {
if (pbi->stage_bufs[i])
vfree(pbi->stage_bufs[i]);
pbi->stage_bufs[i] = NULL;
}
pbi->used_stage_buf_num = 0;
pbi->s1_pos = 0;
pbi->s2_pos = 0;
pbi->s1_buf = NULL;
pbi->s2_buf = NULL;
}
static int get_s1_buf(
struct VP9Decoder_s *pbi)
{
struct stage_buf_s *buf = NULL;
int ret = -1;
int buf_page_num = MAX_STAGE_PAGE_NUM;
int next_s1_pos = pbi->s1_pos + 1;
if (next_s1_pos >= pbi->used_stage_buf_num)
next_s1_pos = 0;
if (next_s1_pos == pbi->s2_pos) {
pbi->s1_buf = NULL;
return ret;
}
buf = pbi->stage_bufs[pbi->s1_pos];
ret = decoder_mmu_box_alloc_idx(
pbi->mmu_box,
buf->index,
buf_page_num,
pbi->stage_mmu_map_addr);
if (ret < 0) {
vp9_print(pbi, 0,
"%s decoder_mmu_box_alloc fail for index %d (s1_pos %d s2_pos %d)\n",
__func__, buf->index,
pbi->s1_pos, pbi->s2_pos);
buf = NULL;
} else {
vp9_print(pbi, VP9_DEBUG_2_STAGE,
"%s decoder_mmu_box_alloc %d page for index %d (s1_pos %d s2_pos %d)\n",
__func__, buf_page_num, buf->index,
pbi->s1_pos, pbi->s2_pos);
}
pbi->s1_buf = buf;
return ret;
}
static void inc_s1_pos(struct VP9Decoder_s *pbi)
{
struct stage_buf_s *buf =
pbi->stage_bufs[pbi->s1_pos];
int used_page_num =
#ifdef FB_DECODING_TEST_SCHEDULE
MAX_STAGE_PAGE_NUM/2;
#else
(READ_VREG(HEVC_ASSIST_HED_FB_W_CTL) >> 16);
#endif
decoder_mmu_box_free_idx_tail(pbi->mmu_box,
FRAME_BUFFERS + buf->index, used_page_num);
pbi->s1_pos++;
if (pbi->s1_pos >= pbi->used_stage_buf_num)
pbi->s1_pos = 0;
vp9_print(pbi, VP9_DEBUG_2_STAGE,
"%s (used_page_num %d) for index %d (s1_pos %d s2_pos %d)\n",
__func__, used_page_num, buf->index,
pbi->s1_pos, pbi->s2_pos);
}
#define s2_buf_available(pbi) (pbi->s1_pos != pbi->s2_pos)
static int get_s2_buf(
struct VP9Decoder_s *pbi)
{
int ret = -1;
struct stage_buf_s *buf = NULL;
if (s2_buf_available(pbi)) {
buf = pbi->stage_bufs[pbi->s2_pos];
vp9_print(pbi, VP9_DEBUG_2_STAGE,
"%s for index %d (s1_pos %d s2_pos %d)\n",
__func__, buf->index,
pbi->s1_pos, pbi->s2_pos);
pbi->s2_buf = buf;
ret = 0;
}
return ret;
}
static void inc_s2_pos(struct VP9Decoder_s *pbi)
{
struct stage_buf_s *buf =
pbi->stage_bufs[pbi->s2_pos];
decoder_mmu_box_free_idx(pbi->mmu_box,
FRAME_BUFFERS + buf->index);
pbi->s2_pos++;
if (pbi->s2_pos >= pbi->used_stage_buf_num)
pbi->s2_pos = 0;
vp9_print(pbi, VP9_DEBUG_2_STAGE,
"%s for index %d (s1_pos %d s2_pos %d)\n",
__func__, buf->index,
pbi->s1_pos, pbi->s2_pos);
}
static int get_free_stage_buf_num(struct VP9Decoder_s *pbi)
{
int num;
if (pbi->s1_pos >= pbi->s2_pos)
num = pbi->used_stage_buf_num -
(pbi->s1_pos - pbi->s2_pos) - 1;
else
num = (pbi->s2_pos - pbi->s1_pos) - 1;
return num;
}
#ifndef FB_DECODING_TEST_SCHEDULE
static DEFINE_SPINLOCK(fb_core_spin_lock);
static u8 is_s2_decoding_finished(struct VP9Decoder_s *pbi)
{
/* to do: VLSI review
completion of last LCU decoding in BACK
*/
return 1;
}
static void start_s1_decoding(struct VP9Decoder_s *pbi)
{
/* to do: VLSI review
after parser, how to start LCU decoding in BACK
*/
}
static void fb_reset_core(struct vdec_s *vdec, u32 mask)
{
/* to do: VLSI review
1. how to disconnect DMC for FRONT and BACK
2. reset bit 13, 24, FRONT or BACK ??
*/
unsigned long flags;
u32 reset_bits = 0;
if (mask & HW_MASK_FRONT)
WRITE_VREG(HEVC_STREAM_CONTROL, 0);
spin_lock_irqsave(&fb_core_spin_lock, flags);
codec_dmcbus_write(DMC_REQ_CTRL,
codec_dmcbus_read(DMC_REQ_CTRL) & (~(1 << 4)));
spin_unlock_irqrestore(&fb_core_spin_lock, flags);
while (!(codec_dmcbus_read(DMC_CHAN_STS)
& (1 << 4)))
;
if ((mask & HW_MASK_FRONT) &&
input_frame_based(vdec))
WRITE_VREG(HEVC_STREAM_CONTROL, 0);
/*
* 2: assist
* 3: parser
* 4: parser_state
* 8: dblk
* 11:mcpu
* 12:ccpu
* 13:ddr
* 14:iqit
* 15:ipp
* 17:qdct
* 18:mpred
* 19:sao
* 24:hevc_afifo
*/
if (mask & HW_MASK_FRONT) {
reset_bits =
(1<<3)|(1<<4)|(1<<11)|
(1<<12)|(1<<18);
}
if (mask & HW_MASK_BACK) {
reset_bits =
(1<<8)|(1<<13)|(1<<14)|(1<<15)|
(1<<17)|(1<<19)|(1<<24);
}
WRITE_VREG(DOS_SW_RESET3, reset_bits);
#if 0
(1<<3)|(1<<4)|(1<<8)|(1<<11)|
(1<<12)|(1<<13)|(1<<14)|(1<<15)|
(1<<17)|(1<<18)|(1<<19)|(1<<24);
#endif
WRITE_VREG(DOS_SW_RESET3, 0);
spin_lock_irqsave(&fb_core_spin_lock, flags);
codec_dmcbus_write(DMC_REQ_CTRL,
codec_dmcbus_read(DMC_REQ_CTRL) | (1 << 4));
spin_unlock_irqrestore(&fb_core_spin_lock, flags);
}
#endif
#endif
static void init_pic_list_hw(struct VP9Decoder_s *pbi);
static int get_free_fb(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
int i;
unsigned long flags;
lock_buffer_pool(cm->buffer_pool, flags);
if (debug & VP9_DEBUG_BUFMGR_MORE) {
for (i = 0; i < pbi->used_buf_num; ++i) {
pr_info("%s:%d, ref_count %d vf_ref %d index %d\r\n",
__func__, i, frame_bufs[i].ref_count,
frame_bufs[i].buf.vf_ref,
frame_bufs[i].buf.index);
}
}
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0) &&
(frame_bufs[i].buf.index != -1) &&
(cm->cur_frame != &frame_bufs[i])
)
break;
}
if (i != pbi->used_buf_num) {
frame_bufs[i].ref_count = 1;
/*pr_info("[MMU DEBUG 1] set ref_count[%d] : %d\r\n",
i, frame_bufs[i].ref_count);*/
} else {
/* Reset i to be INVALID_IDX to indicate
no free buffer found*/
i = INVALID_IDX;
}
unlock_buffer_pool(cm->buffer_pool, flags);
return i;
}
static void update_hide_frame_timestamp(struct VP9Decoder_s *pbi)
{
struct RefCntBuffer_s *const frame_bufs =
pbi->common.buffer_pool->frame_bufs;
int i;
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((!frame_bufs[i].show_frame) &&
(!frame_bufs[i].buf.vf_ref) &&
(frame_bufs[i].buf.BUF_index != -1)) {
frame_bufs[i].buf.timestamp = pbi->chunk->timestamp;
vp9_print(pbi, VP9_DEBUG_OUT_PTS,
"%s, update %d hide frame ts: %lld\n",
__func__, i, frame_bufs[i].buf.timestamp);
}
}
}
static int get_free_fb_idx(struct VP9Decoder_s *pbi)
{
int i;
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0))
break;
}
return i;
}
static int v4l_get_free_fb(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
struct aml_vcodec_ctx * v4l = pbi->v4l2_ctx;
struct v4l_buff_pool *pool = &v4l->cap_pool;
struct PIC_BUFFER_CONFIG_s *pic = NULL;
struct PIC_BUFFER_CONFIG_s *free_pic = NULL;
ulong flags;
int idx, i;
lock_buffer_pool(cm->buffer_pool, flags);
for (i = 0; i < pool->in; ++i) {
u32 state = (pool->seq[i] >> 16);
u32 index = (pool->seq[i] & 0xffff);
switch (state) {
case V4L_CAP_BUFF_IN_DEC:
pic = &frame_bufs[i].buf;
if ((frame_bufs[i].ref_count == 0) &&
(pic->vf_ref == 0) &&
(pic->index != -1) &&
pic->cma_alloc_addr) {
free_pic = pic;
}
break;
case V4L_CAP_BUFF_IN_M2M:
idx = get_free_fb_idx(pbi);
pic = &frame_bufs[idx].buf;
pic->y_crop_width = pbi->frame_width;
pic->y_crop_height = pbi->frame_height;
pbi->buffer_wrap[idx] = index;
if (!v4l_alloc_and_config_pic(pbi, pic)) {
set_canvas(pbi, pic);
init_pic_list_hw(pbi);
free_pic = pic;
}
break;
default:
break;
}
if (free_pic) {
frame_bufs[i].ref_count = 1;
break;
}
}
if (free_pic && pbi->chunk) {
free_pic->timestamp = pbi->chunk->timestamp;
update_hide_frame_timestamp(pbi);
}
unlock_buffer_pool(cm->buffer_pool, flags);
if (free_pic) {
struct vdec_v4l2_buffer *fb =
(struct vdec_v4l2_buffer *)
pbi->m_BUF[i].v4l_ref_buf_addr;
fb->status = FB_ST_DECODER;
}
if (debug & VP9_DEBUG_OUT_PTS) {
if (free_pic) {
pr_debug("%s, idx: %d, ts: %lld\n",
__func__, free_pic->index, free_pic->timestamp);
} else {
pr_debug("%s, vp9 get free pic null\n", __func__);
}
}
return free_pic ? free_pic->index : INVALID_IDX;
}
static int get_free_buf_count(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
int i, free_buf_count = 0;
if (pbi->is_used_v4l) {
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0) &&
frame_bufs[i].buf.cma_alloc_addr) {
free_buf_count++;
}
}
if (ctx->cap_pool.dec < pbi->used_buf_num) {
free_buf_count +=
v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx);
}
/* trigger to parse head data. */
if (!pbi->v4l_params_parsed) {
free_buf_count = pbi->run_ready_min_buf_num;
}
} else {
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0) &&
(frame_bufs[i].buf.index != -1))
free_buf_count++;
}
}
return free_buf_count;
}
static void decrease_ref_count(int idx, struct RefCntBuffer_s *const frame_bufs,
struct BufferPool_s *const pool)
{
if (idx >= 0) {
--frame_bufs[idx].ref_count;
/*pr_info("[MMU DEBUG 7] dec ref_count[%d] : %d\r\n", idx,
* frame_bufs[idx].ref_count);
*/
/*A worker may only get a free framebuffer index when
*calling get_free_fb. But the private buffer is not set up
*until finish decoding header. So any error happens during
*decoding header, the frame_bufs will not have valid priv
*buffer.
*/
if (frame_bufs[idx].ref_count == 0 &&
frame_bufs[idx].raw_frame_buffer.priv)
vp9_release_frame_buffer
(&frame_bufs[idx].raw_frame_buffer);
}
}
static void generate_next_ref_frames(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
struct BufferPool_s *const pool = cm->buffer_pool;
int mask, ref_index = 0;
unsigned long flags;
/* Generate next_ref_frame_map.*/
lock_buffer_pool(pool, flags);
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
if (mask & 1) {
cm->next_ref_frame_map[ref_index] = cm->new_fb_idx;
++frame_bufs[cm->new_fb_idx].ref_count;
/*pr_info("[MMU DEBUG 4] inc ref_count[%d] : %d\r\n",
*cm->new_fb_idx, frame_bufs[cm->new_fb_idx].ref_count);
*/
} else
cm->next_ref_frame_map[ref_index] =
cm->ref_frame_map[ref_index];
/* Current thread holds the reference frame.*/
if (cm->ref_frame_map[ref_index] >= 0) {
++frame_bufs[cm->ref_frame_map[ref_index]].ref_count;
/*pr_info
*("[MMU DEBUG 5] inc ref_count[%d] : %d\r\n",
*cm->ref_frame_map[ref_index],
*frame_bufs[cm->ref_frame_map[ref_index]].ref_count);
*/
}
++ref_index;
}
for (; ref_index < REF_FRAMES; ++ref_index) {
cm->next_ref_frame_map[ref_index] =
cm->ref_frame_map[ref_index];
/* Current thread holds the reference frame.*/
if (cm->ref_frame_map[ref_index] >= 0) {
++frame_bufs[cm->ref_frame_map[ref_index]].ref_count;
/*pr_info("[MMU DEBUG 6] inc ref_count[%d] : %d\r\n",
*cm->ref_frame_map[ref_index],
*frame_bufs[cm->ref_frame_map[ref_index]].ref_count);
*/
}
}
unlock_buffer_pool(pool, flags);
return;
}
static void refresh_ref_frames(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct BufferPool_s *pool = cm->buffer_pool;
struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
int mask, ref_index = 0;
unsigned long flags;
lock_buffer_pool(pool, flags);
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
const int old_idx = cm->ref_frame_map[ref_index];
/*Current thread releases the holding of reference frame.*/
decrease_ref_count(old_idx, frame_bufs, pool);
/*Release the reference frame in reference map.*/
if ((mask & 1) && old_idx >= 0)
decrease_ref_count(old_idx, frame_bufs, pool);
cm->ref_frame_map[ref_index] =
cm->next_ref_frame_map[ref_index];
++ref_index;
}
/*Current thread releases the holding of reference frame.*/
for (; ref_index < REF_FRAMES && !cm->show_existing_frame;
++ref_index) {
const int old_idx = cm->ref_frame_map[ref_index];
decrease_ref_count(old_idx, frame_bufs, pool);
cm->ref_frame_map[ref_index] =
cm->next_ref_frame_map[ref_index];
}
unlock_buffer_pool(pool, flags);
return;
}
int vp9_bufmgr_process(struct VP9Decoder_s *pbi, union param_u *params)
{
struct VP9_Common_s *const cm = &pbi->common;
struct BufferPool_s *pool = cm->buffer_pool;
struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
struct PIC_BUFFER_CONFIG_s *pic = NULL;
int i;
int ret;
pbi->ready_for_new_data = 0;
if ((pbi->has_keyframe == 0) &&
(params->p.frame_type != KEY_FRAME) &&
(!params->p.intra_only)){
on_no_keyframe_skiped++;
pr_info("vp9_bufmgr_process no key frame return\n");
return -2;
}
pbi->has_keyframe = 1;
on_no_keyframe_skiped = 0;
#if 0
if (pbi->mmu_enable) {
if (!pbi->m_ins_flag)
pbi->used_4k_num = (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
if (cm->prev_fb_idx >= 0) {
decoder_mmu_box_free_idx_tail(pbi->mmu_box,
cm->prev_fb_idx, pbi->used_4k_num);
}
}
#endif
if (cm->new_fb_idx >= 0
&& frame_bufs[cm->new_fb_idx].ref_count == 0){
vp9_release_frame_buffer
(&frame_bufs[cm->new_fb_idx].raw_frame_buffer);
}
/*pr_info("Before get_free_fb, prev_fb_idx : %d, new_fb_idx : %d\r\n",
cm->prev_fb_idx, cm->new_fb_idx);*/
#ifndef MV_USE_FIXED_BUF
put_un_used_mv_bufs(pbi);
if (debug & VP9_DEBUG_BUFMGR_DETAIL)
dump_pic_list(pbi);
#endif
cm->new_fb_idx = pbi->is_used_v4l ?
v4l_get_free_fb(pbi) :
get_free_fb(pbi);
if (cm->new_fb_idx == INVALID_IDX) {
pr_info("get_free_fb error\r\n");
return -1;
}
#ifndef MV_USE_FIXED_BUF
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num == 0) {
#endif
if (get_mv_buf(pbi,
&pool->frame_bufs[cm->new_fb_idx].
buf) < 0) {
pr_info("get_mv_buf fail\r\n");
return -1;
}
if (debug & VP9_DEBUG_BUFMGR_DETAIL)
dump_pic_list(pbi);
#ifdef SUPPORT_FB_DECODING
}
#endif
#endif
cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
/*if (debug & VP9_DEBUG_BUFMGR)
pr_info("[VP9 DEBUG]%s(get_free_fb): %d\r\n", __func__,
cm->new_fb_idx);*/
pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
if (pbi->mmu_enable) {
/* moved to after picture size ready
*alloc_mmu(cm, params->p.width, params->p.height,
*params->p.bit_depth, pbi->frame_mmu_map_addr);
*/
cm->prev_fb_idx = cm->new_fb_idx;
}
/*read_uncompressed_header()*/
cm->last_frame_type = cm->frame_type;
cm->last_intra_only = cm->intra_only;
cm->profile = params->p.profile;
if (cm->profile >= MAX_PROFILES) {
pr_err("Error: Unsupported profile %d\r\n", cm->profile);
return -1;
}
cm->show_existing_frame = params->p.show_existing_frame;
if (cm->show_existing_frame) {
/* Show an existing frame directly.*/
int frame_to_show_idx = params->p.frame_to_show_idx;
int frame_to_show;
unsigned long flags;
if (frame_to_show_idx >= REF_FRAMES) {
pr_info("frame_to_show_idx %d exceed max index\r\n",
frame_to_show_idx);
return -1;
}
frame_to_show = cm->ref_frame_map[frame_to_show_idx];
/*pr_info("frame_to_show %d\r\n", frame_to_show);*/
lock_buffer_pool(pool, flags);
if (frame_to_show < 0 ||
frame_bufs[frame_to_show].ref_count < 1) {
unlock_buffer_pool(pool, flags);
pr_err
("Error:Buffer %d does not contain a decoded frame",
frame_to_show);
return -1;
}
ref_cnt_fb(frame_bufs, &cm->new_fb_idx, frame_to_show);
unlock_buffer_pool(pool, flags);
pbi->refresh_frame_flags = 0;
/*cm->lf.filter_level = 0;*/
cm->show_frame = 1;
cm->cur_frame->show_frame = 1;
/*
*if (pbi->frame_parallel_decode) {
* for (i = 0; i < REF_FRAMES; ++i)
* cm->next_ref_frame_map[i] =
* cm->ref_frame_map[i];
*}
*/
/* do not decode, search next start code */
return 1;
}
cm->frame_type = params->p.frame_type;
cm->show_frame = params->p.show_frame;
cm->bit_depth = params->p.bit_depth;
cm->error_resilient_mode = params->p.error_resilient_mode;
cm->cur_frame->show_frame = cm->show_frame;
if (cm->frame_type == KEY_FRAME) {
pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
for (i = 0; i < REFS_PER_FRAME; ++i) {
cm->frame_refs[i].idx = INVALID_IDX;
cm->frame_refs[i].buf = NULL;
}
#ifdef VP9_10B_MMU_DW
ret = setup_frame_size(pbi,
cm, params,
pbi->frame_mmu_map_addr,
pbi->frame_mmu_dw_map_addr,
print_header_info);
#else
ret = setup_frame_size(pbi,
cm, params,
pbi->frame_mmu_map_addr,
NULL,
print_header_info);
#endif
if (ret)
return -1;
if (pbi->need_resync) {
memset(&cm->ref_frame_map, -1,
sizeof(cm->ref_frame_map));
pbi->need_resync = 0;
}
} else {
cm->intra_only = cm->show_frame ? 0 : params->p.intra_only;
/*if (print_header_info) {
* if (cm->show_frame)
* pr_info
* ("intra_only set to 0 because of show_frame\n");
* else
* pr_info
* ("1-bit intra_only read: %d\n", cm->intra_only);
*}
*/
cm->reset_frame_context = cm->error_resilient_mode ?
0 : params->p.reset_frame_context;
if (print_header_info) {
if (cm->error_resilient_mode)
pr_info
("reset to 0 error_resilient_mode\n");
else
pr_info
(" * 2-bits reset_frame_context read : %d\n",
cm->reset_frame_context);
}
if (cm->intra_only) {
if (cm->profile > PROFILE_0) {
/*read_bitdepth_colorspace_sampling(cm,
* rb, print_header_info);
*/
} else {
/*NOTE: The intra-only frame header
*does not include the specification
*of either the color format or
*color sub-sampling
*in profile 0. VP9 specifies that the default
*color format should be YUV 4:2:0 in this
*case (normative).
*/
cm->color_space = VPX_CS_BT_601;
cm->subsampling_y = cm->subsampling_x = 1;
cm->bit_depth = VPX_BITS_8;
cm->use_highbitdepth = 0;
}
pbi->refresh_frame_flags =
params->p.refresh_frame_flags;
/*if (print_header_info)
* pr_info("*%d-bits refresh_frame read:0x%x\n",
* REF_FRAMES, pbi->refresh_frame_flags);
*/
#ifdef VP9_10B_MMU_DW
ret = setup_frame_size(pbi,
cm,
params,
pbi->frame_mmu_map_addr,
pbi->frame_mmu_dw_map_addr,
print_header_info);
#else
ret = setup_frame_size(pbi,
cm,
params,
pbi->frame_mmu_map_addr,
NULL,
print_header_info);
#endif
if (ret)
return -1;
if (pbi->need_resync) {
memset(&cm->ref_frame_map, -1,
sizeof(cm->ref_frame_map));
pbi->need_resync = 0;
}
} else if (pbi->need_resync != 1) { /* Skip if need resync */
pbi->refresh_frame_flags =
params->p.refresh_frame_flags;
if (print_header_info)
pr_info
("*%d-bits refresh_frame read:0x%x\n",
REF_FRAMES, pbi->refresh_frame_flags);
for (i = 0; i < REFS_PER_FRAME; ++i) {
const int ref =
(params->p.ref_info >>
(((REFS_PER_FRAME-i-1)*4)+1))
& 0x7;
const int idx =
cm->ref_frame_map[ref];
struct RefBuffer_s * const ref_frame =
&cm->frame_refs[i];
if (print_header_info)
pr_info("*%d-bits ref[%d]read:%d\n",
REF_FRAMES_LOG2, i, ref);
ref_frame->idx = idx;
ref_frame->buf = &frame_bufs[idx].buf;
cm->ref_frame_sign_bias[LAST_FRAME + i]
= (params->p.ref_info >>
((REFS_PER_FRAME-i-1)*4)) & 0x1;
if (print_header_info)
pr_info("1bit ref_frame_sign_bias");
/*pr_info
*("%dread: %d\n",
*LAST_FRAME+i,
*cm->ref_frame_sign_bias
*[LAST_FRAME + i]);
*/
/*pr_info
*("[VP9 DEBUG]%s(get ref):%d\r\n",
*__func__, ref_frame->idx);
*/
}
#ifdef VP9_10B_MMU_DW
ret = setup_frame_size_with_refs(
pbi,
cm,
params,
pbi->frame_mmu_map_addr,
pbi->frame_mmu_dw_map_addr,
print_header_info);
#else
ret = setup_frame_size_with_refs(
pbi,
cm,
params,
pbi->frame_mmu_map_addr,
NULL,
print_header_info);
#endif
if (ret)
return -1;
for (i = 0; i < REFS_PER_FRAME; ++i) {
/*struct RefBuffer_s *const ref_buf =
*&cm->frame_refs[i];
*/
/* to do:
*vp9_setup_scale_factors_for_frame
*/
}
}
}
pic = get_frame_new_buffer(cm);
if (!pic)
return -1;
pic->bit_depth = cm->bit_depth;
pic->color_space = cm->color_space;
pic->slice_type = cm->frame_type;
if (pbi->need_resync) {
pr_err
("Error: Keyframe/intra-only frame required to reset\r\n");
return -1;
}
generate_next_ref_frames(pbi);
pbi->hold_ref_buf = 1;
#if 0
if (frame_is_intra_only(cm) || cm->error_resilient_mode)
vp9_setup_past_independence(cm);
setup_loopfilter(&cm->lf, rb, print_header_info);
setup_quantization(cm, &pbi->mb, rb, print_header_info);
setup_segmentation(&cm->seg, rb, print_header_info);
setup_segmentation_dequant(cm, print_header_info);
setup_tile_info(cm, rb, print_header_info);
sz = vp9_rb_read_literal(rb, 16);
if (print_header_info)
pr_info(" * 16-bits size read : %d (0x%x)\n", sz, sz);
if (sz == 0)
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
"Invalid header size");
#endif
/*end read_uncompressed_header()*/
cm->use_prev_frame_mvs = !cm->error_resilient_mode &&
cm->width == cm->last_width &&
cm->height == cm->last_height &&
!cm->last_intra_only &&
cm->last_show_frame &&
(cm->last_frame_type != KEY_FRAME);
/*pr_info
*("set use_prev_frame_mvs to %d (last_width %d last_height %d",
*cm->use_prev_frame_mvs, cm->last_width, cm->last_height);
*pr_info
*(" last_intra_only %d last_show_frame %d last_frame_type %d)\n",
*cm->last_intra_only, cm->last_show_frame, cm->last_frame_type);
*/
if (pbi->enable_fence && cm->show_frame) {
struct PIC_BUFFER_CONFIG_s *pic = &cm->cur_frame->buf;
struct vdec_s *vdec = hw_to_vdec(pbi);
/* create fence for each buffers. */
ret = vdec_timeline_create_fence(vdec->sync);
if (ret < 0)
return ret;
pic->fence = vdec->sync->fence;
pic->bit_depth = cm->bit_depth;
pic->slice_type = cm->frame_type;
pic->stream_offset = pbi->pre_stream_offset;
if (pbi->chunk) {
pic->pts = pbi->chunk->pts;
pic->pts64 = pbi->chunk->pts64;
pic->timestamp = pbi->chunk->timestamp;
}
/* post video vframe. */
prepare_display_buf(pbi, pic);
}
return 0;
}
void swap_frame_buffers(struct VP9Decoder_s *pbi)
{
int ref_index = 0;
struct VP9_Common_s *const cm = &pbi->common;
struct BufferPool_s *const pool = cm->buffer_pool;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
unsigned long flags;
refresh_ref_frames(pbi);
pbi->hold_ref_buf = 0;
cm->frame_to_show = get_frame_new_buffer(cm);
if (cm->frame_to_show) {
/*if (!pbi->frame_parallel_decode || !cm->show_frame) {*/
lock_buffer_pool(pool, flags);
--frame_bufs[cm->new_fb_idx].ref_count;
/*pr_info("[MMU DEBUG 8] dec ref_count[%d] : %d\r\n", cm->new_fb_idx,
* frame_bufs[cm->new_fb_idx].ref_count);
*/
unlock_buffer_pool(pool, flags);
/*}*/
}
/*Invalidate these references until the next frame starts.*/
for (ref_index = 0; ref_index < 3; ref_index++)
cm->frame_refs[ref_index].idx = -1;
}
#if 0
static void check_resync(vpx_codec_alg_priv_t *const ctx,
const struct VP9Decoder_s *const pbi)
{
/* Clear resync flag if worker got a key frame or intra only frame.*/
if (ctx->need_resync == 1 && pbi->need_resync == 0 &&
(pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME))
ctx->need_resync = 0;
}
#endif
int vp9_get_raw_frame(struct VP9Decoder_s *pbi, struct PIC_BUFFER_CONFIG_s *sd)
{
struct VP9_Common_s *const cm = &pbi->common;
int ret = -1;
if (pbi->ready_for_new_data == 1)
return ret;
pbi->ready_for_new_data = 1;
/* no raw frame to show!!! */
if (!cm->show_frame)
return ret;
/* may not be get buff in v4l2 */
if (!cm->frame_to_show)
return ret;
pbi->ready_for_new_data = 1;
*sd = *cm->frame_to_show;
ret = 0;
return ret;
}
int vp9_bufmgr_init(struct VP9Decoder_s *pbi, struct BuffInfo_s *buf_spec_i,
struct buff_s *mc_buf_i) {
struct VP9_Common_s *cm = &pbi->common;
/*memset(pbi, 0, sizeof(struct VP9Decoder_s));*/
pbi->frame_count = 0;
pbi->pic_count = 0;
pbi->pre_stream_offset = 0;
cm->buffer_pool = &pbi->vp9_buffer_pool;
spin_lock_init(&cm->buffer_pool->lock);
cm->prev_fb_idx = INVALID_IDX;
cm->new_fb_idx = INVALID_IDX;
pbi->used_4k_num = -1;
cm->cur_fb_idx_mmu = INVALID_IDX;
pr_debug
("After vp9_bufmgr_init, prev_fb_idx : %d, new_fb_idx : %d\r\n",
cm->prev_fb_idx, cm->new_fb_idx);
pbi->need_resync = 1;
/* Initialize the references to not point to any frame buffers.*/
memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));
cm->current_video_frame = 0;
pbi->ready_for_new_data = 1;
/* private init */
pbi->work_space_buf = buf_spec_i;
if (!pbi->mmu_enable)
pbi->mc_buf = mc_buf_i;
pbi->rpm_addr = NULL;
pbi->lmem_addr = NULL;
pbi->use_cma_flag = 0;
pbi->decode_idx = 0;
pbi->slice_idx = 0;
/*int m_uiMaxCUWidth = 1<<7;*/
/*int m_uiMaxCUHeight = 1<<7;*/
pbi->has_keyframe = 0;
pbi->skip_flag = 0;
pbi->wait_buf = 0;
pbi->error_flag = 0;
pbi->pts_mode = PTS_NORMAL;
pbi->last_pts = 0;
pbi->last_lookup_pts = 0;
pbi->last_pts_us64 = 0;
pbi->last_lookup_pts_us64 = 0;
pbi->shift_byte_count = 0;
pbi->shift_byte_count_lo = 0;
pbi->shift_byte_count_hi = 0;
pbi->pts_mode_switching_count = 0;
pbi->pts_mode_recovery_count = 0;
pbi->buf_num = 0;
pbi->pic_num = 0;
return 0;
}
int vp9_bufmgr_postproc(struct VP9Decoder_s *pbi)
{
struct vdec_s *vdec = hw_to_vdec(pbi);
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s sd;
if (pbi->postproc_done)
return 0;
pbi->postproc_done = 1;
swap_frame_buffers(pbi);
if (!cm->show_existing_frame) {
cm->last_show_frame = cm->show_frame;
cm->prev_frame = cm->cur_frame;
#if 0
if (cm->seg.enabled && !pbi->frame_parallel_decode)
vp9_swap_current_and_last_seg_map(cm);
#endif
}
cm->last_width = cm->width;
cm->last_height = cm->height;
pbi->last_width = cm->width;
pbi->last_height = cm->height;
if (cm->show_frame)
cm->current_video_frame++;
if (vp9_get_raw_frame(pbi, &sd) == 0) {
/*pr_info("Display frame index %d\r\n", sd.index);*/
sd.stream_offset = pbi->pre_stream_offset;
if (pbi->enable_fence) {
int i, j, used_size, ret;
int signed_count = 0;
struct vframe_s *signed_fence[VF_POOL_SIZE];
/* notify signal to wake up wq of fence. */
vdec_timeline_increase(vdec->sync, 1);
mutex_lock(&pbi->fence_mutex);
used_size = pbi->fence_vf_s.used_size;
if (used_size) {
for (i = 0, j = 0; i < VF_POOL_SIZE && j < used_size; i++) {
if (pbi->fence_vf_s.fence_vf[i] != NULL) {
ret = dma_fence_get_status(pbi->fence_vf_s.fence_vf[i]->fence);
if (ret == 1) {
signed_fence[signed_count] = pbi->fence_vf_s.fence_vf[i];
pbi->fence_vf_s.fence_vf[i] = NULL;
pbi->fence_vf_s.used_size--;
signed_count++;
}
j++;
}
}
}
mutex_unlock(&pbi->fence_mutex);
if (signed_count != 0) {
for (i = 0; i < signed_count; i++)
vvp9_vf_put(signed_fence[i], vdec);
}
} else {
prepare_display_buf(pbi, &sd);
}
pbi->pre_stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
}
/* else
* pr_info
* ("Not display this frame,ready_for_new_data%d show_frame%d\r\n",
* pbi->ready_for_new_data, cm->show_frame);
*/
return 0;
}
/**************************************************
*
*VP9 buffer management end
*
***************************************************
*/
#define HEVC_CM_BODY_START_ADDR 0x3626
#define HEVC_CM_BODY_LENGTH 0x3627
#define HEVC_CM_HEADER_LENGTH 0x3629
#define HEVC_CM_HEADER_OFFSET 0x362b
#define HEVC_CM_BODY_LENGTH2 0x3663
#define HEVC_CM_HEADER_OFFSET2 0x3664
#define HEVC_CM_HEADER_LENGTH2 0x3665
#define LOSLESS_COMPRESS_MODE
/*#define DECOMP_HEADR_SURGENT*/
#ifdef VP9_10B_NV21
static u32 mem_map_mode = 2 /* 0:linear 1:32x32 2:64x32*/
#else
static u32 mem_map_mode; /* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */
#endif
static u32 enable_mem_saving = 1;
static u32 force_w_h;
static u32 force_fps;
const u32 vp9_version = 201602101;
static u32 debug;
static u32 radr;
static u32 rval;
static u32 pop_shorts;
static u32 dbg_cmd;
static u32 dbg_skip_decode_index;
/*
* bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config
* bit 8~23, for HEVC_SAO_CTRL1 endian config
*/
static u32 endian;
#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8)
#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf)
#ifdef ERROR_HANDLE_DEBUG
static u32 dbg_nal_skip_flag;
/* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */
static u32 dbg_nal_skip_count;
#endif
/*for debug*/
static u32 decode_pic_begin;
static uint slice_parse_begin;
static u32 step;
static u32 vp9_max_pic_w;
static u32 vp9_max_pic_h;
static u32 dynamic_buf_num_margin;
static u32 buf_alloc_depth = 10;
static u32 buf_alloc_size;
/*
*bit[0]: 0,
* bit[1]: 0, always release cma buffer when stop
* bit[1]: 1, never release cma buffer when stop
*bit[0]: 1, when stop, release cma buffer if blackout is 1;
*do not release cma buffer is blackout is not 1
*
*bit[2]: 0, when start decoding, check current displayed buffer
* (only for buffer decoded by vp9) if blackout is 0
* 1, do not check current displayed buffer
*
*bit[3]: 1, if blackout is not 1, do not release current
* displayed cma buffer always.
*/
/* set to 1 for fast play;
* set to 8 for other case of "keep last frame"
*/
static u32 buffer_mode = 1;
/* buffer_mode_dbg: debug only*/
static u32 buffer_mode_dbg = 0xffff0000;
/**/
/*
*bit 0, 1: only display I picture;
*bit 1, 1: only decode I picture;
*/
static u32 i_only_flag;
static u32 low_latency_flag;
static u32 no_head;
static u32 max_decoding_time;
/*
*error handling
*/
/*error_handle_policy:
*bit 0: 0, auto skip error_skip_nal_count nals before error recovery;
*1, skip error_skip_nal_count nals before error recovery;
*bit 1 (valid only when bit0 == 1):
*1, wait vps/sps/pps after error recovery;
*bit 2 (valid only when bit0 == 0):
*0, auto search after error recovery (vp9_recover() called);
*1, manual search after error recovery
*(change to auto search after get IDR: WRITE_VREG(NAL_SEARCH_CTL, 0x2))
*
*bit 4: 0, set error_mark after reset/recover
* 1, do not set error_mark after reset/recover
*bit 5: 0, check total lcu for every picture
* 1, do not check total lcu
*
*/
static u32 error_handle_policy;
/*static u32 parser_sei_enable = 1;*/
#define MAX_BUF_NUM_NORMAL 12
#define MAX_BUF_NUM_LESS 10
static u32 max_buf_num = MAX_BUF_NUM_NORMAL;
#define MAX_BUF_NUM_SAVE_BUF 8
static u32 run_ready_min_buf_num = 2;
static DEFINE_MUTEX(vvp9_mutex);
#ifndef MULTI_INSTANCE_SUPPORT
static struct device *cma_dev;
#endif
#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0
#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1
#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2
#define VP9_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3
#define VP9_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4
#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5
//#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6
#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7
#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8
#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9
#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A
#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B
//#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D
#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E
#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F
#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F
#define HEVC_STREAM_SWAP_TEST HEVC_ASSIST_SCRATCH_L
#ifdef MULTI_INSTANCE_SUPPORT
#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M
#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N
#else
#define HEVC_DECODE_PIC_BEGIN_REG HEVC_ASSIST_SCRATCH_M
#define HEVC_DECODE_PIC_NUM_REG HEVC_ASSIST_SCRATCH_N
#endif
#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G
#define DEBUG_REG2 HEVC_ASSIST_SCRATCH_H
/*
*ucode parser/search control
*bit 0: 0, header auto parse; 1, header manual parse
*bit 1: 0, auto skip for noneseamless stream; 1, no skip
*bit [3:2]: valid when bit1==0;
*0, auto skip nal before first vps/sps/pps/idr;
*1, auto skip nal before first vps/sps/pps
*2, auto skip nal before first vps/sps/pps,
* and not decode until the first I slice (with slice address of 0)
*
*3, auto skip before first I slice (nal_type >=16 && nal_type<=21)
*bit [15:4] nal skip count (valid when bit0 == 1 (manual mode) )
*bit [16]: for NAL_UNIT_EOS when bit0 is 0:
* 0, send SEARCH_DONE to arm ; 1, do not send SEARCH_DONE to arm
*bit [17]: for NAL_SEI when bit0 is 0:
* 0, do not parse SEI in ucode; 1, parse SEI in ucode
*bit [31:20]: used by ucode for debug purpose
*/
#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I
/*[31:24] chip feature
31: 0, use MBOX1; 1, use MBOX0
*/
#define DECODE_MODE HEVC_ASSIST_SCRATCH_J
#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K
#ifdef MULTI_INSTANCE_SUPPORT
#define RPM_BUF_SIZE (0x400 * 2)
#else
#define RPM_BUF_SIZE (0x80*2)
#endif
#define LMEM_BUF_SIZE (0x400 * 2)
//#define VBH_BUF_SIZE (2 * 16 * 2304)
//#define VBH_BUF_COUNT 4
/*mmu_vbh buf is used by HEVC_SAO_MMU_VH0_ADDR, HEVC_SAO_MMU_VH1_ADDR*/
#define VBH_BUF_SIZE_1080P 0x3000
#define VBH_BUF_SIZE_4K 0x5000
#define VBH_BUF_SIZE_8K 0xa000
#define VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh.buf_size / 2)
/*mmu_vbh_dw buf is used by HEVC_SAO_MMU_VH0_ADDR2,HEVC_SAO_MMU_VH1_ADDR2,
HEVC_DW_VH0_ADDDR, HEVC_DW_VH1_ADDDR*/
#define DW_VBH_BUF_SIZE_1080P (VBH_BUF_SIZE_1080P * 2)
#define DW_VBH_BUF_SIZE_4K (VBH_BUF_SIZE_4K * 2)
#define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2)
#define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4)
/* necessary 4K page size align for t7/t3 decoder and after */
#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE))
#define WORK_BUF_SPEC_NUM 6
static struct BuffInfo_s amvvp9_workbuff_spec[WORK_BUF_SPEC_NUM] = {
{
/* 8M bytes */
.max_width = 1920,
.max_height = 1088,
.ipp = {
/* IPP work space calculation :
* 4096 * (Y+CbCr+Flags) = 12k, round to 16k
*/
.buf_size = 0x4000,
},
.sao_abv = {
.buf_size = 0x30000,
},
.sao_vb = {
.buf_size = 0x30000,
},
.short_term_rps = {
/* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
* total 64x16x2 = 2048 bytes (0x800)
*/
.buf_size = 0x800,
},
.vps = {
/* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.sps = {
/* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.pps = {
/* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
* total 0x2000 bytes
*/
.buf_size = 0x2000,
},
.sao_up = {
/* SAO UP STORE AREA - Max 640(10240/16) LCU,
* each has 16 bytes total 0x2800 bytes
*/
.buf_size = 0x2800,
},
.swap_buf = {
/* 256cyclex64bit = 2K bytes 0x800
* (only 144 cycles valid)
*/
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
/* support up to 32 SCALELUT 1024x32 =
* 32Kbytes (0x8000)
*/
.buf_size = 0x8000,
},
.dblk_para = {
/* DBLK -> Max 256(4096/16) LCU,
*each para 1024bytes(total:0x40000),
*data 1024bytes(total:0x40000)
*/
.buf_size = 0x80000,
},
.dblk_data = {
.buf_size = 0x80000,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0xd800,
},
.mmu_vbh = {
.buf_size = 0x5000, /*2*16*(more than 2304)/4, 4K*/
},
#if 0
.cm_header = {
/*add one for keeper.*/
.buf_size = MMU_COMPRESS_HEADER_SIZE *
(FRAME_BUFFERS + 1),
/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
},
#endif
.mpred_above = {
.buf_size = 0x10000, /* 2 * size of hevc*/
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {/* 1080p, 0x40000 per buffer */
.buf_size = 0x40000 * FRAME_BUFFERS,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
},
{
.max_width = 4096,
.max_height = 2304,
.ipp = {
/* IPP work space calculation :
* 4096 * (Y+CbCr+Flags) = 12k, round to 16k
*/
.buf_size = 0x4000,
},
.sao_abv = {
.buf_size = 0x30000,
},
.sao_vb = {
.buf_size = 0x30000,
},
.short_term_rps = {
/* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
* total 64x16x2 = 2048 bytes (0x800)
*/
.buf_size = 0x800,
},
.vps = {
/* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.sps = {
/* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.pps = {
/* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
* total 0x2000 bytes
*/
.buf_size = 0x2000,
},
.sao_up = {
/* SAO UP STORE AREA - Max 640(10240/16) LCU,
* each has 16 bytes total 0x2800 bytes
*/
.buf_size = 0x2800,
},
.swap_buf = {
/* 256cyclex64bit = 2K bytes 0x800
* (only 144 cycles valid)
*/
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
/* support up to 32 SCALELUT 1024x32 = 32Kbytes
* (0x8000)
*/
.buf_size = 0x8000,
},
.dblk_para = {
/* DBLK -> Max 256(4096/16) LCU,
*each para 1024bytes(total:0x40000),
*data 1024bytes(total:0x40000)
*/
.buf_size = 0x80000,
},
.dblk_data = {
.buf_size = 0x80000,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0xd800,
},
.mmu_vbh = {
.buf_size = 0x5000,/*2*16*(more than 2304)/4, 4K*/
},
#if 0
.cm_header = {
/*add one for keeper.*/
.buf_size = MMU_COMPRESS_HEADER_SIZE *
(FRAME_BUFFERS + 1),
/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
},
#endif
.mpred_above = {
.buf_size = 0x10000, /* 2 * size of hevc*/
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {
/* .buf_size = 0x100000*16,
* //4k2k , 0x100000 per buffer
*/
/* 4096x2304 , 0x120000 per buffer */
.buf_size = 0x120000 * FRAME_BUFFERS,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
},
{
.max_width = 4096*2,
.max_height = 2304*2,
.ipp = {
// IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k
.buf_size = 0x4000*2,
},
.sao_abv = {
.buf_size = 0x30000*2,
},
.sao_vb = {
.buf_size = 0x30000*2,
},
.short_term_rps = {
// SHORT_TERM_RPS - Max 64 set, 16 entry every set, total 64x16x2 = 2048 bytes (0x800)
.buf_size = 0x800,
},
.vps = {
// VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, total 0x0800 bytes
.buf_size = 0x800,
},
.sps = {
// SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, total 0x0800 bytes
.buf_size = 0x800,
},
.pps = {
// PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total 0x2000 bytes
.buf_size = 0x2000,
},
.sao_up = {
// SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes
.buf_size = 0x2800*2,
},
.swap_buf = {
// 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
// support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)
.buf_size = 0x8000*2,
},
.dblk_para = {
// DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000)
.buf_size = 0x80000*2,
},
.dblk_data = {
.buf_size = 0x80000*2,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0xd800*4,
},
.mmu_vbh = {
.buf_size = 0x5000*2, //2*16*(more than 2304)/4, 4K
},
#if 0
.cm_header = {
//.buf_size = MMU_COMPRESS_HEADER_SIZE*8, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
.buf_size = MMU_COMPRESS_HEADER_SIZE*16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
},
#endif
.mpred_above = {
.buf_size = 0x10000*2, /* 2 * size of hevc*/
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {
//4k2k , 0x100000 per buffer */
/* 4096x2304 , 0x120000 per buffer */
.buf_size = 0x120000 * FRAME_BUFFERS * 4,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
},
{
/* 8M bytes */
.max_width = 1920,
.max_height = 1088,
.ipp = {
/* IPP work space calculation :
* 4096 * (Y+CbCr+Flags) = 12k, round to 16k
*/
.buf_size = 0x1e00,
},
.sao_abv = {
.buf_size = 0,
},
.sao_vb = {
.buf_size = 0,
},
.short_term_rps = {
/* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
* total 64x16x2 = 2048 bytes (0x800)
*/
.buf_size = 0x800,
},
.vps = {
/* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.sps = {
/* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.pps = {
/* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
* total 0x2000 bytes
*/
.buf_size = 0x2000,
},
.sao_up = {
/* SAO UP STORE AREA - Max 640(10240/16) LCU,
* each has 16 bytes total 0x2800 bytes
*/
.buf_size = 0,
},
.swap_buf = {
/* 256cyclex64bit = 2K bytes 0x800
* (only 144 cycles valid)
*/
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
/* support up to 32 SCALELUT 1024x32 =
* 32Kbytes (0x8000)
*/
.buf_size = 0,
},
.dblk_para = {
/* DBLK -> Max 256(4096/16) LCU,
*each para 1024bytes(total:0x40000),
*data 1024bytes(total:0x40000)
*/
.buf_size = 0x49000,
},
.dblk_data = {
.buf_size = 0x49000,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0x3000, //0x2fd0,
},
.mmu_vbh = {
.buf_size = VBH_BUF_SIZE_1080P, /*2*16*(more than 2304)/4, 4K*/
},
#if 0
.cm_header = {
/*add one for keeper.*/
.buf_size = MMU_COMPRESS_HEADER_SIZE *
(FRAME_BUFFERS + 1),
/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
},
#endif
#ifdef VP9_10B_MMU_DW
.mmu_vbh_dw = {
.buf_size = DW_VBH_BUF_SIZE_1080P, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K
},
#if 0
.cm_header_dw = {
.buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
},
#endif
#endif
.mpred_above = {
.buf_size = 0x2200, //0x21c0, /* 2 * size of hevc*/
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {/* 1080p, 0x40000 per buffer */
.buf_size = 0x48200 * FRAME_BUFFERS,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
},
{
.max_width = 4096,
.max_height = 2304,
.ipp = {
/* IPP work space calculation :
* 4096 * (Y+CbCr+Flags) = 12k, round to 16k
*/
.buf_size = 0x4000,
},
.sao_abv = {
.buf_size = 0,
},
.sao_vb = {
.buf_size = 0,
},
.short_term_rps = {
/* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
* total 64x16x2 = 2048 bytes (0x800)
*/
.buf_size = 0x800,
},
.vps = {
/* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.sps = {
/* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
* total 0x0800 bytes
*/
.buf_size = 0x800,
},
.pps = {
/* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
* total 0x2000 bytes
*/
.buf_size = 0x2000,
},
.sao_up = {
/* SAO UP STORE AREA - Max 640(10240/16) LCU,
* each has 16 bytes total 0x2800 bytes
*/
.buf_size = 0,
},
.swap_buf = {
/* 256cyclex64bit = 2K bytes 0x800
* (only 144 cycles valid)
*/
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
/* support up to 32 SCALELUT 1024x32 = 32Kbytes
* (0x8000)
*/
.buf_size = 0,
},
.dblk_para = {
/* DBLK -> Max 256(4096/16) LCU,
*each para 1024bytes(total:0x40000),
*data 1024bytes(total:0x40000)
*/
.buf_size = 0x52800,
},
.dblk_data = {
.buf_size = 0x52800,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0xd800,
},
.mmu_vbh = {
.buf_size = VBH_BUF_SIZE_4K,/*2*16*(more than 2304)/4, 4K*/
},
#if 0
.cm_header = {
/*add one for keeper.*/
.buf_size = MMU_COMPRESS_HEADER_SIZE *
(FRAME_BUFFERS + 1),
/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
},
#endif
#ifdef VP9_10B_MMU_DW
.mmu_vbh_dw = {
.buf_size = DW_VBH_BUF_SIZE_4K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K
},
#if 0
.cm_header_dw = {
.buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
},
#endif
#endif
.mpred_above = {
.buf_size = 0x4800, /* 2 * size of hevc*/
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {
/* .buf_size = 0x100000*16,
* //4k2k , 0x100000 per buffer
*/
/* 4096x2304 , 0x120000 per buffer */
.buf_size = 0x145400 * FRAME_BUFFERS,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
},
{
.max_width = 4096*2,
.max_height = 2304*2,
.ipp = {
// IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k
.buf_size = 0x4000*2,
},
.sao_abv = {
.buf_size = 0,
},
.sao_vb = {
.buf_size = 0,
},
.short_term_rps = {
// SHORT_TERM_RPS - Max 64 set, 16 entry every set, total 64x16x2 = 2048 bytes (0x800)
.buf_size = 0x800,
},
.vps = {
// VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, total 0x0800 bytes
.buf_size = 0x800,
},
.sps = {
// SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, total 0x0800 bytes
.buf_size = 0x800,
},
.pps = {
// PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total 0x2000 bytes
.buf_size = 0x2000,
},
.sao_up = {
// SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes
.buf_size = 0,
},
.swap_buf = {
// 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)
.buf_size = 0x800,
},
.swap_buf2 = {
.buf_size = 0x800,
},
.scalelut = {
// support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)
.buf_size = 0,
},
.dblk_para = {
// DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000)
.buf_size = 0xa4800,
},
.dblk_data = {
.buf_size = 0xa4800,
},
.seg_map = {
/*4096x2304/64/64 *24 = 0xd800 Bytes*/
.buf_size = 0x36000,
},
.mmu_vbh = {
.buf_size = VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K
},
#if 0
.cm_header = {
//.buf_size = MMU_COMPRESS_HEADER_SIZE*8, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
.buf_size = MMU_COMPRESS_HEADER_SIZE*16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
},
#endif
#ifdef VP9_10B_MMU_DW
.mmu_vbh_dw = {
.buf_size = DW_VBH_BUF_SIZE_8K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K
},
#if 0
.cm_header_dw = {
.buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
},
#endif
#endif
.mpred_above = {
.buf_size = 0x9000,
},
#ifdef MV_USE_FIXED_BUF
.mpred_mv = {
//4k2k , 0x100000 per buffer */
/* 4096x2304 , 0x120000 per buffer */
.buf_size = 0x514800 * FRAME_BUFFERS,
},
#endif
.rpm = {
.buf_size = RPM_BUF_SIZE,
},
.lmem = {
.buf_size = 0x400 * 2,
}
}
};
/*Losless compression body buffer size 4K per 64x32 (jt)*/
static int compute_losless_comp_body_size(int width, int height,
uint8_t is_bit_depth_10)
{
int width_x64;
int height_x32;
int bsize;
width_x64 = width + 63;
width_x64 >>= 6;
height_x32 = height + 31;
height_x32 >>= 5;
bsize = (is_bit_depth_10?4096:3200)*width_x64*height_x32;
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("%s(%d,%d,%d)=>%d\n",
__func__, width, height,
is_bit_depth_10, bsize);
return bsize;
}
/* Losless compression header buffer size 32bytes per 128x64 (jt)*/
static int compute_losless_comp_header_size(int width, int height)
{
int width_x128;
int height_x64;
int hsize;
width_x128 = width + 127;
width_x128 >>= 7;
height_x64 = height + 63;
height_x64 >>= 6;
hsize = 32 * width_x128 * height_x64;
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("%s(%d,%d)=>%d\n",
__func__, width, height,
hsize);
return hsize;
}
static void init_buff_spec(struct VP9Decoder_s *pbi,
struct BuffInfo_s *buf_spec)
{
void *mem_start_virt;
buf_spec->ipp.buf_start =
WORKBUF_ALIGN(buf_spec->start_adr);
buf_spec->sao_abv.buf_start =
WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size);
buf_spec->sao_vb.buf_start =
WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size);
buf_spec->short_term_rps.buf_start =
WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size);
buf_spec->vps.buf_start =
WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size);
buf_spec->sps.buf_start =
WORKBUF_ALIGN(buf_spec->vps.buf_start + buf_spec->vps.buf_size);
buf_spec->pps.buf_start =
WORKBUF_ALIGN(buf_spec->sps.buf_start + buf_spec->sps.buf_size);
buf_spec->sao_up.buf_start =
WORKBUF_ALIGN(buf_spec->pps.buf_start + buf_spec->pps.buf_size);
buf_spec->swap_buf.buf_start =
WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size);
buf_spec->swap_buf2.buf_start =
WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size);
buf_spec->scalelut.buf_start =
WORKBUF_ALIGN(buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size);
buf_spec->dblk_para.buf_start =
WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size);
buf_spec->dblk_data.buf_start =
WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size);
buf_spec->seg_map.buf_start =
WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size);
if (pbi == NULL || pbi->mmu_enable) {
buf_spec->mmu_vbh.buf_start =
WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size);
#ifdef VP9_10B_MMU_DW
if (pbi == NULL || pbi->dw_mmu_enable) {
buf_spec->mmu_vbh_dw.buf_start =
WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size);
buf_spec->mpred_above.buf_start =
WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size);
} else {
buf_spec->mpred_above.buf_start =
WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size);
}
#else
buf_spec->mpred_above.buf_start =
WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size);
#endif
} else {
buf_spec->mpred_above.buf_start =
WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size);
}
#ifdef MV_USE_FIXED_BUF
buf_spec->mpred_mv.buf_start =
WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size);
buf_spec->rpm.buf_start =
WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size);
#else
buf_spec->rpm.buf_start =
WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size);
#endif
buf_spec->lmem.buf_start =
WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size);
buf_spec->end_adr =
WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size);
if (!pbi)
return;
if (!vdec_secure(hw_to_vdec(pbi))) {
mem_start_virt =
codec_mm_phys_to_virt(buf_spec->dblk_para.buf_start);
if (mem_start_virt) {
memset(mem_start_virt, 0,
buf_spec->dblk_para.buf_size);
codec_mm_dma_flush(mem_start_virt,
buf_spec->dblk_para.buf_size,
DMA_TO_DEVICE);
} else {
mem_start_virt = codec_mm_vmap(
buf_spec->dblk_para.buf_start,
buf_spec->dblk_para.buf_size);
if (mem_start_virt) {
memset(mem_start_virt, 0,
buf_spec->dblk_para.buf_size);
codec_mm_dma_flush(mem_start_virt,
buf_spec->dblk_para.buf_size,
DMA_TO_DEVICE);
codec_mm_unmap_phyaddr(mem_start_virt);
} else {
/*not virt for tvp playing,
may need clear on ucode.*/
pr_err("mem_start_virt failed\n");
}
}
}
if (debug) {
pr_info("%s workspace (%x %x) size = %x\n", __func__,
buf_spec->start_adr, buf_spec->end_adr,
buf_spec->end_adr - buf_spec->start_adr);
}
if (debug) {
pr_info("ipp.buf_start :%x\n",
buf_spec->ipp.buf_start);
pr_info("sao_abv.buf_start :%x\n",
buf_spec->sao_abv.buf_start);
pr_info("sao_vb.buf_start :%x\n",
buf_spec->sao_vb.buf_start);
pr_info("short_term_rps.buf_start :%x\n",
buf_spec->short_term_rps.buf_start);
pr_info("vps.buf_start :%x\n",
buf_spec->vps.buf_start);
pr_info("sps.buf_start :%x\n",
buf_spec->sps.buf_start);
pr_info("pps.buf_start :%x\n",
buf_spec->pps.buf_start);
pr_info("sao_up.buf_start :%x\n",
buf_spec->sao_up.buf_start);
pr_info("swap_buf.buf_start :%x\n",
buf_spec->swap_buf.buf_start);
pr_info("swap_buf2.buf_start :%x\n",
buf_spec->swap_buf2.buf_start);
pr_info("scalelut.buf_start :%x\n",
buf_spec->scalelut.buf_start);
pr_info("dblk_para.buf_start :%x\n",
buf_spec->dblk_para.buf_start);
pr_info("dblk_data.buf_start :%x\n",
buf_spec->dblk_data.buf_start);
pr_info("seg_map.buf_start :%x\n",
buf_spec->seg_map.buf_start);
if (pbi->mmu_enable) {
pr_info("mmu_vbh.buf_start :%x\n",
buf_spec->mmu_vbh.buf_start);
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
pr_info("mmu_vbh_dw.buf_start :%x",
buf_spec->mmu_vbh_dw.buf_start);
#if 0
pr_info("cm_header_dw.buf_start :%x",
buf_spec->mmu_vbh_dw.buf_start);
#endif
}
#endif
}
pr_info("mpred_above.buf_start :%x\n",
buf_spec->mpred_above.buf_start);
#ifdef MV_USE_FIXED_BUF
pr_info("mpred_mv.buf_start :%x\n",
buf_spec->mpred_mv.buf_start);
#endif
if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
pr_info("rpm.buf_start :%x\n",
buf_spec->rpm.buf_start);
}
}
}
/* cache_util.c */
#define THODIYIL_MCRCC_CANVAS_ALGX 4
static u32 mcrcc_cache_alg_flag = THODIYIL_MCRCC_CANVAS_ALGX;
static void mcrcc_perfcount_reset(void)
{
if (debug & VP9_DEBUG_CACHE)
pr_info("[cache_util.c] Entered mcrcc_perfcount_reset...\n");
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x1);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x0);
return;
}
static unsigned raw_mcr_cnt_total_prev;
static unsigned hit_mcr_0_cnt_total_prev;
static unsigned hit_mcr_1_cnt_total_prev;
static unsigned byp_mcr_cnt_nchcanv_total_prev;
static unsigned byp_mcr_cnt_nchoutwin_total_prev;
static void mcrcc_get_hitrate(unsigned reset_pre)
{
unsigned delta_hit_mcr_0_cnt;
unsigned delta_hit_mcr_1_cnt;
unsigned delta_raw_mcr_cnt;
unsigned delta_mcr_cnt_nchcanv;
unsigned delta_mcr_cnt_nchoutwin;
unsigned tmp;
unsigned raw_mcr_cnt;
unsigned hit_mcr_cnt;
unsigned byp_mcr_cnt_nchoutwin;
unsigned byp_mcr_cnt_nchcanv;
int hitrate;
if (reset_pre) {
raw_mcr_cnt_total_prev = 0;
hit_mcr_0_cnt_total_prev = 0;
hit_mcr_1_cnt_total_prev = 0;
byp_mcr_cnt_nchcanv_total_prev = 0;
byp_mcr_cnt_nchoutwin_total_prev = 0;
}
if (debug & VP9_DEBUG_CACHE)
pr_info("[cache_util.c] Entered mcrcc_get_hitrate...\n");
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x0<<1));
raw_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x1<<1));
hit_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x2<<1));
byp_mcr_cnt_nchoutwin = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x3<<1));
byp_mcr_cnt_nchcanv = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("raw_mcr_cnt_total: %d\n",
raw_mcr_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("hit_mcr_cnt_total: %d\n",
hit_mcr_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("byp_mcr_cnt_nchoutwin_total: %d\n",
byp_mcr_cnt_nchoutwin);
if (debug & VP9_DEBUG_CACHE)
pr_info("byp_mcr_cnt_nchcanv_total: %d\n",
byp_mcr_cnt_nchcanv);
delta_raw_mcr_cnt = raw_mcr_cnt -
raw_mcr_cnt_total_prev;
delta_mcr_cnt_nchcanv = byp_mcr_cnt_nchcanv -
byp_mcr_cnt_nchcanv_total_prev;
delta_mcr_cnt_nchoutwin = byp_mcr_cnt_nchoutwin -
byp_mcr_cnt_nchoutwin_total_prev;
raw_mcr_cnt_total_prev = raw_mcr_cnt;
byp_mcr_cnt_nchcanv_total_prev = byp_mcr_cnt_nchcanv;
byp_mcr_cnt_nchoutwin_total_prev = byp_mcr_cnt_nchoutwin;
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1));
tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("miss_mcr_0_cnt_total: %d\n", tmp);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x5<<1));
tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("miss_mcr_1_cnt_total: %d\n", tmp);
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x6<<1));
tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("hit_mcr_0_cnt_total: %d\n", tmp);
delta_hit_mcr_0_cnt = tmp - hit_mcr_0_cnt_total_prev;
hit_mcr_0_cnt_total_prev = tmp;
WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1));
tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("hit_mcr_1_cnt_total: %d\n", tmp);
delta_hit_mcr_1_cnt = tmp - hit_mcr_1_cnt_total_prev;
hit_mcr_1_cnt_total_prev = tmp;
if (delta_raw_mcr_cnt != 0) {
hitrate = 100 * delta_hit_mcr_0_cnt
/ delta_raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("CANV0_HIT_RATE : %d\n", hitrate);
hitrate = 100 * delta_hit_mcr_1_cnt
/ delta_raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("CANV1_HIT_RATE : %d\n", hitrate);
hitrate = 100 * delta_mcr_cnt_nchcanv
/ delta_raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("NONCACH_CANV_BYP_RATE : %d\n", hitrate);
hitrate = 100 * delta_mcr_cnt_nchoutwin
/ delta_raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("CACHE_OUTWIN_BYP_RATE : %d\n", hitrate);
}
if (raw_mcr_cnt != 0) {
hitrate = 100 * hit_mcr_cnt / raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("MCRCC_HIT_RATE : %d\n", hitrate);
hitrate = 100 * (byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)
/ raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("MCRCC_BYP_RATE : %d\n", hitrate);
} else {
if (debug & VP9_DEBUG_CACHE)
pr_info("MCRCC_HIT_RATE : na\n");
if (debug & VP9_DEBUG_CACHE)
pr_info("MCRCC_BYP_RATE : na\n");
}
return;
}
static void decomp_perfcount_reset(void)
{
if (debug & VP9_DEBUG_CACHE)
pr_info("[cache_util.c] Entered decomp_perfcount_reset...\n");
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x1);
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x0);
return;
}
static void decomp_get_hitrate(void)
{
unsigned raw_mcr_cnt;
unsigned hit_mcr_cnt;
int hitrate;
if (debug & VP9_DEBUG_CACHE)
pr_info("[cache_util.c] Entered decomp_get_hitrate...\n");
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x0<<1));
raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x1<<1));
hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("hcache_raw_cnt_total: %d\n", raw_mcr_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("hcache_hit_cnt_total: %d\n", hit_mcr_cnt);
if (raw_mcr_cnt != 0) {
hitrate = hit_mcr_cnt * 100 / raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_HCACHE_HIT_RATE : %d\n", hitrate);
} else {
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_HCACHE_HIT_RATE : na\n");
}
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x2<<1));
raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x3<<1));
hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("dcache_raw_cnt_total: %d\n", raw_mcr_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("dcache_hit_cnt_total: %d\n", hit_mcr_cnt);
if (raw_mcr_cnt != 0) {
hitrate = hit_mcr_cnt * 100 / raw_mcr_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_DCACHE_HIT_RATE : %d\n", hitrate);
} else {
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_DCACHE_HIT_RATE : na\n");
}
return;
}
static void decomp_get_comprate(void)
{
unsigned raw_ucomp_cnt;
unsigned fast_comp_cnt;
unsigned slow_comp_cnt;
int comprate;
if (debug & VP9_DEBUG_CACHE)
pr_info("[cache_util.c] Entered decomp_get_comprate...\n");
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x4<<1));
fast_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x5<<1));
slow_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x6<<1));
raw_ucomp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
if (debug & VP9_DEBUG_CACHE)
pr_info("decomp_fast_comp_total: %d\n", fast_comp_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("decomp_slow_comp_total: %d\n", slow_comp_cnt);
if (debug & VP9_DEBUG_CACHE)
pr_info("decomp_raw_uncomp_total: %d\n", raw_ucomp_cnt);
if (raw_ucomp_cnt != 0) {
comprate = (fast_comp_cnt + slow_comp_cnt)
* 100 / raw_ucomp_cnt;
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_COMP_RATIO : %d\n", comprate);
} else {
if (debug & VP9_DEBUG_CACHE)
pr_info("DECOMP_COMP_RATIO : na\n");
}
return;
}
/* cache_util.c end */
/*====================================================
*========================================================================
*vp9_prob define
*========================================================================
*/
#define VP9_PARTITION_START 0
#define VP9_PARTITION_SIZE_STEP (3 * 4)
#define VP9_PARTITION_ONE_SIZE (4 * VP9_PARTITION_SIZE_STEP)
#define VP9_PARTITION_KEY_START 0
#define VP9_PARTITION_P_START VP9_PARTITION_ONE_SIZE
#define VP9_PARTITION_SIZE (2 * VP9_PARTITION_ONE_SIZE)
#define VP9_SKIP_START (VP9_PARTITION_START + VP9_PARTITION_SIZE)
#define VP9_SKIP_SIZE 4 /* only use 3*/
#define VP9_TX_MODE_START (VP9_SKIP_START+VP9_SKIP_SIZE)
#define VP9_TX_MODE_8_0_OFFSET 0
#define VP9_TX_MODE_8_1_OFFSET 1
#define VP9_TX_MODE_16_0_OFFSET 2
#define VP9_TX_MODE_16_1_OFFSET 4
#define VP9_TX_MODE_32_0_OFFSET 6
#define VP9_TX_MODE_32_1_OFFSET 9
#define VP9_TX_MODE_SIZE 12
#define VP9_COEF_START (VP9_TX_MODE_START+VP9_TX_MODE_SIZE)
#define VP9_COEF_BAND_0_OFFSET 0
#define VP9_COEF_BAND_1_OFFSET (VP9_COEF_BAND_0_OFFSET + 3 * 3 + 1)
#define VP9_COEF_BAND_2_OFFSET (VP9_COEF_BAND_1_OFFSET + 6 * 3)
#define VP9_COEF_BAND_3_OFFSET (VP9_COEF_BAND_2_OFFSET + 6 * 3)
#define VP9_COEF_BAND_4_OFFSET (VP9_COEF_BAND_3_OFFSET + 6 * 3)
#define VP9_COEF_BAND_5_OFFSET (VP9_COEF_BAND_4_OFFSET + 6 * 3)
#define VP9_COEF_SIZE_ONE_SET 100 /* ((3 +5*6)*3 + 1 padding)*/
#define VP9_COEF_4X4_START (VP9_COEF_START + 0 * VP9_COEF_SIZE_ONE_SET)
#define VP9_COEF_8X8_START (VP9_COEF_START + 4 * VP9_COEF_SIZE_ONE_SET)
#define VP9_COEF_16X16_START (VP9_COEF_START + 8 * VP9_COEF_SIZE_ONE_SET)
#define VP9_COEF_32X32_START (VP9_COEF_START + 12 * VP9_COEF_SIZE_ONE_SET)
#define VP9_COEF_SIZE_PLANE (2 * VP9_COEF_SIZE_ONE_SET)
#define VP9_COEF_SIZE (4 * 2 * 2 * VP9_COEF_SIZE_ONE_SET)
#define VP9_INTER_MODE_START (VP9_COEF_START+VP9_COEF_SIZE)
#define VP9_INTER_MODE_SIZE 24 /* only use 21 ( #*7)*/
#define VP9_INTERP_START (VP9_INTER_MODE_START+VP9_INTER_MODE_SIZE)
#define VP9_INTERP_SIZE 8
#define VP9_INTRA_INTER_START (VP9_INTERP_START+VP9_INTERP_SIZE)
#define VP9_INTRA_INTER_SIZE 4
#define VP9_INTERP_INTRA_INTER_START VP9_INTERP_START
#define VP9_INTERP_INTRA_INTER_SIZE (VP9_INTERP_SIZE + VP9_INTRA_INTER_SIZE)
#define VP9_COMP_INTER_START \
(VP9_INTERP_INTRA_INTER_START+VP9_INTERP_INTRA_INTER_SIZE)
#define VP9_COMP_INTER_SIZE 5
#define VP9_COMP_REF_START (VP9_COMP_INTER_START+VP9_COMP_INTER_SIZE)
#define VP9_COMP_REF_SIZE 5
#define VP9_SINGLE_REF_START (VP9_COMP_REF_START+VP9_COMP_REF_SIZE)
#define VP9_SINGLE_REF_SIZE 10
#define VP9_REF_MODE_START VP9_COMP_INTER_START
#define VP9_REF_MODE_SIZE \
(VP9_COMP_INTER_SIZE+VP9_COMP_REF_SIZE+VP9_SINGLE_REF_SIZE)
#define VP9_IF_Y_MODE_START (VP9_REF_MODE_START+VP9_REF_MODE_SIZE)
#define VP9_IF_Y_MODE_SIZE 36
#define VP9_IF_UV_MODE_START (VP9_IF_Y_MODE_START+VP9_IF_Y_MODE_SIZE)
#define VP9_IF_UV_MODE_SIZE 92 /* only use 90*/
#define VP9_MV_JOINTS_START (VP9_IF_UV_MODE_START+VP9_IF_UV_MODE_SIZE)
#define VP9_MV_JOINTS_SIZE 3
#define VP9_MV_SIGN_0_START (VP9_MV_JOINTS_START+VP9_MV_JOINTS_SIZE)
#define VP9_MV_SIGN_0_SIZE 1
#define VP9_MV_CLASSES_0_START (VP9_MV_SIGN_0_START+VP9_MV_SIGN_0_SIZE)
#define VP9_MV_CLASSES_0_SIZE 10
#define VP9_MV_CLASS0_0_START (VP9_MV_CLASSES_0_START+VP9_MV_CLASSES_0_SIZE)
#define VP9_MV_CLASS0_0_SIZE 1
#define VP9_MV_BITS_0_START (VP9_MV_CLASS0_0_START+VP9_MV_CLASS0_0_SIZE)
#define VP9_MV_BITS_0_SIZE 10
#define VP9_MV_SIGN_1_START (VP9_MV_BITS_0_START+VP9_MV_BITS_0_SIZE)
#define VP9_MV_SIGN_1_SIZE 1
#define VP9_MV_CLASSES_1_START \
(VP9_MV_SIGN_1_START+VP9_MV_SIGN_1_SIZE)
#define VP9_MV_CLASSES_1_SIZE 10
#define VP9_MV_CLASS0_1_START \
(VP9_MV_CLASSES_1_START+VP9_MV_CLASSES_1_SIZE)
#define VP9_MV_CLASS0_1_SIZE 1
#define VP9_MV_BITS_1_START \
(VP9_MV_CLASS0_1_START+VP9_MV_CLASS0_1_SIZE)
#define VP9_MV_BITS_1_SIZE 10
#define VP9_MV_CLASS0_FP_0_START \
(VP9_MV_BITS_1_START+VP9_MV_BITS_1_SIZE)
#define VP9_MV_CLASS0_FP_0_SIZE 9
#define VP9_MV_CLASS0_FP_1_START \
(VP9_MV_CLASS0_FP_0_START+VP9_MV_CLASS0_FP_0_SIZE)
#define VP9_MV_CLASS0_FP_1_SIZE 9
#define VP9_MV_CLASS0_HP_0_START \
(VP9_MV_CLASS0_FP_1_START+VP9_MV_CLASS0_FP_1_SIZE)
#define VP9_MV_CLASS0_HP_0_SIZE 2
#define VP9_MV_CLASS0_HP_1_START \
(VP9_MV_CLASS0_HP_0_START+VP9_MV_CLASS0_HP_0_SIZE)
#define VP9_MV_CLASS0_HP_1_SIZE 2
#define VP9_MV_START VP9_MV_JOINTS_START
#define VP9_MV_SIZE 72 /*only use 69*/
#define VP9_TOTAL_SIZE (VP9_MV_START + VP9_MV_SIZE)
/*========================================================================
* vp9_count_mem define
*========================================================================
*/
#define VP9_COEF_COUNT_START 0
#define VP9_COEF_COUNT_BAND_0_OFFSET 0
#define VP9_COEF_COUNT_BAND_1_OFFSET \
(VP9_COEF_COUNT_BAND_0_OFFSET + 3*5)
#define VP9_COEF_COUNT_BAND_2_OFFSET \
(VP9_COEF_COUNT_BAND_1_OFFSET + 6*5)
#define VP9_COEF_COUNT_BAND_3_OFFSET \
(VP9_COEF_COUNT_BAND_2_OFFSET + 6*5)
#define VP9_COEF_COUNT_BAND_4_OFFSET \
(VP9_COEF_COUNT_BAND_3_OFFSET + 6*5)
#define VP9_COEF_COUNT_BAND_5_OFFSET \
(VP9_COEF_COUNT_BAND_4_OFFSET + 6*5)
#define VP9_COEF_COUNT_SIZE_ONE_SET 165 /* ((3 +5*6)*5 */
#define VP9_COEF_COUNT_4X4_START \
(VP9_COEF_COUNT_START + 0*VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_COEF_COUNT_8X8_START \
(VP9_COEF_COUNT_START + 4*VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_COEF_COUNT_16X16_START \
(VP9_COEF_COUNT_START + 8*VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_COEF_COUNT_32X32_START \
(VP9_COEF_COUNT_START + 12*VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_COEF_COUNT_SIZE_PLANE (2 * VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_COEF_COUNT_SIZE (4 * 2 * 2 * VP9_COEF_COUNT_SIZE_ONE_SET)
#define VP9_INTRA_INTER_COUNT_START \
(VP9_COEF_COUNT_START+VP9_COEF_COUNT_SIZE)
#define VP9_INTRA_INTER_COUNT_SIZE (4*2)
#define VP9_COMP_INTER_COUNT_START \
(VP9_INTRA_INTER_COUNT_START+VP9_INTRA_INTER_COUNT_SIZE)
#define VP9_COMP_INTER_COUNT_SIZE (5*2)
#define VP9_COMP_REF_COUNT_START \
(VP9_COMP_INTER_COUNT_START+VP9_COMP_INTER_COUNT_SIZE)
#define VP9_COMP_REF_COUNT_SIZE (5*2)
#define VP9_SINGLE_REF_COUNT_START \
(VP9_COMP_REF_COUNT_START+VP9_COMP_REF_COUNT_SIZE)
#define VP9_SINGLE_REF_COUNT_SIZE (10*2)
#define VP9_TX_MODE_COUNT_START \
(VP9_SINGLE_REF_COUNT_START+VP9_SINGLE_REF_COUNT_SIZE)
#define VP9_TX_MODE_COUNT_SIZE (12*2)
#define VP9_SKIP_COUNT_START \
(VP9_TX_MODE_COUNT_START+VP9_TX_MODE_COUNT_SIZE)
#define VP9_SKIP_COUNT_SIZE (3*2)
#define VP9_MV_SIGN_0_COUNT_START \
(VP9_SKIP_COUNT_START+VP9_SKIP_COUNT_SIZE)
#define VP9_MV_SIGN_0_COUNT_SIZE (1*2)
#define VP9_MV_SIGN_1_COUNT_START \
(VP9_MV_SIGN_0_COUNT_START+VP9_MV_SIGN_0_COUNT_SIZE)
#define VP9_MV_SIGN_1_COUNT_SIZE (1*2)
#define VP9_MV_BITS_0_COUNT_START \
(VP9_MV_SIGN_1_COUNT_START+VP9_MV_SIGN_1_COUNT_SIZE)
#define VP9_MV_BITS_0_COUNT_SIZE (10*2)
#define VP9_MV_BITS_1_COUNT_START \
(VP9_MV_BITS_0_COUNT_START+VP9_MV_BITS_0_COUNT_SIZE)
#define VP9_MV_BITS_1_COUNT_SIZE (10*2)
#define VP9_MV_CLASS0_HP_0_COUNT_START \
(VP9_MV_BITS_1_COUNT_START+VP9_MV_BITS_1_COUNT_SIZE)
#define VP9_MV_CLASS0_HP_0_COUNT_SIZE (2*2)
#define VP9_MV_CLASS0_HP_1_COUNT_START \
(VP9_MV_CLASS0_HP_0_COUNT_START+VP9_MV_CLASS0_HP_0_COUNT_SIZE)
#define VP9_MV_CLASS0_HP_1_COUNT_SIZE (2*2)
/* Start merge_tree*/
#define VP9_INTER_MODE_COUNT_START \
(VP9_MV_CLASS0_HP_1_COUNT_START+VP9_MV_CLASS0_HP_1_COUNT_SIZE)
#define VP9_INTER_MODE_COUNT_SIZE (7*4)
#define VP9_IF_Y_MODE_COUNT_START \
(VP9_INTER_MODE_COUNT_START+VP9_INTER_MODE_COUNT_SIZE)
#define VP9_IF_Y_MODE_COUNT_SIZE (10*4)
#define VP9_IF_UV_MODE_COUNT_START \
(VP9_IF_Y_MODE_COUNT_START+VP9_IF_Y_MODE_COUNT_SIZE)
#define VP9_IF_UV_MODE_COUNT_SIZE (10*10)
#define VP9_PARTITION_P_COUNT_START \
(VP9_IF_UV_MODE_COUNT_START+VP9_IF_UV_MODE_COUNT_SIZE)
#define VP9_PARTITION_P_COUNT_SIZE (4*4*4)
#define VP9_INTERP_COUNT_START \
(VP9_PARTITION_P_COUNT_START+VP9_PARTITION_P_COUNT_SIZE)
#define VP9_INTERP_COUNT_SIZE (4*3)
#define VP9_MV_JOINTS_COUNT_START \
(VP9_INTERP_COUNT_START+VP9_INTERP_COUNT_SIZE)
#define VP9_MV_JOINTS_COUNT_SIZE (1 * 4)
#define VP9_MV_CLASSES_0_COUNT_START \
(VP9_MV_JOINTS_COUNT_START+VP9_MV_JOINTS_COUNT_SIZE)
#define VP9_MV_CLASSES_0_COUNT_SIZE (1*11)
#define VP9_MV_CLASS0_0_COUNT_START \
(VP9_MV_CLASSES_0_COUNT_START+VP9_MV_CLASSES_0_COUNT_SIZE)
#define VP9_MV_CLASS0_0_COUNT_SIZE (1*2)
#define VP9_MV_CLASSES_1_COUNT_START \
(VP9_MV_CLASS0_0_COUNT_START+VP9_MV_CLASS0_0_COUNT_SIZE)
#define VP9_MV_CLASSES_1_COUNT_SIZE (1*11)
#define VP9_MV_CLASS0_1_COUNT_START \
(VP9_MV_CLASSES_1_COUNT_START+VP9_MV_CLASSES_1_COUNT_SIZE)
#define VP9_MV_CLASS0_1_COUNT_SIZE (1*2)
#define VP9_MV_CLASS0_FP_0_COUNT_START \
(VP9_MV_CLASS0_1_COUNT_START+VP9_MV_CLASS0_1_COUNT_SIZE)
#define VP9_MV_CLASS0_FP_0_COUNT_SIZE (3*4)
#define VP9_MV_CLASS0_FP_1_COUNT_START \
(VP9_MV_CLASS0_FP_0_COUNT_START+VP9_MV_CLASS0_FP_0_COUNT_SIZE)
#define VP9_MV_CLASS0_FP_1_COUNT_SIZE (3*4)
#define DC_PRED 0 /* Average of above and left pixels*/
#define V_PRED 1 /* Vertical*/
#define H_PRED 2 /* Horizontal*/
#define D45_PRED 3 /*Directional 45 deg = round(arctan(1/1) * 180/pi)*/
#define D135_PRED 4 /* Directional 135 deg = 180 - 45*/
#define D117_PRED 5 /* Directional 117 deg = 180 - 63*/
#define D153_PRED 6 /* Directional 153 deg = 180 - 27*/
#define D207_PRED 7 /* Directional 207 deg = 180 + 27*/
#define D63_PRED 8 /*Directional 63 deg = round(arctan(2/1) * 180/pi)*/
#define TM_PRED 9 /*True-motion*/
int clip_prob(int p)
{
return (p > 255) ? 255 : (p < 1) ? 1 : p;
}
#define ROUND_POWER_OF_TWO(value, n) \
(((value) + (1 << ((n) - 1))) >> (n))
#define MODE_MV_COUNT_SAT 20
static const int count_to_update_factor[MODE_MV_COUNT_SAT + 1] = {
0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64,
70, 76, 83, 89, 96, 102, 108, 115, 121, 128
};
void vp9_tree_merge_probs(unsigned int *prev_prob, unsigned int *cur_prob,
int coef_node_start, int tree_left, int tree_right, int tree_i,
int node) {
int prob_32, prob_res, prob_shift;
int pre_prob, new_prob;
int den, m_count, get_prob, factor;
prob_32 = prev_prob[coef_node_start / 4 * 2];
prob_res = coef_node_start & 3;
prob_shift = prob_res * 8;
pre_prob = (prob_32 >> prob_shift) & 0xff;
den = tree_left + tree_right;
if (den == 0)
new_prob = pre_prob;
else {
m_count = (den < MODE_MV_COUNT_SAT) ?
den : MODE_MV_COUNT_SAT;
get_prob = clip_prob(
div_r32(((int64_t)tree_left * 256 + (den >> 1)),
den));
/*weighted_prob*/
factor = count_to_update_factor[m_count];
new_prob = ROUND_POWER_OF_TWO(pre_prob * (256 - factor)
+ get_prob * factor, 8);
}
cur_prob[coef_node_start / 4 * 2] = (cur_prob[coef_node_start / 4 * 2]
& (~(0xff << prob_shift))) | (new_prob << prob_shift);
/*pr_info(" - [%d][%d] 0x%02X --> 0x%02X (0x%X 0x%X) (%X)\n",
*tree_i, node, pre_prob, new_prob, tree_left, tree_right,
*cur_prob[coef_node_start/4*2]);
*/
}
/*void adapt_coef_probs(void)*/
void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc,
unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count)
{
/* 80 * 64bits = 0xF00 ( use 0x1000 4K bytes)
*unsigned int prev_prob[496*2];
*unsigned int cur_prob[496*2];
*0x300 * 128bits = 0x3000 (32K Bytes)
*unsigned int count[0x300*4];
*/
int tx_size, coef_tx_size_start, coef_count_tx_size_start;
int plane, coef_plane_start, coef_count_plane_start;
int type, coef_type_start, coef_count_type_start;
int band, coef_band_start, coef_count_band_start;
int cxt_num;
int cxt, coef_cxt_start, coef_count_cxt_start;
int node, coef_node_start, coef_count_node_start;
int tree_i, tree_left, tree_right;
int mvd_i;
int count_sat = 24;
/*int update_factor = 112;*/ /*If COEF_MAX_UPDATE_FACTOR_AFTER_KEY,
*use 128
*/
/* If COEF_MAX_UPDATE_FACTOR_AFTER_KEY, use 128*/
/*int update_factor = (pic_count == 1) ? 128 : 112;*/
int update_factor = cur_kf ? 112 :
prev_kf ? 128 : 112;
int prob_32;
int prob_res;
int prob_shift;
int pre_prob;
int num, den;
int get_prob;
int m_count;
int factor;
int new_prob;
if (debug & VP9_DEBUG_MERGE)
pr_info
("\n ##adapt_coef_probs (pre_fc : %d ,prev_kf : %d,cur_kf : %d)##\n\n",
pre_fc, prev_kf, cur_kf);
/*adapt_coef_probs*/
for (tx_size = 0; tx_size < 4; tx_size++) {
coef_tx_size_start = VP9_COEF_START
+ tx_size * 4 * VP9_COEF_SIZE_ONE_SET;
coef_count_tx_size_start = VP9_COEF_COUNT_START
+ tx_size * 4 * VP9_COEF_COUNT_SIZE_ONE_SET;
coef_plane_start = coef_tx_size_start;
coef_count_plane_start = coef_count_tx_size_start;
for (plane = 0; plane < 2; plane++) {
coef_type_start = coef_plane_start;
coef_count_type_start = coef_count_plane_start;
for (type = 0; type < 2; type++) {
coef_band_start = coef_type_start;
coef_count_band_start = coef_count_type_start;
for (band = 0; band < 6; band++) {
if (band == 0)
cxt_num = 3;
else
cxt_num = 6;
coef_cxt_start = coef_band_start;
coef_count_cxt_start =
coef_count_band_start;
for (cxt = 0; cxt < cxt_num; cxt++) {
const int n0 =
count[coef_count_cxt_start];
const int n1 =
count[coef_count_cxt_start + 1];
const int n2 =
count[coef_count_cxt_start + 2];
const int neob =
count[coef_count_cxt_start + 3];
const int nneob =
count[coef_count_cxt_start + 4];
const unsigned int
branch_ct[3][2] = {
{ neob, nneob },
{ n0, n1 + n2 },
{ n1, n2 }
};
coef_node_start =
coef_cxt_start;
for
(node = 0; node < 3; node++) {
prob_32 =
prev_prob[
coef_node_start
/ 4 * 2];
prob_res =
coef_node_start & 3;
prob_shift =
prob_res * 8;
pre_prob =
(prob_32 >> prob_shift)
& 0xff;
/*get_binary_prob*/
num =
branch_ct[node][0];
den =
branch_ct[node][0] +
branch_ct[node][1];
m_count = (den <
count_sat)
? den : count_sat;
get_prob =
(den == 0) ? 128u :
clip_prob(
div_r32(((int64_t)
num * 256
+ (den >> 1)),
den));
factor =
update_factor * m_count
/ count_sat;
new_prob =
ROUND_POWER_OF_TWO
(pre_prob *
(256 - factor) +
get_prob * factor, 8);
cur_prob[coef_node_start
/ 4 * 2] =
(cur_prob
[coef_node_start
/ 4 * 2] & (~(0xff <<
prob_shift))) |
(new_prob <<
prob_shift);
coef_node_start += 1;
}
coef_cxt_start =
coef_cxt_start + 3;
coef_count_cxt_start =
coef_count_cxt_start
+ 5;
}
if (band == 0) {
coef_band_start += 10;
coef_count_band_start += 15;
} else {
coef_band_start += 18;
coef_count_band_start += 30;
}
}
coef_type_start += VP9_COEF_SIZE_ONE_SET;
coef_count_type_start +=
VP9_COEF_COUNT_SIZE_ONE_SET;
}
coef_plane_start += 2 * VP9_COEF_SIZE_ONE_SET;
coef_count_plane_start +=
2 * VP9_COEF_COUNT_SIZE_ONE_SET;
}
}
if (cur_kf == 0) {
/*mode_mv_merge_probs - merge_intra_inter_prob*/
for (coef_count_node_start = VP9_INTRA_INTER_COUNT_START;
coef_count_node_start < (VP9_MV_CLASS0_HP_1_COUNT_START +
VP9_MV_CLASS0_HP_1_COUNT_SIZE); coef_count_node_start += 2) {
if (coef_count_node_start ==
VP9_INTRA_INTER_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_intra_inter_prob\n");
coef_node_start = VP9_INTRA_INTER_START;
} else if (coef_count_node_start ==
VP9_COMP_INTER_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_comp_inter_prob\n");
coef_node_start = VP9_COMP_INTER_START;
}
/*
*else if (coef_count_node_start ==
* VP9_COMP_REF_COUNT_START) {
* pr_info(" # merge_comp_inter_prob\n");
* coef_node_start = VP9_COMP_REF_START;
*}
*else if (coef_count_node_start ==
* VP9_SINGLE_REF_COUNT_START) {
* pr_info(" # merge_comp_inter_prob\n");
* coef_node_start = VP9_SINGLE_REF_START;
*}
*/
else if (coef_count_node_start ==
VP9_TX_MODE_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_tx_mode_probs\n");
coef_node_start = VP9_TX_MODE_START;
} else if (coef_count_node_start ==
VP9_SKIP_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_skip_probs\n");
coef_node_start = VP9_SKIP_START;
} else if (coef_count_node_start ==
VP9_MV_SIGN_0_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_sign_0\n");
coef_node_start = VP9_MV_SIGN_0_START;
} else if (coef_count_node_start ==
VP9_MV_SIGN_1_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_sign_1\n");
coef_node_start = VP9_MV_SIGN_1_START;
} else if (coef_count_node_start ==
VP9_MV_BITS_0_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_bits_0\n");
coef_node_start = VP9_MV_BITS_0_START;
} else if (coef_count_node_start ==
VP9_MV_BITS_1_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_bits_1\n");
coef_node_start = VP9_MV_BITS_1_START;
} else if (coef_count_node_start ==
VP9_MV_CLASS0_HP_0_COUNT_START) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_class0_hp\n");
coef_node_start = VP9_MV_CLASS0_HP_0_START;
}
den = count[coef_count_node_start] +
count[coef_count_node_start + 1];
prob_32 = prev_prob[coef_node_start / 4 * 2];
prob_res = coef_node_start & 3;
prob_shift = prob_res * 8;
pre_prob = (prob_32 >> prob_shift) & 0xff;
if (den == 0)
new_prob = pre_prob;
else {
m_count = (den < MODE_MV_COUNT_SAT) ?
den : MODE_MV_COUNT_SAT;
get_prob =
clip_prob(
div_r32(((int64_t)count[coef_count_node_start]
* 256 + (den >> 1)),
den));
/*weighted_prob*/
factor = count_to_update_factor[m_count];
new_prob =
ROUND_POWER_OF_TWO(pre_prob * (256 - factor)
+ get_prob * factor, 8);
}
cur_prob[coef_node_start / 4 * 2] =
(cur_prob[coef_node_start / 4 * 2] &
(~(0xff << prob_shift)))
| (new_prob << prob_shift);
coef_node_start = coef_node_start + 1;
}
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_inter_mode_tree\n");
coef_node_start = VP9_INTER_MODE_START;
coef_count_node_start = VP9_INTER_MODE_COUNT_START;
for (tree_i = 0; tree_i < 7; tree_i++) {
for (node = 0; node < 3; node++) {
switch (node) {
case 2:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 3];
break;
case 1:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1]
+ count[coef_count_node_start + 3];
break;
default:
tree_left =
count[coef_count_node_start + 2];
tree_right =
count[coef_count_node_start + 0]
+ count[coef_count_node_start + 1]
+ count[coef_count_node_start + 3];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start, tree_left, tree_right,
tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 4;
}
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_intra_mode_tree\n");
coef_node_start = VP9_IF_Y_MODE_START;
coef_count_node_start = VP9_IF_Y_MODE_COUNT_START;
for (tree_i = 0; tree_i < 14; tree_i++) {
for (node = 0; node < 9; node++) {
switch (node) {
case 8:
tree_left =
count[coef_count_node_start+D153_PRED];
tree_right =
count[coef_count_node_start+D207_PRED];
break;
case 7:
tree_left =
count[coef_count_node_start+D63_PRED];
tree_right =
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED];
break;
case 6:
tree_left =
count[coef_count_node_start + D45_PRED];
tree_right =
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED] +
count[coef_count_node_start+D63_PRED];
break;
case 5:
tree_left =
count[coef_count_node_start+D135_PRED];
tree_right =
count[coef_count_node_start+D117_PRED];
break;
case 4:
tree_left =
count[coef_count_node_start+H_PRED];
tree_right =
count[coef_count_node_start+D117_PRED] +
count[coef_count_node_start+D135_PRED];
break;
case 3:
tree_left =
count[coef_count_node_start+H_PRED] +
count[coef_count_node_start+D117_PRED] +
count[coef_count_node_start+D135_PRED];
tree_right =
count[coef_count_node_start+D45_PRED] +
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED] +
count[coef_count_node_start+D63_PRED];
break;
case 2:
tree_left =
count[coef_count_node_start+V_PRED];
tree_right =
count[coef_count_node_start+H_PRED] +
count[coef_count_node_start+D117_PRED] +
count[coef_count_node_start+D135_PRED] +
count[coef_count_node_start+D45_PRED] +
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED] +
count[coef_count_node_start+D63_PRED];
break;
case 1:
tree_left =
count[coef_count_node_start+TM_PRED];
tree_right =
count[coef_count_node_start+V_PRED] +
count[coef_count_node_start+H_PRED] +
count[coef_count_node_start+D117_PRED] +
count[coef_count_node_start+D135_PRED] +
count[coef_count_node_start+D45_PRED] +
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED] +
count[coef_count_node_start+D63_PRED];
break;
default:
tree_left =
count[coef_count_node_start+DC_PRED];
tree_right =
count[coef_count_node_start+TM_PRED] +
count[coef_count_node_start+V_PRED] +
count[coef_count_node_start+H_PRED] +
count[coef_count_node_start+D117_PRED] +
count[coef_count_node_start+D135_PRED] +
count[coef_count_node_start+D45_PRED] +
count[coef_count_node_start+D207_PRED] +
count[coef_count_node_start+D153_PRED] +
count[coef_count_node_start+D63_PRED];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start, tree_left, tree_right,
tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 10;
}
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_partition_tree\n");
coef_node_start = VP9_PARTITION_P_START;
coef_count_node_start = VP9_PARTITION_P_COUNT_START;
for (tree_i = 0; tree_i < 16; tree_i++) {
for (node = 0; node < 3; node++) {
switch (node) {
case 2:
tree_left =
count[coef_count_node_start + 2];
tree_right =
count[coef_count_node_start + 3];
break;
case 1:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3];
break;
default:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1] +
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start,
tree_left, tree_right, tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 4;
}
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_switchable_interp_tree\n");
coef_node_start = VP9_INTERP_START;
coef_count_node_start = VP9_INTERP_COUNT_START;
for (tree_i = 0; tree_i < 4; tree_i++) {
for (node = 0; node < 2; node++) {
switch (node) {
case 1:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 2];
break;
default:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1] +
count[coef_count_node_start + 2];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start,
tree_left, tree_right, tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 3;
}
if (debug & VP9_DEBUG_MERGE)
pr_info("# merge_vp9_mv_joint_tree\n");
coef_node_start = VP9_MV_JOINTS_START;
coef_count_node_start = VP9_MV_JOINTS_COUNT_START;
for (tree_i = 0; tree_i < 1; tree_i++) {
for (node = 0; node < 3; node++) {
switch (node) {
case 2:
tree_left =
count[coef_count_node_start + 2];
tree_right =
count[coef_count_node_start + 3];
break;
case 1:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3];
break;
default:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1] +
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start,
tree_left, tree_right, tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 4;
}
for (mvd_i = 0; mvd_i < 2; mvd_i++) {
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_mv_class_tree [%d] -\n", mvd_i);
coef_node_start =
mvd_i ? VP9_MV_CLASSES_1_START : VP9_MV_CLASSES_0_START;
coef_count_node_start =
mvd_i ? VP9_MV_CLASSES_1_COUNT_START
: VP9_MV_CLASSES_0_COUNT_START;
tree_i = 0;
for (node = 0; node < 10; node++) {
switch (node) {
case 9:
tree_left =
count[coef_count_node_start + 9];
tree_right =
count[coef_count_node_start + 10];
break;
case 8:
tree_left =
count[coef_count_node_start + 7];
tree_right =
count[coef_count_node_start + 8];
break;
case 7:
tree_left =
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8];
tree_right =
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
case 6:
tree_left =
count[coef_count_node_start + 6];
tree_right =
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8] +
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
case 5:
tree_left =
count[coef_count_node_start + 4];
tree_right =
count[coef_count_node_start + 5];
break;
case 4:
tree_left =
count[coef_count_node_start + 4] +
count[coef_count_node_start + 5];
tree_right =
count[coef_count_node_start + 6] +
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8] +
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
case 3:
tree_left =
count[coef_count_node_start + 2];
tree_right =
count[coef_count_node_start + 3];
break;
case 2:
tree_left =
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3];
tree_right =
count[coef_count_node_start + 4] +
count[coef_count_node_start + 5] +
count[coef_count_node_start + 6] +
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8] +
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
case 1:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3] +
count[coef_count_node_start + 4] +
count[coef_count_node_start + 5] +
count[coef_count_node_start + 6] +
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8] +
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
default:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1] +
count[coef_count_node_start + 2] +
count[coef_count_node_start + 3] +
count[coef_count_node_start + 4] +
count[coef_count_node_start + 5] +
count[coef_count_node_start + 6] +
count[coef_count_node_start + 7] +
count[coef_count_node_start + 8] +
count[coef_count_node_start + 9] +
count[coef_count_node_start + 10];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start, tree_left, tree_right,
tree_i, node);
coef_node_start = coef_node_start + 1;
}
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_mv_class0_tree [%d] -\n", mvd_i);
coef_node_start =
mvd_i ? VP9_MV_CLASS0_1_START : VP9_MV_CLASS0_0_START;
coef_count_node_start =
mvd_i ? VP9_MV_CLASS0_1_COUNT_START :
VP9_MV_CLASS0_0_COUNT_START;
tree_i = 0;
node = 0;
tree_left = count[coef_count_node_start + 0];
tree_right = count[coef_count_node_start + 1];
vp9_tree_merge_probs(prev_prob, cur_prob, coef_node_start,
tree_left, tree_right, tree_i, node);
if (debug & VP9_DEBUG_MERGE)
pr_info(" # merge_vp9_mv_fp_tree_class0_fp [%d] -\n",
mvd_i);
coef_node_start =
mvd_i ? VP9_MV_CLASS0_FP_1_START :
VP9_MV_CLASS0_FP_0_START;
coef_count_node_start =
mvd_i ? VP9_MV_CLASS0_FP_1_COUNT_START :
VP9_MV_CLASS0_FP_0_COUNT_START;
for (tree_i = 0; tree_i < 3; tree_i++) {
for (node = 0; node < 3; node++) {
switch (node) {
case 2:
tree_left =
count[coef_count_node_start + 2];
tree_right =
count[coef_count_node_start + 3];
break;
case 1:
tree_left =
count[coef_count_node_start + 1];
tree_right =
count[coef_count_node_start + 2]
+ count[coef_count_node_start + 3];
break;
default:
tree_left =
count[coef_count_node_start + 0];
tree_right =
count[coef_count_node_start + 1]
+ count[coef_count_node_start + 2]
+ count[coef_count_node_start + 3];
break;
}
vp9_tree_merge_probs(prev_prob, cur_prob,
coef_node_start, tree_left, tree_right,
tree_i, node);
coef_node_start = coef_node_start + 1;
}
coef_count_node_start = coef_count_node_start + 4;
}
} /* for mvd_i (mvd_y or mvd_x)*/
}
}
static void uninit_mmu_buffers(struct VP9Decoder_s *pbi)
{
#ifndef MV_USE_FIXED_BUF
dealloc_mv_bufs(pbi);
#endif
if (pbi->mmu_box) {
decoder_mmu_box_free(pbi->mmu_box);
pbi->mmu_box = NULL;
}
#ifdef VP9_10B_MMU_DW
if (pbi->mmu_box_dw) {
decoder_mmu_box_free(pbi->mmu_box_dw);
pbi->mmu_box_dw = NULL;
}
#endif
if (pbi->bmmu_box) {
decoder_bmmu_box_free(pbi->bmmu_box);
pbi->bmmu_box = NULL;
}
}
static int calc_luc_quantity(u32 w, u32 h)
{
int lcu_size = 64; /*fixed 64*/
int pic_width_64 = (w + 63) & (~0x3f);
int pic_height_32 = (h + 31) & (~0x1f);
int pic_width_lcu = (pic_width_64 % lcu_size) ?
pic_width_64 / lcu_size + 1 : pic_width_64 / lcu_size;
int pic_height_lcu = (pic_height_32 % lcu_size) ?
pic_height_32 / lcu_size + 1 : pic_height_32 / lcu_size;
return pic_width_lcu * pic_height_lcu;
}
/* return in MB */
static int vp9_max_mmu_buf_size(int max_w, int max_h)
{
int buf_size = 48;
if ((max_w * max_h > 1280*736) &&
(max_w * max_h <= 1920*1088)) {
buf_size = 12;
} else if ((max_w * max_h > 0) &&
(max_w * max_h <= 1280*736)) {
buf_size = 4;
}
return buf_size;
}
static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic)
{
int ret = -1;
int i = pic->index;
int dw_mode = get_double_write_mode_init(pbi);
int lcu_total = calc_luc_quantity(pbi->frame_width, pbi->frame_height);
#ifdef MV_USE_FIXED_BUF
u32 mpred_mv_end = pbi->work_space_buf->mpred_mv.buf_start +
pbi->work_space_buf->mpred_mv.buf_size;
int mv_size = cal_mv_buf_size(pbi, pbi->frame_width, pbi->frame_height);
#endif
struct aml_vcodec_ctx * ctx = (struct aml_vcodec_ctx *)pbi->v4l2_ctx;
struct vdec_v4l2_buffer *fb = NULL;
if (i < 0)
return ret;
ret = ctx->fb_ops.alloc(&ctx->fb_ops, pbi->fb_token, &fb, AML_FB_REQ_DEC);
if (ret < 0) {
vp9_print(pbi, 0, "[%d] VP9 get buffer fail.\n",
((struct aml_vcodec_ctx *) (pbi->v4l2_ctx))->id);
return ret;
}
fb->status = FB_ST_DECODER;
if (pbi->mmu_enable) {
struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(pbi, fb);
pbi->m_BUF[i].header_addr = ibuf->header_addr;
if (debug & VP9_DEBUG_BUFMGR_MORE) {
pr_info("MMU header_adr %d: %ld\n",
i, pbi->m_BUF[i].header_addr);
}
}
#ifdef MV_USE_FIXED_BUF
if ((pbi->work_space_buf->mpred_mv.buf_start +
((i + 1) * mv_size))
<= mpred_mv_end) {
#endif
pbi->m_BUF[i].v4l_ref_buf_addr = (ulong)fb;
pic->cma_alloc_addr = fb->m.mem[0].addr;
if (fb->num_planes == 1) {
pbi->m_BUF[i].start_adr = fb->m.mem[0].addr;
pbi->m_BUF[i].luma_size = fb->m.mem[0].offset;
pbi->m_BUF[i].size = fb->m.mem[0].size;
fb->m.mem[0].bytes_used = fb->m.mem[0].size;
pic->dw_y_adr = pbi->m_BUF[i].start_adr;
pic->dw_u_v_adr = pic->dw_y_adr + pbi->m_BUF[i].luma_size;
pic->luma_size = fb->m.mem[0].offset;
pic->chroma_size = fb->m.mem[0].size - fb->m.mem[0].offset;
} else if (fb->num_planes == 2) {
pbi->m_BUF[i].start_adr = fb->m.mem[0].addr;
pbi->m_BUF[i].size = fb->m.mem[0].size;
pbi->m_BUF[i].chroma_addr = fb->m.mem[1].addr;
pbi->m_BUF[i].chroma_size = fb->m.mem[1].size;
fb->m.mem[0].bytes_used = fb->m.mem[0].size;
fb->m.mem[1].bytes_used = fb->m.mem[1].size;
pic->dw_y_adr = pbi->m_BUF[i].start_adr;
pic->dw_u_v_adr = pbi->m_BUF[i].chroma_addr;
pic->luma_size = fb->m.mem[0].size;
pic->chroma_size = fb->m.mem[1].size;
}
/* config frame buffer */
if (pbi->mmu_enable)
pic->header_adr = pbi->m_BUF[i].header_addr;
pic->BUF_index = i;
pic->lcu_total = lcu_total;
pic->mc_canvas_y = pic->index;
pic->mc_canvas_u_v = pic->index;
if (dw_mode & 0x10) {
pic->mc_canvas_y = (pic->index << 1);
pic->mc_canvas_u_v = (pic->index << 1) + 1;
}
#ifdef MV_USE_FIXED_BUF
pic->mpred_mv_wr_start_addr =
pbi->work_space_buf->mpred_mv.buf_start +
(pic->index * mv_size);
pic->mv_size = mv_size;
#endif
if (debug) {
pr_info("%s index %d BUF_index %d ",
__func__, pic->index,
pic->BUF_index);
pr_info("comp_body_size %x comp_buf_size %x ",
pic->comp_body_size,
pic->buf_size);
pr_info("mpred_mv_wr_start_adr %ld\n",
pic->mpred_mv_wr_start_addr);
pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
pic->dw_y_adr,
pic->dw_u_v_adr);
}
#ifdef MV_USE_FIXED_BUF
}
#endif
return ret;
}
static int config_pic(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config)
{
int ret = -1;
int i;
int pic_width = pbi->init_pic_w;
int pic_height = pbi->init_pic_h;
int lcu_size = 64; /*fixed 64*/
int pic_width_64 = (pic_width + 63) & (~0x3f);
int pic_height_32 = (pic_height + 31) & (~0x1f);
int pic_width_lcu = (pic_width_64 % lcu_size) ?
pic_width_64 / lcu_size + 1
: pic_width_64 / lcu_size;
int pic_height_lcu = (pic_height_32 % lcu_size) ?
pic_height_32 / lcu_size + 1
: pic_height_32 / lcu_size;
int lcu_total = pic_width_lcu * pic_height_lcu;
#ifdef MV_USE_FIXED_BUF
u32 mpred_mv_end = pbi->work_space_buf->mpred_mv.buf_start +
pbi->work_space_buf->mpred_mv.buf_size;
int mv_size = cal_mv_buf_size(pbi, pbi->init_pic_w, pbi->init_pic_h);
#endif
u32 y_adr = 0;
int buf_size = 0;
int losless_comp_header_size =
compute_losless_comp_header_size(pic_width,
pic_height);
int losless_comp_body_size = compute_losless_comp_body_size(pic_width,
pic_height, buf_alloc_depth == 10);
int mc_buffer_size = losless_comp_header_size + losless_comp_body_size;
int mc_buffer_size_h = (mc_buffer_size + 0xffff) >> 16;
int mc_buffer_size_u_v = 0;
int mc_buffer_size_u_v_h = 0;
int dw_mode = get_double_write_mode_init(pbi);
struct vdec_s *vdec = hw_to_vdec(pbi);
pbi->lcu_total = lcu_total;
if (dw_mode && (dw_mode & 0x20) == 0) {
int pic_width_dw = pic_width /
get_double_write_ratio(dw_mode & 0xf);
int pic_height_dw = pic_height /
get_double_write_ratio(dw_mode & 0xf);
int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f);
int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f);
int pic_width_lcu_dw = (pic_width_64_dw % lcu_size) ?
pic_width_64_dw / lcu_size + 1
: pic_width_64_dw / lcu_size;
int pic_height_lcu_dw = (pic_height_32_dw % lcu_size) ?
pic_height_32_dw / lcu_size + 1
: pic_height_32_dw / lcu_size;
int lcu_total_dw = pic_width_lcu_dw * pic_height_lcu_dw;
mc_buffer_size_u_v = lcu_total_dw * lcu_size * lcu_size / 2;
mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16;
/*64k alignment*/
buf_size = ((mc_buffer_size_u_v_h << 16) * 3);
buf_size = ((buf_size + 0xffff) >> 16) << 16;
}
if (mc_buffer_size & 0xffff) /*64k alignment*/
mc_buffer_size_h += 1;
if ((!pbi->mmu_enable) && ((dw_mode & 0x10) == 0))
buf_size += (mc_buffer_size_h << 16);
if (pbi->mmu_enable) {
pic_config->header_adr = decoder_bmmu_box_get_phy_addr(
pbi->bmmu_box, HEADER_BUFFER_IDX(pic_config->index));
if (debug & VP9_DEBUG_BUFMGR_MORE) {
pr_info("MMU header_adr %d: %ld\n",
pic_config->index, pic_config->header_adr);
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
pic_config->header_dw_adr = pic_config->header_adr +
vvp9_mmu_compress_header_size(pbi->init_pic_w, pbi->init_pic_h);
if (debug & VP9_DEBUG_BUFMGR_MORE) {
pr_info("MMU header_dw_adr %d: %ld size 0x%x\n",
pic_config->index, pic_config->header_dw_adr,
vvp9_mmu_compress_header_size(pbi->init_pic_w, pbi->init_pic_h));
}
}
#endif
}
i = pic_config->index;
#ifdef MV_USE_FIXED_BUF
if ((pbi->work_space_buf->mpred_mv.buf_start +
((i + 1) * mv_size))
<= mpred_mv_end
) {
#endif
if (buf_size > 0) {
ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box,
VF_BUFFER_IDX(i),
buf_size, DRIVER_NAME,
&pic_config->cma_alloc_addr);
if (ret < 0) {
pr_info(
"decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n",
VF_BUFFER_IDX(i),
buf_size
);
return ret;
}
if (pbi->enable_fence) {
//mm->fence_ref_release = vdec_fence_buffer_count_decrease;
vdec_fence_buffer_count_increase((ulong)vdec->sync);
INIT_LIST_HEAD(&vdec->sync->release_callback[VF_BUFFER_IDX(i)].node);
decoder_bmmu_box_add_callback_func(pbi->bmmu_box, VF_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[VF_BUFFER_IDX(i)]);
}
if (pic_config->cma_alloc_addr)
y_adr = pic_config->cma_alloc_addr;
else {
pr_info(
"decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n",
VF_BUFFER_IDX(i),
buf_size
);
return -1;
}
}
{
/*ensure get_pic_by_POC()
not get the buffer not decoded*/
pic_config->BUF_index = i;
pic_config->lcu_total = lcu_total;
pic_config->comp_body_size = losless_comp_body_size;
pic_config->buf_size = buf_size;
pic_config->mc_canvas_y = pic_config->index;
pic_config->mc_canvas_u_v = pic_config->index;
if (dw_mode & 0x10) {
pic_config->dw_y_adr = y_adr;
pic_config->dw_u_v_adr = y_adr +
((mc_buffer_size_u_v_h << 16) << 1);
pic_config->mc_canvas_y =
(pic_config->index << 1);
pic_config->mc_canvas_u_v =
(pic_config->index << 1) + 1;
} else if (dw_mode && ((dw_mode & 0x20) == 0)) {
pic_config->dw_y_adr = y_adr;
pic_config->dw_u_v_adr = pic_config->dw_y_adr +
((mc_buffer_size_u_v_h << 16) << 1);
}
#ifdef MV_USE_FIXED_BUF
pic_config->mpred_mv_wr_start_addr =
pbi->work_space_buf->mpred_mv.buf_start +
(pic_config->index * mv_size);
pic_config->mv_size = mv_size;
#endif
if (debug) {
pr_info
("%s index %d BUF_index %d ",
__func__, pic_config->index,
pic_config->BUF_index);
pr_info
("comp_body_size %x comp_buf_size %x ",
pic_config->comp_body_size,
pic_config->buf_size);
pr_info
("mpred_mv_wr_start_adr %ld\n",
pic_config->mpred_mv_wr_start_addr);
pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
pic_config->dw_y_adr,
pic_config->dw_u_v_adr);
}
ret = 0;
}
#ifdef MV_USE_FIXED_BUF
}
#endif
return ret;
}
static void init_pic_list(struct VP9Decoder_s *pbi)
{
int i;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *pic_config;
u32 header_size;
struct vdec_s *vdec = hw_to_vdec(pbi);
if (!pbi->is_used_v4l && pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
header_size = vvp9_mmu_compress_header_size(
pbi->max_pic_w, pbi->max_pic_h);
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable)
header_size <<= 1;
#endif
/*alloc VP9 compress header first*/
for (i = 0; i < pbi->used_buf_num; i++) {
unsigned long buf_addr;
if (decoder_bmmu_box_alloc_buf_phy
(pbi->bmmu_box,
HEADER_BUFFER_IDX(i), header_size,
DRIVER_HEADER_NAME,
&buf_addr) < 0) {
pr_info("%s malloc compress header failed %d\n",
DRIVER_HEADER_NAME, i);
pbi->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
return;
}
if (pbi->enable_fence) {
vdec_fence_buffer_count_increase((ulong)vdec->sync);
INIT_LIST_HEAD(&vdec->sync->release_callback[HEADER_BUFFER_IDX(i)].node);
decoder_bmmu_box_add_callback_func(pbi->bmmu_box, HEADER_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[HEADER_BUFFER_IDX(i)]);
//mm->fence_ref_release = vdec_fence_buffer_count_decrease;
}
}
}
for (i = 0; i < pbi->used_buf_num; i++) {
pic_config = &cm->buffer_pool->frame_bufs[i].buf;
pic_config->index = i;
pic_config->BUF_index = -1;
pic_config->mv_buf_index = -1;
if (vdec->parallel_dec == 1) {
pic_config->y_canvas_index = -1;
pic_config->uv_canvas_index = -1;
}
pic_config->y_crop_width = pbi->init_pic_w;
pic_config->y_crop_height = pbi->init_pic_h;
pic_config->double_write_mode = get_double_write_mode(pbi);
if (!pbi->is_used_v4l) {
if (config_pic(pbi, pic_config) < 0) {
if (debug)
pr_info("Config_pic %d fail\n",
pic_config->index);
pic_config->index = -1;
break;
}
if (pic_config->double_write_mode &&
(pic_config->double_write_mode & 0x20) == 0) {
set_canvas(pbi, pic_config);
}
}
}
for (; i < pbi->used_buf_num; i++) {
pic_config = &cm->buffer_pool->frame_bufs[i].buf;
pic_config->index = -1;
pic_config->BUF_index = -1;
pic_config->mv_buf_index = -1;
if (vdec->parallel_dec == 1) {
pic_config->y_canvas_index = -1;
pic_config->uv_canvas_index = -1;
}
}
pr_info("%s ok, used_buf_num = %d\n",
__func__, pbi->used_buf_num);
}
static void init_pic_list_hw(struct VP9Decoder_s *pbi)
{
int i;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *pic_config;
/*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);*/
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
(0x1 << 1) | (0x1 << 2));
for (i = 0; i < pbi->used_buf_num; i++) {
pic_config = &cm->buffer_pool->frame_bufs[i].buf;
if (pic_config->index < 0)
break;
if (pbi->mmu_enable && ((pic_config->double_write_mode & 0x10) == 0)) {
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
pic_config->header_adr >> 5);
} else {
/*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
* pic_config->mc_y_adr
* | (pic_config->mc_canvas_y << 8) | 0x1);
*/
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
pic_config->dw_y_adr >> 5);
}
#ifndef LOSLESS_COMPRESS_MODE
/*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
* pic_config->mc_u_v_adr
* | (pic_config->mc_canvas_u_v << 8)| 0x1);
*/
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
pic_config->header_adr >> 5);
#else
if (pic_config->double_write_mode & 0x10) {
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
pic_config->dw_u_v_adr >> 5);
}
#endif
}
WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1);
/*Zero out canvas registers in IPP -- avoid simulation X*/
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
(0 << 8) | (0 << 1) | 1);
for (i = 0; i < 32; i++)
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
}
static void dump_pic_list(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *pic_config;
int i;
for (i = 0; i < FRAME_BUFFERS; i++) {
pic_config = &cm->buffer_pool->frame_bufs[i].buf;
vp9_print(pbi, 0,
"Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d dec_idx %d slice_type %d w/h %d/%d adr: %x\n",
i,
pic_config->index,
#ifndef MV_USE_FIXED_BUF
pic_config->mv_buf_index,
#else
-1,
#endif
cm->buffer_pool->
frame_bufs[i].ref_count,
pic_config->vf_ref,
pic_config->decode_idx,
pic_config->slice_type,
pic_config->y_crop_width,
pic_config->y_crop_height,
pic_config->cma_alloc_addr
);
}
return;
}
static int config_pic_size(struct VP9Decoder_s *pbi, unsigned short bit_depth)
{
#ifdef LOSLESS_COMPRESS_MODE
unsigned int data32;
#endif
int losless_comp_header_size, losless_comp_body_size;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
frame_width = cur_pic_config->y_crop_width;
frame_height = cur_pic_config->y_crop_height;
cur_pic_config->bit_depth = bit_depth;
cur_pic_config->double_write_mode = get_double_write_mode(pbi);
losless_comp_header_size =
compute_losless_comp_header_size(cur_pic_config->y_crop_width,
cur_pic_config->y_crop_height);
losless_comp_body_size =
compute_losless_comp_body_size(cur_pic_config->y_crop_width,
cur_pic_config->y_crop_height, (bit_depth == VPX_BITS_10));
cur_pic_config->comp_body_size = losless_comp_body_size;
#ifdef LOSLESS_COMPRESS_MODE
data32 = READ_VREG(HEVC_SAO_CTRL5);
if (bit_depth == VPX_BITS_10)
data32 &= ~(1 << 9);
else
data32 |= (1 << 9);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
if (pbi->mmu_enable) {
/*bit[4] : paged_mem_mode*/
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
} else {
/*bit[3] smem mdoe*/
if (bit_depth == VPX_BITS_10)
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0 << 3));
else
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1 << 3));
}
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1)
WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, (losless_comp_body_size >> 5));
/*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,(0xff<<20) | (0xff<<10) | 0xff);*/
WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size);
if (get_double_write_mode(pbi) & 0x10)
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
#else
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
#endif
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
/*losless_comp_header_size_dw same as losless_comp_header_size*/
WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size);
}
#endif
return 0;
}
static int config_mc_buffer(struct VP9Decoder_s *pbi, unsigned short bit_depth)
{
int i;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
uint8_t scale_enable = 0;
if (debug&VP9_DEBUG_BUFMGR_MORE)
pr_info("config_mc_buffer entered .....\n");
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
(0 << 8) | (0 << 1) | 1);
for (i = 0; i < REFS_PER_FRAME; ++i) {
struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
if (!pic_config)
continue;
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
(pic_config->mc_canvas_u_v << 16)
| (pic_config->mc_canvas_u_v << 8)
| pic_config->mc_canvas_y);
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("refid %x mc_canvas_u_v %x mc_canvas_y %x\n",
i, pic_config->mc_canvas_u_v,
pic_config->mc_canvas_y);
}
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
(16 << 8) | (0 << 1) | 1);
for (i = 0; i < REFS_PER_FRAME; ++i) {
struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
if (!pic_config)
continue;
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
(pic_config->mc_canvas_u_v << 16)
| (pic_config->mc_canvas_u_v << 8)
| pic_config->mc_canvas_y);
}
/*auto_inc start index:0 field:0*/
WRITE_VREG(VP9D_MPP_REFINFO_TBL_ACCCONFIG, 0x1 << 2);
/*index 0:last 1:golden 2:altref*/
for (i = 0; i < REFS_PER_FRAME; i++) {
int ref_pic_body_size;
struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
if (!pic_config)
continue;
WRITE_VREG(VP9D_MPP_REFINFO_DATA, pic_config->y_crop_width);
WRITE_VREG(VP9D_MPP_REFINFO_DATA, pic_config->y_crop_height);
if (pic_config->y_crop_width != cur_pic_config->y_crop_width ||
pic_config->y_crop_height != cur_pic_config->y_crop_height) {
scale_enable |= (1 << i);
}
ref_pic_body_size =
compute_losless_comp_body_size(pic_config->y_crop_width,
pic_config->y_crop_height, (bit_depth == VPX_BITS_10));
WRITE_VREG(VP9D_MPP_REFINFO_DATA,
(pic_config->y_crop_width << 14)
/ cur_pic_config->y_crop_width);
WRITE_VREG(VP9D_MPP_REFINFO_DATA,
(pic_config->y_crop_height << 14)
/ cur_pic_config->y_crop_height);
if (pbi->mmu_enable)
WRITE_VREG(VP9D_MPP_REFINFO_DATA, 0);
else
WRITE_VREG(VP9D_MPP_REFINFO_DATA, ref_pic_body_size >> 5);
}
WRITE_VREG(VP9D_MPP_REF_SCALE_ENBL, scale_enable);
return 0;
}
static void clear_mpred_hw(struct VP9Decoder_s *pbi)
{
unsigned int data32;
data32 = READ_VREG(HEVC_MPRED_CTRL4);
data32 &= (~(1 << 6));
WRITE_VREG(HEVC_MPRED_CTRL4, data32);
}
static void config_mpred_hw(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
struct PIC_BUFFER_CONFIG_s *last_frame_pic_config =
&cm->prev_frame->buf;
unsigned int data32;
int mpred_curr_lcu_x;
int mpred_curr_lcu_y;
int mpred_mv_rd_end_addr;
mpred_mv_rd_end_addr = last_frame_pic_config->mpred_mv_wr_start_addr
+ last_frame_pic_config->mv_size;
//+ (last_frame_pic_config->lcu_total * MV_MEM_UNIT);
data32 = READ_VREG(HEVC_MPRED_CURR_LCU);
mpred_curr_lcu_x = data32 & 0xffff;
mpred_curr_lcu_y = (data32 >> 16) & 0xffff;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("cur pic_config index %d col pic_config index %d\n",
cur_pic_config->index, last_frame_pic_config->index);
WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412);
WRITE_VREG(HEVC_MPRED_ABV_START_ADDR,
pbi->work_space_buf->mpred_above.buf_start);
data32 = READ_VREG(HEVC_MPRED_CTRL4);
data32 &= (~(1 << 6));
data32 |= (cm->use_prev_frame_mvs << 6);
WRITE_VREG(HEVC_MPRED_CTRL4, data32);
WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
cur_pic_config->mpred_mv_wr_start_addr);
WRITE_VREG(HEVC_MPRED_MV_WPTR, cur_pic_config->mpred_mv_wr_start_addr);
WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
last_frame_pic_config->mpred_mv_wr_start_addr);
WRITE_VREG(HEVC_MPRED_MV_RPTR,
last_frame_pic_config->mpred_mv_wr_start_addr);
/*data32 = ((pbi->lcu_x_num - pbi->tile_width_lcu)*MV_MEM_UNIT);*/
/*WRITE_VREG(HEVC_MPRED_MV_WR_ROW_JUMP,data32);*/
/*WRITE_VREG(HEVC_MPRED_MV_RD_ROW_JUMP,data32);*/
WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr);
}
static void config_sao_hw(struct VP9Decoder_s *pbi, union param_u *params)
{
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *pic_config = &cm->cur_frame->buf;
unsigned int data32;
int lcu_size = 64;
int mc_buffer_size_u_v =
pic_config->lcu_total * lcu_size*lcu_size/2;
int mc_buffer_size_u_v_h =
(mc_buffer_size_u_v + 0xffff) >> 16;/*64k alignment*/
struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
if (get_double_write_mode(pbi) &&
(get_double_write_mode(pbi) & 0x20) == 0) {
WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->dw_y_adr);
WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->dw_u_v_adr);
WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->dw_y_adr);
WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->dw_u_v_adr);
} else {
if (!pbi->dw_mmu_enable) {
WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff);
WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff);
}
}
if (pbi->mmu_enable)
WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->header_adr);
if (pbi->is_used_v4l) {
WRITE_VREG(HEVC_SAO_Y_LENGTH, pic_config->luma_size);
WRITE_VREG(HEVC_SAO_C_LENGTH, pic_config->chroma_size);
if (debug & PRINT_FLAG_V4L_DETAIL) {
pr_info("[%d] config pic, id: %d, Y:(%x, %d) C:(%x, %d).\n",
v4l2_ctx->id, pic_config->index,
pic_config->dw_y_adr, pic_config->luma_size,
pic_config->dw_u_v_adr, pic_config->chroma_size);
}
} else {
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, pic_config->header_dw_adr);
}
#endif
data32 = (mc_buffer_size_u_v_h << 16) << 1;
/*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n",
data32, mc_buffer_size_u_v_h, pic_config->lcu_total);*/
WRITE_VREG(HEVC_SAO_Y_LENGTH, data32);
data32 = (mc_buffer_size_u_v_h << 16);
WRITE_VREG(HEVC_SAO_C_LENGTH, data32);
}
#ifdef VP9_10B_NV21
#ifdef DOS_PROJECT
data32 = READ_VREG(HEVC_SAO_CTRL1);
data32 &= (~0x3000);
/*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/
data32 |= (pbi->mem_map_mode << 12);
data32 &= (~0x3);
data32 |= 0x1; /* [1]:dw_disable [0]:cm_disable*/
WRITE_VREG(HEVC_SAO_CTRL1, data32);
/*[23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl
* [17:16] dw_h0_ctrl
*/
data32 = READ_VREG(HEVC_SAO_CTRL5);
/*set them all 0 for H265_NV21 (no down-scale)*/
data32 &= ~(0xff << 16);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
data32 &= (~0x30);
/*[5:4] address_format 00:linear 01:32x32 10:64x32*/
data32 |= (pbi->mem_map_mode << 4);
WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
#else
/*m8baby test1902*/
data32 = READ_VREG(HEVC_SAO_CTRL1);
data32 &= (~0x3000);
/*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/
data32 |= (pbi->mem_map_mode << 12);
data32 &= (~0xff0);
/*data32 |= 0x670;*/ /*Big-Endian per 64-bit*/
data32 |= 0x880; /*.Big-Endian per 64-bit */
data32 &= (~0x3);
data32 |= 0x1; /*[1]:dw_disable [0]:cm_disable*/
WRITE_VREG(HEVC_SAO_CTRL1, data32);
/* [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl
*[19:18] dw_h1_ctrl [17:16] dw_h0_ctrl
*/
data32 = READ_VREG(HEVC_SAO_CTRL5);
/* set them all 0 for H265_NV21 (no down-scale)*/
data32 &= ~(0xff << 16);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
data32 &= (~0x30);
/*[5:4] address_format 00:linear 01:32x32 10:64x32*/
data32 |= (pbi->mem_map_mode << 4);
data32 &= (~0xF);
data32 |= 0x8; /*Big-Endian per 64-bit*/
WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
#endif
#else
data32 = READ_VREG(HEVC_SAO_CTRL1);
data32 &= (~(3 << 14));
data32 |= (2 << 14); /* line align with 64*/
data32 &= (~0x3000);
/* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */
data32 |= (pbi->mem_map_mode << 12);
data32 &= (~0xff0);
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable == 0)
data32 |= ((pbi->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */
#else
data32 |= ((pbi->endian >> 8) & 0xfff);
#endif
data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/
if (get_double_write_mode(pbi) == 0)
data32 |= 0x2; /*disable double write*/
else if (get_double_write_mode(pbi) & 0x10)
data32 |= 0x1; /*disable cm*/
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { /* >= G12A dw write control */
unsigned int data;
data = READ_VREG(HEVC_DBLK_CFGB);
data &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/
if (get_double_write_mode(pbi) == 0)
data |= (0x1 << 8); /*enable first write*/
else if (get_double_write_mode(pbi) & 0x10)
data |= (0x1 << 9); /*double write only*/
else
data |= ((0x1 << 8) |(0x1 << 9));
WRITE_VREG(HEVC_DBLK_CFGB, data);
}
/* swap uv */
if (pbi->is_used_v4l) {
if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
(v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
data32 &= ~(1 << 8); /* NV21 */
else
data32 |= (1 << 8); /* NV12 */
}
/*
* [31:24] ar_fifo1_axi_thred
* [23:16] ar_fifo0_axi_thred
* [15:14] axi_linealign, 0-16bytes, 1-32bytes, 2-64bytes
* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32
* [11:08] axi_lendian_C
* [07:04] axi_lendian_Y
* [3] reserved
* [2] clk_forceon
* [1] dw_disable:disable double write output
* [0] cm_disable:disable compress output
*/
WRITE_VREG(HEVC_SAO_CTRL1, data32);
if (get_double_write_mode(pbi) & 0x10) {
/* [23:22] dw_v1_ctrl
*[21:20] dw_v0_ctrl
*[19:18] dw_h1_ctrl
*[17:16] dw_h0_ctrl
*/
data32 = READ_VREG(HEVC_SAO_CTRL5);
/*set them all 0 for H265_NV21 (no down-scale)*/
data32 &= ~(0xff << 16);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
} else {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7)
WRITE_VREG(HEVC_SAO_CTRL26, 0);
data32 = READ_VREG(HEVC_SAO_CTRL5);
data32 &= (~(0xff << 16));
if ((get_double_write_mode(pbi) & 0xf) == 8 ||
(get_double_write_mode(pbi) & 0xf) == 9) {
data32 |= (0xff << 16);
WRITE_VREG(HEVC_SAO_CTRL26, 0xf);
} else if ((get_double_write_mode(pbi) & 0xf) == 2 ||
(get_double_write_mode(pbi) & 0xf) == 3)
data32 |= (0xff << 16);
else if ((get_double_write_mode(pbi) & 0xf) == 4)
data32 |= (0x33 << 16);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
}
data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
data32 &= (~0x30);
/* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */
data32 |= (pbi->mem_map_mode << 4);
data32 &= (~0xf);
data32 |= (pbi->endian & 0xf); /* valid only when double write only */
/* swap uv */
if (pbi->is_used_v4l) {
if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
(v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
data32 |= (1 << 12); /* NV21 */
else
data32 &= ~(1 << 12); /* NV12 */
}
data32 &= (~(3 << 8));
data32 |= (2 << 8); /* line align with 64 for dw only */
/*
* [3:0] little_endian
* [5:4] address_format 00:linear 01:32x32 10:64x32
* [7:6] reserved
* [9:8] Linear_LineAlignment 00:16byte 01:32byte 10:64byte
* [11:10] reserved
* [12] CbCr_byte_swap
* [31:13] reserved
*/
WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
#endif
}
static void vp9_config_work_space_hw(struct VP9Decoder_s *pbi, u32 mask)
{
struct BuffInfo_s *buf_spec = pbi->work_space_buf;
unsigned int data32, data_tmp;
int losless_comp_header_size, losless_comp_body_size;
if (debug && pbi->init_flag == 0)
pr_info("%s w %d h %d %x %x %x %x %x %x %x %x %x %x %x %x\n",
__func__,
buf_spec->max_width,
buf_spec->max_height,
buf_spec->ipp.buf_start,
buf_spec->start_adr,
buf_spec->short_term_rps.buf_start,
buf_spec->vps.buf_start,
buf_spec->sps.buf_start,
buf_spec->pps.buf_start,
buf_spec->sao_up.buf_start,
buf_spec->swap_buf.buf_start,
buf_spec->swap_buf2.buf_start,
buf_spec->scalelut.buf_start,
buf_spec->dblk_para.buf_start,
buf_spec->dblk_data.buf_start);
if (mask & HW_MASK_FRONT) {
if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0)
WRITE_VREG(HEVC_RPM_BUFFER, (u32)pbi->rpm_phy_addr);
WRITE_VREG(HEVC_SHORT_TERM_RPS,
buf_spec->short_term_rps.buf_start);
/*WRITE_VREG(HEVC_VPS_BUFFER, buf_spec->vps.buf_start);*/
/*WRITE_VREG(HEVC_SPS_BUFFER, buf_spec->sps.buf_start);*/
WRITE_VREG(HEVC_PPS_BUFFER, buf_spec->pps.buf_start);
WRITE_VREG(HEVC_STREAM_SWAP_BUFFER,
buf_spec->swap_buf.buf_start);
WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2,
buf_spec->swap_buf2.buf_start);
WRITE_VREG(LMEM_DUMP_ADR, (u32)pbi->lmem_phy_addr);
}
if ((mask & HW_MASK_BACK) == 0)
return;
#ifdef LOSLESS_COMPRESS_MODE
losless_comp_header_size =
compute_losless_comp_header_size(pbi->init_pic_w,
pbi->init_pic_h);
losless_comp_body_size =
compute_losless_comp_body_size(pbi->init_pic_w,
pbi->init_pic_h, buf_alloc_depth == 10);
#endif
WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE,
buf_spec->ipp.buf_start);
//WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start);
//WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
/* cfg_addr_adp*/
WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_para.buf_start);
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("Write HEVC_DBLK_CFGE\n");
}
/* cfg_p_addr */
WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start);
/* cfg_d_addr */
WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
/*
* data32 = (READ_VREG(P_HEVC_DBLK_CFG3)>>8) & 0xff; // xio left offset, default is 0x40
* data32 = data32 * 2;
* data32 = (READ_VREG(P_HEVC_DBLK_CFG3)>>16) & 0xff; // adp left offset, default is 0x040
* data32 = data32 * 2;
*/
if (buf_spec->max_width <= 4096 && buf_spec->max_height <= 2304)
WRITE_VREG(HEVC_DBLK_CFG3, 0x404010); //default value
else
WRITE_VREG(HEVC_DBLK_CFG3, 0x808020); // make left storage 2 x 4k]
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
"HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3));
}
#ifdef LOSLESS_COMPRESS_MODE
if (pbi->mmu_enable) {
/*bit[4] : paged_mem_mode*/
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1)
WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0);
} else {
/*if(cur_pic_config->bit_depth == VPX_BITS_10)
* WRITE_VREG(P_HEVCD_MPP_DECOMP_CTL1, (0<<3));
*/
/*bit[3] smem mdoe*/
/*else WRITE_VREG(P_HEVCD_MPP_DECOMP_CTL1, (1<<3));*/
/*bit[3] smem mdoe*/
WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,
(losless_comp_body_size >> 5));
}
/*WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,
(losless_comp_body_size >> 5));*/
/*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,
(0xff<<20) | (0xff<<10) | 0xff);*/
/*8-bit mode */
WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size);
if (get_double_write_mode(pbi) & 0x10)
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
#else
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
#endif
if (pbi->mmu_enable) {
WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR, buf_spec->mmu_vbh.buf_start);
WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR, buf_spec->mmu_vbh.buf_start
+ VBH_BUF_SIZE(buf_spec));
/*data32 = READ_VREG(P_HEVC_SAO_CTRL9);*/
/*data32 |= 0x1;*/
/*WRITE_VREG(P_HEVC_SAO_CTRL9, data32);*/
/* use HEVC_CM_HEADER_START_ADDR */
data32 = READ_VREG(HEVC_SAO_CTRL5);
data32 |= (1<<10);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
data_tmp = READ_VREG(HEVC_SAO_CTRL9);
data_tmp |= (1<<10);
WRITE_VREG(HEVC_SAO_CTRL9, data_tmp);
WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size);
WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size);
WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR2, buf_spec->mmu_vbh_dw.buf_start);
WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR2, buf_spec->mmu_vbh_dw.buf_start
+ DW_VBH_BUF_SIZE(buf_spec));
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) {
if (get_double_write_mode(pbi) & 0x20) {
WRITE_VREG(HEVC_DW_VH0_ADDDR,
buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec) * 2);
WRITE_VREG(HEVC_DW_VH1_ADDDR,
buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec) * 3);
}
}
data32 = READ_VREG(HEVC_SAO_CTRL5);
/* use HEVC_CM_HEADER_START_ADDR */
data32 |= (1<<15);
WRITE_VREG(HEVC_SAO_CTRL5, data32);
}
#endif
/* config mpred axi burst threshold */
WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412);
#ifdef CO_MV_COMPRESS
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) {
data32 = READ_VREG(HEVC_MPRED_CTRL4);
data32 |= (1 << 1);
WRITE_VREG(HEVC_MPRED_CTRL4, data32);
}
#endif
WRITE_VREG(VP9_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start);
WRITE_VREG(LMEM_DUMP_ADR, (u32)pbi->lmem_phy_addr);
WRITE_VREG(VP9_PROB_SWAP_BUFFER, pbi->prob_buffer_phy_addr);
WRITE_VREG(VP9_COUNT_SWAP_BUFFER, pbi->count_buffer_phy_addr);
if (pbi->mmu_enable) {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, pbi->frame_mmu_map_phy_addr);
else
WRITE_VREG(VP9_MMU_MAP_BUFFER, pbi->frame_mmu_map_phy_addr);
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) {
WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, pbi->frame_mmu_dw_map_phy_addr);
//WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, pbi->frame_mmu_dw_map_phy_addr);
} else {
WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, pbi->frame_mmu_dw_map_phy_addr);
}
WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0);
WRITE_VREG(HEVC_SAO_C_START_ADDR, 0);
#ifdef VP9_10B_HED_FB
WRITE_VREG(HEVC_ASSIST_FB_MMU_MAP_ADDR2, FB_FRAME_MMU_MAP_ADDR);
#ifdef VP9_10B_HED_SAME_FB
WRITE_VREG(HEVC_ASSIST_FBD_MMU_MAP_ADDR2, FB_FRAME_MMU_MAP_ADDR);
#endif
#endif
}
#endif
}
#ifdef VP9_LPF_LVL_UPDATE
/*
* Defines, declarations, sub-functions for vp9 de-block loop
filter Thr/Lvl table update
* - struct segmentation is for loop filter only (removed something)
* - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will
be instantiated in C_Entry
* - vp9_loop_filter_init run once before decoding start
* - vp9_loop_filter_frame_init run before every frame decoding start
* - set video format to VP9 is in vp9_loop_filter_init
*/
#define MAX_LOOP_FILTER 63
#define MAX_REF_LF_DELTAS 4
#define MAX_MODE_LF_DELTAS 2
/*#define INTRA_FRAME 0*/
/*#define LAST_FRAME 1*/
/*#define MAX_REF_FRAMES 4*/
#define SEGMENT_DELTADATA 0
#define SEGMENT_ABSDATA 1
#define MAX_SEGMENTS 8
/*.#define SEG_TREE_PROBS (MAX_SEGMENTS-1)*/
/*no use for loop filter, if this struct for common use, pls add it back*/
/*#define PREDICTION_PROBS 3*/
/* no use for loop filter, if this struct for common use, pls add it back*/
enum SEG_LVL_FEATURES {
SEG_LVL_ALT_Q = 0, /*Use alternate Quantizer ....*/
SEG_LVL_ALT_LF = 1, /*Use alternate loop filter value...*/
SEG_LVL_REF_FRAME = 2, /*Optional Segment reference frame*/
SEG_LVL_SKIP = 3, /*Optional Segment (0,0) + skip mode*/
SEG_LVL_MAX = 4 /*Number of features supported*/
};
struct segmentation {
uint8_t enabled;
uint8_t update_map;
uint8_t update_data;
uint8_t abs_delta;
uint8_t temporal_update;
/*no use for loop filter, if this struct
*for common use, pls add it back
*/
/*vp9_prob tree_probs[SEG_TREE_PROBS]; */
/* no use for loop filter, if this struct
* for common use, pls add it back
*/
/*vp9_prob pred_probs[PREDICTION_PROBS];*/
int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
unsigned int feature_mask[MAX_SEGMENTS];
};
struct loop_filter_thresh {
uint8_t mblim;
uint8_t lim;
uint8_t hev_thr;
};
struct loop_filter_info_n {
struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
};
struct loopfilter {
int filter_level;
int sharpness_level;
int last_sharpness_level;
uint8_t mode_ref_delta_enabled;
uint8_t mode_ref_delta_update;
/*0 = Intra, Last, GF, ARF*/
signed char ref_deltas[MAX_REF_LF_DELTAS];
signed char last_ref_deltas[MAX_REF_LF_DELTAS];
/*0 = ZERO_MV, MV*/
signed char mode_deltas[MAX_MODE_LF_DELTAS];
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
};
static int vp9_clamp(int value, int low, int high)
{
return value < low ? low : (value > high ? high : value);
}
int segfeature_active(struct segmentation *seg,
int segment_id,
enum SEG_LVL_FEATURES feature_id) {
return seg->enabled &&
(seg->feature_mask[segment_id] & (1 << feature_id));
}
int get_segdata(struct segmentation *seg, int segment_id,
enum SEG_LVL_FEATURES feature_id) {
return seg->feature_data[segment_id][feature_id];
}
static void vp9_update_sharpness(struct loop_filter_info_n *lfi,
int sharpness_lvl)
{
int lvl;
/*For each possible value for the loop filter fill out limits*/
for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) {
/*Set loop filter parameters that control sharpness.*/
int block_inside_limit = lvl >> ((sharpness_lvl > 0) +
(sharpness_lvl > 4));
if (sharpness_lvl > 0) {
if (block_inside_limit > (9 - sharpness_lvl))
block_inside_limit = (9 - sharpness_lvl);
}
if (block_inside_limit < 1)
block_inside_limit = 1;
lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit;
lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) +
block_inside_limit);
}
}
/*instantiate this function once when decode is started*/
void vp9_loop_filter_init(struct VP9Decoder_s *pbi)
{
struct loop_filter_info_n *lfi = pbi->lfi;
struct loopfilter *lf = pbi->lf;
struct segmentation *seg_4lf = pbi->seg_4lf;
int i;
unsigned int data32;
memset(lfi, 0, sizeof(struct loop_filter_info_n));
memset(lf, 0, sizeof(struct loopfilter));
memset(seg_4lf, 0, sizeof(struct segmentation));
lf->sharpness_level = 0; /*init to 0 */
/*init limits for given sharpness*/
vp9_update_sharpness(lfi, lf->sharpness_level);
lf->last_sharpness_level = lf->sharpness_level;
/*init hev threshold const vectors (actually no use)
*for (i = 0; i <= MAX_LOOP_FILTER; i++)
* lfi->lfthr[i].hev_thr = (uint8_t)(i >> 4);
*/
/*Write to register*/
for (i = 0; i < 32; i++) {
unsigned int thr;
thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f)<<8) |
(lfi->lfthr[i * 2 + 1].mblim & 0xff);
thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) |
(lfi->lfthr[i * 2].mblim & 0xff);
WRITE_VREG(HEVC_DBLK_CFG9, thr);
}
/*video format is VP9*/
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
data32 = (0x3 << 14) | // (dw fifo thres r and b)
(0x3 << 12) | // (dw fifo thres r or b)
(0x3 << 10) | // (dw fifo thres not r/b)
(0x3 << 8) | // 1st/2nd write both enable
(0x1 << 0); // vp9 video format
if (get_double_write_mode(pbi) == 0x10)
data32 &= (~0x100);
} else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
data32 = (0x57 << 8) | /*1st/2nd write both enable*/
(0x1 << 0); /*vp9 video format*/
if (get_double_write_mode(pbi) == 0x10)
data32 &= (~0x100);
} else
data32 = 0x40400001;
WRITE_VREG(HEVC_DBLK_CFGB, data32);
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("[DBLK DEBUG] CFGB : 0x%x\n", data32);
}
/* perform this function per frame*/
void vp9_loop_filter_frame_init(struct segmentation *seg,
struct loop_filter_info_n *lfi, struct loopfilter *lf,
int default_filt_lvl) {
int i;
int seg_id;
/*n_shift is the multiplier for lf_deltas
*the multiplier is 1 for when filter_lvl is between 0 and 31;
*2 when filter_lvl is between 32 and 63
*/
const int scale = 1 << (default_filt_lvl >> 5);
/*update limits if sharpness has changed*/
if (lf->last_sharpness_level != lf->sharpness_level) {
vp9_update_sharpness(lfi, lf->sharpness_level);
lf->last_sharpness_level = lf->sharpness_level;
/*Write to register*/
for (i = 0; i < 32; i++) {
unsigned int thr;
thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8)
| (lfi->lfthr[i * 2 + 1].mblim & 0xff);
thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8)
| (lfi->lfthr[i * 2].mblim & 0xff);
WRITE_VREG(HEVC_DBLK_CFG9, thr);
}
}
for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {/*MAX_SEGMENTS = 8*/
int lvl_seg = default_filt_lvl;
if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) {
const int data = get_segdata(seg, seg_id,
SEG_LVL_ALT_LF);
lvl_seg = vp9_clamp(seg->abs_delta == SEGMENT_ABSDATA ?
data : default_filt_lvl + data,
0, MAX_LOOP_FILTER);
#ifdef DBG_LF_PRINT
pr_info("segfeature_active!!!seg_id=%d,lvl_seg=%d\n", seg_id, lvl_seg);
#endif
}
if (!lf->mode_ref_delta_enabled) {
/*we could get rid of this if we assume that deltas are set to
*zero when not in use; encoder always uses deltas
*/
memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id]));
} else {
int ref, mode;
const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME]
* scale;
#ifdef DBG_LF_PRINT
pr_info("LF_PRINT:vp9_loop_filter_frame_init,seg_id=%d\n", seg_id);
pr_info("ref_deltas[INTRA_FRAME]=%d\n", lf->ref_deltas[INTRA_FRAME]);
#endif
lfi->lvl[seg_id][INTRA_FRAME][0] =
vp9_clamp(intra_lvl, 0, MAX_LOOP_FILTER);
for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) {
/* LAST_FRAME = 1, MAX_REF_FRAMES = 4*/
for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) {
/*MAX_MODE_LF_DELTAS = 2*/
const int inter_lvl =
lvl_seg + lf->ref_deltas[ref] * scale
+ lf->mode_deltas[mode] * scale;
#ifdef DBG_LF_PRINT
#endif
lfi->lvl[seg_id][ref][mode] =
vp9_clamp(inter_lvl, 0,
MAX_LOOP_FILTER);
}
}
}
}
#ifdef DBG_LF_PRINT
/*print out thr/lvl table per frame*/
for (i = 0; i <= MAX_LOOP_FILTER; i++) {
pr_info("LF_PRINT:(%d)thr=%d,blim=%d,lim=%d\n",
i, lfi->lfthr[i].hev_thr, lfi->lfthr[i].mblim,
lfi->lfthr[i].lim);
}
for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {
pr_info("LF_PRINT:lvl(seg_id=%d)(mode=0,%d,%d,%d,%d)\n",
seg_id, lfi->lvl[seg_id][0][0],
lfi->lvl[seg_id][1][0], lfi->lvl[seg_id][2][0],
lfi->lvl[seg_id][3][0]);
pr_info("i(mode=1,%d,%d,%d,%d)\n", lfi->lvl[seg_id][0][1],
lfi->lvl[seg_id][1][1], lfi->lvl[seg_id][2][1],
lfi->lvl[seg_id][3][1]);
}
#endif
/*Write to register */
for (i = 0; i < 16; i++) {
unsigned int level;
level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) |
((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) |
((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) |
(lfi->lvl[i >> 1][0][i & 1] & 0x3f);
if (!default_filt_lvl)
level = 0;
WRITE_VREG(HEVC_DBLK_CFGA, level);
}
}
/* VP9_LPF_LVL_UPDATE */
#endif
static void vp9_init_decoder_hw(struct VP9Decoder_s *pbi, u32 mask)
{
unsigned int data32;
int i;
const unsigned short parser_cmd[PARSER_CMD_NUMBER] = {
0x0401, 0x8401, 0x0800, 0x0402, 0x9002, 0x1423,
0x8CC3, 0x1423, 0x8804, 0x9825, 0x0800, 0x04FE,
0x8406, 0x8411, 0x1800, 0x8408, 0x8409, 0x8C2A,
0x9C2B, 0x1C00, 0x840F, 0x8407, 0x8000, 0x8408,
0x2000, 0xA800, 0x8410, 0x04DE, 0x840C, 0x840D,
0xAC00, 0xA000, 0x08C0, 0x08E0, 0xA40E, 0xFC00,
0x7C00
};
#if 0
if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) {
/* Set MCR fetch priorities*/
data32 = 0x1 | (0x1 << 2) | (0x1 <<3) |
(24 << 4) | (32 << 11) | (24 << 18) | (32 << 25);
WRITE_VREG(HEVCD_MPP_DECOMP_AXIURG_CTL, data32);
}
#endif
/*if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("%s\n", __func__);*/
if (mask & HW_MASK_FRONT) {
data32 = READ_VREG(HEVC_PARSER_INT_CONTROL);
#if 1
/* set bit 31~29 to 3 if HEVC_STREAM_FIFO_CTL[29] is 1 */
data32 &= ~(7 << 29);
data32 |= (3 << 29);
#endif
data32 = data32 |
(1 << 24) |/*stream_buffer_empty_int_amrisc_enable*/
(1 << 22) |/*stream_fifo_empty_int_amrisc_enable*/
(1 << 7) |/*dec_done_int_cpu_enable*/
(1 << 4) |/*startcode_found_int_cpu_enable*/
(0 << 3) |/*startcode_found_int_amrisc_enable*/
(1 << 0) /*parser_int_enable*/
;
#ifdef SUPPORT_FB_DECODING
#ifndef FB_DECODING_TEST_SCHEDULE
/*fed_fb_slice_done_int_cpu_enable*/
if (pbi->used_stage_buf_num > 0)
data32 |= (1 << 10);
#endif
#endif
WRITE_VREG(HEVC_PARSER_INT_CONTROL, data32);
data32 = READ_VREG(HEVC_SHIFT_STATUS);
data32 = data32 |
(0 << 1) |/*emulation_check_off VP9
do not have emulation*/
(1 << 0)/*startcode_check_on*/
;
WRITE_VREG(HEVC_SHIFT_STATUS, data32);
WRITE_VREG(HEVC_SHIFT_CONTROL,
(0 << 14) | /*disable_start_code_protect*/
(1 << 10) | /*length_zero_startcode_en for VP9*/
(1 << 9) | /*length_valid_startcode_en for VP9*/
(3 << 6) | /*sft_valid_wr_position*/
(2 << 4) | /*emulate_code_length_sub_1*/
(3 << 1) | /*start_code_length_sub_1
VP9 use 0x00000001 as startcode (4 Bytes)*/
(1 << 0) /*stream_shift_enable*/
);
WRITE_VREG(HEVC_CABAC_CONTROL,
(1 << 0)/*cabac_enable*/
);
WRITE_VREG(HEVC_PARSER_CORE_CONTROL,
(1 << 0)/* hevc_parser_core_clk_en*/
);
WRITE_VREG(HEVC_DEC_STATUS_REG, 0);
}
if (mask & HW_MASK_BACK) {
/*Initial IQIT_SCALELUT memory
-- just to avoid X in simulation*/
if (is_rdma_enable())
rdma_back_end_work(pbi->rdma_phy_adr, RDMA_SIZE);
else {
WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/
for (i = 0; i < 1024; i++)
WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0);
}
}
if (mask & HW_MASK_FRONT) {
u32 decode_mode;
#ifdef ENABLE_SWAP_TEST
WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100);
#else
WRITE_VREG(HEVC_STREAM_SWAP_TEST, 0);
#endif
#ifdef MULTI_INSTANCE_SUPPORT
if (!pbi->m_ins_flag) {
if (pbi->low_latency_flag)
decode_mode = DECODE_MODE_SINGLE_LOW_LATENCY;
else
decode_mode = DECODE_MODE_SINGLE;
} else if (vdec_frame_based(hw_to_vdec(pbi)))
decode_mode = pbi->no_head ?
DECODE_MODE_MULTI_FRAMEBASE_NOHEAD :
DECODE_MODE_MULTI_FRAMEBASE;
else
decode_mode = DECODE_MODE_MULTI_STREAMBASE;
#ifdef SUPPORT_FB_DECODING
#ifndef FB_DECODING_TEST_SCHEDULE
if (pbi->used_stage_buf_num > 0)
decode_mode |= (0x01 << 24);
#endif
#endif
WRITE_VREG(DECODE_MODE, decode_mode);
WRITE_VREG(HEVC_DECODE_SIZE, 0);
WRITE_VREG(HEVC_DECODE_COUNT, 0);
#else
WRITE_VREG(DECODE_MODE, DECODE_MODE_SINGLE);
WRITE_VREG(HEVC_DECODE_PIC_BEGIN_REG, 0);
WRITE_VREG(HEVC_DECODE_PIC_NUM_REG, 0x7fffffff); /*to remove*/
#endif
/*Send parser_cmd*/
WRITE_VREG(HEVC_PARSER_CMD_WRITE, (1 << 16) | (0 << 0));
for (i = 0; i < PARSER_CMD_NUMBER; i++)
WRITE_VREG(HEVC_PARSER_CMD_WRITE, parser_cmd[i]);
WRITE_VREG(HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0);
WRITE_VREG(HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1);
WRITE_VREG(HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2);
WRITE_VREG(HEVC_PARSER_IF_CONTROL,
/* (1 << 8) |*/ /*sao_sw_pred_enable*/
(1 << 5) | /*parser_sao_if_en*/
(1 << 2) | /*parser_mpred_if_en*/
(1 << 0) /*parser_scaler_if_en*/
);
}
if (mask & HW_MASK_BACK) {
/*Changed to Start MPRED in microcode*/
/*
pr_info("[test.c] Start MPRED\n");
WRITE_VREG(HEVC_MPRED_INT_STATUS,
(1<<31)
);
*/
WRITE_VREG(HEVCD_IPP_TOP_CNTL,
(0 << 1) | /*enable ipp*/
(1 << 0) /*software reset ipp and mpp*/
);
WRITE_VREG(HEVCD_IPP_TOP_CNTL,
(1 << 1) | /*enable ipp*/
(0 << 0) /*software reset ipp and mpp*/
);
if (get_double_write_mode(pbi) & 0x10) {
/*Enable NV21 reference read mode for MC*/
WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
}
/*Initialize mcrcc and decomp perf counters*/
if (mcrcc_cache_alg_flag &&
pbi->init_flag == 0) {
mcrcc_perfcount_reset();
decomp_perfcount_reset();
}
}
return;
}
#ifdef CONFIG_HEVC_CLK_FORCED_ON
static void config_vp9_clk_forced_on(void)
{
unsigned int rdata32;
/*IQIT*/
rdata32 = READ_VREG(HEVC_IQIT_CLK_RST_CTRL);
WRITE_VREG(HEVC_IQIT_CLK_RST_CTRL, rdata32 | (0x1 << 2));
/* DBLK*/
rdata32 = READ_VREG(HEVC_DBLK_CFG0);
WRITE_VREG(HEVC_DBLK_CFG0, rdata32 | (0x1 << 2));
/* SAO*/
rdata32 = READ_VREG(HEVC_SAO_CTRL1);
WRITE_VREG(HEVC_SAO_CTRL1, rdata32 | (0x1 << 2));
/*MPRED*/
rdata32 = READ_VREG(HEVC_MPRED_CTRL1);
WRITE_VREG(HEVC_MPRED_CTRL1, rdata32 | (0x1 << 24));
/* PARSER*/
rdata32 = READ_VREG(HEVC_STREAM_CONTROL);
WRITE_VREG(HEVC_STREAM_CONTROL, rdata32 | (0x1 << 15));
rdata32 = READ_VREG(HEVC_SHIFT_CONTROL);
WRITE_VREG(HEVC_SHIFT_CONTROL, rdata32 | (0x1 << 15));
rdata32 = READ_VREG(HEVC_CABAC_CONTROL);
WRITE_VREG(HEVC_CABAC_CONTROL, rdata32 | (0x1 << 13));
rdata32 = READ_VREG(HEVC_PARSER_CORE_CONTROL);
WRITE_VREG(HEVC_PARSER_CORE_CONTROL, rdata32 | (0x1 << 15));
rdata32 = READ_VREG(HEVC_PARSER_INT_CONTROL);
WRITE_VREG(HEVC_PARSER_INT_CONTROL, rdata32 | (0x1 << 15));
rdata32 = READ_VREG(HEVC_PARSER_IF_CONTROL);
WRITE_VREG(HEVC_PARSER_IF_CONTROL,
rdata32 | (0x1 << 6) | (0x1 << 3) | (0x1 << 1));
/*IPP*/
rdata32 = READ_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG);
WRITE_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG, rdata32 | 0xffffffff);
/* MCRCC*/
rdata32 = READ_VREG(HEVCD_MCRCC_CTL1);
WRITE_VREG(HEVCD_MCRCC_CTL1, rdata32 | (0x1 << 3));
}
#endif
#ifdef MCRCC_ENABLE
static void dump_hit_rate(struct VP9Decoder_s *pbi)
{
if (debug & VP9_DEBUG_CACHE_HIT_RATE) {
mcrcc_get_hitrate(pbi->m_ins_flag);
decomp_get_hitrate();
decomp_get_comprate();
}
}
static void config_mcrcc_axi_hw(struct VP9Decoder_s *pbi)
{
unsigned int rdata32;
unsigned short is_inter;
/*pr_info("Entered config_mcrcc_axi_hw...\n");*/
WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2);/* reset mcrcc*/
is_inter = ((pbi->common.frame_type != KEY_FRAME) &&
(!pbi->common.intra_only)) ? 1 : 0;
if (!is_inter) { /* I-PIC*/
/*remove reset -- disables clock*/
WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0);
return;
}
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
mcrcc_get_hitrate(pbi->m_ins_flag);
decomp_get_hitrate();
decomp_get_comprate();
}
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
(0 << 8) | (1 << 1) | 0);
rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
/*Programme canvas1 */
rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
/*enable mcrcc progressive-mode*/
WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0);
}
static void config_mcrcc_axi_hw_new(struct VP9Decoder_s *pbi)
{
u32 curr_picnum = -1;
u32 lastref_picnum = -1;
u32 goldenref_picnum = -1;
u32 altref_picnum = -1;
u32 lastref_delta_picnum;
u32 goldenref_delta_picnum;
u32 altref_delta_picnum;
u32 rdata32;
u32 lastcanvas;
u32 goldencanvas;
u32 altrefcanvas;
u16 is_inter;
u16 lastref_inref;
u16 goldenref_inref;
u16 altref_inref;
u32 refcanvas_array[3], utmp;
int deltapicnum_array[3], tmp;
struct VP9_Common_s *cm = &pbi->common;
struct PIC_BUFFER_CONFIG_s *cur_pic_config
= &cm->cur_frame->buf;
curr_picnum = cur_pic_config->decode_idx;
if (cm->frame_refs[0].buf)
lastref_picnum = cm->frame_refs[0].buf->decode_idx;
if (cm->frame_refs[1].buf)
goldenref_picnum = cm->frame_refs[1].buf->decode_idx;
if (cm->frame_refs[2].buf)
altref_picnum = cm->frame_refs[2].buf->decode_idx;
lastref_delta_picnum = (lastref_picnum >= curr_picnum) ?
(lastref_picnum - curr_picnum) : (curr_picnum - lastref_picnum);
goldenref_delta_picnum = (goldenref_picnum >= curr_picnum) ?
(goldenref_picnum - curr_picnum) :
(curr_picnum - goldenref_picnum);
altref_delta_picnum =
(altref_picnum >= curr_picnum) ?
(altref_picnum - curr_picnum) : (curr_picnum - altref_picnum);
lastref_inref = (cm->frame_refs[0].idx != INVALID_IDX) ? 1 : 0;
goldenref_inref = (cm->frame_refs[1].idx != INVALID_IDX) ? 1 : 0;
altref_inref = (cm->frame_refs[2].idx != INVALID_IDX) ? 1 : 0;
if (debug & VP9_DEBUG_CACHE)
pr_info("%s--0--lastref_inref:%d goldenref_inref:%d altref_inref:%d\n",
__func__, lastref_inref, goldenref_inref, altref_inref);
WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); /* reset mcrcc */
is_inter = ((pbi->common.frame_type != KEY_FRAME)
&& (!pbi->common.intra_only)) ? 1 : 0;
if (!is_inter) { /* I-PIC */
/* remove reset -- disables clock */
WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0);
return;
}
if (!pbi->m_ins_flag)
dump_hit_rate(pbi);
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (1<<1) | 0);
lastcanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
goldencanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
altrefcanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
if (debug & VP9_DEBUG_CACHE)
pr_info("[test.c] lastref_canv:%x goldenref_canv:%x altref_canv:%x\n",
lastcanvas, goldencanvas, altrefcanvas);
altref_inref = ((altref_inref == 1) &&
(altrefcanvas != (goldenref_inref
? goldencanvas : 0xffffffff)) &&
(altrefcanvas != (lastref_inref ?
lastcanvas : 0xffffffff))) ? 1 : 0;
goldenref_inref = ((goldenref_inref == 1) &&
(goldencanvas != (lastref_inref ?
lastcanvas : 0xffffffff))) ? 1 : 0;
if (debug & VP9_DEBUG_CACHE)
pr_info("[test.c]--1--lastref_inref:%d goldenref_inref:%d altref_inref:%d\n",
lastref_inref, goldenref_inref, altref_inref);
altref_delta_picnum = altref_inref ? altref_delta_picnum : 0x7fffffff;
goldenref_delta_picnum = goldenref_inref ?
goldenref_delta_picnum : 0x7fffffff;
lastref_delta_picnum = lastref_inref ?
lastref_delta_picnum : 0x7fffffff;
if (debug & VP9_DEBUG_CACHE)
pr_info("[test.c]--1--lastref_delta_picnum:%d goldenref_delta_picnum:%d altref_delta_picnum:%d\n",
lastref_delta_picnum, goldenref_delta_picnum,
altref_delta_picnum);
/*ARRAY SORT HERE DELTA/CANVAS ARRAY SORT -- use DELTA*/
refcanvas_array[0] = lastcanvas;
refcanvas_array[1] = goldencanvas;
refcanvas_array[2] = altrefcanvas;
deltapicnum_array[0] = lastref_delta_picnum;
deltapicnum_array[1] = goldenref_delta_picnum;
deltapicnum_array[2] = altref_delta_picnum;
/* sort0 : 2-to-1 */
if (deltapicnum_array[2] < deltapicnum_array[1]) {
utmp = refcanvas_array[2];
refcanvas_array[2] = refcanvas_array[1];
refcanvas_array[1] = utmp;
tmp = deltapicnum_array[2];
deltapicnum_array[2] = deltapicnum_array[1];
deltapicnum_array[1] = tmp;
}
/* sort1 : 1-to-0 */
if (deltapicnum_array[1] < deltapicnum_array[0]) {
utmp = refcanvas_array[1];
refcanvas_array[1] = refcanvas_array[0];
refcanvas_array[0] = utmp;
tmp = deltapicnum_array[1];
deltapicnum_array[1] = deltapicnum_array[0];
deltapicnum_array[0] = tmp;
}
/* sort2 : 2-to-1 */
if (deltapicnum_array[2] < deltapicnum_array[1]) {
utmp = refcanvas_array[2]; refcanvas_array[2] =
refcanvas_array[1]; refcanvas_array[1] = utmp;
tmp = deltapicnum_array[2]; deltapicnum_array[2] =
deltapicnum_array[1]; deltapicnum_array[1] = tmp;
}
if (mcrcc_cache_alg_flag ==
THODIYIL_MCRCC_CANVAS_ALGX) { /*09/15/2017*/
/* lowest delta_picnum */
rdata32 = refcanvas_array[0];
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
/* 2nd-lowest delta_picnum */
rdata32 = refcanvas_array[1];
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
} else {
/* previous version -- LAST/GOLDEN ALWAYS -- before 09/13/2017*/
WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
(0 << 8) | (1<<1) | 0);
rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
/* Programme canvas1 */
rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
rdata32 = rdata32 & 0xffff;
rdata32 = rdata32 | (rdata32 << 16);
WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
}
WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); /* enable mcrcc progressive-mode */
return;
}
#endif
static void free_lf_buf(struct VP9Decoder_s *pbi)
{
if (pbi->lfi)
vfree(pbi->lfi);
if (pbi->lf)
vfree(pbi->lf);
if (pbi->seg_4lf)
vfree(pbi->seg_4lf);
pbi->lfi = NULL;
pbi->lf = NULL;
pbi->seg_4lf = NULL;
}
static int alloc_lf_buf(struct VP9Decoder_s *pbi)
{
pbi->lfi = vmalloc(sizeof(struct loop_filter_info_n));
pbi->lf = vmalloc(sizeof(struct loopfilter));
pbi->seg_4lf = vmalloc(sizeof(struct segmentation));
if (pbi->lfi == NULL || pbi->lf == NULL || pbi->seg_4lf == NULL) {
free_lf_buf(pbi);
pr_err("[test.c] vp9_loop_filter init malloc error!!!\n");
return -1;
}
return 0;
}
static void vp9_local_uninit(struct VP9Decoder_s *pbi)
{
pbi->rpm_ptr = NULL;
pbi->lmem_ptr = NULL;
if (pbi->rpm_addr) {
dma_free_coherent(amports_get_dma_device(),
RPM_BUF_SIZE,
pbi->rpm_addr,
pbi->rpm_phy_addr);
pbi->rpm_addr = NULL;
}
if (pbi->lmem_addr) {
if (pbi->lmem_phy_addr)
dma_free_coherent(amports_get_dma_device(),
LMEM_BUF_SIZE, pbi->lmem_addr,
pbi->lmem_phy_addr);
pbi->lmem_addr = NULL;
}
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
(vdec_secure(hw_to_vdec(pbi)))) {
tee_vp9_prob_free((u32)pbi->prob_buffer_phy_addr);
pbi->prob_buffer_phy_addr = 0;
pbi->count_buffer_phy_addr = 0;
pbi->prob_buffer_addr = NULL;
pbi->count_buffer_addr = NULL;
} else {
if (pbi->prob_buffer_addr) {
if (pbi->prob_buffer_phy_addr)
dma_free_coherent(amports_get_dma_device(),
PROB_BUF_SIZE, pbi->prob_buffer_addr,
pbi->prob_buffer_phy_addr);
pbi->prob_buffer_addr = NULL;
}
if (pbi->count_buffer_addr) {
if (pbi->count_buffer_phy_addr)
dma_free_coherent(amports_get_dma_device(),
COUNT_BUF_SIZE, pbi->count_buffer_addr,
pbi->count_buffer_phy_addr);
pbi->count_buffer_addr = NULL;
}
}
if (pbi->mmu_enable) {
u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi);
if (pbi->frame_mmu_map_addr) {
if (pbi->frame_mmu_map_phy_addr)
dma_free_coherent(amports_get_dma_device(),
mmu_map_size,
pbi->frame_mmu_map_addr,
pbi->frame_mmu_map_phy_addr);
pbi->frame_mmu_map_addr = NULL;
}
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
u32 dw_mmu_map_size = vvp9_frame_mmu_map_size(pbi);
if (pbi->frame_mmu_dw_map_addr) {
if (pbi->frame_mmu_dw_map_phy_addr)
dma_free_coherent(amports_get_dma_device(),
dw_mmu_map_size,
pbi->frame_mmu_dw_map_addr,
pbi->frame_mmu_dw_map_phy_addr);
pbi->frame_mmu_dw_map_addr = NULL;
}
}
#endif
#ifdef SUPPORT_FB_DECODING
if (pbi->stage_mmu_map_addr) {
if (pbi->stage_mmu_map_phy_addr)
dma_free_coherent(amports_get_dma_device(),
STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS,
pbi->stage_mmu_map_addr,
pbi->stage_mmu_map_phy_addr);
pbi->stage_mmu_map_addr = NULL;
}
uninit_stage_buf(pbi);
#endif
#ifdef VP9_LPF_LVL_UPDATE
free_lf_buf(pbi);
#endif
if (pbi->gvs)
vfree(pbi->gvs);
pbi->gvs = NULL;
}
static int vp9_local_init(struct VP9Decoder_s *pbi)
{
int ret = -1;
/*int losless_comp_header_size, losless_comp_body_size;*/
struct BuffInfo_s *cur_buf_info = NULL;
memset(&pbi->param, 0, sizeof(union param_u));
memset(&pbi->common, 0, sizeof(struct VP9_Common_s));
#ifdef MULTI_INSTANCE_SUPPORT
cur_buf_info = &pbi->work_space_buf_store;
if (force_bufspec) {
memcpy(cur_buf_info, &amvvp9_workbuff_spec[force_bufspec & 0xf],
sizeof(struct BuffInfo_s));
pr_info("force buffer spec %d\n", force_bufspec & 0xf);
} else {
if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) {
if (vdec_is_support_4k()) {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
memcpy(cur_buf_info, &amvvp9_workbuff_spec[2], /* 8k */
sizeof(struct BuffInfo_s));
} else
memcpy(cur_buf_info, &amvvp9_workbuff_spec[1], /* 4k */
sizeof(struct BuffInfo_s));
} else
memcpy(cur_buf_info, &amvvp9_workbuff_spec[0],/* 1080p */
sizeof(struct BuffInfo_s));
} else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb()
if (vdec_is_support_4k()) {
memcpy(cur_buf_info, &amvvp9_workbuff_spec[5], /* 8k */
sizeof(struct BuffInfo_s));
} else
memcpy(cur_buf_info, &amvvp9_workbuff_spec[3],/* 1080p */
sizeof(struct BuffInfo_s));
}
}
cur_buf_info->start_adr = pbi->buf_start;
if (!pbi->mmu_enable)
pbi->mc_buf_spec.buf_end = pbi->buf_start + pbi->buf_size;
#endif
init_buff_spec(pbi, cur_buf_info);
vp9_bufmgr_init(pbi, cur_buf_info, NULL);
/* vp9_max_pic_w/h for debug */
pbi->init_pic_w = (vp9_max_pic_w) ? vp9_max_pic_w:
((pbi->max_pic_w) ? pbi->max_pic_w : pbi->work_space_buf->max_width);
pbi->init_pic_h = (vp9_max_pic_h) ? vp9_max_pic_h:
((pbi->max_pic_h) ? pbi->max_pic_h : pbi->work_space_buf->max_height);
/* video is not support unaligned with 64 in tl1
** vdec canvas mode will be linear when dump yuv is set
*/
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
(pbi->double_write_mode != 0) &&
(((pbi->max_pic_w % 64) != 0) ||
(pbi->vvp9_amstream_dec_info.width % 64) != 0)) {
if (hw_to_vdec(pbi)->canvas_mode !=
CANVAS_BLKMODE_LINEAR)
pbi->mem_map_mode = 2;
else {
pbi->mem_map_mode = 0;
pr_info("vdec blkmod linear, force mem_map_mode 0\n");
}
}
#ifndef MV_USE_FIXED_BUF
if (!pbi->is_used_v4l) {
if (init_mv_buf_list(pbi) < 0) {
pr_err("%s: init_mv_buf_list fail\n", __func__);
return -1;
}
}
#endif
if (pbi->save_buffer_mode)
pbi->used_buf_num = MAX_BUF_NUM_SAVE_BUF;
else {
if (pbi->is_used_v4l)
pbi->used_buf_num = 5 + pbi->dynamic_buf_num_margin;
else
pbi->used_buf_num = max_buf_num;
}
if (pbi->used_buf_num > MAX_BUF_NUM)
pbi->used_buf_num = MAX_BUF_NUM;
if (pbi->used_buf_num > FRAME_BUFFERS)
pbi->used_buf_num = FRAME_BUFFERS;
pbi->pts_unstable = ((unsigned long)(pbi->vvp9_amstream_dec_info.param)
& 0x40) >> 6;
if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
pbi->rpm_addr = dma_alloc_coherent(amports_get_dma_device(),
RPM_BUF_SIZE,
&pbi->rpm_phy_addr, GFP_KERNEL);
if (pbi->rpm_addr == NULL) {
pr_err("%s: failed to alloc rpm buffer\n", __func__);
return -1;
}
pbi->rpm_ptr = pbi->rpm_addr;
}
pbi->lmem_addr = dma_alloc_coherent(amports_get_dma_device(),
LMEM_BUF_SIZE,
&pbi->lmem_phy_addr, GFP_KERNEL);
if (pbi->lmem_addr == NULL) {
pr_err("%s: failed to alloc lmem buffer\n", __func__);
return -1;
}
pbi->lmem_ptr = pbi->lmem_addr;
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
(vdec_secure(hw_to_vdec(pbi)))) {
u32 prob_addr, id;
id = tee_vp9_prob_malloc(&prob_addr);
if (prob_addr <= 0)
pr_err("%s, tee[%d] malloc prob buf failed\n", __func__, id);
else {
pbi->prob_buffer_phy_addr = prob_addr;
pbi->count_buffer_phy_addr = pbi->prob_buffer_phy_addr + PROB_BUF_SIZE;
}
pbi->prob_buffer_addr = NULL;
pbi->count_buffer_addr = NULL;
} else {
pbi->prob_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
PROB_BUF_SIZE,
&pbi->prob_buffer_phy_addr, GFP_KERNEL);
if (pbi->prob_buffer_addr == NULL) {
pr_err("%s: failed to alloc prob_buffer\n", __func__);
return -1;
}
memset(pbi->prob_buffer_addr, 0, PROB_BUF_SIZE);
pbi->count_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
COUNT_BUF_SIZE,
&pbi->count_buffer_phy_addr, GFP_KERNEL);
if (pbi->count_buffer_addr == NULL) {
pr_err("%s: failed to alloc count_buffer\n", __func__);
return -1;
}
memset(pbi->count_buffer_addr, 0, COUNT_BUF_SIZE);
}
if (pbi->mmu_enable) {
u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi);
pbi->frame_mmu_map_addr =
dma_alloc_coherent(amports_get_dma_device(),
mmu_map_size,
&pbi->frame_mmu_map_phy_addr, GFP_KERNEL);
if (pbi->frame_mmu_map_addr == NULL) {
pr_err("%s: failed to alloc count_buffer\n", __func__);
return -1;
}
memset(pbi->frame_mmu_map_addr, 0, COUNT_BUF_SIZE);
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable) {
u32 dw_mmu_map_size = vvp9_frame_mmu_map_size(pbi);
pbi->frame_mmu_dw_map_addr =
dma_alloc_coherent(amports_get_dma_device(),
dw_mmu_map_size,
&pbi->frame_mmu_dw_map_phy_addr, GFP_KERNEL);
if (pbi->frame_mmu_dw_map_addr == NULL) {
pr_err("%s: failed to alloc count_buffer mmu dw\n", __func__);
return -1;
}
memset(pbi->frame_mmu_dw_map_addr, 0, COUNT_BUF_SIZE);
}
#endif
#ifdef SUPPORT_FB_DECODING
if (pbi->m_ins_flag && stage_buf_num > 0) {
pbi->stage_mmu_map_addr =
dma_alloc_coherent(amports_get_dma_device(),
STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS,
&pbi->stage_mmu_map_phy_addr, GFP_KERNEL);
if (pbi->stage_mmu_map_addr == NULL) {
pr_err("%s: failed to alloc count_buffer\n", __func__);
return -1;
}
memset(pbi->stage_mmu_map_addr,
0, STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS);
init_stage_buf(pbi);
}
#endif
ret = 0;
return ret;
}
/********************************************
* Mailbox command
********************************************/
#define CMD_FINISHED 0
#define CMD_ALLOC_VIEW 1
#define CMD_FRAME_DISPLAY 3
#define CMD_DEBUG 10
#define DECODE_BUFFER_NUM_MAX 32
#define DISPLAY_BUFFER_NUM 6
#define video_domain_addr(adr) (adr&0x7fffffff)
#define DECODER_WORK_SPACE_SIZE 0x800000
#define spec2canvas(x) \
(((x)->uv_canvas_index << 16) | \
((x)->uv_canvas_index << 8) | \
((x)->y_canvas_index << 0))
static void set_canvas(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config)
{
struct vdec_s *vdec = hw_to_vdec(pbi);
int canvas_w = ALIGN(pic_config->y_crop_width, 64)/4;
int canvas_h = ALIGN(pic_config->y_crop_height, 32)/4;
int blkmode = pbi->mem_map_mode;
/*CANVAS_BLKMODE_64X32*/
if (pic_config->double_write_mode) {
canvas_w = pic_config->y_crop_width /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
canvas_h = pic_config->y_crop_height /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
/* sao ctrl1 reg alignline with 64, align with 64 */
canvas_w = ALIGN(canvas_w, 64);
canvas_h = ALIGN(canvas_h, 32);
if (vdec->parallel_dec == 1) {
if (pic_config->y_canvas_index == -1)
pic_config->y_canvas_index =
vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
if (pic_config->uv_canvas_index == -1)
pic_config->uv_canvas_index =
vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
} else {
pic_config->y_canvas_index = 128 + pic_config->index * 2;
pic_config->uv_canvas_index = 128 + pic_config->index * 2 + 1;
}
config_cav_lut_ex(pic_config->y_canvas_index,
pic_config->dw_y_adr, canvas_w, canvas_h,
CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7, VDEC_HEVC);
config_cav_lut_ex(pic_config->uv_canvas_index,
pic_config->dw_u_v_adr, canvas_w, canvas_h,
CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7, VDEC_HEVC);
#ifdef MULTI_INSTANCE_SUPPORT
pic_config->canvas_config[0].phy_addr =
pic_config->dw_y_adr;
pic_config->canvas_config[0].width =
canvas_w;
pic_config->canvas_config[0].height =
canvas_h;
pic_config->canvas_config[0].block_mode =
blkmode;
pic_config->canvas_config[0].endian = pbi->is_used_v4l ? 0 : 7;
pic_config->canvas_config[1].phy_addr =
pic_config->dw_u_v_adr;
pic_config->canvas_config[1].width =
canvas_w;
pic_config->canvas_config[1].height =
canvas_h;
pic_config->canvas_config[1].block_mode =
blkmode;
pic_config->canvas_config[1].endian = pbi->is_used_v4l ? 0 : 7;
#endif
}
}
static void set_frame_info(struct VP9Decoder_s *pbi, struct vframe_s *vf)
{
unsigned int ar = DISP_RATIO_ASPECT_RATIO_MAX;
vf->duration = pbi->frame_dur;
vf->duration_pulldown = 0;
vf->flag = 0;
vf->prop.master_display_colour = pbi->vf_dp;
vf->signal_type = pbi->video_signal_type;
if (vf->compWidth && vf->compHeight)
pbi->frame_ar = vf->compHeight * 0x100 / vf->compWidth;
ar = min_t(u32, ar, DISP_RATIO_ASPECT_RATIO_MAX);
vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
vf->sar_width = 1;
vf->sar_height = 1;
if (pbi->is_used_v4l && pbi->vf_dp.present_flag) {
struct aml_vdec_hdr_infos hdr;
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
memset(&hdr, 0, sizeof(hdr));
hdr.signal_type = vf->signal_type;
hdr.color_parms = pbi->vf_dp;
hdr.color_parms.luminance[0] = hdr.color_parms.luminance[0] / 10000;
vdec_v4l_set_hdr_infos(ctx, &hdr);
}
if ((pbi->chunk != NULL) && (pbi->chunk->hdr10p_data_buf != NULL)
&& (pbi->chunk->hdr10p_data_size != 0)) {
if (pbi->chunk->hdr10p_data_size <= 128) {
char *new_buf;
int i = 0;
new_buf = kzalloc(pbi->chunk->hdr10p_data_size, GFP_ATOMIC);
if (new_buf) {
memcpy(new_buf, pbi->chunk->hdr10p_data_buf, pbi->chunk->hdr10p_data_size);
if (debug & VP9_DEBUG_BUFMGR_MORE) {
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
"hdr10p data: (size %d)\n",
pbi->chunk->hdr10p_data_size);
for (i = 0; i < pbi->chunk->hdr10p_data_size; i++) {
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
"%02x ", pbi->chunk->hdr10p_data_buf[i]);
if (((i + 1) & 0xf) == 0)
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n");
}
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n");
}
vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size;
vf->hdr10p_data_buf = new_buf;
} else {
vp9_print(pbi, 0, "%s:hdr10p data vzalloc size(%d) fail\n",
__func__, pbi->chunk->hdr10p_data_size);
vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size;
vf->hdr10p_data_buf = new_buf;
}
}
vfree(pbi->chunk->hdr10p_data_buf);
pbi->chunk->hdr10p_data_buf = NULL;
pbi->chunk->hdr10p_data_size = 0;
}
vf->sidebind_type = pbi->sidebind_type;
vf->sidebind_channel_id = pbi->sidebind_channel_id;
}
static int vvp9_vf_states(struct vframe_states *states, void *op_arg)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
states->vf_pool_size = VF_POOL_SIZE;
states->buf_free_num = kfifo_len(&pbi->newframe_q);
states->buf_avail_num = kfifo_len(&pbi->display_q);
if (step == 2)
states->buf_avail_num = 0;
return 0;
}
static struct vframe_s *vvp9_vf_peek(void *op_arg)
{
struct vframe_s *vf[2] = {0, 0};
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
if (step == 2)
return NULL;
if (kfifo_len(&pbi->display_q) > VF_POOL_SIZE) {
vp9_print(pbi, VP9_DEBUG_BUFMGR,
"kfifo len:%d invaild, peek error\n",
kfifo_len(&pbi->display_q));
return NULL;
}
if (kfifo_out_peek(&pbi->display_q, (void *)&vf, 2)) {
if (vf[1]) {
vf[0]->next_vf_pts_valid = true;
vf[0]->next_vf_pts = vf[1]->pts;
} else
vf[0]->next_vf_pts_valid = false;
return vf[0];
}
return NULL;
}
static struct vframe_s *vvp9_vf_get(void *op_arg)
{
struct vframe_s *vf;
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
if (step == 2)
return NULL;
else if (step == 1)
step = 2;
if (kfifo_get(&pbi->display_q, &vf)) {
struct vframe_s *next_vf = NULL;
uint8_t index = vf->index & 0xff;
ATRACE_COUNTER(pbi->trace.disp_q_name, kfifo_len(&pbi->display_q));
if (index < pbi->used_buf_num ||
(vf->type & VIDTYPE_V4L_EOS)) {
vf->index_disp = pbi->vf_get_count;
pbi->vf_get_count++;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("%s idx: %d, type 0x%x w/h %d/%d, pts %d, %lld, ts: %lld\n",
__func__, index, vf->type,
vf->width, vf->height,
vf->pts,
vf->pts_us64,
vf->timestamp);
if (kfifo_peek(&pbi->display_q, &next_vf) && next_vf) {
vf->next_vf_pts_valid = true;
vf->next_vf_pts = next_vf->pts;
} else
vf->next_vf_pts_valid = false;
return vf;
}
}
return NULL;
}
static void vvp9_vf_put(struct vframe_s *vf, void *op_arg)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
uint8_t index;
if (vf == (&pbi->vframe_dummy))
return;
if (!vf)
return;
if (pbi->enable_fence && vf->fence) {
int ret, i;
mutex_lock(&pbi->fence_mutex);
ret = dma_fence_get_status(vf->fence);
if (ret == 0) {
for (i = 0; i < VF_POOL_SIZE; i++) {
if (pbi->fence_vf_s.fence_vf[i] == NULL) {
pbi->fence_vf_s.fence_vf[i] = vf;
pbi->fence_vf_s.used_size++;
mutex_unlock(&pbi->fence_mutex);
return;
}
}
}
mutex_unlock(&pbi->fence_mutex);
}
index = vf->index & 0xff;
if (pbi->enable_fence && vf->fence) {
vdec_fence_put(vf->fence);
vf->fence = NULL;
}
if (vf->hdr10p_data_buf) {
kfree(vf->hdr10p_data_buf);
vf->hdr10p_data_buf = NULL;
vf->hdr10p_data_size = 0;
}
kfifo_put(&pbi->newframe_q, (const struct vframe_s *)vf);
ATRACE_COUNTER(pbi->trace.new_q_name, kfifo_len(&pbi->newframe_q));
pbi->vf_put_count++;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("%s idx: %d, type 0x%x w/h %d/%d, pts %d, %lld, ts: %lld\n",
__func__, index, vf->type,
vf->width, vf->height,
vf->pts,
vf->pts_us64,
vf->timestamp);
if (index < pbi->used_buf_num) {
struct VP9_Common_s *cm = &pbi->common;
struct BufferPool_s *pool = cm->buffer_pool;
unsigned long flags;
lock_buffer_pool(pool, flags);
if (pool->frame_bufs[index].buf.vf_ref > 0)
pool->frame_bufs[index].buf.vf_ref--;
if (pbi->wait_buf)
WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
0x1);
pbi->last_put_idx = index;
pbi->new_frame_displayed++;
unlock_buffer_pool(pool, flags);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0 &&
pbi->back_not_run_ready)
trigger_schedule(pbi);
#endif
}
}
static int vvp9_event_cb(int type, void *data, void *private_data)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)private_data;
if (type & VFRAME_EVENT_RECEIVER_RESET) {
#if 0
unsigned long flags;
amhevc_stop();
#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
vf_light_unreg_provider(&vvp9_vf_prov);
#endif
spin_lock_irqsave(&pbi->lock, flags);
vvp9_local_init();
vvp9_prot_init();
spin_unlock_irqrestore(&pbi->lock, flags);
#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
vf_reg_provider(&vvp9_vf_prov);
#endif
amhevc_start();
#endif
} else if (type & VFRAME_EVENT_RECEIVER_REQ_STATE) {
struct provider_state_req_s *req =
(struct provider_state_req_s *)data;
if (req->req_type == REQ_STATE_SECURE)
req->req_result[0] = vdec_secure(hw_to_vdec(pbi));
else
req->req_result[0] = 0xffffffff;
}
return 0;
}
void inc_vf_ref(struct VP9Decoder_s *pbi, int index)
{
struct VP9_Common_s *cm = &pbi->common;
cm->buffer_pool->frame_bufs[index].buf.vf_ref++;
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("%s index = %d new vf_ref = %d\r\n",
__func__, index,
cm->buffer_pool->frame_bufs[index].buf.vf_ref);
}
static int frame_duration_adapt(struct VP9Decoder_s *pbi, struct vframe_s *vf, u32 valid)
{
u32 old_duration, pts_duration = 0;
u32 pts = vf->pts;
if (pbi->get_frame_dur == true)
return true;
pbi->frame_cnt_window++;
if (!(pbi->vp9_first_pts_ready == 1)) {
if (valid) {
pbi->pts1 = pts;
pbi->frame_cnt_window = 0;
pbi->duration_from_pts_done = 0;
pbi->vp9_first_pts_ready = 1;
} else {
return false;
}
} else {
if (pts < pbi->pts1) {
if (pbi->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) {
pbi->pts1 = pts;
pbi->frame_cnt_window = 0;
}
}
if (valid && (pbi->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) &&
(pts > pbi->pts1) && (pbi->duration_from_pts_done == 0)) {
old_duration = pbi->frame_dur;
pbi->pts2 = pts;
pts_duration = (((pbi->pts2 - pbi->pts1) * 16) /
(pbi->frame_cnt_window * 15));
if (close_to(pts_duration, old_duration, 2000)) {
pbi->frame_dur = pts_duration;
if ((debug & VP9_DEBUG_OUT_PTS) != 0)
pr_info("use calc duration %d\n", pts_duration);
}
if (pbi->duration_from_pts_done == 0) {
if (close_to(pts_duration, old_duration, RATE_CORRECTION_THRESHOLD)) {
pbi->duration_from_pts_done = 1;
} else {
if (!close_to(pts_duration,
old_duration, 1000) &&
!close_to(pts_duration,
pbi->frame_dur, 1000) &&
close_to(pts_duration,
pbi->last_duration, 200)) {
/* frame_dur must
* wrong,recover it.
*/
pbi->frame_dur = pts_duration;
}
pbi->pts1 = pbi->pts2;
pbi->frame_cnt_window = 0;
pbi->duration_from_pts_done = 0;
}
}
pbi->last_duration = pts_duration;
}
}
return true;
}
static void update_vf_memhandle(struct VP9Decoder_s *pbi,
struct vframe_s *vf, struct PIC_BUFFER_CONFIG_s *pic)
{
vf->mem_handle = NULL;
vf->mem_head_handle = NULL;
vf->mem_dw_handle = NULL;
/* keeper not needed for v4l solution */
if (pbi->is_used_v4l)
return;
if (vf->type & VIDTYPE_SCATTER) {
#ifdef VP9_10B_MMU_DW
if (pic->double_write_mode & 0x20) {
vf->mem_handle =
decoder_mmu_box_get_mem_handle(
pbi->mmu_box_dw, pic->index);
vf->mem_head_handle =
decoder_bmmu_box_get_mem_handle(
pbi->bmmu_box,
HEADER_BUFFER_IDX(pic->BUF_index));
vf->mem_dw_handle = NULL;
} else
#endif
{
vf->mem_handle =
decoder_mmu_box_get_mem_handle(
pbi->mmu_box, pic->index);
vf->mem_head_handle =
decoder_bmmu_box_get_mem_handle(
pbi->bmmu_box,
HEADER_BUFFER_IDX(pic->BUF_index));
if (pbi->double_write_mode == 3)
vf->mem_dw_handle =
decoder_bmmu_box_get_mem_handle(
pbi->bmmu_box,
VF_BUFFER_IDX(pic->BUF_index));
else
vf->mem_dw_handle = NULL;
}
} else {
vf->mem_handle =
decoder_bmmu_box_get_mem_handle(
pbi->bmmu_box, VF_BUFFER_IDX(pic->BUF_index));
vf->mem_head_handle = NULL;
vf->mem_dw_handle = NULL;
/*vf->mem_head_handle =
*decoder_bmmu_box_get_mem_handle(
*hevc->bmmu_box, VF_BUFFER_IDX(BUF_index));
*/
}
}
static inline void pbi_update_gvs(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config)
{
if (pbi->gvs->frame_height != pic_config->y_crop_height) {
pbi->gvs->frame_width = pic_config->y_crop_width;
pbi->gvs->frame_height = pic_config->y_crop_height;
}
if (pbi->gvs->frame_dur != pbi->frame_dur) {
pbi->gvs->frame_dur = pbi->frame_dur;
if (pbi->frame_dur != 0)
pbi->gvs->frame_rate = ((96000 * 10 / pbi->frame_dur) % 10) < 5 ?
96000 / pbi->frame_dur : (96000 / pbi->frame_dur +1);
else
pbi->gvs->frame_rate = -1;
}
pbi->gvs->status = pbi->stat | pbi->fatal_error;
}
static int prepare_display_buf(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *pic_config)
{
struct vframe_s *vf = NULL;
struct vdec_s *pvdec = hw_to_vdec(pbi);
int stream_offset = pic_config->stream_offset;
unsigned short slice_type = pic_config->slice_type;
struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
struct vdec_v4l2_buffer *fb = NULL;
ulong nv_order = VIDTYPE_VIU_NV21;
u32 pts_valid = 0, pts_us64_valid = 0;
u32 pts_save;
u64 pts_us64_save;
u32 frame_size = 0;
int i = 0;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("%s index = %d\r\n", __func__, pic_config->index);
if (kfifo_get(&pbi->newframe_q, &vf) == 0) {
pr_info("fatal error, no available buffer slot.");
return -1;
}
/* swap uv */
if (pbi->is_used_v4l) {
if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
(v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
nv_order = VIDTYPE_VIU_NV12;
}
if (pic_config->double_write_mode &&
(pic_config->double_write_mode & 0x20) == 0)
set_canvas(pbi, pic_config);
display_frame_count[pbi->index]++;
if (vf) {
if (!force_pts_unstable) {
if ((pic_config->pts == 0) || ((pic_config->pts <= pbi->last_pts) &&
(pic_config->pts64 <= pbi->last_pts_us64))) {
for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
if ((pbi->last_pts == pbi->frame_mode_pts_save[i]) ||
(pbi->last_pts_us64 == pbi->frame_mode_pts64_save[i])) {
pic_config->pts = pbi->frame_mode_pts_save[i - 1];
pic_config->pts64 = pbi->frame_mode_pts64_save[i - 1];
break;
}
}
if ((i == 0) || (pic_config->pts <= pbi->last_pts)) {
vp9_print(pbi, VP9_DEBUG_OUT_PTS,
"no found pts %d, set 0. %d, %d\n",
i, pic_config->pts, pbi->last_pts);
pic_config->pts = 0;
pic_config->pts64 = 0;
}
}
}
if (pbi->is_used_v4l) {
vf->v4l_mem_handle
= pbi->m_BUF[pic_config->BUF_index].v4l_ref_buf_addr;
fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
if (pbi->mmu_enable) {
vf->mm_box.bmmu_box = pbi->bmmu_box;
vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(pbi->buffer_wrap[pic_config->BUF_index]);
vf->mm_box.mmu_box = pbi->mmu_box;
vf->mm_box.mmu_idx = pbi->buffer_wrap[pic_config->index];
}
}
if (pbi->enable_fence) {
/* fill fence information. */
if (pbi->fence_usage == FENCE_USE_FOR_DRIVER)
vf->fence = pic_config->fence;
}
#ifdef MULTI_INSTANCE_SUPPORT
if (vdec_frame_based(pvdec)) {
vf->pts = pic_config->pts;
vf->pts_us64 = pic_config->pts64;
if (pbi->is_used_v4l && v4l_bitstream_id_enable)
vf->timestamp = pic_config->timestamp;
else
vf->timestamp = pic_config->pts64;
if (vf->pts != 0 || vf->pts_us64 != 0) {
pts_valid = 1;
pts_us64_valid = 1;
} else {
pts_valid = 0;
pts_us64_valid = 0;
}
} else
#endif
/* if (pts_lookup_offset(PTS_TYPE_VIDEO,
* stream_offset, &vf->pts, 0) != 0) {
*/
if ((pvdec->vbuf.no_parser == 0) || (pvdec->vbuf.use_ptsserv)) {
if (pts_lookup_offset_us64
(PTS_TYPE_VIDEO, stream_offset, &vf->pts,
&frame_size, 0,
&vf->pts_us64) != 0) {
#ifdef DEBUG_PTS
pbi->pts_missed++;
#endif
vf->pts = 0;
vf->pts_us64 = 0;
pts_valid = 0;
pts_us64_valid = 0;
} else {
#ifdef DEBUG_PTS
pbi->pts_hit++;
#endif
pts_valid = 1;
pts_us64_valid = 1;
}
}
fill_frame_info(pbi, pic_config, frame_size, vf->pts);
pts_save = vf->pts;
pts_us64_save = vf->pts_us64;
if (pbi->is_used_v4l || pbi->pts_unstable) {
frame_duration_adapt(pbi, vf, pts_valid);
if (pbi->duration_from_pts_done) {
pbi->pts_mode = PTS_NONE_REF_USE_DURATION;
} else {
if (pts_valid || pts_us64_valid)
pbi->pts_mode = PTS_NORMAL;
}
}
if ((pbi->pts_mode == PTS_NORMAL) && (vf->pts != 0)
&& pbi->get_frame_dur) {
int pts_diff = (int)vf->pts - pbi->last_lookup_pts;
if (pts_diff < 0) {
pbi->pts_mode_switching_count++;
pbi->pts_mode_recovery_count = 0;
if (pbi->pts_mode_switching_count >=
PTS_MODE_SWITCHING_THRESHOLD) {
pbi->pts_mode =
PTS_NONE_REF_USE_DURATION;
pr_info
("HEVC: switch to n_d mode.\n");
}
} else {
int p = PTS_MODE_SWITCHING_RECOVERY_THREASHOLD;
pbi->pts_mode_recovery_count++;
if (pbi->pts_mode_recovery_count > p) {
pbi->pts_mode_switching_count = 0;
pbi->pts_mode_recovery_count = 0;
}
}
}
if (vf->pts != 0)
pbi->last_lookup_pts = vf->pts;
if ((pbi->pts_mode == PTS_NONE_REF_USE_DURATION)
&& (slice_type != KEY_FRAME))
vf->pts = pbi->last_pts + DUR2PTS(pbi->frame_dur);
pbi->last_pts = vf->pts;
if (vf->pts_us64 != 0)
pbi->last_lookup_pts_us64 = vf->pts_us64;
if ((pbi->pts_mode == PTS_NONE_REF_USE_DURATION)
&& (slice_type != KEY_FRAME)) {
vf->pts_us64 =
pbi->last_pts_us64 +
(DUR2PTS(pbi->frame_dur) * 100 / 9);
}
pbi->last_pts_us64 = vf->pts_us64;
if (pbi->pts_mode == PTS_NONE_REF_USE_DURATION) {
vf->disp_pts = vf->pts;
vf->disp_pts_us64 = vf->pts_us64;
vf->pts = pts_save;
vf->pts_us64 = pts_us64_save;
} else {
vf->disp_pts = 0;
vf->disp_pts_us64 = 0;
}
vf->index = 0xff00 | pic_config->index;
if (pic_config->double_write_mode & 0x10) {
/* double write only */
vf->compBodyAddr = 0;
vf->compHeadAddr = 0;
#ifdef VP9_10B_MMU_DW
vf->dwBodyAddr = 0;
vf->dwHeadAddr = 0;
#endif
} else {
if (pbi->mmu_enable) {
vf->compBodyAddr = 0;
vf->compHeadAddr = pic_config->header_adr;
#ifdef VP9_10B_MMU_DW
vf->dwBodyAddr = 0;
vf->dwHeadAddr = 0;
if (pic_config->double_write_mode & 0x20) {
u32 mode = pic_config->double_write_mode & 0xf;
if (mode == 5 || mode == 3)
vf->dwHeadAddr = pic_config->header_dw_adr;
else if ((mode == 1 || mode == 2 || mode == 4)
&& (debug & VP9_DEBUG_OUT_PTS) == 0) {
vf->compHeadAddr = pic_config->header_dw_adr;
pr_debug("Use dw mmu for display\n");
}
}
#endif
} else {
/*vf->compBodyAddr = pic_config->mc_y_adr;
*vf->compHeadAddr = pic_config->mc_y_adr +
*pic_config->comp_body_size; */
/*head adr*/
}
vf->canvas0Addr = vf->canvas1Addr = 0;
}
if (pic_config->double_write_mode &&
(pic_config->double_write_mode & 0x20) == 0) {
vf->type = VIDTYPE_PROGRESSIVE |
VIDTYPE_VIU_FIELD;
vf->type |= nv_order;
if ((pic_config->double_write_mode == 3 ||
pic_config->double_write_mode == 5) &&
(!IS_8K_SIZE(pic_config->y_crop_width,
pic_config->y_crop_height))) {
vf->type |= VIDTYPE_COMPRESS;
if (pbi->mmu_enable)
vf->type |= VIDTYPE_SCATTER;
}
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag) {
vf->canvas0Addr = vf->canvas1Addr = -1;
vf->plane_num = 2;
vf->canvas0_config[0] =
pic_config->canvas_config[0];
vf->canvas0_config[1] =
pic_config->canvas_config[1];
vf->canvas1_config[0] =
pic_config->canvas_config[0];
vf->canvas1_config[1] =
pic_config->canvas_config[1];
} else
#endif
vf->canvas0Addr = vf->canvas1Addr =
spec2canvas(pic_config);
} else {
vf->canvas0Addr = vf->canvas1Addr = 0;
vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
if (pbi->mmu_enable)
vf->type |= VIDTYPE_SCATTER;
}
switch (pic_config->bit_depth) {
case VPX_BITS_8:
vf->bitdepth = BITDEPTH_Y8 |
BITDEPTH_U8 | BITDEPTH_V8;
break;
case VPX_BITS_10:
case VPX_BITS_12:
vf->bitdepth = BITDEPTH_Y10 |
BITDEPTH_U10 | BITDEPTH_V10;
break;
default:
vf->bitdepth = BITDEPTH_Y10 |
BITDEPTH_U10 | BITDEPTH_V10;
break;
}
if ((vf->type & VIDTYPE_COMPRESS) == 0)
vf->bitdepth =
BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
if (pic_config->bit_depth == VPX_BITS_8)
vf->bitdepth |= BITDEPTH_SAVING_MODE;
vf->width = pic_config->y_crop_width /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
vf->height = pic_config->y_crop_height /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
if (force_w_h != 0) {
vf->width = (force_w_h >> 16) & 0xffff;
vf->height = force_w_h & 0xffff;
}
if ((pic_config->double_write_mode & 0x20) &&
((pic_config->double_write_mode & 0xf) == 2 ||
(pic_config->double_write_mode & 0xf) == 4)) {
vf->compWidth = pic_config->y_crop_width /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
vf->compHeight = pic_config->y_crop_height /
get_double_write_ratio(
pic_config->double_write_mode & 0xf);
} else {
vf->compWidth = pic_config->y_crop_width;
vf->compHeight = pic_config->y_crop_height;
}
set_frame_info(pbi, vf);
if (force_fps & 0x100) {
u32 rate = force_fps & 0xff;
if (rate)
vf->duration = 96000/rate;
else
vf->duration = 0;
}
update_vf_memhandle(pbi, vf, pic_config);
if (vdec_stream_based(pvdec) && (!pvdec->vbuf.use_ptsserv)) {
vf->pts_us64 = stream_offset;
vf->pts = 0;
}
if ((debug & VP9_DEBUG_OUT_PTS) != 0) {
pr_info
("VP9 dec out pts: pts_mode=%d,dur=%d,pts(%d,%lld,%lld)(%d,%lld)\n",
pbi->pts_mode, pbi->frame_dur, vf->pts,
vf->pts_us64, vf->timestamp, pts_save,
pts_us64_save);
}
if (!(pic_config->y_crop_width == 196
&& pic_config->y_crop_height == 196
&& (debug & VP9_DEBUG_NO_TRIGGER_FRAME) == 0
&& (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX))) {
struct vdec_info tmp4x;
inc_vf_ref(pbi, pic_config->index);
decoder_do_frame_check(pvdec, vf);
vdec_vframe_ready(pvdec, vf);
kfifo_put(&pbi->display_q, (const struct vframe_s *)vf);
ATRACE_COUNTER(pbi->trace.pts_name, vf->pts);
ATRACE_COUNTER(pbi->trace.new_q_name, kfifo_len(&pbi->newframe_q));
ATRACE_COUNTER(pbi->trace.disp_q_name, kfifo_len(&pbi->display_q));
pbi->vf_pre_count++;
pbi_update_gvs(pbi, pic_config);
/*count info*/
vdec_count_info(pbi->gvs, 0, stream_offset);
if (stream_offset) {
if (slice_type == KEY_FRAME) {
pbi->gvs->i_decoded_frames++;
} else if (slice_type == INTER_FRAME) {
pbi->gvs->p_decoded_frames++;
} else if (slice_type == FRAME_TYPES) {
pbi->gvs->b_decoded_frames++;
}
}
memcpy(&tmp4x, pbi->gvs, sizeof(struct vdec_info));
tmp4x.bit_depth_luma = pbi->vp9_param.p.bit_depth;
tmp4x.bit_depth_chroma = pbi->vp9_param.p.bit_depth;
tmp4x.double_write_mode = pic_config->double_write_mode;
vdec_fill_vdec_frame(pvdec, &pbi->vframe_qos, &tmp4x,
vf, pic_config->hw_decode_time);
pvdec->vdec_fps_detec(pvdec->id);
if (without_display_mode == 0) {
if (pbi->is_used_v4l) {
if (v4l2_ctx->is_stream_off) {
vvp9_vf_put(vvp9_vf_get(pbi), pbi);
} else {
fb->task->submit(fb->task, TASK_TYPE_DEC);
}
} else {
vf_notify_receiver(pbi->provider_name,
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
}
} else
vvp9_vf_put(vvp9_vf_get(pbi), pbi);
} else {
pbi->stat |= VP9_TRIGGER_FRAME_DONE;
hevc_source_changed(VFORMAT_VP9, 196, 196, 30);
pr_debug("[%s %d] drop trigger frame width %d height %d state 0x%x\n",
__func__, __LINE__, vf->width,
vf->height, pbi->stat);
}
}
return 0;
}
static int notify_v4l_eos(struct vdec_s *vdec)
{
struct VP9Decoder_s *hw = (struct VP9Decoder_s *)vdec->private;
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
struct vframe_s *vf = &hw->vframe_dummy;
struct vdec_v4l2_buffer *fb = NULL;
int index = INVALID_IDX;
ulong expires;
if (hw->eos) {
if (hw->is_used_v4l) {
expires = jiffies + msecs_to_jiffies(2000);
while (INVALID_IDX == (index = v4l_get_free_fb(hw))) {
if (time_after(jiffies, expires) ||
v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx))
break;
}
if (index == INVALID_IDX) {
ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token);
if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) {
pr_err("[%d] EOS get free buff fail.\n", ctx->id);
return -1;
}
}
}
vf->type |= VIDTYPE_V4L_EOS;
vf->timestamp = ULONG_MAX;
vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb :
hw->m_BUF[index].v4l_ref_buf_addr;
fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
vdec_vframe_ready(vdec, vf);
kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
if (hw->is_used_v4l)
fb->task->submit(fb->task, TASK_TYPE_DEC);
else
vf_notify_receiver(vdec->vf_provider_name,
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
pr_info("[%d] VP9 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
}
return 0;
}
static void get_rpm_param(union param_u *params)
{
int i;
unsigned int data32;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("enter %s\r\n", __func__);
for (i = 0; i < 128; i++) {
do {
data32 = READ_VREG(RPM_CMD_REG);
/*pr_info("%x\n", data32);*/
} while ((data32 & 0x10000) == 0);
params->l.data[i] = data32&0xffff;
/*pr_info("%x\n", data32);*/
WRITE_VREG(RPM_CMD_REG, 0);
}
if (debug & VP9_DEBUG_BUFMGR)
pr_info("leave %s\r\n", __func__);
}
static void debug_buffer_mgr_more(struct VP9Decoder_s *pbi)
{
int i;
if (!(debug & VP9_DEBUG_BUFMGR_MORE))
return;
pr_info("vp9_param: (%d)\n", pbi->slice_idx);
for (i = 0; i < (RPM_END-RPM_BEGIN); i++) {
pr_info("%04x ", pbi->vp9_param.l.data[i]);
if (((i + 1) & 0xf) == 0)
pr_info("\n");
}
pr_info("=============param==========\r\n");
pr_info("profile %x\r\n", pbi->vp9_param.p.profile);
pr_info("show_existing_frame %x\r\n",
pbi->vp9_param.p.show_existing_frame);
pr_info("frame_to_show_idx %x\r\n",
pbi->vp9_param.p.frame_to_show_idx);
pr_info("frame_type %x\r\n", pbi->vp9_param.p.frame_type);
pr_info("show_frame %x\r\n", pbi->vp9_param.p.show_frame);
pr_info("e.r.r.o.r_resilient_mode %x\r\n",
pbi->vp9_param.p.error_resilient_mode);
pr_info("intra_only %x\r\n", pbi->vp9_param.p.intra_only);
pr_info("display_size_present %x\r\n",
pbi->vp9_param.p.display_size_present);
pr_info("reset_frame_context %x\r\n",
pbi->vp9_param.p.reset_frame_context);
pr_info("refresh_frame_flags %x\r\n",
pbi->vp9_param.p.refresh_frame_flags);
pr_info("bit_depth %x\r\n", pbi->vp9_param.p.bit_depth);
pr_info("width %x\r\n", pbi->vp9_param.p.width);
pr_info("height %x\r\n", pbi->vp9_param.p.height);
pr_info("display_width %x\r\n", pbi->vp9_param.p.display_width);
pr_info("display_height %x\r\n", pbi->vp9_param.p.display_height);
pr_info("ref_info %x\r\n", pbi->vp9_param.p.ref_info);
pr_info("same_frame_size %x\r\n", pbi->vp9_param.p.same_frame_size);
if (!(debug & VP9_DEBUG_DBG_LF_PRINT))
return;
pr_info("mode_ref_delta_enabled: 0x%x\r\n",
pbi->vp9_param.p.mode_ref_delta_enabled);
pr_info("sharpness_level: 0x%x\r\n",
pbi->vp9_param.p.sharpness_level);
pr_info("ref_deltas: 0x%x, 0x%x, 0x%x, 0x%x\r\n",
pbi->vp9_param.p.ref_deltas[0], pbi->vp9_param.p.ref_deltas[1],
pbi->vp9_param.p.ref_deltas[2], pbi->vp9_param.p.ref_deltas[3]);
pr_info("mode_deltas: 0x%x, 0x%x\r\n", pbi->vp9_param.p.mode_deltas[0],
pbi->vp9_param.p.mode_deltas[1]);
pr_info("filter_level: 0x%x\r\n", pbi->vp9_param.p.filter_level);
pr_info("seg_enabled: 0x%x\r\n", pbi->vp9_param.p.seg_enabled);
pr_info("seg_abs_delta: 0x%x\r\n", pbi->vp9_param.p.seg_abs_delta);
pr_info("seg_lf_feature_enabled: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n",
(pbi->vp9_param.p.seg_lf_info[0]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[1]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[2]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[3]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[4]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[5]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[6]>>15 & 1),
(pbi->vp9_param.p.seg_lf_info[7]>>15 & 1));
pr_info("seg_lf_feature_data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n",
(pbi->vp9_param.p.seg_lf_info[0] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[1] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[2] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[3] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[4] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[5] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[6] & 0x13f),
(pbi->vp9_param.p.seg_lf_info[7] & 0x13f));
}
static int recycle_mmu_buf_tail(struct VP9Decoder_s *pbi,
bool check_dma)
{
struct VP9_Common_s *const cm = &pbi->common;
if (pbi->used_4k_num == -1) {
pbi->used_4k_num =
READ_VREG(HEVC_SAO_MMU_STATUS) >> 16;
}
vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
"pic index %d page_start %d\n",
cm->cur_fb_idx_mmu, pbi->used_4k_num);
if (check_dma)
hevc_mmu_dma_check(hw_to_vdec(pbi));
if (pbi->is_used_v4l) {
int index = cm->cur_fb_idx_mmu;
struct internal_comp_buf *ibuf =
index_to_icomp_buf(pbi, index);
decoder_mmu_box_free_idx_tail(
ibuf->mmu_box,
ibuf->index,
pbi->used_4k_num);
} else {
decoder_mmu_box_free_idx_tail(
pbi->mmu_box,
cm->cur_fb_idx_mmu,
pbi->used_4k_num);
}
cm->cur_fb_idx_mmu = INVALID_IDX;
pbi->used_4k_num = -1;
return 0;
}
static void vp9_recycle_mmu_buf_tail(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
if (pbi->double_write_mode & 0x10)
return;
if (cm->cur_fb_idx_mmu != INVALID_IDX) {
recycle_mmu_buf_tail(pbi,
((pbi->used_4k_num == -1) &&
pbi->m_ins_flag) ? 1 : 0);
}
}
#ifdef MULTI_INSTANCE_SUPPORT
static void vp9_recycle_mmu_buf(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
if (pbi->is_used_v4l)
return;
if (pbi->double_write_mode & 0x10)
return;
if (cm->cur_fb_idx_mmu != INVALID_IDX) {
decoder_mmu_box_free_idx(pbi->mmu_box,
cm->cur_fb_idx_mmu);
cm->cur_fb_idx_mmu = INVALID_IDX;
pbi->used_4k_num = -1;
}
}
void vp9_recycle_mmu_work(struct work_struct *work)
{
struct VP9Decoder_s *pbi = container_of(work,
struct VP9Decoder_s, recycle_mmu_work);
if (pbi)
vp9_recycle_mmu_buf(pbi);
}
#endif
static void dec_again_process(struct VP9Decoder_s *pbi)
{
amhevc_stop();
pbi->dec_result = DEC_RESULT_AGAIN;
if (pbi->process_state ==
PROC_STATE_DECODESLICE) {
pbi->process_state =
PROC_STATE_SENDAGAIN;
if (pbi->mmu_enable) {
/*
* Because vp9_recycle_mmu_buf has sleep function,we can't
* call it directly. Use a recycle_mmu_work to substitude it.
*/
vdec_schedule_work(&pbi->recycle_mmu_work);
}
}
reset_process_time(pbi);
vdec_schedule_work(&pbi->work);
}
int continue_decoding(struct VP9Decoder_s *pbi)
{
int ret;
int i;
struct VP9_Common_s *const cm = &pbi->common;
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
debug_buffer_mgr_more(pbi);
if (pbi->is_used_v4l && ctx->param_sets_from_ucode)
pbi->res_ch_flag = 0;
bit_depth_luma = pbi->vp9_param.p.bit_depth;
bit_depth_chroma = pbi->vp9_param.p.bit_depth;
if ((pbi->vp9_param.p.bit_depth >= VPX_BITS_10) &&
(get_double_write_mode(pbi) == 0x10)) {
pbi->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
pr_err("fatal err, bit_depth %d, unsupport dw 0x10\n",
pbi->vp9_param.p.bit_depth);
return -1;
}
if (pbi->process_state != PROC_STATE_SENDAGAIN) {
ret = vp9_bufmgr_process(pbi, &pbi->vp9_param);
if (!pbi->m_ins_flag)
pbi->slice_idx++;
} else {
union param_u *params = &pbi->vp9_param;
if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
ret = vp9_alloc_mmu(pbi,
cm->new_fb_idx,
params->p.width,
params->p.height,
params->p.bit_depth,
pbi->frame_mmu_map_addr);
if (ret >= 0)
cm->cur_fb_idx_mmu = cm->new_fb_idx;
else
pr_err("can't alloc need mmu1,idx %d ret =%d\n",
cm->new_fb_idx,
ret);
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
ret = vp9_alloc_mmu_dw(pbi,
cm->new_fb_idx,
params->p.width,
params->p.height,
params->p.bit_depth,
pbi->frame_mmu_dw_map_addr);
if (ret < 0)
pr_err("can't alloc need dw mmu1,idx %d ret =%d\n",
cm->new_fb_idx,
ret);
}
#endif
} else {
ret = 0;
}
WRITE_VREG(HEVC_PARSER_PICTURE_SIZE,
(params->p.height << 16) | params->p.width);
}
if (ret < 0) {
pr_info("vp9_bufmgr_process=> %d, VP9_10B_DISCARD_NAL\r\n",
ret);
WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DISCARD_NAL);
cm->show_frame = 0;
if (pbi->mmu_enable) {
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START);
vp9_recycle_mmu_buf(pbi);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END);
}
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag) {
pbi->dec_result = DEC_RESULT_DONE;
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num == 0)
#endif
amhevc_stop();
vdec_schedule_work(&pbi->work);
}
#endif
return ret;
} else if (ret == 0) {
struct PIC_BUFFER_CONFIG_s *cur_pic_config
= &cm->cur_frame->buf;
cur_pic_config->decode_idx = pbi->frame_count;
if (pbi->process_state != PROC_STATE_SENDAGAIN) {
if (!pbi->m_ins_flag) {
pbi->frame_count++;
decode_frame_count[pbi->index]
= pbi->frame_count;
}
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->chunk) {
cur_pic_config->pts = pbi->chunk->pts;
cur_pic_config->pts64 = pbi->chunk->pts64;
if (pbi->is_used_v4l && !v4l_bitstream_id_enable)
cur_pic_config->pts64 = pbi->chunk->timestamp;
}
#endif
}
/*pr_info("Decode Frame Data %d\n", pbi->frame_count);*/
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_START);
config_pic_size(pbi, pbi->vp9_param.p.bit_depth);
if ((pbi->common.frame_type != KEY_FRAME)
&& (!pbi->common.intra_only)) {
config_mc_buffer(pbi, pbi->vp9_param.p.bit_depth);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num == 0)
#endif
config_mpred_hw(pbi);
} else {
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num == 0)
#endif
clear_mpred_hw(pbi);
}
#ifdef MCRCC_ENABLE
if (mcrcc_cache_alg_flag)
config_mcrcc_axi_hw_new(pbi);
else
config_mcrcc_axi_hw(pbi);
#endif
config_sao_hw(pbi, &pbi->vp9_param);
#ifdef VP9_LPF_LVL_UPDATE
/*
* Get loop filter related picture level parameters from Parser
*/
pbi->lf->mode_ref_delta_enabled = pbi->vp9_param.p.mode_ref_delta_enabled;
pbi->lf->sharpness_level = pbi->vp9_param.p.sharpness_level;
for (i = 0; i < 4; i++)
pbi->lf->ref_deltas[i] = pbi->vp9_param.p.ref_deltas[i];
for (i = 0; i < 2; i++)
pbi->lf->mode_deltas[i] = pbi->vp9_param.p.mode_deltas[i];
pbi->default_filt_lvl = pbi->vp9_param.p.filter_level;
pbi->seg_4lf->enabled = pbi->vp9_param.p.seg_enabled;
pbi->seg_4lf->abs_delta = pbi->vp9_param.p.seg_abs_delta;
for (i = 0; i < MAX_SEGMENTS; i++)
pbi->seg_4lf->feature_mask[i] = (pbi->vp9_param.p.seg_lf_info[i] &
0x8000) ? (1 << SEG_LVL_ALT_LF) : 0;
for (i = 0; i < MAX_SEGMENTS; i++)
pbi->seg_4lf->feature_data[i][SEG_LVL_ALT_LF]
= (pbi->vp9_param.p.seg_lf_info[i]
& 0x100) ? -(pbi->vp9_param.p.seg_lf_info[i]
& 0x3f) : (pbi->vp9_param.p.seg_lf_info[i] & 0x3f);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
/*Set pipeline mode*/
uint32_t lpf_data32 = READ_VREG(HEVC_DBLK_CFGB);
/*dblk pipeline mode=1 for performance*/
if (pbi->vp9_param.p.width >= 1280)
lpf_data32 |= (0x1 << 4);
else
lpf_data32 &= ~(0x3 << 4);
WRITE_VREG(HEVC_DBLK_CFGB, lpf_data32);
}
/*
* Update loop filter Thr/Lvl table for every frame
*/
/*pr_info
("vp9_loop_filter (run before every frame decoding start)\n");*/
vp9_loop_filter_frame_init(pbi->seg_4lf,
pbi->lfi, pbi->lf, pbi->default_filt_lvl);
#endif
/*pr_info("HEVC_DEC_STATUS_REG <= VP9_10B_DECODE_SLICE\n");*/
WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DECODE_SLICE);
} else {
pr_info("Skip search next start code\n");
cm->prev_fb_idx = INVALID_IDX;
/*skip, search next start code*/
WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DECODE_SLICE);
}
pbi->process_state = PROC_STATE_DECODESLICE;
if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
if (pbi->last_put_idx < pbi->used_buf_num) {
struct RefCntBuffer_s *frame_bufs =
cm->buffer_pool->frame_bufs;
int i = pbi->last_put_idx;
/*free not used buffers.*/
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0) &&
(frame_bufs[i].buf.index != -1)) {
if (pbi->is_used_v4l) {
struct internal_comp_buf *ibuf =
index_to_icomp_buf(pbi, i);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START);
decoder_mmu_box_free_idx(ibuf->mmu_box, ibuf->index);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END);
} else {
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START);
decoder_mmu_box_free_idx(pbi->mmu_box, i);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END);
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable)
decoder_mmu_box_free_idx(pbi->mmu_box_dw, i);
#endif
}
}
pbi->last_put_idx = -1;
}
}
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_END);
return ret;
}
static void fill_frame_info(struct VP9Decoder_s *pbi,
struct PIC_BUFFER_CONFIG_s *frame,
unsigned int framesize,
unsigned int pts)
{
struct vframe_qos_s *vframe_qos = &pbi->vframe_qos;
if (frame->slice_type == KEY_FRAME)
vframe_qos->type = 1;
else if (frame->slice_type == INTER_FRAME)
vframe_qos->type = 2;
/*
#define SHOW_QOS_INFO
*/
if (input_frame_based(hw_to_vdec(pbi)))
vframe_qos->size = frame->frame_size2;
else
vframe_qos->size = framesize;
vframe_qos->pts = pts;
#ifdef SHOW_QOS_INFO
vp9_print(pbi, 0, "slice:%d\n", frame->slice_type);
#endif
vframe_qos->max_mv = frame->max_mv;
vframe_qos->avg_mv = frame->avg_mv;
vframe_qos->min_mv = frame->min_mv;
#ifdef SHOW_QOS_INFO
vp9_print(pbi, 0, "mv: max:%d, avg:%d, min:%d\n",
vframe_qos->max_mv,
vframe_qos->avg_mv,
vframe_qos->min_mv);
#endif
vframe_qos->max_qp = frame->max_qp;
vframe_qos->avg_qp = frame->avg_qp;
vframe_qos->min_qp = frame->min_qp;
#ifdef SHOW_QOS_INFO
vp9_print(pbi, 0, "qp: max:%d, avg:%d, min:%d\n",
vframe_qos->max_qp,
vframe_qos->avg_qp,
vframe_qos->min_qp);
#endif
vframe_qos->max_skip = frame->max_skip;
vframe_qos->avg_skip = frame->avg_skip;
vframe_qos->min_skip = frame->min_skip;
#ifdef SHOW_QOS_INFO
vp9_print(pbi, 0, "skip: max:%d, avg:%d, min:%d\n",
vframe_qos->max_skip,
vframe_qos->avg_skip,
vframe_qos->min_skip);
#endif
vframe_qos->num++;
}
/* only when we decoded one field or one frame,
we can call this function to get qos info*/
static void get_picture_qos_info(struct VP9Decoder_s *pbi)
{
struct PIC_BUFFER_CONFIG_s *frame = &pbi->cur_buf->buf;
struct vdec_s *vdec = hw_to_vdec(pbi);
if (!frame)
return;
if (vdec->mvfrm) {
frame->frame_size2 = vdec->mvfrm->frame_size;
frame->hw_decode_time =
local_clock() - vdec->mvfrm->hw_decode_start;
}
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) {
unsigned char a[3];
unsigned char i, j, t;
unsigned long data;
data = READ_VREG(HEVC_MV_INFO);
if (frame->slice_type == KEY_FRAME)
data = 0;
a[0] = data & 0xff;
a[1] = (data >> 8) & 0xff;
a[2] = (data >> 16) & 0xff;
for (i = 0; i < 3; i++) {
for (j = i+1; j < 3; j++) {
if (a[j] < a[i]) {
t = a[j];
a[j] = a[i];
a[i] = t;
} else if (a[j] == a[i]) {
a[i]++;
t = a[j];
a[j] = a[i];
a[i] = t;
}
}
}
frame->max_mv = a[2];
frame->avg_mv = a[1];
frame->min_mv = a[0];
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"mv data %x a[0]= %x a[1]= %x a[2]= %x\n",
data, a[0], a[1], a[2]);
data = READ_VREG(HEVC_QP_INFO);
a[0] = data & 0x1f;
a[1] = (data >> 8) & 0x3f;
a[2] = (data >> 16) & 0x7f;
for (i = 0; i < 3; i++) {
for (j = i+1; j < 3; j++) {
if (a[j] < a[i]) {
t = a[j];
a[j] = a[i];
a[i] = t;
} else if (a[j] == a[i]) {
a[i]++;
t = a[j];
a[j] = a[i];
a[i] = t;
}
}
}
frame->max_qp = a[2];
frame->avg_qp = a[1];
frame->min_qp = a[0];
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"qp data %x a[0]= %x a[1]= %x a[2]= %x\n",
data, a[0], a[1], a[2]);
data = READ_VREG(HEVC_SKIP_INFO);
a[0] = data & 0x1f;
a[1] = (data >> 8) & 0x3f;
a[2] = (data >> 16) & 0x7f;
for (i = 0; i < 3; i++) {
for (j = i+1; j < 3; j++) {
if (a[j] < a[i]) {
t = a[j];
a[j] = a[i];
a[i] = t;
} else if (a[j] == a[i]) {
a[i]++;
t = a[j];
a[j] = a[i];
a[i] = t;
}
}
}
frame->max_skip = a[2];
frame->avg_skip = a[1];
frame->min_skip = a[0];
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"skip data %x a[0]= %x a[1]= %x a[2]= %x\n",
data, a[0], a[1], a[2]);
} else {
uint32_t blk88_y_count;
uint32_t blk88_c_count;
uint32_t blk22_mv_count;
uint32_t rdata32;
int32_t mv_hi;
int32_t mv_lo;
uint32_t rdata32_l;
uint32_t mvx_L0_hi;
uint32_t mvy_L0_hi;
uint32_t mvx_L1_hi;
uint32_t mvy_L1_hi;
int64_t value;
uint64_t temp_value;
int pic_number = frame->decode_idx;
frame->max_mv = 0;
frame->avg_mv = 0;
frame->min_mv = 0;
frame->max_skip = 0;
frame->avg_skip = 0;
frame->min_skip = 0;
frame->max_qp = 0;
frame->avg_qp = 0;
frame->min_qp = 0;
vp9_print(pbi, VP9_DEBUG_QOS_INFO, "slice_type:%d, poc:%d\n",
frame->slice_type,
pic_number);
/* set rd_idx to 0 */
WRITE_VREG(HEVC_PIC_QUALITY_CTRL, 0);
blk88_y_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
if (blk88_y_count == 0) {
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] NO Data yet.\n",
pic_number);
/* reset all counts */
WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
return;
}
/* qp_y_sum */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y QP AVG : %d (%d/%d)\n",
pic_number, rdata32/blk88_y_count,
rdata32, blk88_y_count);
frame->avg_qp = rdata32/blk88_y_count;
/* intra_y_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y intra rate : %d%c (%d)\n",
pic_number, rdata32*100/blk88_y_count,
'%', rdata32);
/* skipped_y_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y skipped rate : %d%c (%d)\n",
pic_number, rdata32*100/blk88_y_count,
'%', rdata32);
frame->avg_skip = rdata32*100/blk88_y_count;
/* coeff_non_zero_y_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n",
pic_number, (100 - rdata32*100/(blk88_y_count*1)),
'%', rdata32);
/* blk66_c_count */
blk88_c_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
if (blk88_c_count == 0) {
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] NO Data yet.\n",
pic_number);
/* reset all counts */
WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
return;
}
/* qp_c_sum */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C QP AVG : %d (%d/%d)\n",
pic_number, rdata32/blk88_c_count,
rdata32, blk88_c_count);
/* intra_c_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C intra rate : %d%c (%d)\n",
pic_number, rdata32*100/blk88_c_count,
'%', rdata32);
/* skipped_cu_c_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C skipped rate : %d%c (%d)\n",
pic_number, rdata32*100/blk88_c_count,
'%', rdata32);
/* coeff_non_zero_c_count */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n",
pic_number, (100 - rdata32*100/(blk88_c_count*1)),
'%', rdata32);
/* 1'h0, qp_c_max[6:0], 1'h0, qp_c_min[6:0],
1'h0, qp_y_max[6:0], 1'h0, qp_y_min[6:0] */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y QP min : %d\n",
pic_number, (rdata32>>0)&0xff);
frame->min_qp = (rdata32>>0)&0xff;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] Y QP max : %d\n",
pic_number, (rdata32>>8)&0xff);
frame->max_qp = (rdata32>>8)&0xff;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C QP min : %d\n",
pic_number, (rdata32>>16)&0xff);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] C QP max : %d\n",
pic_number, (rdata32>>24)&0xff);
/* blk22_mv_count */
blk22_mv_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
if (blk22_mv_count == 0) {
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] NO MV Data yet.\n",
pic_number);
/* reset all counts */
WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
return;
}
/* mvy_L1_count[39:32], mvx_L1_count[39:32],
mvy_L0_count[39:32], mvx_L0_count[39:32] */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
/* should all be 0x00 or 0xff */
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MV AVG High Bits: 0x%X\n",
pic_number, rdata32);
mvx_L0_hi = ((rdata32>>0)&0xff);
mvy_L0_hi = ((rdata32>>8)&0xff);
mvx_L1_hi = ((rdata32>>16)&0xff);
mvy_L1_hi = ((rdata32>>24)&0xff);
/* mvx_L0_count[31:0] */
rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA);
temp_value = mvx_L0_hi;
temp_value = (temp_value << 32) | rdata32_l;
if (mvx_L0_hi & 0x80)
value = 0xFFFFFFF000000000 | temp_value;
else
value = temp_value;
value = div_s64(value, blk22_mv_count);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n",
pic_number, (int)value,
value, blk22_mv_count);
frame->avg_mv = value;
/* mvy_L0_count[31:0] */
rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA);
temp_value = mvy_L0_hi;
temp_value = (temp_value << 32) | rdata32_l;
if (mvy_L0_hi & 0x80)
value = 0xFFFFFFF000000000 | temp_value;
else
value = temp_value;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n",
pic_number, rdata32_l/blk22_mv_count,
value, blk22_mv_count);
/* mvx_L1_count[31:0] */
rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA);
temp_value = mvx_L1_hi;
temp_value = (temp_value << 32) | rdata32_l;
if (mvx_L1_hi & 0x80)
value = 0xFFFFFFF000000000 | temp_value;
else
value = temp_value;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n",
pic_number, rdata32_l/blk22_mv_count,
value, blk22_mv_count);
/* mvy_L1_count[31:0] */
rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA);
temp_value = mvy_L1_hi;
temp_value = (temp_value << 32) | rdata32_l;
if (mvy_L1_hi & 0x80)
value = 0xFFFFFFF000000000 | temp_value;
else
value = temp_value;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n",
pic_number, rdata32_l/blk22_mv_count,
value, blk22_mv_count);
/* {mvx_L0_max, mvx_L0_min} // format : {sign, abs[14:0]} */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
mv_hi = (rdata32>>16)&0xffff;
if (mv_hi & 0x8000)
mv_hi = 0x8000 - mv_hi;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L0 MAX : %d\n",
pic_number, mv_hi);
frame->max_mv = mv_hi;
mv_lo = (rdata32>>0)&0xffff;
if (mv_lo & 0x8000)
mv_lo = 0x8000 - mv_lo;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L0 MIN : %d\n",
pic_number, mv_lo);
frame->min_mv = mv_lo;
/* {mvy_L0_max, mvy_L0_min} */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
mv_hi = (rdata32>>16)&0xffff;
if (mv_hi & 0x8000)
mv_hi = 0x8000 - mv_hi;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L0 MAX : %d\n",
pic_number, mv_hi);
mv_lo = (rdata32>>0)&0xffff;
if (mv_lo & 0x8000)
mv_lo = 0x8000 - mv_lo;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L0 MIN : %d\n",
pic_number, mv_lo);
/* {mvx_L1_max, mvx_L1_min} */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
mv_hi = (rdata32>>16)&0xffff;
if (mv_hi & 0x8000)
mv_hi = 0x8000 - mv_hi;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L1 MAX : %d\n",
pic_number, mv_hi);
mv_lo = (rdata32>>0)&0xffff;
if (mv_lo & 0x8000)
mv_lo = 0x8000 - mv_lo;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVX_L1 MIN : %d\n",
pic_number, mv_lo);
/* {mvy_L1_max, mvy_L1_min} */
rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
mv_hi = (rdata32>>16)&0xffff;
if (mv_hi & 0x8000)
mv_hi = 0x8000 - mv_hi;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L1 MAX : %d\n",
pic_number, mv_hi);
mv_lo = (rdata32>>0)&0xffff;
if (mv_lo & 0x8000)
mv_lo = 0x8000 - mv_lo;
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] MVY_L1 MIN : %d\n",
pic_number, mv_lo);
rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL);
vp9_print(pbi, VP9_DEBUG_QOS_INFO,
"[Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n",
pic_number, rdata32);
/* reset all counts */
WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
}
}
static void vvp9_get_comp_buf_info(struct VP9Decoder_s *pbi,
struct vdec_comp_buf_info *info)
{
u16 bit_depth = pbi->param.p.bit_depth;
info->max_size = vp9_max_mmu_buf_size(
pbi->max_pic_w,
pbi->max_pic_h);
info->header_size = vvp9_mmu_compress_header_size(
pbi->frame_width,
pbi->frame_height);
info->frame_buffer_size = vp9_mmu_page_num(
pbi, pbi->frame_width,
pbi->frame_height,
bit_depth == 0);
}
static int vvp9_get_ps_info(struct VP9Decoder_s *pbi, struct aml_vdec_ps_infos *ps)
{
ps->visible_width = pbi->frame_width;
ps->visible_height = pbi->frame_height;
ps->coded_width = ALIGN(pbi->frame_width, 64);
ps->coded_height = ALIGN(pbi->frame_height, 64);
ps->dpb_size = pbi->used_buf_num;
return 0;
}
static int v4l_res_change(struct VP9Decoder_s *pbi)
{
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
int ret = 0;
if (ctx->param_sets_from_ucode &&
pbi->res_ch_flag == 0) {
struct aml_vdec_ps_infos ps;
struct vdec_comp_buf_info comp;
if ((pbi->last_width != 0 &&
pbi->last_height != 0) &&
(pbi->frame_width != pbi->last_width ||
pbi->frame_height != pbi->last_height)) {
vp9_print(pbi, 0, "%s (%d,%d)=>(%d,%d)\r\n", __func__, pbi->last_width,
pbi->last_height, pbi->frame_width, pbi->frame_height);
if (get_valid_double_write_mode(pbi) != 16) {
vvp9_get_comp_buf_info(pbi, &comp);
vdec_v4l_set_comp_buf_info(ctx, &comp);
}
vvp9_get_ps_info(pbi, &ps);
vdec_v4l_set_ps_infos(ctx, &ps);
vdec_v4l_res_ch_event(ctx);
pbi->init_pic_w = pbi->frame_width;
pbi->init_pic_h = pbi->frame_height;
init_mv_buf_list(pbi);
pbi->v4l_params_parsed = false;
pbi->res_ch_flag = 1;
ctx->v4l_resolution_change = 1;
pbi->eos = 1;
vp9_bufmgr_postproc(pbi);
//del_timer_sync(&pbi->timer);
notify_v4l_eos(hw_to_vdec(pbi));
ret = 1;
}
}
return ret;
}
static irqreturn_t vvp9_isr_thread_fn(int irq, void *data)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data;
unsigned int dec_status = pbi->dec_status;
int i;
/*if (pbi->wait_buf)
* pr_info("set wait_buf to 0\r\n");
*/
if (dec_status == VP9_HEAD_PARSER_DONE) {
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START);
}
else if (dec_status == HEVC_DECPIC_DATA_DONE) {
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START);
}
if (pbi->eos)
return IRQ_HANDLED;
pbi->wait_buf = 0;
#ifdef MULTI_INSTANCE_SUPPORT
#ifdef SUPPORT_FB_DECODING
#ifdef FB_DECODING_TEST_SCHEDULE
if (pbi->s1_test_cmd == TEST_SET_PIC_DONE)
dec_status = HEVC_DECPIC_DATA_DONE;
else if (pbi->s1_test_cmd == TEST_SET_S2_DONE
&& dec_status == HEVC_DECPIC_DATA_DONE)
dec_status = HEVC_S2_DECODING_DONE;
pbi->s1_test_cmd = TEST_SET_NONE;
#else
/*if (irq != VDEC_IRQ_0)
dec_status = HEVC_S2_DECODING_DONE;*/
#endif
if (dec_status == HEVC_S2_DECODING_DONE) {
pbi->dec_result = DEC_RESULT_DONE;
vdec_schedule_work(&pbi->work);
#ifdef FB_DECODING_TEST_SCHEDULE
amhevc_stop();
pbi->dec_s1_result = DEC_S1_RESULT_DONE;
vdec_schedule_work(&pbi->s1_work);
#endif
} else
#endif
if ((dec_status == HEVC_NAL_DECODE_DONE) ||
(dec_status == HEVC_SEARCH_BUFEMPTY) ||
(dec_status == HEVC_DECODE_BUFEMPTY)
) {
if (pbi->m_ins_flag) {
reset_process_time(pbi);
if (!vdec_frame_based(hw_to_vdec(pbi)))
dec_again_process(pbi);
else {
if (pbi->common.show_existing_frame) {
pbi->dec_result = DEC_RESULT_DONE;
amhevc_stop();
vdec_schedule_work(&pbi->work);
}
else {
pbi->dec_result = DEC_RESULT_GET_DATA;
vdec_schedule_work(&pbi->work);
}
}
}
pbi->process_busy = 0;
return IRQ_HANDLED;
} else if (dec_status == HEVC_DECPIC_DATA_DONE) {
if (pbi->m_ins_flag) {
get_picture_qos_info(pbi);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0) {
reset_process_time(pbi);
inc_s1_pos(pbi);
trigger_schedule(pbi);
#ifdef FB_DECODING_TEST_SCHEDULE
pbi->s1_test_cmd = TEST_SET_S2_DONE;
#else
amhevc_stop();
pbi->dec_s1_result = DEC_S1_RESULT_DONE;
vdec_schedule_work(&pbi->s1_work);
#endif
} else
#endif
{
reset_process_time(pbi);
if (pbi->vf_pre_count == 0 || pbi->low_latency_flag)
vp9_bufmgr_postproc(pbi);
pbi->dec_result = DEC_RESULT_DONE;
amhevc_stop();
if (mcrcc_cache_alg_flag)
dump_hit_rate(pbi);
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_EDN);
vdec_schedule_work(&pbi->work);
}
} else {
if (pbi->low_latency_flag) {
vp9_bufmgr_postproc(pbi);
WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
vdec_profile(hw_to_vdec(pbi), VDEC_PROFILE_EVENT_CB);
if (debug & PRINT_FLAG_VDEC_DETAIL)
pr_info("%s VP9 frame done \n", __func__);
#endif
}
}
pbi->process_busy = 0;
return IRQ_HANDLED;
}
#endif
if (dec_status == VP9_EOS) {
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag)
reset_process_time(pbi);
#endif
pr_info("VP9_EOS, flush buffer\r\n");
vp9_bufmgr_postproc(pbi);
pr_info("send VP9_10B_DISCARD_NAL\r\n");
WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DISCARD_NAL);
pbi->process_busy = 0;
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag) {
pbi->dec_result = DEC_RESULT_DONE;
amhevc_stop();
vdec_schedule_work(&pbi->work);
}
#endif
return IRQ_HANDLED;
} else if (dec_status == HEVC_DECODE_OVER_SIZE) {
pr_info("vp9 decode oversize !!\n");
debug |= (VP9_DEBUG_DIS_LOC_ERROR_PROC |
VP9_DEBUG_DIS_SYS_ERROR_PROC);
pbi->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag)
reset_process_time(pbi);
#endif
return IRQ_HANDLED;
}
if (dec_status != VP9_HEAD_PARSER_DONE) {
pbi->process_busy = 0;
return IRQ_HANDLED;
}
if (pbi->m_ins_flag &&
!get_free_buf_count(pbi)) {
pbi->run_ready_min_buf_num = pbi->one_package_frame_cnt + 1;
pr_err("need buffer, one package frame count = %d\n", pbi->one_package_frame_cnt + 1);
pbi->dec_result = DEC_RESULT_NEED_MORE_BUFFER;
vdec_schedule_work(&pbi->work);
return IRQ_HANDLED;
}
pbi->one_package_frame_cnt++;
#ifdef MULTI_INSTANCE_SUPPORT
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
if (pbi->m_ins_flag ==0 && pbi->low_latency_flag) {
vdec_profile(hw_to_vdec(pbi), VDEC_PROFILE_EVENT_RUN);
if (debug & PRINT_FLAG_VDEC_DETAIL)
pr_info("%s VP9 frame header found \n", __func__);
}
#endif
if (pbi->m_ins_flag)
reset_process_time(pbi);
#endif
if (pbi->process_state != PROC_STATE_SENDAGAIN
#ifdef SUPPORT_FB_DECODING
&& pbi->used_stage_buf_num == 0
#endif
) {
if (pbi->mmu_enable) {
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START);
vp9_recycle_mmu_buf_tail(pbi);
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END);
}
if (pbi->frame_count > 0)
vp9_bufmgr_postproc(pbi);
}
if (debug & VP9_DEBUG_SEND_PARAM_WITH_REG) {
get_rpm_param(&pbi->vp9_param);
} else {
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0) {
reset_process_time(pbi);
get_s1_buf(pbi);
if (get_mv_buf(pbi,
&pbi->s1_mv_buf_index,
&pbi->s1_mpred_mv_wr_start_addr
) < 0) {
vp9_print(pbi, 0,
"%s: Error get_mv_buf fail\n",
__func__);
}
if (pbi->s1_buf == NULL) {
vp9_print(pbi, 0,
"%s: Error get_s1_buf fail\n",
__func__);
pbi->process_busy = 0;
return IRQ_HANDLED;
}
for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
int ii;
for (ii = 0; ii < 4; ii++) {
pbi->s1_buf->rpm[i + 3 - ii] =
pbi->rpm_ptr[i + 3 - ii];
pbi->s1_param.l.data[i + ii] =
pbi->rpm_ptr[i + 3 - ii];
}
}
mpred_process(pbi);
#ifdef FB_DECODING_TEST_SCHEDULE
pbi->dec_s1_result =
DEC_S1_RESULT_TEST_TRIGGER_DONE;
vdec_schedule_work(&pbi->s1_work);
#else
WRITE_VREG(HEVC_ASSIST_FB_MMU_MAP_ADDR,
pbi->stage_mmu_map_phy_addr +
pbi->s1_buf->index * STAGE_MMU_MAP_SIZE);
start_s1_decoding(pbi);
#endif
start_process_time(pbi);
pbi->process_busy = 0;
return IRQ_HANDLED;
} else
#endif
{
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_START);
for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
int ii;
for (ii = 0; ii < 4; ii++)
pbi->vp9_param.l.data[i + ii] =
pbi->rpm_ptr[i + 3 - ii];
}
ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_END);
}
}
if (pbi->is_used_v4l) {
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
pbi->frame_width = pbi->vp9_param.p.width;
pbi->frame_height = pbi->vp9_param.p.height;
if (!pbi->has_keyframe &&
((pbi->frame_width == 0) ||
(pbi->frame_height == 0))) {
continue_decoding(pbi);
pbi->postproc_done = 0;
pbi->process_busy = 0;
return IRQ_HANDLED;
}
if (!v4l_res_change(pbi)) {
if (ctx->param_sets_from_ucode && !pbi->v4l_params_parsed) {
struct aml_vdec_ps_infos ps;
struct vdec_comp_buf_info comp;
pr_debug("set ucode parse\n");
if (get_valid_double_write_mode(pbi) != 16) {
vvp9_get_comp_buf_info(pbi, &comp);
vdec_v4l_set_comp_buf_info(ctx, &comp);
}
vvp9_get_ps_info(pbi, &ps);
/*notice the v4l2 codec.*/
vdec_v4l_set_ps_infos(ctx, &ps);
pbi->init_pic_w = pbi->frame_width;
pbi->init_pic_h = pbi->frame_height;
init_mv_buf_list(pbi);
pbi->v4l_params_parsed = true;
pbi->postproc_done = 0;
pbi->process_busy = 0;
dec_again_process(pbi);
return IRQ_HANDLED;
}
} else {
pbi->postproc_done = 0;
pbi->process_busy = 0;
dec_again_process(pbi);
return IRQ_HANDLED;
}
}
continue_decoding(pbi);
pbi->postproc_done = 0;
pbi->process_busy = 0;
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag)
start_process_time(pbi);
#endif
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END);
return IRQ_HANDLED;
}
static irqreturn_t vvp9_isr(int irq, void *data)
{
int i;
unsigned int dec_status;
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data;
unsigned int adapt_prob_status;
uint debug_tag;
WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1);
dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
if (dec_status == VP9_HEAD_PARSER_DONE) {
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_HEAD_DONE);
}
else if (dec_status == HEVC_DECPIC_DATA_DONE) {
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_PIC_DONE);
}
adapt_prob_status = READ_VREG(VP9_ADAPT_PROB_REG);
if (!pbi)
return IRQ_HANDLED;
if (pbi->init_flag == 0)
return IRQ_HANDLED;
if (pbi->process_busy)/*on process.*/
return IRQ_HANDLED;
pbi->dec_status = dec_status;
pbi->process_busy = 1;
if (debug & VP9_DEBUG_BUFMGR)
pr_info("vp9 isr (%d) dec status = 0x%x, lcu 0x%x shiftbyte 0x%x (%x %x lev %x, wr %x, rd %x)\n",
irq,
dec_status, READ_VREG(HEVC_PARSER_LCU_START),
READ_VREG(HEVC_SHIFT_BYTE_COUNT),
READ_VREG(HEVC_STREAM_START_ADDR),
READ_VREG(HEVC_STREAM_END_ADDR),
READ_VREG(HEVC_STREAM_LEVEL),
READ_VREG(HEVC_STREAM_WR_PTR),
READ_VREG(HEVC_STREAM_RD_PTR)
);
#ifdef SUPPORT_FB_DECODING
/*if (irq != VDEC_IRQ_0)
return IRQ_WAKE_THREAD;*/
#endif
debug_tag = READ_HREG(DEBUG_REG1);
if (debug_tag & 0x10000) {
pr_info("LMEM<tag %x>:\n", READ_HREG(DEBUG_REG1));
for (i = 0; i < 0x400; i += 4) {
int ii;
if ((i & 0xf) == 0)
pr_info("%03x: ", i);
for (ii = 0; ii < 4; ii++) {
pr_info("%04x ",
pbi->lmem_ptr[i + 3 - ii]);
}
if (((i + ii) & 0xf) == 0)
pr_info("\n");
}
if ((udebug_pause_pos == (debug_tag & 0xffff)) &&
(udebug_pause_decode_idx == 0 ||
udebug_pause_decode_idx == pbi->slice_idx) &&
(udebug_pause_val == 0 ||
udebug_pause_val == READ_HREG(DEBUG_REG2)))
pbi->ucode_pause_pos = udebug_pause_pos;
else if (debug_tag & 0x20000)
pbi->ucode_pause_pos = 0xffffffff;
if (pbi->ucode_pause_pos)
reset_process_time(pbi);
else
WRITE_HREG(DEBUG_REG1, 0);
} else if (debug_tag != 0) {
pr_info(
"dbg%x: %x lcu %x\n", READ_HREG(DEBUG_REG1),
READ_HREG(DEBUG_REG2),
READ_VREG(HEVC_PARSER_LCU_START));
if ((udebug_pause_pos == (debug_tag & 0xffff)) &&
(udebug_pause_decode_idx == 0 ||
udebug_pause_decode_idx == pbi->slice_idx) &&
(udebug_pause_val == 0 ||
udebug_pause_val == READ_HREG(DEBUG_REG2)))
pbi->ucode_pause_pos = udebug_pause_pos;
if (pbi->ucode_pause_pos)
reset_process_time(pbi);
else
WRITE_HREG(DEBUG_REG1, 0);
pbi->process_busy = 0;
return IRQ_HANDLED;
}
#ifdef MULTI_INSTANCE_SUPPORT
if (!pbi->m_ins_flag) {
#endif
if (pbi->error_flag == 1) {
pbi->error_flag = 2;
pbi->process_busy = 0;
return IRQ_HANDLED;
} else if (pbi->error_flag == 3) {
pbi->process_busy = 0;
return IRQ_HANDLED;
}
if (get_free_buf_count(pbi) <= 0) {
/*
if (pbi->wait_buf == 0)
pr_info("set wait_buf to 1\r\n");
*/
pbi->wait_buf = 1;
pbi->process_busy = 0;
return IRQ_HANDLED;
}
#ifdef MULTI_INSTANCE_SUPPORT
}
#endif
if ((adapt_prob_status & 0xff) == 0xfd) {
struct VP9_Common_s *const cm = &pbi->common;
int pre_fc = 0;
if (pbi->m_ins_flag)
reset_process_time(pbi);
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
(vdec_secure(hw_to_vdec(pbi)))) {
pre_fc = ((cm->frame_type == KEY_FRAME) || (cm->intra_only)) ? 0 : 1;
tee_vp9_prob_process(pre_fc, cm->last_frame_type,
adapt_prob_status, (unsigned int)pbi->prob_buffer_phy_addr);
} else {
uint8_t *prev_prob_b, *cur_prob_b, *count_b;
/*VP9_REQ_ADAPT_PROB*/
pre_fc = ((cm->frame_type == KEY_FRAME) || (cm->intra_only));
prev_prob_b = ((uint8_t *)pbi->prob_buffer_addr) +
((adapt_prob_status >> 8) * 0x1000);
cur_prob_b = ((uint8_t *)pbi->prob_buffer_addr) + 0x4000;
count_b = (uint8_t *)pbi->count_buffer_addr;
adapt_coef_probs(pbi->pic_count,
(cm->last_frame_type == KEY_FRAME),
pre_fc, (adapt_prob_status >> 8),
(unsigned int *)prev_prob_b,
(unsigned int *)cur_prob_b, (unsigned int *)count_b);
memcpy(prev_prob_b, cur_prob_b, PROB_SIZE);
}
WRITE_VREG(VP9_ADAPT_PROB_REG, 0);
pbi->pic_count += 1;
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag)
start_process_time(pbi);
#endif
}
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_END);
return IRQ_WAKE_THREAD;
}
static void vp9_set_clk(struct work_struct *work)
{
struct VP9Decoder_s *pbi = container_of(work,
struct VP9Decoder_s, set_clk_work);
int fps = 96000 / pbi->frame_dur;
if (hevc_source_changed(VFORMAT_VP9,
frame_width, frame_height, fps) > 0)
pbi->saved_resolution = frame_width *
frame_height * fps;
}
static void vvp9_put_timer_func(struct timer_list *timer)
{
struct VP9Decoder_s *pbi = container_of(timer,
struct VP9Decoder_s, timer);
enum receviver_start_e state = RECEIVER_INACTIVE;
uint8_t empty_flag;
unsigned int buf_level;
if (pbi->m_ins_flag) {
if (hw_to_vdec(pbi)->next_status
== VDEC_STATUS_DISCONNECTED &&
!pbi->is_used_v4l) {
#ifdef SUPPORT_FB_DECODING
if (pbi->run2_busy)
return;
pbi->dec_s1_result = DEC_S1_RESULT_FORCE_EXIT;
vdec_schedule_work(&pbi->s1_work);
#endif
pbi->dec_result = DEC_RESULT_FORCE_EXIT;
vdec_schedule_work(&pbi->work);
pr_debug(
"vdec requested to be disconnected\n");
return;
}
}
if (pbi->init_flag == 0) {
if (pbi->stat & STAT_TIMER_ARM) {
timer->expires = jiffies + PUT_INTERVAL;
add_timer(&pbi->timer);
}
return;
}
if (pbi->m_ins_flag == 0) {
if (vf_get_receiver(pbi->provider_name)) {
state =
vf_notify_receiver(pbi->provider_name,
VFRAME_EVENT_PROVIDER_QUREY_STATE,
NULL);
if ((state == RECEIVER_STATE_NULL)
|| (state == RECEIVER_STATE_NONE))
state = RECEIVER_INACTIVE;
} else
state = RECEIVER_INACTIVE;
empty_flag = (READ_VREG(HEVC_PARSER_INT_STATUS) >> 6) & 0x1;
/* error watchdog */
if (empty_flag == 0) {
/* decoder has input */
if ((debug & VP9_DEBUG_DIS_LOC_ERROR_PROC) == 0) {
buf_level = READ_VREG(HEVC_STREAM_LEVEL);
/* receiver has no buffer to recycle */
if ((state == RECEIVER_INACTIVE) &&
(kfifo_is_empty(&pbi->display_q) &&
buf_level > 0x200)
) {
WRITE_VREG
(HEVC_ASSIST_MBOX0_IRQ_REG,
0x1);
}
}
if ((debug & VP9_DEBUG_DIS_SYS_ERROR_PROC) == 0) {
/* receiver has no buffer to recycle */
/*if ((state == RECEIVER_INACTIVE) &&
* (kfifo_is_empty(&pbi->display_q))) {
*pr_info("vp9 something error,need reset\n");
*}
*/
}
}
}
#ifdef MULTI_INSTANCE_SUPPORT
else {
if (
(decode_timeout_val > 0) &&
(pbi->start_process_time > 0) &&
((1000 * (jiffies - pbi->start_process_time) / HZ)
> decode_timeout_val)
) {
int current_lcu_idx =
READ_VREG(HEVC_PARSER_LCU_START)
& 0xffffff;
if (pbi->last_lcu_idx == current_lcu_idx) {
if (pbi->decode_timeout_count > 0)
pbi->decode_timeout_count--;
if (pbi->decode_timeout_count == 0) {
if (input_frame_based(
hw_to_vdec(pbi)) ||
(READ_VREG(HEVC_STREAM_LEVEL) > 0x200))
timeout_process(pbi);
else {
vp9_print(pbi, 0,
"timeout & empty, again\n");
dec_again_process(pbi);
}
}
} else {
start_process_time(pbi);
pbi->last_lcu_idx = current_lcu_idx;
}
}
}
#endif
if ((pbi->ucode_pause_pos != 0) &&
(pbi->ucode_pause_pos != 0xffffffff) &&
udebug_pause_pos != pbi->ucode_pause_pos) {
pbi->ucode_pause_pos = 0;
WRITE_HREG(DEBUG_REG1, 0);
}
#ifdef MULTI_INSTANCE_SUPPORT
if (debug & VP9_DEBUG_FORCE_SEND_AGAIN) {
pr_info(
"Force Send Again\r\n");
debug &= ~VP9_DEBUG_FORCE_SEND_AGAIN;
reset_process_time(pbi);
pbi->dec_result = DEC_RESULT_AGAIN;
if (pbi->process_state ==
PROC_STATE_DECODESLICE) {
if (pbi->mmu_enable)
vp9_recycle_mmu_buf(pbi);
pbi->process_state =
PROC_STATE_SENDAGAIN;
}
amhevc_stop();
vdec_schedule_work(&pbi->work);
}
if (debug & VP9_DEBUG_DUMP_DATA) {
debug &= ~VP9_DEBUG_DUMP_DATA;
vp9_print(pbi, 0,
"%s: chunk size 0x%x off 0x%x sum 0x%x\n",
__func__,
pbi->chunk->size,
pbi->chunk->offset,
get_data_check_sum(pbi, pbi->chunk->size)
);
dump_data(pbi, pbi->chunk->size);
}
#endif
if (debug & VP9_DEBUG_DUMP_PIC_LIST) {
dump_pic_list(pbi);
debug &= ~VP9_DEBUG_DUMP_PIC_LIST;
}
if (debug & VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC) {
WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
debug &= ~VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC;
}
/*if (debug & VP9_DEBUG_HW_RESET) {
}*/
if (radr != 0) {
if (rval != 0) {
WRITE_VREG(radr, rval);
pr_info("WRITE_VREG(%x,%x)\n", radr, rval);
} else
pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr));
rval = 0;
radr = 0;
}
if (pop_shorts != 0) {
int i;
u32 sum = 0;
pr_info("pop stream 0x%x shorts\r\n", pop_shorts);
for (i = 0; i < pop_shorts; i++) {
u32 data =
(READ_HREG(HEVC_SHIFTED_DATA) >> 16);
WRITE_HREG(HEVC_SHIFT_COMMAND,
(1<<7)|16);
if ((i & 0xf) == 0)
pr_info("%04x:", i);
pr_info("%04x ", data);
if (((i + 1) & 0xf) == 0)
pr_info("\r\n");
sum += data;
}
pr_info("\r\nsum = %x\r\n", sum);
pop_shorts = 0;
}
if (dbg_cmd != 0) {
if (dbg_cmd == 1) {
u32 disp_laddr;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB &&
get_double_write_mode(pbi) == 0) {
disp_laddr =
READ_VCBUS_REG(AFBC_BODY_BADDR) << 4;
} else {
struct canvas_s cur_canvas;
canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0)
& 0xff), &cur_canvas);
disp_laddr = cur_canvas.addr;
}
pr_info("current displayed buffer address %x\r\n",
disp_laddr);
}
dbg_cmd = 0;
}
/*don't changed at start.*/
if (pbi->get_frame_dur && pbi->show_frame_num > 60 &&
pbi->frame_dur > 0 && pbi->saved_resolution !=
frame_width * frame_height *
(96000 / pbi->frame_dur))
vdec_schedule_work(&pbi->set_clk_work);
timer->expires = jiffies + PUT_INTERVAL;
add_timer(timer);
}
int vvp9_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
{
struct VP9Decoder_s *vp9 =
(struct VP9Decoder_s *)vdec->private;
if (!vp9)
return -1;
vstatus->frame_width = frame_width;
vstatus->frame_height = frame_height;
if (vp9->error_frame_width &&
vp9->error_frame_height) {
vstatus->frame_width = vp9->error_frame_width;
vstatus->frame_height = vp9->error_frame_height;
}
if (vp9->frame_dur != 0)
vstatus->frame_rate = ((96000 * 10 / vp9->frame_dur) % 10) < 5 ?
96000 / vp9->frame_dur : (96000 / vp9->frame_dur +1);
else
vstatus->frame_rate = -1;
vstatus->error_count = 0;
vstatus->status = vp9->stat | vp9->fatal_error;
vstatus->frame_dur = vp9->frame_dur;
vstatus->bit_rate = vp9->gvs->bit_rate;
vstatus->frame_data = vp9->gvs->frame_data;
vstatus->total_data = vp9->gvs->total_data;
vstatus->frame_count = vp9->gvs->frame_count;
vstatus->error_frame_count = vp9->gvs->error_frame_count;
vstatus->drop_frame_count = vp9->gvs->drop_frame_count;
vstatus->i_decoded_frames = vp9->gvs->i_decoded_frames;
vstatus->i_lost_frames = vp9->gvs->i_lost_frames;
vstatus->i_concealed_frames = vp9->gvs->i_concealed_frames;
vstatus->p_decoded_frames = vp9->gvs->p_decoded_frames;
vstatus->p_lost_frames = vp9->gvs->p_lost_frames;
vstatus->p_concealed_frames = vp9->gvs->p_concealed_frames;
vstatus->b_decoded_frames = vp9->gvs->b_decoded_frames;
vstatus->b_lost_frames = vp9->gvs->b_lost_frames;
vstatus->b_concealed_frames = vp9->gvs->b_concealed_frames;
vstatus->total_data = vp9->gvs->total_data;
vstatus->samp_cnt = vp9->gvs->samp_cnt;
vstatus->offset = vp9->gvs->offset;
snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
"%s", DRIVER_NAME);
return 0;
}
int vvp9_set_isreset(struct vdec_s *vdec, int isreset)
{
is_reset = isreset;
return 0;
}
#if 0
static void VP9_DECODE_INIT(void)
{
/* enable vp9 clocks */
WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);
/* *************************************************************** */
/* Power ON HEVC */
/* *************************************************************** */
/* Powerup HEVC */
WRITE_VREG(AO_RTI_GEN_PWR_SLEEP0,
READ_VREG(AO_RTI_GEN_PWR_SLEEP0) & (~(0x3 << 6)));
WRITE_VREG(DOS_MEM_PD_HEVC, 0x0);
WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) | (0x3ffff << 2));
WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) & (~(0x3ffff << 2)));
/* remove isolations */
WRITE_VREG(AO_RTI_GEN_PWR_ISO0,
READ_VREG(AO_RTI_GEN_PWR_ISO0) & (~(0x3 << 10)));
}
#endif
static void vvp9_prot_init(struct VP9Decoder_s *pbi, u32 mask)
{
unsigned int data32;
/* VP9_DECODE_INIT(); */
vp9_config_work_space_hw(pbi, mask);
if (mask & HW_MASK_BACK)
init_pic_list_hw(pbi);
vp9_init_decoder_hw(pbi, mask);
#ifdef VP9_LPF_LVL_UPDATE
if (mask & HW_MASK_BACK)
vp9_loop_filter_init(pbi);
#endif
if ((mask & HW_MASK_FRONT) == 0)
return;
#if 1
if (debug & VP9_DEBUG_BUFMGR_MORE)
pr_info("%s\n", __func__);
data32 = READ_VREG(HEVC_STREAM_CONTROL);
data32 = data32 |
(1 << 0)/*stream_fetch_enable*/
;
WRITE_VREG(HEVC_STREAM_CONTROL, data32);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
if (debug & VP9_DEBUG_BUFMGR)
pr_info("[test.c] Config STREAM_FIFO_CTL\n");
data32 = READ_VREG(HEVC_STREAM_FIFO_CTL);
data32 = data32 |
(1 << 29) // stream_fifo_hole
;
WRITE_VREG(HEVC_STREAM_FIFO_CTL, data32);
}
#if 0
data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
if (data32 != 0x00000100) {
pr_info("vp9 prot init error %d\n", __LINE__);
return;
}
data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
if (data32 != 0x00000300) {
pr_info("vp9 prot init error %d\n", __LINE__);
return;
}
WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x12345678);
WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x9abcdef0);
data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
if (data32 != 0x12345678) {
pr_info("vp9 prot init error %d\n", __LINE__);
return;
}
data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
if (data32 != 0x9abcdef0) {
pr_info("vp9 prot init error %d\n", __LINE__);
return;
}
#endif
WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x000000001);
WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000300);
#endif
WRITE_VREG(HEVC_WAIT_FLAG, 1);
/* WRITE_VREG(HEVC_MPSR, 1); */
/* clear mailbox interrupt */
WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1);
/* enable mailbox interrupt */
WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 1);
/* disable PSCALE for hardware sharing */
WRITE_VREG(HEVC_PSCALE_CTRL, 0);
WRITE_VREG(DEBUG_REG1, 0x0);
/*check vps/sps/pps/i-slice in ucode*/
WRITE_VREG(NAL_SEARCH_CTL, 0x8);
WRITE_VREG(DECODE_STOP_POS, udebug_flag);
#ifdef SUPPORT_FB_DECODING
#ifndef FB_DECODING_TEST_SCHEDULE
if (pbi->used_stage_buf_num > 0) {
if (mask & HW_MASK_FRONT) {
data32 = READ_VREG(
HEVC_ASSIST_HED_FB_W_CTL);
data32 = data32 |
(1 << 0) /*hed_fb_wr_en*/
;
WRITE_VREG(HEVC_ASSIST_HED_FB_W_CTL,
data32);
}
if (mask & HW_MASK_BACK) {
data32 = READ_VREG(
HEVC_ASSIST_HED_FB_R_CTL);
while (data32 & (1 << 7)) {
/*wait finish*/
data32 = READ_VREG(
HEVC_ASSIST_HED_FB_R_CTL);
}
data32 &= (~(0x1 << 0));
/*hed_fb_rd_addr_auto_rd*/
data32 &= (~(0x1 << 1));
/*rd_id = 0, hed_rd_map_auto_halt_num,
after wr 2 ready, then start reading*/
data32 |= (0x2 << 16);
WRITE_VREG(HEVC_ASSIST_HED_FB_R_CTL,
data32);
data32 |= (0x1 << 11); /*hed_rd_map_auto_halt_en*/
data32 |= (0x1 << 1); /*hed_fb_rd_addr_auto_rd*/
data32 |= (0x1 << 0); /*hed_fb_rd_en*/
WRITE_VREG(HEVC_ASSIST_HED_FB_R_CTL,
data32);
}
}
#endif
#endif
}
static int vvp9_local_init(struct VP9Decoder_s *pbi)
{
int i;
int ret;
int width, height;
if (alloc_lf_buf(pbi) < 0)
return -1;
pbi->gvs = vzalloc(sizeof(struct vdec_info));
if (NULL == pbi->gvs) {
pr_info("the struct of vdec status malloc failed.\n");
return -1;
}
vdec_set_vframe_comm(hw_to_vdec(pbi), DRIVER_NAME);
#ifdef DEBUG_PTS
pbi->pts_missed = 0;
pbi->pts_hit = 0;
#endif
pbi->new_frame_displayed = 0;
pbi->last_put_idx = -1;
pbi->saved_resolution = 0;
pbi->get_frame_dur = false;
on_no_keyframe_skiped = 0;
pbi->duration_from_pts_done = 0;
pbi->vp9_first_pts_ready = 0;
pbi->frame_cnt_window = 0;
width = pbi->vvp9_amstream_dec_info.width;
height = pbi->vvp9_amstream_dec_info.height;
pbi->frame_dur =
(pbi->vvp9_amstream_dec_info.rate ==
0) ? 3200 : pbi->vvp9_amstream_dec_info.rate;
if (width && height)
pbi->frame_ar = height * 0x100 / width;
/*
*TODO:FOR VERSION
*/
pr_info("vp9: ver (%d,%d) decinfo: %dx%d rate=%d\n", vp9_version,
0, width, height, pbi->frame_dur);
if (pbi->frame_dur == 0)
pbi->frame_dur = 96000 / 24;
INIT_KFIFO(pbi->display_q);
INIT_KFIFO(pbi->newframe_q);
for (i = 0; i < VF_POOL_SIZE; i++) {
const struct vframe_s *vf = &pbi->vfpool[i];
pbi->vfpool[i].index = -1;
kfifo_put(&pbi->newframe_q, vf);
}
ret = vp9_local_init(pbi);
if (!pbi->pts_unstable) {
pbi->pts_unstable =
(pbi->vvp9_amstream_dec_info.rate == 0)?1:0;
pr_info("set pts unstable\n");
}
return ret;
}
#ifdef MULTI_INSTANCE_SUPPORT
static s32 vvp9_init(struct vdec_s *vdec)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)vdec->private;
#else
static s32 vvp9_init(struct VP9Decoder_s *pbi)
{
#endif
int ret;
int fw_size = 0x1000 * 16;
struct firmware_s *fw = NULL;
pbi->stat |= STAT_TIMER_INIT;
if (vvp9_local_init(pbi) < 0)
return -EBUSY;
fw = vmalloc(sizeof(struct firmware_s) + fw_size);
if (IS_ERR_OR_NULL(fw))
return -ENOMEM;
if (get_firmware_data(VIDEO_DEC_VP9_MMU, fw->data) < 0) {
pr_err("get firmware fail.\n");
vfree(fw);
return -1;
}
fw->len = fw_size;
INIT_WORK(&pbi->set_clk_work, vp9_set_clk);
timer_setup(&pbi->timer, vvp9_put_timer_func, 0);
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag) {
pbi->timer.expires = jiffies + PUT_INTERVAL;
/*add_timer(&pbi->timer);
pbi->stat |= STAT_TIMER_ARM;
pbi->stat |= STAT_ISR_REG;*/
INIT_WORK(&pbi->work, vp9_work);
INIT_WORK(&pbi->recycle_mmu_work, vp9_recycle_mmu_work);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0)
INIT_WORK(&pbi->s1_work, vp9_s1_work);
#endif
pbi->fw = fw;
/* picture list init.*/
pbi->dec_result = DEC_INIT_PICLIST;
vdec_schedule_work(&pbi->work);
return 0;
}
#endif
amhevc_enable();
init_pic_list(pbi);
ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, fw->data);
if (ret < 0) {
amhevc_disable();
vfree(fw);
pr_err("VP9: the %s fw loading failed, err: %x\n",
tee_enabled() ? "TEE" : "local", ret);
return -EBUSY;
}
vfree(fw);
pbi->stat |= STAT_MC_LOAD;
/* enable AMRISC side protocol */
vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
if (vdec_request_threaded_irq(VDEC_IRQ_0,
vvp9_isr,
vvp9_isr_thread_fn,
IRQF_ONESHOT,/*run thread on this irq disabled*/
"vvp9-irq", (void *)pbi)) {
pr_info("vvp9 irq register error.\n");
amhevc_disable();
return -ENOENT;
}
pbi->stat |= STAT_ISR_REG;
pbi->provider_name = PROVIDER_NAME;
#ifdef MULTI_INSTANCE_SUPPORT
if (!pbi->is_used_v4l) {
vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME,
&vvp9_vf_provider, pbi);
vf_reg_provider(&vvp9_vf_prov);
vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
if (pbi->frame_dur != 0) {
if (!is_reset)
vf_notify_receiver(pbi->provider_name,
VFRAME_EVENT_PROVIDER_FR_HINT,
(void *)
((unsigned long)pbi->frame_dur));
}
}
#else
vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME, &vvp9_vf_provider,
pbi);
vf_reg_provider(&vvp9_vf_prov);
vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
if (!is_reset)
vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
(void *)((unsigned long)pbi->frame_dur));
#endif
pbi->stat |= STAT_VF_HOOK;
pbi->timer.expires = jiffies + PUT_INTERVAL;
add_timer(&pbi->timer);
pbi->stat |= STAT_VDEC_RUN;
pbi->stat |= STAT_TIMER_ARM;
amhevc_start();
pbi->init_flag = 1;
pbi->process_busy = 0;
pr_info("%d, vvp9_init, RP=0x%x\n",
__LINE__, READ_VREG(HEVC_STREAM_RD_PTR));
return 0;
}
static int vmvp9_stop(struct VP9Decoder_s *pbi)
{
pbi->init_flag = 0;
if (pbi->stat & STAT_VDEC_RUN) {
amhevc_stop();
pbi->stat &= ~STAT_VDEC_RUN;
}
if (pbi->stat & STAT_ISR_REG) {
vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
pbi->stat &= ~STAT_ISR_REG;
}
if (pbi->stat & STAT_TIMER_ARM) {
del_timer_sync(&pbi->timer);
pbi->stat &= ~STAT_TIMER_ARM;
}
if (!pbi->is_used_v4l && (pbi->stat & STAT_VF_HOOK)) {
if (!is_reset)
vf_notify_receiver(pbi->provider_name,
VFRAME_EVENT_PROVIDER_FR_END_HINT,
NULL);
vf_unreg_provider(&vvp9_vf_prov);
pbi->stat &= ~STAT_VF_HOOK;
}
vp9_local_uninit(pbi);
reset_process_time(pbi);
cancel_work_sync(&pbi->work);
cancel_work_sync(&pbi->recycle_mmu_work);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0)
cancel_work_sync(&pbi->s1_work);
#endif
cancel_work_sync(&pbi->set_clk_work);
uninit_mmu_buffers(pbi);
if (pbi->fw)
vfree(pbi->fw);
pbi->fw = NULL;
return 0;
}
static int vvp9_stop(struct VP9Decoder_s *pbi)
{
pbi->init_flag = 0;
pbi->first_sc_checked = 0;
if (pbi->stat & STAT_VDEC_RUN) {
amhevc_stop();
pbi->stat &= ~STAT_VDEC_RUN;
}
if (pbi->stat & STAT_ISR_REG) {
#ifdef MULTI_INSTANCE_SUPPORT
if (!pbi->m_ins_flag)
#endif
WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
pbi->stat &= ~STAT_ISR_REG;
}
if (pbi->stat & STAT_TIMER_ARM) {
del_timer_sync(&pbi->timer);
pbi->stat &= ~STAT_TIMER_ARM;
}
if (!pbi->is_used_v4l && (pbi->stat & STAT_VF_HOOK)) {
if (!is_reset)
vf_notify_receiver(pbi->provider_name,
VFRAME_EVENT_PROVIDER_FR_END_HINT,
NULL);
vf_unreg_provider(&vvp9_vf_prov);
pbi->stat &= ~STAT_VF_HOOK;
}
vp9_local_uninit(pbi);
cancel_work_sync(&pbi->set_clk_work);
#ifdef MULTI_INSTANCE_SUPPORT
if (pbi->m_ins_flag) {
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0)
cancel_work_sync(&pbi->s1_work);
#endif
cancel_work_sync(&pbi->work);
cancel_work_sync(&pbi->recycle_mmu_work);
} else
amhevc_disable();
#else
amhevc_disable();
#endif
uninit_mmu_buffers(pbi);
vfree(pbi->fw);
pbi->fw = NULL;
return 0;
}
static int amvdec_vp9_mmu_init(struct VP9Decoder_s *pbi)
{
int tvp_flag = vdec_secure(hw_to_vdec(pbi)) ?
CODEC_MM_FLAGS_TVP : 0;
int buf_size = vp9_max_mmu_buf_size(pbi->max_pic_w, pbi->max_pic_h);
pbi->need_cache_size = buf_size * SZ_1M;
pbi->sc_start_time = get_jiffies_64();
if (pbi->mmu_enable && !pbi->is_used_v4l) {
pbi->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
pbi->index, FRAME_BUFFERS,
pbi->need_cache_size,
tvp_flag
);
if (!pbi->mmu_box) {
pr_err("vp9 alloc mmu box failed!!\n");
return -1;
}
}
#ifdef VP9_10B_MMU_DW
if (pbi->dw_mmu_enable && !pbi->is_used_v4l) {
pbi->mmu_box_dw = decoder_mmu_box_alloc_box(DRIVER_NAME,
pbi->index, FRAME_BUFFERS,
pbi->need_cache_size,
tvp_flag
);
if (!pbi->mmu_box_dw) {
pr_err("vp9 alloc mmu dw box failed!!\n");
}
}
#endif
pbi->bmmu_box = decoder_bmmu_box_alloc_box(
DRIVER_NAME,
pbi->index,
MAX_BMMU_BUFFER_NUM,
4 + PAGE_SHIFT,
CODEC_MM_FLAGS_CMA_CLEAR |
CODEC_MM_FLAGS_FOR_VDECODER |
tvp_flag);
if (!pbi->bmmu_box) {
pr_err("vp9 alloc bmmu box failed!!\n");
return -1;
}
return 0;
}
static struct VP9Decoder_s *gHevc;
static int amvdec_vp9_probe(struct platform_device *pdev)
{
struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
struct BUF_s BUF[MAX_BUF_NUM];
struct VP9Decoder_s *pbi;
int ret;
#ifndef MULTI_INSTANCE_SUPPORT
int i;
#endif
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) {
pr_info("vp9 unsupported on cpu 0x%x\n", get_cpu_major_id());
return -EINVAL;
}
pr_debug("%s\n", __func__);
mutex_lock(&vvp9_mutex);
pbi = vzalloc(sizeof(struct VP9Decoder_s));
if (pbi == NULL) {
pr_info("\namvdec_vp9 device data allocation failed\n");
mutex_unlock(&vvp9_mutex);
return -ENOMEM;
}
gHevc = pbi;
memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
memset(pbi, 0, sizeof(struct VP9Decoder_s));
memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
pbi->init_flag = 0;
pbi->first_sc_checked= 0;
if (!vdec_is_support_4k()) {
pbi->max_pic_w = 1920;
pbi->max_pic_h = 1088;
} else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) {
pbi->max_pic_w = 4096;
pbi->max_pic_h = 2304;
} else {
pbi->max_pic_w = 8192;
pbi->max_pic_h = 4608;
}
if (pdata->sys_info) {
pbi->vvp9_amstream_dec_info = *pdata->sys_info;
if ((pbi->vvp9_amstream_dec_info.width != 0) &&
(pbi->vvp9_amstream_dec_info.height != 0)) {
pbi->max_pic_w = pbi->vvp9_amstream_dec_info.width;
pbi->max_pic_h = pbi->vvp9_amstream_dec_info.height;
}
} else {
pbi->vvp9_amstream_dec_info.width = 0;
pbi->vvp9_amstream_dec_info.height = 0;
pbi->vvp9_amstream_dec_info.rate = 30;
}
#ifdef MULTI_INSTANCE_SUPPORT
pbi->eos = 0;
pbi->start_process_time = 0;
pbi->timeout_num = 0;
#endif
pbi->fatal_error = 0;
pbi->show_frame_num = 0;
if (pdata == NULL) {
pr_info("\namvdec_vp9 memory resource undefined.\n");
vfree(pbi);
mutex_unlock(&vvp9_mutex);
return -EFAULT;
}
pbi->m_ins_flag = 0;
#ifdef MULTI_INSTANCE_SUPPORT
pbi->platform_dev = pdev;
platform_set_drvdata(pdev, pdata);
#endif
pbi->double_write_mode = double_write_mode;
pbi->mmu_enable = 1;
#ifdef VP9_10B_MMU_DW
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) {
pbi->dw_mmu_enable =
(get_double_write_mode(pbi) & 0x20) ? 1 : 0;
} else {
pbi->dw_mmu_enable = 0;
}
#endif
if (amvdec_vp9_mmu_init(pbi) < 0) {
vfree(pbi);
mutex_unlock(&vvp9_mutex);
pr_err("vp9 alloc bmmu box failed!!\n");
return -1;
}
ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box, WORK_SPACE_BUF_ID,
work_buf_size, DRIVER_NAME, &pdata->mem_start);
if (ret < 0) {
uninit_mmu_buffers(pbi);
vfree(pbi);
mutex_unlock(&vvp9_mutex);
return ret;
}
pbi->buf_size = work_buf_size;
#ifdef MULTI_INSTANCE_SUPPORT
pbi->buf_start = pdata->mem_start;
#else
if (!pbi->mmu_enable)
pbi->mc_buf_spec.buf_end = pdata->mem_start + pbi->buf_size;
for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
amvvp9_workbuff_spec[i].start_adr = pdata->mem_start;
#endif
if (debug) {
pr_info("===VP9 decoder mem resource 0x%lx size 0x%x\n",
pdata->mem_start, pbi->buf_size);
}
pbi->no_head = no_head;
#ifdef MULTI_INSTANCE_SUPPORT
pbi->cma_dev = pdata->cma_dev;
#else
cma_dev = pdata->cma_dev;
#endif
/* config endian */
pbi->endian = HEVC_CONFIG_LITTLE_ENDIAN;
if (is_support_vdec_canvas())
pbi->endian = HEVC_CONFIG_BIG_ENDIAN;
if (endian)
pbi->endian = endian;
#ifdef MULTI_INSTANCE_SUPPORT
pdata->private = pbi;
pdata->dec_status = vvp9_dec_status;
pdata->set_isreset = vvp9_set_isreset;
is_reset = 0;
if (vvp9_init(pdata) < 0) {
#else
if (vvp9_init(pbi) < 0) {
#endif
pr_info("\namvdec_vp9 init failed.\n");
vp9_local_uninit(pbi);
uninit_mmu_buffers(pbi);
vfree(pbi);
pdata->dec_status = NULL;
mutex_unlock(&vvp9_mutex);
return -ENODEV;
}
/*set the max clk for smooth playing...*/
hevc_source_changed(VFORMAT_VP9,
4096, 2048, 60);
mutex_unlock(&vvp9_mutex);
return 0;
}
static void vdec_fence_release(struct VP9Decoder_s *pbi,
struct vdec_sync *sync)
{
ulong expires;
/* notify signal to wake up all fences. */
vdec_timeline_increase(sync, VF_POOL_SIZE);
expires = jiffies + msecs_to_jiffies(2000);
while (!check_objs_all_signaled(sync)) {
if (time_after(jiffies, expires)) {
pr_err("wait fence signaled timeout.\n");
break;
}
}
/* decreases refcnt of timeline. */
vdec_timeline_put(sync);
}
static int amvdec_vp9_remove(struct platform_device *pdev)
{
struct VP9Decoder_s *pbi = gHevc;
struct vdec_s *vdec = hw_to_vdec(pbi);
int i;
if (debug)
pr_info("amvdec_vp9_remove\n");
mutex_lock(&vvp9_mutex);
vvp9_stop(pbi);
hevc_source_changed(VFORMAT_VP9, 0, 0, 0);
if (vdec->parallel_dec == 1) {
for (i = 0; i < FRAME_BUFFERS; i++) {
vdec->free_canvas_ex(pbi->common.buffer_pool->
frame_bufs[i].buf.y_canvas_index, vdec->id);
vdec->free_canvas_ex(pbi->common.buffer_pool->
frame_bufs[i].buf.uv_canvas_index, vdec->id);
}
}
#ifdef DEBUG_PTS
pr_info("pts missed %ld, pts hit %ld, duration %d\n",
pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
#endif
mem_map_mode = 0;
if (pbi->enable_fence)
vdec_fence_release(pbi, vdec->sync);
vfree(pbi);
mutex_unlock(&vvp9_mutex);
return 0;
}
/****************************************/
static struct platform_driver amvdec_vp9_driver = {
.probe = amvdec_vp9_probe,
.remove = amvdec_vp9_remove,
#ifdef CONFIG_PM
.suspend = amhevc_suspend,
.resume = amhevc_resume,
#endif
.driver = {
.name = DRIVER_NAME,
}
};
static struct codec_profile_t amvdec_vp9_profile = {
.name = "vp9",
.profile = ""
};
static struct codec_profile_t amvdec_vp9_profile_mult;
static unsigned char get_data_check_sum
(struct VP9Decoder_s *pbi, int size)
{
int jj;
int sum = 0;
u8 *data = NULL;
if (vdec_secure(hw_to_vdec(pbi)))
return 0;
if (!pbi->chunk->block->is_mapped)
data = codec_mm_vmap(pbi->chunk->block->start +
pbi->chunk->offset, size);
else
data = ((u8 *)pbi->chunk->block->start_virt) +
pbi->chunk->offset;
for (jj = 0; jj < size; jj++)
sum += data[jj];
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n",
__func__, size, sum,
(size < 1) ? 0 : data[0],
(size < 2) ? 0 : data[1],
(size < 3) ? 0 : data[2],
(size < 4) ? 0 : data[3],
(size < 5) ? 0 : data[4],
(size < 6) ? 0 : data[5],
(size < 4) ? 0 : data[size - 4],
(size < 3) ? 0 : data[size - 3],
(size < 2) ? 0 : data[size - 2],
(size < 1) ? 0 : data[size - 1]);
if (!pbi->chunk->block->is_mapped)
codec_mm_unmap_phyaddr(data);
return sum;
}
static void dump_data(struct VP9Decoder_s *pbi, int size)
{
int jj;
u8 *data = NULL;
int padding_size = pbi->chunk->offset &
(VDEC_FIFO_ALIGN - 1);
if (!pbi->chunk->block->is_mapped)
data = codec_mm_vmap(pbi->chunk->block->start +
pbi->chunk->offset, size);
else
data = ((u8 *)pbi->chunk->block->start_virt) +
pbi->chunk->offset;
vp9_print(pbi, 0, "padding: ");
for (jj = padding_size; jj > 0; jj--)
vp9_print_cont(pbi,
0,
"%02x ", *(data - jj));
vp9_print_cont(pbi, 0, "data adr %p\n",
data);
for (jj = 0; jj < size; jj++) {
if ((jj & 0xf) == 0)
vp9_print(pbi,
0,
"%06x:", jj);
vp9_print_cont(pbi,
0,
"%02x ", data[jj]);
if (((jj + 1) & 0xf) == 0)
vp9_print(pbi,
0,
"\n");
}
vp9_print(pbi,
0,
"\n");
if (!pbi->chunk->block->is_mapped)
codec_mm_unmap_phyaddr(data);
}
static void vp9_work(struct work_struct *work)
{
struct VP9Decoder_s *pbi = container_of(work,
struct VP9Decoder_s, work);
struct vdec_s *vdec = hw_to_vdec(pbi);
/* finished decoding one frame or error,
* notify vdec core to switch context
*/
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_START);
if (pbi->dec_result == DEC_RESULT_AGAIN)
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_AGAIN);
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"%s dec_result %d %x %x %x\n",
__func__,
pbi->dec_result,
READ_VREG(HEVC_STREAM_LEVEL),
READ_VREG(HEVC_STREAM_WR_PTR),
READ_VREG(HEVC_STREAM_RD_PTR));
if (pbi->dec_result == DEC_INIT_PICLIST) {
init_pic_list(pbi);
pbi->pic_list_init_done = true;
return;
}
if (pbi->dec_result == DEC_RESULT_NEED_MORE_BUFFER) {
reset_process_time(pbi);
if (!get_free_buf_count(pbi)) {
pbi->dec_result = DEC_RESULT_NEED_MORE_BUFFER;
vdec_schedule_work(&pbi->work);
} else {
int i;
if (pbi->mmu_enable)
vp9_recycle_mmu_buf_tail(pbi);
if (pbi->frame_count > 0)
vp9_bufmgr_postproc(pbi);
for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
int ii;
for (ii = 0; ii < 4; ii++)
pbi->vp9_param.l.data[i + ii] =
pbi->rpm_ptr[i + 3 - ii];
}
continue_decoding(pbi);
pbi->postproc_done = 0;
pbi->process_busy = 0;
start_process_time(pbi);
}
return;
}
if (((pbi->dec_result == DEC_RESULT_GET_DATA) ||
(pbi->dec_result == DEC_RESULT_GET_DATA_RETRY))
&& (hw_to_vdec(pbi)->next_status !=
VDEC_STATUS_DISCONNECTED)) {
if (!vdec_has_more_input(vdec)) {
pbi->dec_result = DEC_RESULT_EOS;
vdec_schedule_work(&pbi->work);
return;
}
if (pbi->dec_result == DEC_RESULT_GET_DATA) {
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s DEC_RESULT_GET_DATA %x %x %x\n",
__func__,
READ_VREG(HEVC_STREAM_LEVEL),
READ_VREG(HEVC_STREAM_WR_PTR),
READ_VREG(HEVC_STREAM_RD_PTR));
vdec_vframe_dirty(vdec, pbi->chunk);
vdec_clean_input(vdec);
}
if (get_free_buf_count(pbi) >=
pbi->run_ready_min_buf_num) {
int r;
int decode_size;
r = vdec_prepare_input(vdec, &pbi->chunk);
if (r < 0) {
pbi->dec_result = DEC_RESULT_GET_DATA_RETRY;
vp9_print(pbi,
PRINT_FLAG_VDEC_DETAIL,
"amvdec_vh265: Insufficient data\n");
vdec_schedule_work(&pbi->work);
return;
}
pbi->dec_result = DEC_RESULT_NONE;
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s: chunk size 0x%x sum 0x%x\n",
__func__, r,
(debug & PRINT_FLAG_VDEC_STATUS) ?
get_data_check_sum(pbi, r) : 0
);
if (debug & PRINT_FLAG_VDEC_DATA)
dump_data(pbi, pbi->chunk->size);
decode_size = pbi->chunk->size +
(pbi->chunk->offset & (VDEC_FIFO_ALIGN - 1));
WRITE_VREG(HEVC_DECODE_SIZE,
READ_VREG(HEVC_DECODE_SIZE) + decode_size);
vdec_enable_input(vdec);
WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
start_process_time(pbi);
} else{
pbi->dec_result = DEC_RESULT_GET_DATA_RETRY;
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"amvdec_vh265: Insufficient data\n");
vdec_schedule_work(&pbi->work);
}
return;
} else if (pbi->dec_result == DEC_RESULT_DONE) {
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0) {
#ifndef FB_DECODING_TEST_SCHEDULE
if (!is_s2_decoding_finished(pbi)) {
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"s2 decoding not done, check again later\n");
vdec_schedule_work(&pbi->work);
}
#endif
inc_s2_pos(pbi);
if (mcrcc_cache_alg_flag)
dump_hit_rate(pbi);
}
#endif
/* if (!pbi->ctx_valid)
pbi->ctx_valid = 1; */
pbi->slice_idx++;
pbi->frame_count++;
pbi->process_state = PROC_STATE_INIT;
decode_frame_count[pbi->index] = pbi->frame_count;
if (pbi->mmu_enable)
pbi->used_4k_num =
(READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s (===> %d) dec_result %d %x %x %x shiftbytes 0x%x decbytes 0x%x\n",
__func__,
pbi->frame_count,
pbi->dec_result,
READ_VREG(HEVC_STREAM_LEVEL),
READ_VREG(HEVC_STREAM_WR_PTR),
READ_VREG(HEVC_STREAM_RD_PTR),
READ_VREG(HEVC_SHIFT_BYTE_COUNT),
READ_VREG(HEVC_SHIFT_BYTE_COUNT) -
pbi->start_shift_bytes
);
vdec_vframe_dirty(hw_to_vdec(pbi), pbi->chunk);
} else if (pbi->dec_result == DEC_RESULT_AGAIN) {
/*
stream base: stream buf empty or timeout
frame base: vdec_prepare_input fail
*/
if (!vdec_has_more_input(vdec)) {
pbi->dec_result = DEC_RESULT_EOS;
vdec_schedule_work(&pbi->work);
return;
}
} else if (pbi->dec_result == DEC_RESULT_EOS) {
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s: end of stream\n",
__func__);
pbi->eos = 1;
vp9_bufmgr_postproc(pbi);
notify_v4l_eos(hw_to_vdec(pbi));
vdec_vframe_dirty(hw_to_vdec(pbi), pbi->chunk);
} else if (pbi->dec_result == DEC_RESULT_FORCE_EXIT) {
vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
"%s: force exit\n",
__func__);
if (pbi->stat & STAT_VDEC_RUN) {
amhevc_stop();
pbi->stat &= ~STAT_VDEC_RUN;
}
if (pbi->stat & STAT_ISR_REG) {
#ifdef MULTI_INSTANCE_SUPPORT
if (!pbi->m_ins_flag)
#endif
WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
pbi->stat &= ~STAT_ISR_REG;
}
}
if (pbi->stat & STAT_VDEC_RUN) {
amhevc_stop();
pbi->stat &= ~STAT_VDEC_RUN;
}
if (pbi->stat & STAT_TIMER_ARM) {
del_timer_sync(&pbi->timer);
pbi->stat &= ~STAT_TIMER_ARM;
}
/* mark itself has all HW resource released and input released */
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_END);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0)
vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_HEVC_BACK);
else
vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_VDEC_1
| CORE_MASK_HEVC
| CORE_MASK_HEVC_FRONT
| CORE_MASK_HEVC_BACK
);
#else
if (vdec->parallel_dec == 1)
vdec_core_finish_run(vdec, CORE_MASK_HEVC);
else
vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_VDEC_1
| CORE_MASK_HEVC);
#endif
trigger_schedule(pbi);
}
static int vp9_hw_ctx_restore(struct VP9Decoder_s *pbi)
{
/* new to do ... */
#if (!defined SUPPORT_FB_DECODING)
vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
#elif (defined FB_DECODING_TEST_SCHEDULE)
vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
#else
if (pbi->used_stage_buf_num > 0)
vvp9_prot_init(pbi, HW_MASK_FRONT);
else
vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
#endif
return 0;
}
static bool is_avaliable_buffer(struct VP9Decoder_s *pbi)
{
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
int i, free_count = 0;
if (ctx->cap_pool.dec < pbi->used_buf_num) {
free_count = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx);
if (free_count &&
!ctx->fb_ops.query(&ctx->fb_ops, &pbi->fb_token)) {
return false;
}
}
for (i = 0; i < pbi->used_buf_num; ++i) {
if ((frame_bufs[i].ref_count == 0) &&
(frame_bufs[i].buf.vf_ref == 0) &&
frame_bufs[i].buf.cma_alloc_addr) {
free_count++;
}
}
return free_count < pbi->run_ready_min_buf_num ? 0 : 1;
}
static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
int tvp = vdec_secure(hw_to_vdec(pbi)) ?
CODEC_MM_FLAGS_TVP : 0;
unsigned long ret = 0;
if (!(pbi->pic_list_init_done && pbi->pic_list_init_done2) || pbi->eos)
return ret;
if (!pbi->first_sc_checked && pbi->mmu_enable) {
int size;
void * mmu_box;
if (pbi->is_used_v4l) {
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
mmu_box = ctx->mmu_box;
} else
mmu_box = pbi->mmu_box;
size = decoder_mmu_box_sc_check(mmu_box, tvp);
pbi->first_sc_checked = 1;
vp9_print(pbi, 0, "vp9 cached=%d need_size=%d speed= %d ms\n",
size, (pbi->need_cache_size >> PAGE_SHIFT),
(int)(get_jiffies_64() - pbi->sc_start_time) * 1000/HZ);
}
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0) {
if (mask & CORE_MASK_HEVC_FRONT) {
if (get_free_stage_buf_num(pbi) > 0
&& mv_buf_available(pbi))
ret |= CORE_MASK_HEVC_FRONT;
}
if (mask & CORE_MASK_HEVC_BACK) {
if (s2_buf_available(pbi) &&
(get_free_buf_count(pbi) >=
pbi->run_ready_min_buf_num)) {
ret |= CORE_MASK_HEVC_BACK;
pbi->back_not_run_ready = 0;
} else
pbi->back_not_run_ready = 1;
#if 0
if (get_free_buf_count(pbi) <
run_ready_min_buf_num)
dump_pic_list(pbi);
#endif
}
} else if (get_free_buf_count(pbi) >=
pbi->run_ready_min_buf_num)
ret = CORE_MASK_VDEC_1 | CORE_MASK_HEVC
| CORE_MASK_HEVC_FRONT
| CORE_MASK_HEVC_BACK;
if (ret & CORE_MASK_HEVC_FRONT)
not_run_ready[pbi->index] = 0;
else
not_run_ready[pbi->index]++;
if (ret & CORE_MASK_HEVC_BACK)
not_run2_ready[pbi->index] = 0;
else
not_run2_ready[pbi->index]++;
vp9_print(pbi,
PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx (%d %d %d %d)\r\n",
__func__, mask, ret,
get_free_stage_buf_num(pbi),
mv_buf_available(pbi),
s2_buf_available(pbi),
get_free_buf_count(pbi)
);
return ret;
#else
if (get_free_buf_count(pbi) >=
pbi->run_ready_min_buf_num) {
if (vdec->parallel_dec == 1)
ret = CORE_MASK_HEVC;
else
ret = CORE_MASK_VDEC_1 | CORE_MASK_HEVC;
}
if (pbi->is_used_v4l) {
struct aml_vcodec_ctx *ctx =
(struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
if (ctx->param_sets_from_ucode) {
if (pbi->v4l_params_parsed) {
if (ctx->cap_pool.dec < pbi->used_buf_num) {
if (is_avaliable_buffer(pbi))
ret = CORE_MASK_HEVC;
else
ret = 0;
}
} else {
if (ctx->v4l_resolution_change)
ret = 0;
}
} else if (ctx->cap_pool.in < ctx->dpb_size) {
if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
pbi->run_ready_min_buf_num)
ret = 0;
}
}
if (ret)
not_run_ready[pbi->index] = 0;
else
not_run_ready[pbi->index]++;
vp9_print(pbi,
PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx\r\n",
__func__, mask, ret);
return ret;
#endif
}
static void vp9_frame_mode_pts_save(struct VP9Decoder_s *pbi)
{
int i = 0;
if (pbi->chunk == NULL)
return;
vp9_print(pbi, VP9_DEBUG_OUT_PTS,
"run front: pts %d, pts64 %lld, ts: %lld\n",
pbi->chunk->pts, pbi->chunk->pts64, pbi->chunk->timestamp);
for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
pbi->frame_mode_pts_save[i] = pbi->frame_mode_pts_save[i - 1];
pbi->frame_mode_pts64_save[i] = pbi->frame_mode_pts64_save[i - 1];
}
pbi->frame_mode_pts_save[0] = pbi->chunk->pts;
pbi->frame_mode_pts64_save[0] = pbi->chunk->pts64;
if (pbi->is_used_v4l && !v4l_bitstream_id_enable)
pbi->frame_mode_pts64_save[0] = pbi->chunk->timestamp;
}
static void run_front(struct vdec_s *vdec)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
int ret, size;
run_count[pbi->index]++;
/* pbi->chunk = vdec_prepare_input(vdec); */
#if (!defined SUPPORT_FB_DECODING)
hevc_reset_core(vdec);
#elif (defined FB_DECODING_TEST_SCHEDULE)
hevc_reset_core(vdec);
#else
if (pbi->used_stage_buf_num > 0)
fb_reset_core(vdec, HW_MASK_FRONT);
else
hevc_reset_core(vdec);
#endif
size = vdec_prepare_input(vdec, &pbi->chunk);
if (size < 0) {
input_empty[pbi->index]++;
pbi->dec_result = DEC_RESULT_AGAIN;
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"ammvdec_vh265: Insufficient data\n");
vdec_schedule_work(&pbi->work);
return;
}
input_empty[pbi->index] = 0;
pbi->dec_result = DEC_RESULT_NONE;
pbi->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
vp9_frame_mode_pts_save(pbi);
if (debug & PRINT_FLAG_VDEC_STATUS) {
int ii;
vp9_print(pbi, 0,
"%s (%d): size 0x%x (0x%x 0x%x) sum 0x%x (%x %x %x %x %x) bytes 0x%x",
__func__,
pbi->frame_count, size,
pbi->chunk ? pbi->chunk->size : 0,
pbi->chunk ? pbi->chunk->offset : 0,
pbi->chunk ? ((vdec_frame_based(vdec) &&
(debug & PRINT_FLAG_VDEC_STATUS)) ?
get_data_check_sum(pbi, size) : 0) : 0,
READ_VREG(HEVC_STREAM_START_ADDR),
READ_VREG(HEVC_STREAM_END_ADDR),
READ_VREG(HEVC_STREAM_LEVEL),
READ_VREG(HEVC_STREAM_WR_PTR),
READ_VREG(HEVC_STREAM_RD_PTR),
pbi->start_shift_bytes);
if (!vdec_secure(hw_to_vdec(pbi)) &&
vdec_frame_based(vdec) && pbi->chunk) {
u8 *data = NULL;
if (!pbi->chunk->block->is_mapped)
data = codec_mm_vmap(pbi->chunk->block->start +
pbi->chunk->offset, 8);
else
data = ((u8 *)pbi->chunk->block->start_virt) +
pbi->chunk->offset;
vp9_print_cont(pbi, 0, "data adr %p:",
data);
for (ii = 0; ii < 8; ii++)
vp9_print_cont(pbi, 0, "%02x ",
data[ii]);
if (!pbi->chunk->block->is_mapped)
codec_mm_unmap_phyaddr(data);
}
vp9_print_cont(pbi, 0, "\r\n");
}
ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_START);
if (vdec->mc_loaded) {
/*firmware have load before,
and not changes to another.
ignore reload.
*/
} else {
ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, pbi->fw->data);
if (ret < 0) {
amhevc_disable();
vp9_print(pbi, PRINT_FLAG_ERROR,
"VP9: the %s fw loading failed, err: %x\n",
tee_enabled() ? "TEE" : "local", ret);
pbi->dec_result = DEC_RESULT_FORCE_EXIT;
vdec_schedule_work(&pbi->work);
return;
}
vdec->mc_loaded = 1;
vdec->mc_type = VFORMAT_VP9;
}
ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END);
ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START);
if (vp9_hw_ctx_restore(pbi) < 0) {
vdec_schedule_work(&pbi->work);
return;
}
ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_END);
vdec_enable_input(vdec);
WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
if (vdec_frame_based(vdec)) {
if (debug & PRINT_FLAG_VDEC_DATA)
dump_data(pbi, pbi->chunk->size);
WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0);
size = pbi->chunk->size +
(pbi->chunk->offset & (VDEC_FIFO_ALIGN - 1));
if (vdec->mvfrm)
vdec->mvfrm->frame_size = pbi->chunk->size;
}
WRITE_VREG(HEVC_DECODE_SIZE, size);
WRITE_VREG(HEVC_DECODE_COUNT, pbi->slice_idx);
pbi->init_flag = 1;
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"%s: start hevc (%x %x %x)\n",
__func__,
READ_VREG(HEVC_DEC_STATUS_REG),
READ_VREG(HEVC_MPC_E),
READ_VREG(HEVC_MPSR));
start_process_time(pbi);
mod_timer(&pbi->timer, jiffies);
pbi->stat |= STAT_TIMER_ARM;
pbi->stat |= STAT_ISR_REG;
amhevc_start();
pbi->stat |= STAT_VDEC_RUN;
}
#ifdef SUPPORT_FB_DECODING
static void mpred_process(struct VP9Decoder_s *pbi)
{
union param_u *params = &pbi->s1_param;
unsigned char use_prev_frame_mvs =
!params->p.error_resilient_mode &&
params->p.width == pbi->s1_width &&
params->p.height == pbi->s1_height &&
!pbi->s1_intra_only &&
pbi->s1_last_show_frame &&
(pbi->s1_frame_type != KEY_FRAME);
pbi->s1_width = params->p.width;
pbi->s1_height = params->p.height;
pbi->s1_frame_type = params->p.frame_type;
pbi->s1_intra_only =
(params->p.show_frame ||
params->p.show_existing_frame)
? 0 : params->p.intra_only;
if ((pbi->s1_frame_type != KEY_FRAME)
&& (!pbi->s1_intra_only)) {
unsigned int data32;
int mpred_mv_rd_end_addr;
mpred_mv_rd_end_addr =
pbi->s1_mpred_mv_wr_start_addr_pre
+ (pbi->lcu_total * MV_MEM_UNIT);
WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412);
WRITE_VREG(HEVC_MPRED_ABV_START_ADDR,
pbi->work_space_buf->
mpred_above.buf_start);
data32 = READ_VREG(HEVC_MPRED_CTRL4);
data32 &= (~(1 << 6));
data32 |= (use_prev_frame_mvs << 6);
WRITE_VREG(HEVC_MPRED_CTRL4, data32);
WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
pbi->s1_mpred_mv_wr_start_addr);
WRITE_VREG(HEVC_MPRED_MV_WPTR,
pbi->s1_mpred_mv_wr_start_addr);
WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
pbi->s1_mpred_mv_wr_start_addr_pre);
WRITE_VREG(HEVC_MPRED_MV_RPTR,
pbi->s1_mpred_mv_wr_start_addr_pre);
WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR,
mpred_mv_rd_end_addr);
} else
clear_mpred_hw(pbi);
if (!params->p.show_existing_frame) {
pbi->s1_mpred_mv_wr_start_addr_pre =
pbi->s1_mpred_mv_wr_start_addr;
pbi->s1_last_show_frame =
params->p.show_frame;
if (pbi->s1_mv_buf_index_pre_pre != MV_BUFFER_NUM)
put_mv_buf(pbi, &pbi->s1_mv_buf_index_pre_pre);
pbi->s1_mv_buf_index_pre_pre =
pbi->s1_mv_buf_index_pre;
pbi->s1_mv_buf_index_pre = pbi->s1_mv_buf_index;
} else
put_mv_buf(pbi, &pbi->s1_mv_buf_index);
}
static void vp9_s1_work(struct work_struct *s1_work)
{
struct VP9Decoder_s *pbi = container_of(s1_work,
struct VP9Decoder_s, s1_work);
vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
"%s dec_s1_result %d\n",
__func__,
pbi->dec_s1_result);
#ifdef FB_DECODING_TEST_SCHEDULE
if (pbi->dec_s1_result ==
DEC_S1_RESULT_TEST_TRIGGER_DONE) {
pbi->s1_test_cmd = TEST_SET_PIC_DONE;
WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
}
#endif
if (pbi->dec_s1_result == DEC_S1_RESULT_DONE ||
pbi->dec_s1_result == DEC_S1_RESULT_FORCE_EXIT) {
vdec_core_finish_run(hw_to_vdec(pbi),
CORE_MASK_HEVC_FRONT);
trigger_schedule(pbi);
/*pbi->dec_s1_result = DEC_S1_RESULT_NONE;*/
}
}
static void run_back(struct vdec_s *vdec)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
int i;
run2_count[pbi->index]++;
if (debug & PRINT_FLAG_VDEC_STATUS) {
vp9_print(pbi, 0,
"%s", __func__);
}
pbi->run2_busy = 1;
#ifndef FB_DECODING_TEST_SCHEDULE
fb_reset_core(vdec, HW_MASK_BACK);
vvp9_prot_init(pbi, HW_MASK_BACK);
#endif
vp9_recycle_mmu_buf_tail(pbi);
if (pbi->frame_count > 0)
vp9_bufmgr_postproc(pbi);
if (get_s2_buf(pbi) >= 0) {
for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
int ii;
for (ii = 0; ii < 4; ii++)
pbi->vp9_param.l.data[i + ii] =
pbi->s2_buf->rpm[i + 3 - ii];
}
#ifndef FB_DECODING_TEST_SCHEDULE
WRITE_VREG(HEVC_ASSIST_FBD_MMU_MAP_ADDR,
pbi->stage_mmu_map_phy_addr +
pbi->s2_buf->index * STAGE_MMU_MAP_SIZE);
#endif
continue_decoding(pbi);
}
pbi->run2_busy = 0;
}
#endif
static void run(struct vdec_s *vdec, unsigned long mask,
void (*callback)(struct vdec_s *, void *), void *arg)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_RUN_START);
vp9_print(pbi,
PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n",
__func__, mask);
if (vdec->mvfrm)
vdec->mvfrm->hw_decode_start = local_clock();
run_count[pbi->index]++;
pbi->vdec_cb_arg = arg;
pbi->vdec_cb = callback;
pbi->one_package_frame_cnt = 0;
#ifdef SUPPORT_FB_DECODING
if ((mask & CORE_MASK_HEVC) ||
(mask & CORE_MASK_HEVC_FRONT))
run_front(vdec);
if ((pbi->used_stage_buf_num > 0)
&& (mask & CORE_MASK_HEVC_BACK))
run_back(vdec);
#else
run_front(vdec);
#endif
ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_RUN_END);
}
static void vp9_decoder_ctx_reset(struct VP9Decoder_s *pbi)
{
struct vdec_s *vdec = hw_to_vdec(pbi);
struct VP9_Common_s *const cm = &pbi->common;
struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
struct BufferPool_s *buffer_pool = cm->buffer_pool;
int i;
cm->buffer_pool = buffer_pool;
for (i = 0; i < FRAME_BUFFERS; ++i) {
frame_bufs[i].buf.index = i;
frame_bufs[i].ref_count = 0;
frame_bufs[i].buf.vf_ref = 0;
frame_bufs[i].buf.decode_idx = 0;
frame_bufs[i].buf.cma_alloc_addr = 0;
frame_bufs[i].buf.BUF_index = -1;
frame_bufs[i].buf.slice_type = 0;
}
for (i = 0; i < MV_BUFFER_NUM; ++i) {
pbi->m_mv_BUF[i].used_flag = 0;
}
for (i = 0; i < FRAME_BUFFERS; i++) {
pbi->buffer_wrap[i] = i;
}
if (vdec->parallel_dec == 1) {
for (i = 0; i < FRAME_BUFFERS; i++) {
vdec->free_canvas_ex
(pbi->common.buffer_pool->frame_bufs[i].buf.y_canvas_index,
vdec->id);
vdec->free_canvas_ex
(pbi->common.buffer_pool->frame_bufs[i].buf.uv_canvas_index,
vdec->id);
}
}
pbi->init_flag = 0;
pbi->first_sc_checked = 0;
pbi->fatal_error = 0;
pbi->show_frame_num = 0;
pbi->eos = 0;
}
static void reset(struct vdec_s *vdec)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
cancel_work_sync(&pbi->set_clk_work);
cancel_work_sync(&pbi->work);
if (pbi->stat & STAT_VDEC_RUN) {
amhevc_stop();
pbi->stat &= ~STAT_VDEC_RUN;
}
if (pbi->stat & STAT_TIMER_ARM) {
del_timer_sync(&pbi->timer);
pbi->stat &= ~STAT_TIMER_ARM;
}
reset_process_time(pbi);
vp9_local_uninit(pbi);
if (vvp9_local_init(pbi) < 0)
vp9_print(pbi, 0, "%s local_init failed \r\n", __func__);
vp9_decoder_ctx_reset(pbi);
vp9_print(pbi, 0, "%s\r\n", __func__);
}
static irqreturn_t vp9_irq_cb(struct vdec_s *vdec, int irq)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
return vvp9_isr(0, pbi);
}
static irqreturn_t vp9_threaded_irq_cb(struct vdec_s *vdec, int irq)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
return vvp9_isr_thread_fn(0, pbi);
}
static void vp9_dump_state(struct vdec_s *vdec)
{
struct VP9Decoder_s *pbi =
(struct VP9Decoder_s *)vdec->private;
struct VP9_Common_s *const cm = &pbi->common;
int i;
vp9_print(pbi, 0, "====== %s\n", __func__);
vp9_print(pbi, 0,
"width/height (%d/%d), used_buf_num %d video_signal_type 0x%x\n",
cm->width,
cm->height,
pbi->used_buf_num,
pbi->video_signal_type
);
vp9_print(pbi, 0,
"is_framebase(%d), eos %d, dec_result 0x%x dec_frm %d disp_frm %d run %d not_run_ready %d input_empty %d low_latency %d no_head %d \n",
input_frame_based(vdec),
pbi->eos,
pbi->dec_result,
decode_frame_count[pbi->index],
display_frame_count[pbi->index],
run_count[pbi->index],
not_run_ready[pbi->index],
input_empty[pbi->index],
pbi->low_latency_flag,
pbi->no_head
);
if (!pbi->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) {
enum receviver_start_e state =
vf_notify_receiver(vdec->vf_provider_name,
VFRAME_EVENT_PROVIDER_QUREY_STATE,
NULL);
vp9_print(pbi, 0,
"\nreceiver(%s) state %d\n",
vdec->vf_provider_name,
state);
}
vp9_print(pbi, 0,
"%s, newq(%d/%d), dispq(%d/%d), vf prepare/get/put (%d/%d/%d), free_buf_count %d (min %d for run_ready)\n",
__func__,
kfifo_len(&pbi->newframe_q),
VF_POOL_SIZE,
kfifo_len(&pbi->display_q),
VF_POOL_SIZE,
pbi->vf_pre_count,
pbi->vf_get_count,
pbi->vf_put_count,
get_free_buf_count(pbi),
pbi->run_ready_min_buf_num
);
dump_pic_list(pbi);
for (i = 0; i < MAX_BUF_NUM; i++) {
vp9_print(pbi, 0,
"mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n",
i,
pbi->m_mv_BUF[i].start_adr,
pbi->m_mv_BUF[i].size,
pbi->m_mv_BUF[i].used_flag);
}
vp9_print(pbi, 0,
"HEVC_DEC_STATUS_REG=0x%x\n",
READ_VREG(HEVC_DEC_STATUS_REG));
vp9_print(pbi, 0,
"HEVC_MPC_E=0x%x\n",
READ_VREG(HEVC_MPC_E));
vp9_print(pbi, 0,
"DECODE_MODE=0x%x\n",
READ_VREG(DECODE_MODE));
vp9_print(pbi, 0,
"NAL_SEARCH_CTL=0x%x\n",
READ_VREG(NAL_SEARCH_CTL));
vp9_print(pbi, 0,
"HEVC_PARSER_LCU_START=0x%x\n",
READ_VREG(HEVC_PARSER_LCU_START));
vp9_print(pbi, 0,
"HEVC_DECODE_SIZE=0x%x\n",
READ_VREG(HEVC_DECODE_SIZE));
vp9_print(pbi, 0,
"HEVC_SHIFT_BYTE_COUNT=0x%x\n",
READ_VREG(HEVC_SHIFT_BYTE_COUNT));
vp9_print(pbi, 0,
"HEVC_STREAM_START_ADDR=0x%x\n",
READ_VREG(HEVC_STREAM_START_ADDR));
vp9_print(pbi, 0,
"HEVC_STREAM_END_ADDR=0x%x\n",
READ_VREG(HEVC_STREAM_END_ADDR));
vp9_print(pbi, 0,
"HEVC_STREAM_LEVEL=0x%x\n",
READ_VREG(HEVC_STREAM_LEVEL));
vp9_print(pbi, 0,
"HEVC_STREAM_WR_PTR=0x%x\n",
READ_VREG(HEVC_STREAM_WR_PTR));
vp9_print(pbi, 0,
"HEVC_STREAM_RD_PTR=0x%x\n",
READ_VREG(HEVC_STREAM_RD_PTR));
vp9_print(pbi, 0,
"PARSER_VIDEO_RP=0x%x\n",
STBUF_READ(&vdec->vbuf, get_rp));
vp9_print(pbi, 0,
"PARSER_VIDEO_WP=0x%x\n",
STBUF_READ(&vdec->vbuf, get_wp));
if (input_frame_based(vdec) &&
(debug & PRINT_FLAG_VDEC_DATA)
) {
int jj;
if (pbi->chunk && pbi->chunk->block &&
pbi->chunk->size > 0) {
u8 *data = NULL;
if (!pbi->chunk->block->is_mapped)
data = codec_mm_vmap(
pbi->chunk->block->start +
pbi->chunk->offset,
pbi->chunk->size);
else
data = ((u8 *)pbi->chunk->block->start_virt)
+ pbi->chunk->offset;
vp9_print(pbi, 0,
"frame data size 0x%x\n",
pbi->chunk->size);
for (jj = 0; jj < pbi->chunk->size; jj++) {
if ((jj & 0xf) == 0)
vp9_print(pbi, 0,
"%06x:", jj);
vp9_print_cont(pbi, 0,
"%02x ", data[jj]);
if (((jj + 1) & 0xf) == 0)
vp9_print_cont(pbi, 0,
"\n");
}
if (!pbi->chunk->block->is_mapped)
codec_mm_unmap_phyaddr(data);
}
}
}
static int ammvdec_vp9_probe(struct platform_device *pdev)
{
struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
int ret;
int config_val;
int transfer_val;
struct vframe_content_light_level_s content_light_level;
struct vframe_master_display_colour_s vf_dp;
struct VP9Decoder_s *pbi = NULL;
int i;
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) {
pr_info("vp9 unsupported on cpu 0x%x\n", get_cpu_major_id());
return -EINVAL;
}
pr_debug("%s\n", __func__);
if (pdata == NULL) {
pr_info("\nammvdec_vp9 memory resource undefined.\n");
return -EFAULT;
}
/*pbi = (struct VP9Decoder_s *)devm_kzalloc(&pdev->dev,
sizeof(struct VP9Decoder_s), GFP_KERNEL);*/
memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s));
pbi = vmalloc(sizeof(struct VP9Decoder_s));
if (pbi == NULL) {
pr_info("\nammvdec_vp9 device data allocation failed\n");
return -ENOMEM;
}
memset(pbi, 0, sizeof(struct VP9Decoder_s));
/* the ctx from v4l2 driver. */
pbi->v4l2_ctx = pdata->private;
pdata->private = pbi;
pdata->dec_status = vvp9_dec_status;
/* pdata->set_trickmode = set_trickmode; */
pdata->run_ready = run_ready;
pdata->run = run;
pdata->reset = reset;
pdata->irq_handler = vp9_irq_cb;
pdata->threaded_irq_handler = vp9_threaded_irq_cb;
pdata->dump_state = vp9_dump_state;
pbi->index = pdev->id;
if (is_rdma_enable()) {
pbi->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &pbi->rdma_phy_adr, GFP_KERNEL);
for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) {
pbi->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff;
pbi->rdma_adr[i * 4 + 1] = i;
pbi->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff;
pbi->rdma_adr[i * 4 + 3] = 0;
if (i == SCALELUT_DATA_WRITE_NUM - 1) {
pbi->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000;
}
}
}
snprintf(pbi->trace.vdec_name, sizeof(pbi->trace.vdec_name),
"vp9-%d", pbi->index);
snprintf(pbi->trace.pts_name, sizeof(pbi->trace.pts_name),
"%s-pts", pbi->trace.vdec_name);
snprintf(pbi->trace.new_q_name, sizeof(pbi->trace.new_q_name),
"%s-newframe_q", pbi->trace.vdec_name);
snprintf(pbi->trace.disp_q_name, sizeof(pbi->trace.disp_q_name),
"%s-dispframe_q", pbi->trace.vdec_name);
snprintf(pbi->trace.decode_time_name, sizeof(pbi->trace.decode_time_name),
"decoder_time%d", pdev->id);
snprintf(pbi->trace.decode_run_time_name, sizeof(pbi->trace.decode_run_time_name),
"decoder_run_time%d", pdev->id);
snprintf(pbi->trace.decode_header_memory_time_name, sizeof(pbi->trace.decode_header_memory_time_name),
"decoder_header_time%d", pdev->id);
if (pdata->use_vfm_path)
snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
VFM_DEC_PROVIDER_NAME);
else
snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff);
pbi->provider_name = pdata->vf_provider_name;
platform_set_drvdata(pdev, pdata);
pbi->platform_dev = pdev;
pbi->video_signal_type = 0;
pbi->m_ins_flag = 1;
if (!vdec_is_support_4k()) {
pbi->max_pic_w = 1920;
pbi->max_pic_h = 1088;
} else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) {
pbi->max_pic_w = 4096;
pbi->max_pic_h = 2304;
} else {
pbi->max_pic_w = 8192;
pbi->max_pic_h = 4608;
}
if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 &&
pdata->config_len) {
#ifdef MULTI_INSTANCE_SUPPORT
int vp9_buf_width = 0;
int vp9_buf_height = 0;
/*use ptr config for doubel_write_mode, etc*/
vp9_print(pbi, 0, "pdata->config=%s\n", pdata->config);
if (get_config_int(pdata->config, "vp9_double_write_mode",
&config_val) == 0)
pbi->double_write_mode = config_val;
else
pbi->double_write_mode = double_write_mode;
if (get_config_int(pdata->config, "save_buffer_mode",
&config_val) == 0)
pbi->save_buffer_mode = config_val;
else
pbi->save_buffer_mode = 0;
if (get_config_int(pdata->config, "vp9_buf_width",
&config_val) == 0) {
vp9_buf_width = config_val;
}
if (get_config_int(pdata->config, "vp9_buf_height",
&config_val) == 0) {
vp9_buf_height = config_val;
}
if (get_config_int(pdata->config, "no_head",
&config_val) == 0)
pbi->no_head = config_val;
else
pbi->no_head = no_head;
/*use ptr config for max_pic_w, etc*/
if (get_config_int(pdata->config, "vp9_max_pic_w",
&config_val) == 0) {
pbi->max_pic_w = config_val;
}
if (get_config_int(pdata->config, "vp9_max_pic_h",
&config_val) == 0) {
pbi->max_pic_h = config_val;
}
if ((pbi->max_pic_w * pbi->max_pic_h)
< (vp9_buf_width * vp9_buf_height)) {
pbi->max_pic_w = vp9_buf_width;
pbi->max_pic_h = vp9_buf_height;
vp9_print(pbi, 0, "use buf resolution\n");
}
if (get_config_int(pdata->config, "sidebind_type",
&config_val) == 0)
pbi->sidebind_type = config_val;
if (get_config_int(pdata->config, "sidebind_channel_id",
&config_val) == 0)
pbi->sidebind_channel_id = config_val;
if (get_config_int(pdata->config,
"parm_v4l_codec_enable",
&config_val) == 0)
pbi->is_used_v4l = config_val;
if (get_config_int(pdata->config,
"parm_v4l_buffer_margin",
&config_val) == 0)
pbi->dynamic_buf_num_margin = config_val;
if (get_config_int(pdata->config,
"parm_v4l_canvas_mem_mode",
&config_val) == 0)
pbi->mem_map_mode = config_val;
if (get_config_int(pdata->config,
"parm_enable_fence",
&config_val) == 0)
pbi->enable_fence = config_val;
if (get_config_int(pdata->config,
"parm_fence_usage",
&config_val) == 0)
pbi->fence_usage = config_val;
if (get_config_int(pdata->config,
"parm_v4l_low_latency_mode",
&config_val) == 0)
pbi->low_latency_flag = config_val;
#endif
if (get_config_int(pdata->config, "HDRStaticInfo",
&vf_dp.present_flag) == 0
&& vf_dp.present_flag == 1) {
get_config_int(pdata->config, "signal_type",
&pbi->video_signal_type);
get_config_int(pdata->config, "mG.x",
&vf_dp.primaries[0][0]);
get_config_int(pdata->config, "mG.y",
&vf_dp.primaries[0][1]);
get_config_int(pdata->config, "mB.x",
&vf_dp.primaries[1][0]);
get_config_int(pdata->config, "mB.y",
&vf_dp.primaries[1][1]);
get_config_int(pdata->config, "mR.x",
&vf_dp.primaries[2][0]);
get_config_int(pdata->config, "mR.y",
&vf_dp.primaries[2][1]);
get_config_int(pdata->config, "mW.x",
&vf_dp.white_point[0]);
get_config_int(pdata->config, "mW.y",
&vf_dp.white_point[1]);
get_config_int(pdata->config, "mMaxDL",
&vf_dp.luminance[0]);
get_config_int(pdata->config, "mMinDL",
&vf_dp.luminance[1]);
vf_dp.content_light_level.present_flag = 1;
get_config_int(pdata->config, "mMaxCLL",
&content_light_level.max_content);
get_config_int(pdata->config, "mMaxFALL",
&content_light_level.max_pic_average);
get_config_int(pdata->config, "mTransfer",
&transfer_val);
if (transfer_val == 0)
transfer_val = 16;
vp9_print(pbi, 0, "transfer_val=%d\n",transfer_val);
vf_dp.content_light_level = content_light_level;
if (!pbi->video_signal_type) {
pbi->video_signal_type = (1 << 29)
| (5 << 26) /* unspecified */
| (0 << 25) /* limit */
| (1 << 24) /* color available */
| (9 << 16) /* 2020 */
| (transfer_val << 8) /* 2084 */
| (9 << 0); /* 2020 */
}
}
pbi->vf_dp = vf_dp;
} else {
if (pdata->sys_info) {
pbi->vvp9_amstream_dec_info = *pdata->sys_info;
if ((pbi->vvp9_amstream_dec_info.width != 0) &&
(pbi->vvp9_amstream_dec_info.height != 0)) {
pbi->max_pic_w = pbi->vvp9_amstream_dec_info.width;
pbi->max_pic_h = pbi->vvp9_amstream_dec_info.height;
}
}
/*pbi->vvp9_amstream_dec_info.width = 0;
pbi->vvp9_amstream_dec_info.height = 0;
pbi->vvp9_amstream_dec_info.rate = 30;*/
pbi->double_write_mode = double_write_mode;
}
if (!pbi->is_used_v4l) {
vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
&vvp9_vf_provider, pbi);
}
if (no_head & 0x10) {
pbi->no_head = (no_head & 0xf);
}
pbi->endian = HEVC_CONFIG_LITTLE_ENDIAN;
if (!pbi->is_used_v4l) {
pbi->mem_map_mode = mem_map_mode;
if (is_support_vdec_canvas())
pbi->endian = HEVC_CONFIG_BIG_ENDIAN;
}
if (endian)
pbi->endian = endian;
if (pbi->is_used_v4l)
pbi->run_ready_min_buf_num = run_ready_min_buf_num - 1 ;
else
pbi->run_ready_min_buf_num = run_ready_min_buf_num;
if (is_oversize(pbi->max_pic_w, pbi->max_pic_h)) {
pr_err("over size: %dx%d, probe failed\n",
pbi->max_pic_w, pbi->max_pic_h);
return -1;
}
if (force_config_fence) {
pbi->enable_fence = true;
pbi->fence_usage =
(force_config_fence >> 4) & 0xf;
if (force_config_fence & 0x2)
pbi->enable_fence = false;
vp9_print(pbi, 0, "enable fence: %d, fence usage: %d\n",
pbi->enable_fence, pbi->fence_usage);
}
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL ||
pbi->double_write_mode == 0x10)
pbi->mmu_enable = 0;
else
pbi->mmu_enable = 1;
#ifdef VP9_10B_MMU_DW
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) {
pbi->dw_mmu_enable =
(get_double_write_mode(pbi) & 0x20) ? 1 : 0;
} else {
pbi->dw_mmu_enable = 0;
}
#endif
video_signal_type = pbi->video_signal_type;
if (pdata->sys_info) {
pbi->vvp9_amstream_dec_info = *pdata->sys_info;
} else {
pbi->vvp9_amstream_dec_info.width = 0;
pbi->vvp9_amstream_dec_info.height = 0;
pbi->vvp9_amstream_dec_info.rate = 30;
}
pbi->low_latency_flag = 1;
vp9_print(pbi, 0,
"no_head %d low_latency %d, signal_type 0x%x\n",
pbi->no_head, pbi->low_latency_flag, pbi->video_signal_type);
#if 0
pbi->buf_start = pdata->mem_start;
pbi->buf_size = pdata->mem_end - pdata->mem_start + 1;
#else
if (amvdec_vp9_mmu_init(pbi) < 0) {
pr_err("vp9 alloc bmmu box failed!!\n");
/* devm_kfree(&pdev->dev, (void *)pbi); */
vfree((void *)pbi);
pdata->dec_status = NULL;
return -1;
}
pbi->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE;
ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box, WORK_SPACE_BUF_ID,
pbi->cma_alloc_count * PAGE_SIZE, DRIVER_NAME,
&pbi->cma_alloc_addr);
if (ret < 0) {
uninit_mmu_buffers(pbi);
/* devm_kfree(&pdev->dev, (void *)pbi); */
vfree((void *)pbi);
pdata->dec_status = NULL;
return ret;
}
pbi->buf_start = pbi->cma_alloc_addr;
pbi->buf_size = work_buf_size;
#endif
pbi->init_flag = 0;
pbi->first_sc_checked = 0;
pbi->fatal_error = 0;
pbi->show_frame_num = 0;
if (debug) {
pr_info("===VP9 decoder mem resource 0x%lx size 0x%x\n",
pbi->buf_start,
pbi->buf_size);
}
pbi->cma_dev = pdata->cma_dev;
mutex_init(&pbi->fence_mutex);
if (pbi->enable_fence) {
pdata->sync = vdec_sync_get();
if (!pdata->sync) {
vp9_print(pbi, 0, "alloc fence timeline error\n");
vp9_local_uninit(pbi);
uninit_mmu_buffers(pbi);
/* devm_kfree(&pdev->dev, (void *)pbi); */
vfree((void *)pbi);
pdata->dec_status = NULL;
return -1;
}
pdata->sync->usage = pbi->fence_usage;
vdec_timeline_create(pdata->sync, DRIVER_NAME);
}
if (vvp9_init(pdata) < 0) {
pr_info("\namvdec_vp9 init failed.\n");
vdec_timeline_put(pdata->sync);
vp9_local_uninit(pbi);
uninit_mmu_buffers(pbi);
/* devm_kfree(&pdev->dev, (void *)pbi); */
vfree((void *)pbi);
pdata->dec_status = NULL;
return -ENODEV;
}
vdec_set_prepare_level(pdata, start_decode_buf_level);
hevc_source_changed(VFORMAT_VP9,
4096, 2048, 60);
#ifdef SUPPORT_FB_DECODING
if (pbi->used_stage_buf_num > 0)
vdec_core_request(pdata,
CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK);
else
vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC
| CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK
| CORE_MASK_COMBINE);
#else
if (pdata->parallel_dec == 1)
vdec_core_request(pdata, CORE_MASK_HEVC);
else
vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC
| CORE_MASK_COMBINE);
#endif
pbi->pic_list_init_done2 = true;
return 0;
}
static int ammvdec_vp9_remove(struct platform_device *pdev)
{
struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)
(((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
struct vdec_s *vdec = hw_to_vdec(pbi);
int i;
if (debug)
pr_info("amvdec_vp9_remove\n");
vmvp9_stop(pbi);
#ifdef SUPPORT_FB_DECODING
vdec_core_release(hw_to_vdec(pbi), CORE_MASK_VDEC_1 | CORE_MASK_HEVC
| CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK
);
#else
if (vdec->parallel_dec == 1)
vdec_core_release(hw_to_vdec(pbi), CORE_MASK_HEVC);
else
vdec_core_release(hw_to_vdec(pbi), CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
#endif
vdec_set_status(hw_to_vdec(pbi), VDEC_STATUS_DISCONNECTED);
if (vdec->parallel_dec == 1) {
for (i = 0; i < FRAME_BUFFERS; i++) {
vdec->free_canvas_ex
(pbi->common.buffer_pool->frame_bufs[i].buf.y_canvas_index,
vdec->id);
vdec->free_canvas_ex
(pbi->common.buffer_pool->frame_bufs[i].buf.uv_canvas_index,
vdec->id);
}
}
if (pbi->enable_fence)
vdec_fence_release(pbi, vdec->sync);
#ifdef DEBUG_PTS
pr_info("pts missed %ld, pts hit %ld, duration %d\n",
pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
#endif
mem_map_mode = 0;
/* devm_kfree(&pdev->dev, (void *)pbi); */
if (is_rdma_enable())
dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, pbi->rdma_adr, pbi->rdma_phy_adr);
vfree((void *)pbi);
return 0;
}
static struct platform_driver ammvdec_vp9_driver = {
.probe = ammvdec_vp9_probe,
.remove = ammvdec_vp9_remove,
#ifdef CONFIG_PM
.suspend = amhevc_suspend,
.resume = amhevc_resume,
#endif
.driver = {
.name = MULTI_DRIVER_NAME,
}
};
#endif
static struct mconfig vp9_configs[] = {
MC_PU32("bit_depth_luma", &bit_depth_luma),
MC_PU32("bit_depth_chroma", &bit_depth_chroma),
MC_PU32("frame_width", &frame_width),
MC_PU32("frame_height", &frame_height),
MC_PU32("debug", &debug),
MC_PU32("radr", &radr),
MC_PU32("rval", &rval),
MC_PU32("pop_shorts", &pop_shorts),
MC_PU32("dbg_cmd", &dbg_cmd),
MC_PU32("dbg_skip_decode_index", &dbg_skip_decode_index),
MC_PU32("endian", &endian),
MC_PU32("step", &step),
MC_PU32("udebug_flag", &udebug_flag),
MC_PU32("decode_pic_begin", &decode_pic_begin),
MC_PU32("slice_parse_begin", &slice_parse_begin),
MC_PU32("i_only_flag", &i_only_flag),
MC_PU32("error_handle_policy", &error_handle_policy),
MC_PU32("buf_alloc_depth", &buf_alloc_depth),
MC_PU32("buf_alloc_size", &buf_alloc_size),
MC_PU32("buffer_mode", &buffer_mode),
MC_PU32("buffer_mode_dbg", &buffer_mode_dbg),
MC_PU32("max_buf_num", &max_buf_num),
MC_PU32("dynamic_buf_num_margin", &dynamic_buf_num_margin),
MC_PU32("mem_map_mode", &mem_map_mode),
MC_PU32("double_write_mode", &double_write_mode),
MC_PU32("enable_mem_saving", &enable_mem_saving),
MC_PU32("force_w_h", &force_w_h),
MC_PU32("force_fps", &force_fps),
MC_PU32("max_decoding_time", &max_decoding_time),
MC_PU32("on_no_keyframe_skiped", &on_no_keyframe_skiped),
MC_PU32("start_decode_buf_level", &start_decode_buf_level),
MC_PU32("decode_timeout_val", &decode_timeout_val),
MC_PU32("vp9_max_pic_w", &vp9_max_pic_w),
MC_PU32("vp9_max_pic_h", &vp9_max_pic_h),
};
static struct mconfig_node vp9_node;
static int __init amvdec_vp9_driver_init_module(void)
{
struct BuffInfo_s *p_buf_info;
if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) {
if (vdec_is_support_4k()) {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
p_buf_info = &amvvp9_workbuff_spec[2];
else
p_buf_info = &amvvp9_workbuff_spec[1];
} else
p_buf_info = &amvvp9_workbuff_spec[0];
} else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb()
if (vdec_is_support_4k())
p_buf_info = &amvvp9_workbuff_spec[5];
else
p_buf_info = &amvvp9_workbuff_spec[4];
}
init_buff_spec(NULL, p_buf_info);
work_buf_size =
(p_buf_info->end_adr - p_buf_info->start_adr
+ 0xffff) & (~0xffff);
pr_debug("amvdec_vp9 module init\n");
error_handle_policy = 0;
#ifdef ERROR_HANDLE_DEBUG
dbg_nal_skip_flag = 0;
dbg_nal_skip_count = 0;
#endif
udebug_flag = 0;
decode_pic_begin = 0;
slice_parse_begin = 0;
step = 0;
buf_alloc_size = 0;
#ifdef MULTI_INSTANCE_SUPPORT
if (platform_driver_register(&ammvdec_vp9_driver))
pr_err("failed to register ammvdec_vp9 driver\n");
#endif
if (platform_driver_register(&amvdec_vp9_driver)) {
pr_err("failed to register amvdec_vp9 driver\n");
return -ENODEV;
}
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL ||
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) {
amvdec_vp9_profile.name = "vp9_unsupport";
} else if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) {
amvdec_vp9_profile.profile =
"8k, 10bit, dwrite, compressed, fence, v4l-uvm";
} else {
if (vdec_is_support_4k())
amvdec_vp9_profile.profile =
"4k, 10bit, dwrite, compressed, fence, v4l-uvm";
else
amvdec_vp9_profile.profile =
"10bit, dwrite, compressed, fence, v4l-uvm";
}
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
max_buf_num = MAX_BUF_NUM_LESS;
vcodec_profile_register(&amvdec_vp9_profile);
amvdec_vp9_profile_mult = amvdec_vp9_profile;
amvdec_vp9_profile_mult.name = "mvp9";
vcodec_profile_register(&amvdec_vp9_profile_mult);
INIT_REG_NODE_CONFIGS("media.decoder", &vp9_node,
"vp9", vp9_configs, CONFIG_FOR_RW);
vcodec_feature_register(VFORMAT_VP9, 0);
return 0;
}
static void __exit amvdec_vp9_driver_remove_module(void)
{
pr_debug("amvdec_vp9 module remove.\n");
#ifdef MULTI_INSTANCE_SUPPORT
platform_driver_unregister(&ammvdec_vp9_driver);
#endif
platform_driver_unregister(&amvdec_vp9_driver);
}
/****************************************/
module_param(bit_depth_luma, uint, 0664);
MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_vp9 bit_depth_luma\n");
module_param(bit_depth_chroma, uint, 0664);
MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_vp9 bit_depth_chroma\n");
module_param(frame_width, uint, 0664);
MODULE_PARM_DESC(frame_width, "\n amvdec_vp9 frame_width\n");
module_param(frame_height, uint, 0664);
MODULE_PARM_DESC(frame_height, "\n amvdec_vp9 frame_height\n");
module_param(debug, uint, 0664);
MODULE_PARM_DESC(debug, "\n amvdec_vp9 debug\n");
module_param(radr, uint, 0664);
MODULE_PARM_DESC(radr, "\n radr\n");
module_param(rval, uint, 0664);
MODULE_PARM_DESC(rval, "\n rval\n");
module_param(pop_shorts, uint, 0664);
MODULE_PARM_DESC(pop_shorts, "\n rval\n");
module_param(dbg_cmd, uint, 0664);
MODULE_PARM_DESC(dbg_cmd, "\n dbg_cmd\n");
module_param(dbg_skip_decode_index, uint, 0664);
MODULE_PARM_DESC(dbg_skip_decode_index, "\n dbg_skip_decode_index\n");
module_param(endian, uint, 0664);
MODULE_PARM_DESC(endian, "\n rval\n");
module_param(step, uint, 0664);
MODULE_PARM_DESC(step, "\n amvdec_vp9 step\n");
module_param(decode_pic_begin, uint, 0664);
MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_vp9 decode_pic_begin\n");
module_param(slice_parse_begin, uint, 0664);
MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_vp9 slice_parse_begin\n");
module_param(i_only_flag, uint, 0664);
MODULE_PARM_DESC(i_only_flag, "\n amvdec_vp9 i_only_flag\n");
module_param(low_latency_flag, uint, 0664);
MODULE_PARM_DESC(low_latency_flag, "\n amvdec_vp9 low_latency_flag\n");
module_param(no_head, uint, 0664);
MODULE_PARM_DESC(no_head, "\n amvdec_vp9 no_head\n");
module_param(error_handle_policy, uint, 0664);
MODULE_PARM_DESC(error_handle_policy, "\n amvdec_vp9 error_handle_policy\n");
module_param(buf_alloc_depth, uint, 0664);
MODULE_PARM_DESC(buf_alloc_depth, "\n buf_alloc_depth\n");
module_param(buf_alloc_size, uint, 0664);
MODULE_PARM_DESC(buf_alloc_size, "\n buf_alloc_size\n");
module_param(buffer_mode, uint, 0664);
MODULE_PARM_DESC(buffer_mode, "\n buffer_mode\n");
module_param(buffer_mode_dbg, uint, 0664);
MODULE_PARM_DESC(buffer_mode_dbg, "\n buffer_mode_dbg\n");
/*USE_BUF_BLOCK*/
module_param(max_buf_num, uint, 0664);
MODULE_PARM_DESC(max_buf_num, "\n max_buf_num\n");
module_param(dynamic_buf_num_margin, uint, 0664);
MODULE_PARM_DESC(dynamic_buf_num_margin, "\n dynamic_buf_num_margin\n");
module_param(mv_buf_margin, uint, 0664);
MODULE_PARM_DESC(mv_buf_margin, "\n mv_buf_margin\n");
module_param(mv_buf_dynamic_alloc, uint, 0664);
MODULE_PARM_DESC(mv_buf_dynamic_alloc, "\n mv_buf_dynamic_alloc\n");
module_param(run_ready_min_buf_num, uint, 0664);
MODULE_PARM_DESC(run_ready_min_buf_num, "\n run_ready_min_buf_num\n");
/**/
module_param(mem_map_mode, uint, 0664);
MODULE_PARM_DESC(mem_map_mode, "\n mem_map_mode\n");
#ifdef SUPPORT_10BIT
module_param(double_write_mode, uint, 0664);
MODULE_PARM_DESC(double_write_mode, "\n double_write_mode\n");
module_param(enable_mem_saving, uint, 0664);
MODULE_PARM_DESC(enable_mem_saving, "\n enable_mem_saving\n");
module_param(force_w_h, uint, 0664);
MODULE_PARM_DESC(force_w_h, "\n force_w_h\n");
#endif
module_param(force_fps, uint, 0664);
MODULE_PARM_DESC(force_fps, "\n force_fps\n");
module_param(max_decoding_time, uint, 0664);
MODULE_PARM_DESC(max_decoding_time, "\n max_decoding_time\n");
module_param(on_no_keyframe_skiped, uint, 0664);
MODULE_PARM_DESC(on_no_keyframe_skiped, "\n on_no_keyframe_skiped\n");
module_param(mcrcc_cache_alg_flag, uint, 0664);
MODULE_PARM_DESC(mcrcc_cache_alg_flag, "\n mcrcc_cache_alg_flag\n");
#ifdef MULTI_INSTANCE_SUPPORT
module_param(start_decode_buf_level, int, 0664);
MODULE_PARM_DESC(start_decode_buf_level,
"\n vp9 start_decode_buf_level\n");
module_param(decode_timeout_val, uint, 0664);
MODULE_PARM_DESC(decode_timeout_val,
"\n vp9 decode_timeout_val\n");
module_param(vp9_max_pic_w, uint, 0664);
MODULE_PARM_DESC(vp9_max_pic_w, "\n vp9_max_pic_w\n");
module_param(vp9_max_pic_h, uint, 0664);
MODULE_PARM_DESC(vp9_max_pic_h, "\n vp9_max_pic_h\n");
module_param_array(decode_frame_count, uint,
&max_decode_instance_num, 0664);
module_param_array(display_frame_count, uint,
&max_decode_instance_num, 0664);
module_param_array(max_process_time, uint,
&max_decode_instance_num, 0664);
module_param_array(run_count, uint,
&max_decode_instance_num, 0664);
module_param_array(input_empty, uint,
&max_decode_instance_num, 0664);
module_param_array(not_run_ready, uint,
&max_decode_instance_num, 0664);
#endif
#ifdef SUPPORT_FB_DECODING
module_param_array(not_run2_ready, uint,
&max_decode_instance_num, 0664);
module_param_array(run2_count, uint,
&max_decode_instance_num, 0664);
module_param(stage_buf_num, uint, 0664);
MODULE_PARM_DESC(stage_buf_num, "\n amvdec_h265 stage_buf_num\n");
#endif
module_param(force_bufspec, uint, 0664);
MODULE_PARM_DESC(force_bufspec, "\n amvdec_h265 force_bufspec\n");
module_param(udebug_flag, uint, 0664);
MODULE_PARM_DESC(udebug_flag, "\n amvdec_h265 udebug_flag\n");
module_param(udebug_pause_pos, uint, 0664);
MODULE_PARM_DESC(udebug_pause_pos, "\n udebug_pause_pos\n");
module_param(udebug_pause_val, uint, 0664);
MODULE_PARM_DESC(udebug_pause_val, "\n udebug_pause_val\n");
module_param(udebug_pause_decode_idx, uint, 0664);
MODULE_PARM_DESC(udebug_pause_decode_idx, "\n udebug_pause_decode_idx\n");
module_param(without_display_mode, uint, 0664);
MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n");
module_param(force_config_fence, uint, 0664);
MODULE_PARM_DESC(force_config_fence, "\n force enable fence\n");
module_param(force_pts_unstable, uint, 0664);
MODULE_PARM_DESC(force_pts_unstable, "\n force_pts_unstable\n");
module_param(v4l_bitstream_id_enable, uint, 0664);
MODULE_PARM_DESC(v4l_bitstream_id_enable, "\n v4l_bitstream_id_enable\n");
module_init(amvdec_vp9_driver_init_module);
module_exit(amvdec_vp9_driver_remove_module);
MODULE_DESCRIPTION("AMLOGIC vp9 Video Decoder Driver");
MODULE_LICENSE("GPL");