| /* |
| * drivers/amlogic/amports/vav1.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/sched/clock.h> |
| #include <linux/sched.h> |
| #include <linux/sched/rt.h> |
| #include <uapi/linux/sched/types.h> |
| #include <linux/signal.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 "../../../stream_input/amports/amports_priv.h" |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include "../../decoder/utils/decoder_mmu_box.h" |
| #include "../../decoder/utils/decoder_bmmu_box.h" |
| #include <linux/crc32.h> |
| |
| #define MEM_NAME "codec_av1" |
| /* #include <mach/am_regs.h> */ |
| #include <linux/amlogic/media/utils/vdec_reg.h> |
| #include "../../decoder/utils/vdec.h" |
| #include "../../decoder/utils/amvdec.h" |
| #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC |
| #include "../../decoder/utils/vdec_profile.h" |
| #endif |
| |
| #include <linux/amlogic/media/video_sink/video.h> |
| #include <linux/amlogic/media/codec_mm/configs.h> |
| #include "../../decoder/utils/config_parser.h" |
| #include "../../decoder/utils/firmware.h" |
| #include "../../../common/chips/decoder_cpu_ver_info.h" |
| #include "../../../amvdec_ports/vdec_drv_base.h" |
| |
| //#define DEBUG_UCODE_LOG |
| #define DEBUG_CMD |
| #define DEBUG_CRC_ERROR |
| |
| #define SUPPORT_V4L2 |
| //#define DEBUG_USE_VP9_DEVICE_NAME |
| //#define BUFMGR_ONLY_OLD_CHIP |
| |
| #ifdef SUPPORT_V4L2 |
| #include "../../decoder/utils/vdec_v4l2_buffer_ops.h" |
| #include <media/v4l2-mem2mem.h> |
| #endif |
| #include "../../../amvdec_ports/utils/common.h" |
| #include "../../decoder/utils/vdec_feature.h" |
| #include "../../decoder/utils/vdec_ge2d_utils.h" |
| |
| #define AML |
| #include "aom_av1_define.h" |
| #include "av1_global.h" |
| |
| #define DUMP_FILMGRAIN |
| #define MIX_STREAM_SUPPORT |
| //#define MV_USE_FIXED_BUF |
| //#define USE_SPEC_BUF_FOR_MMU_HEAD |
| |
| #define AOM_AV1_DBLK_INIT |
| #define AOM_AV1_UPSCALE_INIT |
| |
| #define USE_DEC_PIC_END |
| |
| #define SANITY_CHECK |
| #define CO_MV_COMPRESS |
| |
| #include "vav1.h" |
| |
| #define FGS_TABLE_SIZE (512 * 128 / 8) |
| |
| #define AV1_GMC_PARAM_BUFF_ADDR 0x316d |
| #define HEVCD_MPP_DECOMP_AXIURG_CTL 0x34c7 |
| #define HEVC_FGS_IDX 0x3660 |
| #define HEVC_FGS_DATA 0x3661 |
| #define HEVC_FGS_CTRL 0x3662 |
| #define AV1_SKIP_MODE_INFO 0x316c |
| #define AV1_QUANT_WR 0x3146 |
| #define AV1_SEG_W_ADDR 0x3165 |
| #define AV1_SEG_R_ADDR 0x3166 |
| #define AV1_REF_SEG_INFO 0x3171 |
| #define HEVC_ASSIST_PIC_SIZE_FB_READ 0x300d |
| #define PARSER_REF_SCALE_ENBL 0x316b |
| #define HEVC_MPRED_MV_RPTR_1 0x3263 |
| #define HEVC_MPRED_MV_RPTR_2 0x3264 |
| #define HEVC_SAO_CTRL9 0x362d |
| #define HEVC_FGS_TABLE_START 0x3666 |
| #define HEVC_FGS_TABLE_LENGTH 0x3667 |
| #define HEVC_DBLK_CDEF0 0x3515 |
| #define HEVC_DBLK_CDEF1 0x3516 |
| #define HEVC_DBLK_UPS1 0x351c |
| #define HEVC_DBLK_UPS2 0x351d |
| #define HEVC_DBLK_UPS3 0x351e |
| #define HEVC_DBLK_UPS4 0x351f |
| #define HEVC_DBLK_UPS5 0x3520 |
| #define AV1_UPSCALE_X0_QN 0x316e |
| #define AV1_UPSCALE_STEP_QN 0x316f |
| #define HEVC_DBLK_DBLK0 0x3523 |
| #define HEVC_DBLK_DBLK1 0x3524 |
| #define HEVC_DBLK_DBLK2 0x3525 |
| |
| #define HW_MASK_FRONT 0x1 |
| #define HW_MASK_BACK 0x2 |
| |
| #define AV1D_MPP_REFINFO_TBL_ACCCONFIG 0x3442 |
| #define AV1D_MPP_REFINFO_DATA 0x3443 |
| #define AV1D_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_MV_INFO 0x310d |
| #define HEVC_QP_INFO 0x3137 |
| #define HEVC_SKIP_INFO 0x3136 |
| |
| #define HEVC_CM_BODY_LENGTH2 0x3663 |
| #define HEVC_CM_HEADER_OFFSET2 0x3664 |
| #define HEVC_CM_HEADER_LENGTH2 0x3665 |
| |
| #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 |
| |
| #ifdef BUFMGR_ONLY_OLD_CHIP |
| #undef AV1_SKIP_MODE_INFO |
| #define AV1_SKIP_MODE_INFO HEVC_ASSIST_SCRATCH_B |
| #endif |
| |
| |
| #define AOM_AV1_DEC_IDLE 0 |
| #define AOM_AV1_DEC_FRAME_HEADER 1 |
| #define AOM_AV1_DEC_TILE_END 2 |
| #define AOM_AV1_DEC_TG_END 3 |
| #define AOM_AV1_DEC_LCU_END 4 |
| #define AOM_AV1_DECODE_SLICE 5 |
| #define AOM_AV1_SEARCH_HEAD 6 |
| #define AOM_AV1_DUMP_LMEM 7 |
| #define AOM_AV1_FGS_PARAM_CONT 8 |
| #define AOM_AV1_DISCARD_NAL 0x10 |
| #define AOM_AV1_RESULT_NEED_MORE_BUFFER 0x11 |
| #define DEC_RESULT_UNFINISH 0x12 |
| |
| /*status*/ |
| #define AOM_AV1_DEC_PIC_END 0xe0 |
| /*AOM_AV1_FGS_PARA: |
| Bit[11] - 0 Read, 1 - Write |
| Bit[10:8] - film_grain_params_ref_idx, For Write request |
| */ |
| #define AOM_AV1_FGS_PARAM 0xe1 |
| #define AOM_AV1_DEC_PIC_END_PRE 0xe2 |
| #define AOM_AV1_HEAD_PARSER_DONE 0xf0 |
| #define AOM_AV1_HEAD_SEARCH_DONE 0xf1 |
| #define AOM_AV1_SEQ_HEAD_PARSER_DONE 0xf2 |
| #define AOM_AV1_FRAME_HEAD_PARSER_DONE 0xf3 |
| #define AOM_AV1_FRAME_PARSER_DONE 0xf4 |
| #define AOM_AV1_REDUNDANT_FRAME_HEAD_PARSER_DONE 0xf5 |
| #define HEVC_ACTION_DONE 0xff |
| |
| #define AOM_DECODE_BUFEMPTY 0x20 |
| #define AOM_DECODE_TIMEOUT 0x21 |
| #define AOM_SEARCH_BUFEMPTY 0x22 |
| #define AOM_DECODE_OVER_SIZE 0x23 |
| #define AOM_EOS 0x24 |
| #define AOM_NAL_DECODE_DONE 0x25 |
| |
| #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 AV1_TRIGGER_FRAME_DONE 0x100 |
| #define AV1_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 |
| |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| #define MULTI_DRIVER_NAME "ammvdec_vp9_v4l" |
| #else |
| #define MULTI_DRIVER_NAME "ammvdec_av1_v4l" |
| #endif |
| |
| #define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf)) |
| #ifdef DEBUG_UCODE_LOG |
| static u32 prefix_aux_buf_size; |
| static u32 suffix_aux_buf_size; |
| #else |
| static u32 prefix_aux_buf_size = (16 * 1024); |
| static u32 suffix_aux_buf_size; |
| #endif |
| #if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| //#define UCODE_LOG_BUF_SIZE (16 * 1024) |
| #define UCODE_LOG_BUF_SIZE (1024 * 1024) |
| #endif |
| 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]; |
| #ifdef AOM_AV1_MMU_DW |
| static unsigned int dw_mmu_enable[MAX_DECODE_INSTANCE_NUM]; |
| #endif |
| |
| static u32 decode_timeout_val = 600; |
| static u32 enable_single_slice = 1; |
| static int start_decode_buf_level = 0x8000; |
| //static u32 work_buf_size; |
| static u32 force_pts_unstable; |
| static u32 mv_buf_margin = REF_FRAMES; |
| static u32 mv_buf_dynamic_alloc; |
| static u32 force_max_one_mv_buffer_size; |
| |
| /* 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; |
| * 5, (1/2):(1/2) ratio, with both compressed frame included |
| * 8, (1/8):(1/8) ratio; |
| * 0x10, double write only |
| * 0x20, mmu double write |
| * 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; |
| |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| #define DRIVER_NAME "amvdec_vp9_v4l" |
| #define MODULE_NAME "amvdec_vp9_v4l" |
| #define DRIVER_HEADER_NAME "amvdec_vp9_header" |
| #else |
| #define DRIVER_NAME "amvdec_av1_v4l" |
| #define DRIVER_HEADER_NAME "amvdec_av1_header" |
| #endif |
| |
| #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) |
| #define PTS2DUR(x) ((x)*96/90) |
| #define PTS2DUR_u64(x) (div_u64((x)*96, 90)) |
| |
| struct AV1HW_s; |
| static int vav1_vf_states(struct vframe_states *states, void *); |
| static struct vframe_s *vav1_vf_peek(void *); |
| static struct vframe_s *vav1_vf_get(void *); |
| static void vav1_vf_put(struct vframe_s *, void *); |
| static int vav1_event_cb(int type, void *data, void *private_data); |
| #ifdef MULTI_INSTANCE_SUPPORT |
| static s32 vav1_init(struct vdec_s *vdec); |
| #else |
| static s32 vav1_init(struct AV1HW_s *hw); |
| #endif |
| static void vav1_prot_init(struct AV1HW_s *hw, u32 mask); |
| static int vav1_local_init(struct AV1HW_s *hw, bool reset_flag); |
| static void vav1_put_timer_func(struct timer_list *timer); |
| static void dump_data(struct AV1HW_s *hw, int size); |
| static unsigned int get_data_check_sum |
| (struct AV1HW_s *hw, int size); |
| static void dump_pic_list(struct AV1HW_s *hw); |
| static int vav1_mmu_map_alloc(struct AV1HW_s *hw); |
| static void vav1_mmu_map_free(struct AV1HW_s *hw); |
| static int av1_alloc_mmu( |
| struct AV1HW_s *hw, |
| int cur_buf_idx, |
| int pic_width, |
| int pic_height, |
| unsigned short bit_depth, |
| unsigned int *mmu_index_adr); |
| |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| static const char vav1_dec_id[] = "vvp9-dev"; |
| |
| #define PROVIDER_NAME "decoder.vp9" |
| #define MULTI_INSTANCE_PROVIDER_NAME "vdec.vp9" |
| #else |
| static const char vav1_dec_id[] = "vav1-dev"; |
| |
| #define PROVIDER_NAME "decoder.av1" |
| #define MULTI_INSTANCE_PROVIDER_NAME "vdec.av1" |
| #endif |
| #define DV_PROVIDER_NAME "dvbldec" |
| |
| static const struct vframe_operations_s vav1_vf_provider = { |
| .peek = vav1_vf_peek, |
| .get = vav1_vf_get, |
| .put = vav1_vf_put, |
| .event_cb = vav1_event_cb, |
| .vf_states = vav1_vf_states, |
| }; |
| |
| static struct vframe_provider_s vav1_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; |
| static u32 without_display_mode; |
| static u32 v4l_bitstream_id_enable = 1; |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| static u32 force_dv_enable; |
| #endif |
| |
| #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 |
| |
| |
| /*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; |
| ulong header_dw_addr; |
| } /*BUF_t */; |
| |
| struct MVBUF_s { |
| unsigned long start_adr; |
| unsigned int size; |
| int used_flag; |
| } /*MVBUF_t */; |
| |
| /*#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 CONFIG_HEVC_CLK_FORCED_ON*/ |
| /*#define ENABLE_SWAP_TEST*/ |
| #ifndef BUFMGR_ONLY_OLD_CHIP |
| #define MCRCC_ENABLE |
| #endif |
| |
| #ifdef AV1_10B_NV21 |
| #else |
| #define LOSLESS_COMPRESS_MODE |
| #endif |
| |
| static u32 get_picture_qos; |
| |
| static u32 disable_repeat; |
| |
| static u32 debug; |
| static u32 disable_fg; |
| |
| static bool is_reset; |
| /*for debug*/ |
| static u32 force_bufspec; |
| /* |
| 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; |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| static u32 dv_toggle_prov_name; |
| #endif |
| |
| static u32 run_ready_min_buf_num = 2; |
| #ifdef DEBUG_CRC_ERROR |
| /* |
| bit[4] fill zero in header before starting |
| bit[5] dump mmu header always |
| |
| bit[6] dump mv buffer always |
| |
| bit[8] delay after decoding |
| bit[31~16] delayed mseconds |
| */ |
| static u32 crc_debug_flag; |
| #endif |
| #ifdef DEBUG_CMD |
| static u32 header_dump_size = 0x10000; |
| static u32 debug_cmd_wait_count; |
| static u32 debug_cmd_wait_type; |
| #endif |
| #define DEBUG_REG |
| #ifdef DEBUG_REG |
| void AV1_WRITE_VREG_DBG2(unsigned int adr, unsigned int val, int line) |
| { |
| if (debug & AV1_DEBUG_REG) |
| pr_info("%d:%s(%x, %x)\n", line, __func__, adr, val); |
| if (adr != 0) |
| WRITE_VREG(adr, val); |
| } |
| |
| #undef WRITE_VREG |
| #define WRITE_VREG(a,v) AV1_WRITE_VREG_DBG2(a,v,__LINE__) |
| #endif |
| |
| #define FRAME_CNT_WINDOW_SIZE 59 |
| #define RATE_CORRECTION_THRESHOLD 5 |
| /************************************************** |
| |
| AV1 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 MAX_ONE_MV_BUFFER_SIZE 0x260000 |
| //#define MAX_ONE_MV_BUFFER_SIZE 0x130000 |
| |
| #define MAX_ONE_MV_BUFFER_SIZE_1080P 0x20400 |
| #define MAX_ONE_MV_BUFFER_SIZE_4K 0x91400 |
| #define MAX_ONE_MV_BUFFER_SIZE_8K 0x244800 |
| /*to support tm2revb and sc2*/ |
| #define MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB 0x26400 |
| #define MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB 0xac400 |
| #define MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB 0x2b0800 |
| |
| static int vav1_mmu_compress_header_size(struct AV1HW_s *hw); |
| |
| //#define MMU_COMPRESS_HEADER_SIZE 0x48000 |
| //#define MMU_COMPRESS_HEADER_SIZE_DW MMU_COMPRESS_HEADER_SIZE |
| //#define MMU_COMPRESS_8K_HEADER_SIZE (0x48000*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.*/ |
| |
| |
| /*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 REF_FRAMES_4K (6) |
| #define REF_FRAMES_4K REF_FRAMES |
| |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| #define HEADER_FRAME_BUFFERS (0) |
| #elif (defined AOM_AV1_MMU_DW) |
| #define HEADER_FRAME_BUFFERS (2 * FRAME_BUFFERS) |
| #else |
| #define HEADER_FRAME_BUFFERS (FRAME_BUFFERS) |
| #endif |
| #define MAX_BUF_NUM (FRAME_BUFFERS) |
| #define MV_BUFFER_NUM FRAME_BUFFERS |
| |
| //#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 |
| #ifdef AOM_AV1_MMU_DW |
| #define DW_HEADER_BUFFER_IDX(n) (HEADER_BUFFER_IDX(HEADER_FRAME_BUFFERS/2) + n) |
| #endif |
| |
| |
| static void set_canvas(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic_config); |
| |
| static void fill_frame_info(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *frame, |
| unsigned int framesize, |
| unsigned int pts); |
| |
| |
| static int compute_losless_comp_body_size(int width, int height, |
| uint8_t is_bit_depth_10); |
| |
| void clear_frame_buf_ref_count(AV1Decoder *pbi); |
| |
| #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_DISCARD_DATA 11 |
| |
| #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 av1_work(struct work_struct *work); |
| #endif |
| |
| #ifdef DUMP_FILMGRAIN |
| u32 fg_dump_index = 0xff; |
| #endif |
| |
| #ifdef AOM_AV1_DBLK_INIT |
| struct loop_filter_info_n_s; |
| struct loopfilter; |
| struct segmentation_lf; |
| #endif |
| |
| struct vav1_assit_task { |
| bool use_sfgs; |
| bool running; |
| struct mutex assit_mutex; |
| struct semaphore sem; |
| struct task_struct *task; |
| void *private; |
| }; |
| |
| struct AV1HW_s { |
| AV1Decoder *pbi; |
| union param_u aom_param; |
| unsigned char frame_decoded; |
| unsigned char one_compressed_data_done; |
| unsigned char new_compressed_data; |
| #if 1 |
| /*def CHECK_OBU_REDUNDANT_FRAME_HEADER*/ |
| int obu_frame_frame_head_come_after_tile; |
| #endif |
| 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 set_clk_work; |
| u32 start_shift_bytes; |
| u32 data_size; |
| |
| 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; |
| |
| 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 config_next_ref_info_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 vav1_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; |
| #ifdef DUMP_FILMGRAIN |
| dma_addr_t fg_phy_addr; |
| unsigned char *fg_ptr; |
| void *fg_addr; |
| #endif |
| u32 fgs_valid; |
| |
| u8 aux_data_dirty; |
| u32 prefix_aux_size; |
| u32 suffix_aux_size; |
| void *aux_addr; |
| dma_addr_t aux_phy_addr; |
| char *dv_data_buf; |
| int dv_data_size; |
| #if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| void *ucode_log_addr; |
| dma_addr_t ucode_log_phy_addr; |
| #endif |
| |
| 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 AOM_AV1_MMU_DW |
| void *dw_frame_mmu_map_addr; |
| dma_addr_t dw_frame_mmu_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; |
| u32 mv_buf_margin; |
| 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]; |
| atomic_t vf_pre_count; |
| atomic_t vf_get_count; |
| atomic_t vf_put_count; |
| int buf_num; |
| int pic_num; |
| int lcu_size_log2; |
| unsigned int losless_comp_body_size; |
| |
| u32 video_signal_type; |
| |
| u32 pts_unstable; |
| bool av1_first_pts_ready; |
| bool dur_recalc_flag; |
| u8 first_pts_index; |
| u32 frame_mode_pts_save[FRAME_BUFFERS]; |
| u64 frame_mode_pts64_save[FRAME_BUFFERS]; |
| |
| int last_pts; |
| u64 last_pts_us64; |
| u64 shift_byte_count; |
| |
| 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 AV1_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 av1_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 current_lcu_size; |
| |
| int slice_type; |
| |
| int skip_flag; |
| int decode_idx; |
| int result_done_count; |
| uint8_t has_keyframe; |
| uint8_t has_sequence; |
| 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*/ |
| |
| /**/ |
| 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 AOM_AV1_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; |
| int buffer_spec_index; |
| int32_t max_one_mv_buffer_size; |
| |
| 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; |
| |
| #ifdef AOM_AV1_DBLK_INIT |
| /* |
| * malloc may not work in real chip, please allocate memory for the following structures |
| */ |
| struct loop_filter_info_n_s *lfi; |
| struct loopfilter *lf; |
| struct segmentation_lf *seg_4lf; |
| #endif |
| u32 mem_map_mode; |
| u32 dynamic_buf_num_margin; |
| struct vframe_s vframe_dummy; |
| u32 res_ch_flag; |
| int buffer_wrap[FRAME_BUFFERS]; |
| int sidebind_type; |
| int sidebind_channel_id; |
| u32 cur_obu_type; |
| u32 multi_frame_cnt; |
| u32 endian; |
| u32 run_ready_min_buf_num; |
| int one_package_frame_cnt; |
| ulong fb_token; |
| bool wait_more_buf; |
| dma_addr_t rdma_phy_adr; |
| unsigned *rdma_adr; |
| u32 aux_data_size; |
| bool no_need_aux_data; |
| struct trace_decoder_name trace; |
| struct vav1_assit_task assit_task; |
| int film_grain_present; |
| ulong fg_table_handle; |
| struct vdec_ge2d *ge2d; |
| u32 data_offset; |
| u32 data_invalid; |
| u32 consume_byte; |
| }; |
| static void av1_dump_state(struct vdec_s *vdec); |
| |
| int av1_print(struct AV1HW_s *hw, |
| int flag, const char *fmt, ...) |
| { |
| #define HEVC_PRINT_BUF 512 |
| unsigned char buf[HEVC_PRINT_BUF]; |
| int len = 0; |
| |
| if (hw == NULL || |
| (flag == 0) || |
| (debug & flag)) { |
| va_list args; |
| |
| va_start(args, fmt); |
| if (hw) |
| len = sprintf(buf, "[%d]", hw->index); |
| vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args); |
| pr_info("%s", buf); |
| va_end(args); |
| } |
| return 0; |
| } |
| |
| unsigned char av1_is_debug(int flag) |
| { |
| if ((flag == 0) || (debug & flag)) |
| return 1; |
| |
| return 0; |
| } |
| |
| int av1_print2(int flag, const char *fmt, ...) |
| { |
| unsigned char buf[HEVC_PRINT_BUF]; |
| int len = 0; |
| |
| if ((flag == 0) || |
| (debug & flag)) { |
| va_list args; |
| |
| va_start(args, fmt); |
| vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args); |
| pr_info("%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 v4l_alloc_and_config_pic(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic); |
| |
| static inline bool close_to(int a, int b, int m) |
| { |
| return (abs(a - b) < m) ? true : false; |
| } |
| |
| #ifdef MULTI_INSTANCE_SUPPORT |
| static int av1_print_cont(struct AV1HW_s *hw, |
| int flag, const char *fmt, ...) |
| { |
| unsigned char buf[HEVC_PRINT_BUF]; |
| int len = 0; |
| |
| if (hw == NULL || |
| (flag == 0) || |
| (debug & flag)) { |
| va_list args; |
| |
| va_start(args, fmt); |
| vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args); |
| pr_info("%s", buf); |
| va_end(args); |
| } |
| return 0; |
| } |
| |
| static void trigger_schedule(struct AV1HW_s *hw) |
| { |
| if (hw->is_used_v4l) { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| |
| if (ctx->param_sets_from_ucode && |
| !hw->v4l_params_parsed) |
| vdec_v4l_write_frame_sync(ctx); |
| } |
| |
| ATRACE_COUNTER("V_ST_DEC-chunk_size", 0); |
| |
| if (hw->vdec_cb) |
| hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); |
| } |
| |
| static void reset_process_time(struct AV1HW_s *hw) |
| { |
| if (hw->start_process_time) { |
| unsigned process_time = |
| 1000 * (jiffies - hw->start_process_time) / HZ; |
| hw->start_process_time = 0; |
| if (process_time > max_process_time[hw->index]) |
| max_process_time[hw->index] = process_time; |
| } |
| } |
| |
| static void start_process_time(struct AV1HW_s *hw) |
| { |
| hw->start_process_time = jiffies; |
| hw->decode_timeout_count = 0; |
| hw->last_lcu_idx = 0; |
| } |
| |
| static void timeout_process(struct AV1HW_s *hw) |
| { |
| reset_process_time(hw); |
| if (hw->process_busy) { |
| av1_print(hw, |
| 0, "%s decoder timeout but process_busy\n", __func__); |
| if (debug) |
| av1_print(hw, 0, "debug disable timeout notify\n"); |
| return; |
| } |
| hw->timeout_num++; |
| amhevc_stop(); |
| |
| av1_print(hw, |
| 0, "%s decoder timeout\n", __func__); |
| |
| hw->dec_result = DEC_RESULT_DONE; |
| vdec_schedule_work(&hw->work); |
| } |
| |
| static u32 get_valid_double_write_mode(struct AV1HW_s *hw) |
| { |
| u32 dw = ((double_write_mode & 0x80000000) == 0) ? |
| hw->double_write_mode : |
| (double_write_mode & 0x7fffffff); |
| if ((dw & 0x20) && |
| ((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 AV1HW_s *hw) |
| { |
| u32 valid_dw_mode = get_valid_double_write_mode(hw); |
| u32 dw; |
| int w, h; |
| struct AV1_Common_s *cm = &hw->common; |
| struct PIC_BUFFER_CONFIG_s *cur_pic_config; |
| |
| if (hw->is_used_v4l) { |
| unsigned int out; |
| |
| vdec_v4l_get_dw_mode(hw->v4l2_ctx, &out); |
| dw = out; |
| return dw; |
| } |
| |
| 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: |
| dw = valid_dw_mode; |
| break; |
| } |
| return dw; |
| } |
| |
| /* for double write buf alloc */ |
| static int get_double_write_mode_init(struct AV1HW_s *hw) |
| { |
| u32 valid_dw_mode = get_valid_double_write_mode(hw); |
| u32 dw; |
| int w = hw->init_pic_w; |
| int h = hw->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 FILM_GRAIN_TASK |
| #ifdef FILM_GRAIN_TASK |
| |
| static u32 use_sfgs; |
| module_param(use_sfgs, uint, 0664); |
| |
| void film_grain_task_wakeup(struct AV1HW_s *hw) |
| { |
| u32 fg_reg0, fg_reg1, num_y_points, num_cb_points, num_cr_points; |
| struct AV1_Common_s *cm = &hw->common; |
| |
| if (!hw->assit_task.use_sfgs || hw->eos) |
| return; |
| |
| fg_reg0 = cm->cur_frame->film_grain_reg[0]; |
| fg_reg1 = cm->cur_frame->film_grain_reg[1]; |
| num_y_points = fg_reg1 & 0xf; |
| num_cr_points = (fg_reg1 >> 8) & 0xf; |
| num_cb_points = (fg_reg1 >> 4) & 0xf; |
| if ((num_y_points > 0) || |
| ((num_cb_points > 0) | ((fg_reg0 >> 17) & 0x1)) || |
| ((num_cr_points > 0) | ((fg_reg0 >> 17) & 0x1))) |
| hw->fgs_valid = 1; |
| else |
| hw->fgs_valid = 0; |
| |
| if (cm->cur_frame) { |
| init_waitqueue_head(&cm->cur_frame->wait_sfgs); |
| if (((get_debug_fgs() & DEBUG_FGS_BYPASS) == 0) |
| && hw->fgs_valid) { |
| atomic_set(&cm->cur_frame->fgs_done, 0); |
| hw->assit_task.private = cm->cur_frame; |
| up(&hw->assit_task.sem); |
| } else { |
| atomic_set(&cm->cur_frame->fgs_done, 1); |
| } |
| } |
| } |
| EXPORT_SYMBOL(film_grain_task_wakeup); |
| |
| static int film_grain_task(void *args) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *)args; |
| struct vav1_assit_task *assit = &hw->assit_task; |
| struct sched_param param = {.sched_priority = MAX_RT_PRIO/2}; |
| RefCntBuffer *cur_frame; |
| |
| sched_setscheduler(current, SCHED_FIFO, ¶m); |
| |
| allow_signal(SIGTERM); |
| |
| while (down_interruptible(&assit->sem) == 0) { |
| if (assit->running == false) |
| break; |
| |
| if (assit->private == NULL) |
| continue; |
| |
| mutex_lock(&assit->assit_mutex); |
| cur_frame = (RefCntBuffer *)assit->private; |
| if ((!hw->eos) && (atomic_read(&cur_frame->fgs_done) == 0)) { |
| pic_film_grain_run(hw->frame_count, cur_frame->buf.sfgs_table_ptr, |
| cur_frame->film_grain_ctrl, cur_frame->film_grain_reg); |
| atomic_set(&cur_frame->fgs_done, 1); |
| wake_up_interruptible(&cur_frame->wait_sfgs); |
| assit->private = NULL; |
| vdec_sync_irq(VDEC_IRQ_0); |
| } |
| mutex_unlock(&assit->assit_mutex); |
| } |
| |
| while (!kthread_should_stop()) { |
| usleep_range(500, 1000); |
| } |
| |
| return 0; |
| } |
| |
| static int film_grain_task_create(struct AV1HW_s *hw) |
| { |
| struct vav1_assit_task *assit = &hw->assit_task; |
| |
| mutex_init(&assit->assit_mutex); |
| |
| if ((!vdec_secure(hw_to_vdec(hw)) || (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_SC2)) |
| && !use_sfgs) |
| return 0; |
| |
| assit->use_sfgs = 1; |
| sema_init(&assit->sem, 0); |
| |
| assit->task = kthread_run(film_grain_task, hw, "fgs_task"); |
| if (IS_ERR(assit->task)) { |
| pr_err("%s, creat film grain task thread faild %ld\n", |
| __func__, PTR_ERR(assit->task)); |
| return PTR_ERR(assit->task); |
| } |
| assit->running = true; |
| assit->private = NULL; |
| av1_print(hw, 0, "%s, task %px create sucess\n", __func__, assit->task); |
| |
| return 0; |
| } |
| |
| static void film_grain_task_exit(struct AV1HW_s *hw) |
| { |
| struct vav1_assit_task *assit = &hw->assit_task; |
| |
| if ((!assit->use_sfgs) || (IS_ERR(assit->task))) |
| return; |
| |
| assit->running = false; |
| up(&assit->sem); |
| |
| if (assit->task) { |
| kthread_stop(assit->task); |
| assit->task = NULL; |
| } |
| assit->use_sfgs = 0; |
| av1_print(hw, 0, "%s, task kthread stoped\n", __func__); |
| } |
| #endif |
| |
| |
| /* return page number */ |
| static int av1_mmu_page_num(struct AV1HW_s *hw, |
| 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); |
| |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) |
| max_frame_num = MAX_FRAME_8K_NUM; |
| else |
| max_frame_num = MAX_FRAME_4K_NUM; |
| |
| 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 AV1HW_s *hw, |
| struct vdec_v4l2_buffer *fb) |
| { |
| struct aml_video_dec_buf *aml_fb = NULL; |
| struct aml_vcodec_ctx * v4l2_ctx = hw->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 AV1HW_s *hw, int index) |
| { |
| struct aml_video_dec_buf *aml_fb = NULL; |
| struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; |
| struct vdec_v4l2_buffer *fb = NULL; |
| |
| fb = (struct vdec_v4l2_buffer *) |
| hw->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]; |
| } |
| |
| //#define MAX_4K_NUM 0x1200 |
| int av1_alloc_mmu( |
| struct AV1HW_s *hw, |
| int cur_buf_idx, |
| int pic_width, |
| int pic_height, |
| unsigned short bit_depth, |
| unsigned int *mmu_index_adr) |
| { |
| int ret = 0; |
| int bit_depth_10 = (bit_depth == AOM_BITS_10); |
| int cur_mmu_4k_number; |
| |
| if (get_double_write_mode(hw) & 0x10) |
| return 0; |
| |
| if (bit_depth >= AOM_BITS_12) { |
| hw->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW; |
| pr_err("fatal_error, un support bit depth 12!\n\n"); |
| return -1; |
| } |
| |
| cur_mmu_4k_number = av1_mmu_page_num(hw, |
| pic_width, |
| pic_height, |
| bit_depth_10); |
| if (cur_mmu_4k_number < 0) |
| return -1; |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); |
| if (hw->is_used_v4l) { |
| struct internal_comp_buf *ibuf = |
| index_to_icomp_buf(hw, cur_buf_idx); |
| |
| ret = decoder_mmu_box_alloc_idx( |
| ibuf->mmu_box, |
| ibuf->index, |
| ibuf->frame_buffer_size, |
| mmu_index_adr); |
| } else { |
| ret = decoder_mmu_box_alloc_idx( |
| hw->mmu_box, |
| cur_buf_idx, |
| cur_mmu_4k_number, |
| mmu_index_adr); |
| } |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); |
| return ret; |
| } |
| |
| #ifdef AOM_AV1_MMU_DW |
| static int compute_losless_comp_body_size_dw(int width, int height, |
| uint8_t is_bit_depth_10); |
| |
| int av1_alloc_mmu_dw( |
| struct AV1HW_s *hw, |
| int cur_buf_idx, |
| int pic_width, |
| int pic_height, |
| unsigned short bit_depth, |
| unsigned int *mmu_index_adr) |
| { |
| int ret = 0; |
| int bit_depth_10 = (bit_depth == AOM_BITS_10); |
| int picture_size; |
| int cur_mmu_4k_number, max_frame_num; |
| |
| if (get_double_write_mode(hw) & 0x10) |
| return 0; |
| if (bit_depth >= AOM_BITS_12) { |
| hw->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW; |
| pr_err("fatal_error, un support bit depth 12!\n\n"); |
| return -1; |
| } |
| picture_size = compute_losless_comp_body_size_dw(pic_width, pic_height, |
| bit_depth_10); |
| cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12); |
| |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) |
| max_frame_num = MAX_FRAME_8K_NUM; |
| else |
| max_frame_num = MAX_FRAME_4K_NUM; |
| |
| 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, pic_width, pic_height); |
| return -1; |
| } |
| if (hw->is_used_v4l) { |
| struct internal_comp_buf *ibuf = |
| index_to_icomp_buf(hw, cur_buf_idx); |
| |
| ret = decoder_mmu_box_alloc_idx( |
| ibuf->mmu_box_dw, |
| ibuf->index, |
| ibuf->frame_buffer_size, |
| mmu_index_adr); |
| } else { |
| ret = decoder_mmu_box_alloc_idx( |
| hw->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 AV1HW_s *hw) |
| { |
| int i; |
| for (i = 0; i < MV_BUFFER_NUM; i++) { |
| if (hw->m_mv_BUF[i].start_adr) { |
| if (debug) |
| pr_info( |
| "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n", |
| i, hw->m_mv_BUF[i].start_adr, |
| hw->m_mv_BUF[i].size, |
| hw->m_mv_BUF[i].used_flag); |
| decoder_bmmu_box_free_idx( |
| hw->bmmu_box, |
| MV_BUFFER_IDX(i)); |
| hw->m_mv_BUF[i].start_adr = 0; |
| hw->m_mv_BUF[i].size = 0; |
| hw->m_mv_BUF[i].used_flag = 0; |
| } |
| } |
| } |
| |
| static int alloc_mv_buf(struct AV1HW_s *hw, |
| int i, int size) |
| { |
| int ret = 0; |
| |
| if (hw->m_mv_BUF[i].start_adr && |
| size > hw->m_mv_BUF[i].size) { |
| dealloc_mv_bufs(hw); |
| } else if (hw->m_mv_BUF[i].start_adr) |
| return 0; |
| |
| if (decoder_bmmu_box_alloc_buf_phy |
| (hw->bmmu_box, |
| MV_BUFFER_IDX(i), size, |
| DRIVER_NAME, |
| &hw->m_mv_BUF[i].start_adr) < 0) { |
| hw->m_mv_BUF[i].start_adr = 0; |
| ret = -1; |
| } else { |
| hw->m_mv_BUF[i].size = size; |
| hw->m_mv_BUF[i].used_flag = 0; |
| ret = 0; |
| if (debug) { |
| pr_info( |
| "MV Buffer %d: start_adr %p size %x\n", |
| i, |
| (void *)hw->m_mv_BUF[i].start_adr, |
| hw->m_mv_BUF[i].size); |
| } |
| } |
| return ret; |
| } |
| |
| static int cal_mv_buf_size(struct AV1HW_s *hw, int pic_width, int pic_height) |
| { |
| unsigned lcu_size = hw->current_lcu_size; |
| int extended_pic_width = (pic_width + lcu_size -1) |
| & (~(lcu_size - 1)); |
| int extended_pic_height = (pic_height + lcu_size -1) |
| & (~(lcu_size - 1)); |
| |
| int lcu_x_num = extended_pic_width / lcu_size; |
| int lcu_y_num = extended_pic_height / lcu_size; |
| int size_a, size_b, size; |
| |
| if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) |
| /*tm2revb and sc2*/ |
| size_a = lcu_x_num * lcu_y_num * 16 * |
| ((lcu_size == 64) ? 16 : 64); |
| else |
| size_a = lcu_x_num * lcu_y_num * 16 * |
| ((lcu_size == 64) ? 19 : 76); |
| |
| size_b = lcu_x_num * ((lcu_y_num >> 3) + |
| (lcu_y_num & 0x7)) * 16; |
| size = ((size_a + size_b) + 0xffff) & (~0xffff); |
| |
| if (debug & AOM_DEBUG_USE_FIXED_MV_BUF_SIZE) |
| size = hw->max_one_mv_buffer_size; |
| if (force_max_one_mv_buffer_size) |
| size = force_max_one_mv_buffer_size; |
| return size; |
| } |
| |
| static int init_mv_buf_list(struct AV1HW_s *hw) |
| { |
| int i; |
| int ret = 0; |
| int count = MV_BUFFER_NUM; |
| int pic_width = hw->init_pic_w; |
| int pic_height = hw->init_pic_h; |
| int size = cal_mv_buf_size(hw, pic_width, pic_height); |
| |
| if (mv_buf_dynamic_alloc) |
| return 0; |
| #if 0 |
| if (mv_buf_margin > 0) |
| count = REF_FRAMES + mv_buf_margin; |
| if (hw->init_pic_w > 2048 && hw->init_pic_h > 1088) |
| count = REF_FRAMES_4K + mv_buf_margin; |
| #else |
| if (debug) |
| pr_info("%s, calculated mv size 0x%x\n", |
| __func__, size); |
| |
| if ((hw->is_used_v4l) && !IS_8K_SIZE(pic_width, pic_height)) { |
| if (vdec_is_support_4k()) |
| size = 0xb0000; |
| else |
| size = 0x30000; |
| } |
| |
| if (hw->init_pic_w > 4096 && hw->init_pic_h > 2048) |
| count = REF_FRAMES_4K + hw->mv_buf_margin; |
| else if (hw->init_pic_w > 2048 && hw->init_pic_h > 1088) |
| count = REF_FRAMES_4K + hw->mv_buf_margin; |
| else |
| count = REF_FRAMES + hw->mv_buf_margin; |
| |
| #endif |
| if (debug) { |
| pr_info("%s w:%d, h:%d, count: %d, size 0x%x\n", |
| __func__, hw->init_pic_w, hw->init_pic_h, |
| count, size); |
| } |
| |
| for (i = 0; |
| i < count && i < MV_BUFFER_NUM; i++) { |
| if (alloc_mv_buf(hw, i, size) < 0) { |
| ret = -1; |
| break; |
| } |
| } |
| return ret; |
| } |
| |
| static int get_mv_buf(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| int i; |
| int ret = -1; |
| if (mv_buf_dynamic_alloc) { |
| int size = cal_mv_buf_size(hw, |
| pic_config->y_crop_width, pic_config->y_crop_height); |
| for (i = 0; i < MV_BUFFER_NUM; i++) { |
| if (hw->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(hw, ret, size) >= 0) { |
| pic_config->mv_buf_index = ret; |
| pic_config->mpred_mv_wr_start_addr = |
| (hw->m_mv_BUF[ret].start_adr + 0xffff) & |
| (~0xffff); |
| } else { |
| pr_info( |
| "%s: Error, mv buf alloc fail\n", |
| __func__); |
| } |
| return ret; |
| } |
| |
| for (i = 0; i < MV_BUFFER_NUM; i++) { |
| if (hw->m_mv_BUF[i].start_adr && |
| hw->m_mv_BUF[i].used_flag == 0) { |
| hw->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 = |
| (hw->m_mv_BUF[ret].start_adr + 0xffff) & |
| (~0xffff); |
| if (debug & AV1_DEBUG_BUFMGR_MORE) |
| pr_info( |
| "%s => %d (%d) size 0x%x\n", |
| __func__, ret, |
| pic_config->mpred_mv_wr_start_addr, |
| hw->m_mv_BUF[ret].size); |
| } else { |
| pr_info( |
| "%s: Error, mv buf is not enough\n", |
| __func__); |
| } |
| return ret; |
| } |
| static void put_mv_buf(struct AV1HW_s *hw, |
| int *mv_buf_index) |
| { |
| int i = *mv_buf_index; |
| if (i >= MV_BUFFER_NUM) { |
| if (debug & AV1_DEBUG_BUFMGR_MORE) |
| pr_info( |
| "%s: index %d beyond range\n", |
| __func__, i); |
| return; |
| } |
| if (mv_buf_dynamic_alloc) { |
| if (hw->m_mv_BUF[i].start_adr) { |
| if (debug) |
| pr_info( |
| "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n", |
| i, hw->m_mv_BUF[i].start_adr, |
| hw->m_mv_BUF[i].size, |
| hw->m_mv_BUF[i].used_flag); |
| decoder_bmmu_box_free_idx( |
| hw->bmmu_box, |
| MV_BUFFER_IDX(i)); |
| hw->m_mv_BUF[i].start_adr = 0; |
| hw->m_mv_BUF[i].size = 0; |
| hw->m_mv_BUF[i].used_flag = 0; |
| } |
| *mv_buf_index = -1; |
| return; |
| } |
| |
| if (debug & AV1_DEBUG_BUFMGR_MORE) |
| pr_info( |
| "%s(%d): used_flag(%d)\n", |
| __func__, i, |
| hw->m_mv_BUF[i].used_flag); |
| |
| *mv_buf_index = -1; |
| if (hw->m_mv_BUF[i].start_adr && |
| hw->m_mv_BUF[i].used_flag) |
| hw->m_mv_BUF[i].used_flag = 0; |
| } |
| static void put_un_used_mv_bufs(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; |
| int i; |
| for (i = 0; i < hw->used_buf_num; ++i) { |
| if ((frame_bufs[i].ref_count == 0) && |
| (frame_bufs[i].buf.index != -1) && |
| (frame_bufs[i].buf.mv_buf_index >= 0) |
| ) |
| put_mv_buf(hw, &frame_bufs[i].buf.mv_buf_index); |
| } |
| } |
| #endif |
| |
| static void init_pic_list_hw(struct AV1HW_s *pbi); |
| |
| static void update_hide_frame_timestamp(struct AV1HW_s *hw) |
| { |
| RefCntBuffer *const frame_bufs = hw->common.buffer_pool->frame_bufs; |
| int i; |
| |
| for (i = 0; i < hw->used_buf_num; ++i) { |
| if ((!frame_bufs[i].show_frame) && |
| (frame_bufs[i].showable_frame) && |
| (!frame_bufs[i].buf.vf_ref) && |
| (frame_bufs[i].buf.BUF_index != -1)) { |
| frame_bufs[i].buf.timestamp = hw->chunk->timestamp; |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "%s, update %d hide frame ts: %lld\n", |
| __func__, i, frame_bufs[i].buf.timestamp); |
| } |
| } |
| } |
| |
| int check_buff_has_show(struct RefCntBuffer_s *frame_buf) |
| { |
| int ret = 1; |
| |
| if (disable_repeat || |
| ((frame_buf->buf.vf_ref == 0) && |
| (frame_buf->buf.index != -1) && |
| frame_buf->buf.cma_alloc_addr)) { |
| ret = 0; |
| if (debug & AV1_DEBUG_BUFMGR) |
| pr_info("existing buff can use\n"); |
| } else { |
| if (debug & AV1_DEBUG_BUFMGR) |
| pr_info("existing buff can't use\n"); |
| } |
| return ret; |
| } |
| |
| static int get_free_fb_idx(AV1_COMMON *cm) |
| { |
| int i; |
| RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; |
| |
| for (i = 0; i < FRAME_BUFFERS; ++i) { |
| if ((frame_bufs[i].ref_count == 0) && |
| (frame_bufs[i].buf.vf_ref == 0) && |
| (frame_bufs[i].buf.repeat_count == 0)) |
| break; |
| } |
| |
| return (i != FRAME_BUFFERS) ? i : -1; |
| } |
| |
| static int v4l_get_free_fb(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; |
| struct aml_vcodec_ctx * v4l = hw->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->repeat_count == 0) && |
| (pic->index != -1) && |
| pic->cma_alloc_addr) { |
| free_pic = pic; |
| } |
| break; |
| case V4L_CAP_BUFF_IN_M2M: |
| idx = get_free_fb_idx(cm); |
| if (idx < 0) |
| break; |
| |
| pic = &frame_bufs[idx].buf; |
| pic->y_crop_width = hw->frame_width; |
| pic->y_crop_height = hw->frame_height; |
| hw->buffer_wrap[idx] = index; |
| if (!v4l_alloc_and_config_pic(hw, pic)) { |
| set_canvas(hw, pic); |
| init_pic_list_hw(hw); |
| free_pic = pic; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (free_pic) { |
| if (frame_bufs[i].buf.use_external_reference_buffers) { |
| // If this frame buffer's y_buffer, u_buffer, and v_buffer point to the |
| // external reference buffers. Restore the buffer pointers to point to the |
| // internally allocated memory. |
| PIC_BUFFER_CONFIG *ybf = &frame_bufs[i].buf; |
| |
| ybf->y_buffer = ybf->store_buf_adr[0]; |
| ybf->u_buffer = ybf->store_buf_adr[1]; |
| ybf->v_buffer = ybf->store_buf_adr[2]; |
| ybf->use_external_reference_buffers = 0; |
| } |
| |
| frame_bufs[i].ref_count = 1; |
| break; |
| } |
| } |
| |
| if (free_pic && hw->chunk) { |
| free_pic->timestamp = hw->chunk->timestamp; |
| update_hide_frame_timestamp(hw); |
| } |
| |
| unlock_buffer_pool(cm->buffer_pool, flags); |
| |
| if (free_pic) { |
| struct vdec_v4l2_buffer *fb = |
| (struct vdec_v4l2_buffer *) |
| hw->m_BUF[free_pic->index].v4l_ref_buf_addr; |
| |
| fb->status = FB_ST_DECODER; |
| |
| v4l->aux_infos.bind_sei_buffer(v4l, &free_pic->aux_data_buf, |
| &free_pic->aux_data_size, &free_pic->ctx_buf_idx); |
| |
| } |
| |
| if (debug & AV1_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, av1 get free pic null\n", __func__); |
| } |
| } |
| |
| return free_pic ? free_pic->index : INVALID_IDX; |
| } |
| |
| static int get_free_fb(AV1_COMMON *cm) { |
| RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; |
| unsigned long flags; |
| int i; |
| |
| lock_buffer_pool(cm->buffer_pool, flags); |
| for (i = 0; i < FRAME_BUFFERS; ++i) { |
| if (frame_bufs[i].ref_count == 0 |
| #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC |
| && frame_bufs[i].buf.vf_ref == 0 |
| #endif |
| ) |
| break; |
| } |
| |
| if (i != FRAME_BUFFERS) { |
| if (frame_bufs[i].buf.use_external_reference_buffers) { |
| // If this frame buffer's y_buffer, u_buffer, and v_buffer point to the |
| // external reference buffers. Restore the buffer pointers to point to the |
| // internally allocated memory. |
| PIC_BUFFER_CONFIG *ybf = &frame_bufs[i].buf; |
| ybf->y_buffer = ybf->store_buf_adr[0]; |
| ybf->u_buffer = ybf->store_buf_adr[1]; |
| ybf->v_buffer = ybf->store_buf_adr[2]; |
| ybf->use_external_reference_buffers = 0; |
| } |
| |
| frame_bufs[i].ref_count = 1; |
| } else { |
| // We should never run out of free buffers. If this assertion fails, there |
| // is a reference leak. |
| //assert(0 && "Ran out of free frame buffers. Likely a reference leak."); |
| // Reset i to be INVALID_IDX to indicate no free buffer found. |
| i = INVALID_IDX; |
| } |
| |
| unlock_buffer_pool(cm->buffer_pool, flags); |
| return i; |
| } |
| |
| int get_free_frame_buffer(struct AV1_Common_s *cm) |
| { |
| struct AV1HW_s *hw = container_of(cm, struct AV1HW_s, common); |
| |
| return hw->is_used_v4l ? v4l_get_free_fb(hw) : get_free_fb(cm); |
| } |
| |
| static int get_free_buf_count(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; |
| struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| int i, free_buf_count = 0; |
| |
| //clear_frame_buf_ref_count(hw->pbi); |
| |
| if (hw->is_used_v4l) { |
| for (i = 0; i < hw->used_buf_num; ++i) { |
| if ((frame_bufs[i].ref_count == 0) && |
| (frame_bufs[i].buf.vf_ref == 0) && |
| (frame_bufs[i].buf.repeat_count == 0) && |
| frame_bufs[i].buf.cma_alloc_addr) { |
| free_buf_count++; |
| } |
| } |
| |
| if (ctx->cap_pool.dec < hw->used_buf_num) { |
| if (ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) { |
| free_buf_count += |
| v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) + 1; |
| } |
| } |
| |
| /* trigger to parse head data. */ |
| if (!hw->v4l_params_parsed) { |
| free_buf_count = hw->run_ready_min_buf_num; |
| } |
| if ((debug & AV1_DEBUG_BUFMGR_MORE) && |
| (free_buf_count <= 0)) { |
| pr_info("%s, free count %d, m2m_ready %d\n", |
| __func__, |
| free_buf_count, |
| v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)); |
| } |
| } else { |
| for (i = 0; i < hw->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; |
| } |
| |
| int aom_bufmgr_init(struct AV1HW_s *hw, struct BuffInfo_s *buf_spec_i, |
| struct buff_s *mc_buf_i) { |
| struct AV1_Common_s *cm = &hw->common; |
| if (debug) |
| pr_info("%s %d %p\n", __func__, __LINE__, hw->pbi); |
| hw->frame_count = 0; |
| hw->pic_count = 0; |
| hw->pre_stream_offset = 0; |
| spin_lock_init(&cm->buffer_pool->lock); |
| cm->prev_fb_idx = INVALID_IDX; |
| cm->new_fb_idx = INVALID_IDX; |
| hw->used_4k_num = -1; |
| cm->cur_fb_idx_mmu = INVALID_IDX; |
| pr_debug |
| ("After aom_bufmgr_init, prev_fb_idx : %d, new_fb_idx : %d\r\n", |
| cm->prev_fb_idx, cm->new_fb_idx); |
| hw->need_resync = 1; |
| |
| cm->current_video_frame = 0; |
| hw->ready_for_new_data = 1; |
| |
| /* private init */ |
| hw->work_space_buf = buf_spec_i; |
| if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL) || |
| (get_double_write_mode(hw) == 0x10)) { |
| hw->mc_buf = mc_buf_i; |
| } |
| |
| hw->rpm_addr = NULL; |
| hw->lmem_addr = NULL; |
| |
| hw->use_cma_flag = 0; |
| hw->decode_idx = 0; |
| hw->result_done_count = 0; |
| /*int m_uiMaxCUWidth = 1<<7;*/ |
| /*int m_uiMaxCUHeight = 1<<7;*/ |
| hw->has_keyframe = 0; |
| hw->has_sequence = 0; |
| hw->skip_flag = 0; |
| hw->wait_buf = 0; |
| hw->error_flag = 0; |
| |
| hw->last_pts = 0; |
| hw->last_pts_us64 = 0; |
| hw->shift_byte_count = 0; |
| hw->shift_byte_count_lo = 0; |
| hw->shift_byte_count_hi = 0; |
| hw->pts_mode_switching_count = 0; |
| hw->pts_mode_recovery_count = 0; |
| |
| hw->buf_num = 0; |
| hw->pic_num = 0; |
| |
| return 0; |
| } |
| |
| /* |
| struct AV1HW_s av1_decoder; |
| union param_u av1_param; |
| */ |
| /************************************************** |
| * |
| *AV1 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 LOSLESS_COMPRESS_MODE |
| |
| /*#define DECOMP_HEADR_SURGENT*/ |
| #ifdef AV1_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 av1_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) |
| |
| static u32 multi_frames_in_one_pack = 1; |
| #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; |
| #ifdef MIX_STREAM_SUPPORT |
| static u32 buf_alloc_width = 4096; |
| static u32 buf_alloc_height = 2304; |
| static u32 av1_max_pic_w = 4096; |
| static u32 av1_max_pic_h = 2304; |
| |
| static u32 dynamic_buf_num_margin = 3; |
| #else |
| static u32 buf_alloc_width; |
| static u32 buf_alloc_height; |
| static u32 dynamic_buf_num_margin = 7; |
| #endif |
| 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 AV1) 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 (av1_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 16 |
| /*less bufs num 12 caused frame drop, nts failed*/ |
| #define MAX_BUF_NUM_LESS 14 |
| static u32 max_buf_num = MAX_BUF_NUM_NORMAL; |
| #define MAX_BUF_NUM_SAVE_BUF 8 |
| |
| static DEFINE_MUTEX(vav1_mutex); |
| #ifndef MULTI_INSTANCE_SUPPORT |
| static struct device *cma_dev; |
| #endif |
| #define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 |
| #define HEVC_FG_STATUS HEVC_ASSIST_SCRATCH_B |
| #define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 |
| #define AOM_AV1_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3 |
| #define AOM_AV1_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4 // changed to use HEVC_ASSIST_MMU_MAP_ADDR |
| #define AOM_AV1_DAALA_TOP_BUFFER HEVC_ASSIST_SCRATCH_5 |
| //#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6 |
| //#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 |
| #define AOM_AV1_CDF_BUFFER_W HEVC_ASSIST_SCRATCH_8 |
| #define AOM_AV1_CDF_BUFFER_R HEVC_ASSIST_SCRATCH_9 |
| #define AOM_AV1_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A |
| #define AOM_AV1_SEG_MAP_BUFFER_W AV1_SEG_W_ADDR // HEVC_ASSIST_SCRATCH_B |
| #define AOM_AV1_SEG_MAP_BUFFER_R AV1_SEG_R_ADDR // HEVC_ASSIST_SCRATCH_C |
| //#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B |
| //#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C |
| //#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D |
| #define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E |
| #define RPM_CMD_REG 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 AOM_AV1_SEGMENT_FEATURE AV1_QUANT_WR |
| |
| #define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G |
| #define DEBUG_REG2 HEVC_ASSIST_SCRATCH_H |
| |
| #define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_I |
| #define CUR_NAL_UNIT_TYPE HEVC_ASSIST_SCRATCH_J |
| #define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K |
| |
| #define PIC_END_LCU_COUNT HEVC_ASSIST_SCRATCH_2 |
| |
| #define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L |
| #define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_7 |
| #if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| #define HEVC_DBG_LOG_ADR HEVC_ASSIST_SCRATCH_C |
| #ifdef DEBUG_CMD |
| #define HEVC_D_ADR HEVC_ASSIST_SCRATCH_4 |
| #endif |
| #endif |
| /* |
| *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 |
| [24:16] debug |
| 0x1, bufmgr only |
| */ |
| #define DECODE_MODE HEVC_ASSIST_SCRATCH_J |
| #define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K |
| |
| #define RPM_BUF_SIZE ((RPM_END - RPM_BEGIN) * 2) |
| #define LMEM_BUF_SIZE (0x600 * 2) |
| |
| /* |
| #ifdef MAP_8K |
| static u32 seg_map_size = 0xd8000; |
| #else |
| static u32 seg_map_size = 0x36000; |
| #endif |
| */ |
| //static u32 seg_map_size = 0x36000; |
| |
| //#define VBH_BUF_COUNT 4 |
| //#define VBH_BUF_SIZE_1080P ((((2 * 16 * 1088) + 0xffff) & (~0xffff)) * VBH_BUF_COUNT) |
| //#define VBH_BUF_SIZE_4K ((((2 * 16 * 2304) + 0xffff) & (~0xffff))) * VBH_BUF_COUNT) |
| //#define VBH_BUF_SIZE_8K ((((2 * 16 * 4608) + 0xffff) & (~0xffff))) * VBH_BUF_COUNT) |
| |
| /*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. fix case1440 dec timeout */ |
| #define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) |
| |
| #define WORK_BUF_SPEC_NUM 3 |
| |
| static struct BuffInfo_s aom_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 = 0x1E00, |
| }, |
| .sao_abv = { |
| .buf_size = 0x0, //0x30000, |
| }, |
| .sao_vb = { |
| .buf_size = 0x0, //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, |
| }, |
| .seg_map = { |
| // SEGMENT MAP AREA - 1920x1088/4/4 * 3 bits = 0xBF40 Bytes * 16 = 0xBF400 |
| .buf_size = 0xBF400, |
| }, |
| .daala_top = { |
| // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000 |
| .buf_size = 0xf00, |
| }, |
| .sao_up = { |
| // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes |
| .buf_size = 0x0, //0x2800, |
| }, |
| .swap_buf = { |
| // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid) |
| .buf_size = 0x800, |
| }, |
| .cdf_buf = { |
| // for context store/load 1024x256 x16 = 512K bytes 16*0x8000 |
| .buf_size = 0x80000, |
| }, |
| .gmc_buf = { |
| // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800 |
| .buf_size = 0x800, |
| }, |
| .scalelut = { |
| // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000) |
| .buf_size = 0x0, //0x8000, |
| }, |
| .dblk_para = { |
| // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000) |
| .buf_size = 0xd00, /*0xc40*/ |
| }, |
| .dblk_data = { |
| .buf_size = 0x49000, |
| }, |
| .cdef_data = { |
| .buf_size = 0x22400, |
| }, |
| .ups_data = { |
| .buf_size = 0x36000, |
| }, |
| .fgs_table = { |
| .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits |
| }, |
| #ifdef AOM_AV1_MMU |
| .mmu_vbh = { |
| .buf_size = VBH_BUF_SIZE_1080P, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P * FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| .mmu_vbh_dw = { |
| .buf_size = DW_VBH_BUF_SIZE_1080P, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header_dw = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| .mpred_above = { |
| .buf_size = 0x2800, /*round from 0x2760*/ /* 2 * size of hw*/ |
| }, |
| #ifdef MV_USE_FIXED_BUF |
| .mpred_mv = { |
| .buf_size = MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB * FRAME_BUFFERS,/*round from 203A0*/ //1080p, 0x40000 per buffer |
| }, |
| #endif |
| .rpm = { |
| .buf_size = 0x80*2, |
| }, |
| .lmem = { |
| .buf_size = 0x400 * 2, |
| } |
| }, |
| { |
| #ifdef VPU_FILMGRAIN_DUMP |
| .max_width = 640, |
| .max_height = 480, |
| #else |
| .max_width = 4096, |
| .max_height = 2304, |
| #endif |
| .ipp = { |
| // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k |
| .buf_size = 0x4000, |
| }, |
| .sao_abv = { |
| .buf_size = 0x0, //0x30000, |
| }, |
| .sao_vb = { |
| .buf_size = 0x0, //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, |
| }, |
| .seg_map = { |
| // SEGMENT MAP AREA - 4096x2304/4/4 * 3 bits = 0x36000 Bytes * 16 = 0x360000 |
| .buf_size = 0x360000, |
| }, |
| .daala_top = { |
| // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000 |
| .buf_size = 0x2000, |
| }, |
| .sao_up = { |
| // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes |
| .buf_size = 0x0, //0x2800, |
| }, |
| .swap_buf = { |
| // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid) |
| .buf_size = 0x800, |
| }, |
| .cdf_buf = { |
| // for context store/load 1024x256 x16 = 512K bytes 16*0x8000 |
| .buf_size = 0x80000, |
| }, |
| .gmc_buf = { |
| // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800 |
| .buf_size = 0x800, |
| }, |
| .scalelut = { |
| // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000) |
| .buf_size = 0x0, //0x8000, |
| }, |
| .dblk_para = { |
| // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000) |
| .buf_size = 0x1a00, /*0x1980*/ |
| }, |
| .dblk_data = { |
| .buf_size = 0x52800, |
| }, |
| .cdef_data = { |
| .buf_size = 0x24a00, |
| }, |
| .ups_data = { |
| .buf_size = 0x6f000, |
| }, |
| .fgs_table = { |
| .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits |
| }, |
| #ifdef AOM_AV1_MMU |
| .mmu_vbh = { |
| .buf_size = VBH_BUF_SIZE_4K, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_4K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| .mmu_vbh_dw = { |
| .buf_size = DW_VBH_BUF_SIZE_4K, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header_dw = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_4K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| .mpred_above = { |
| .buf_size = 0x5400, /* 2 * size of hw*/ |
| }, |
| #ifdef MV_USE_FIXED_BUF |
| .mpred_mv = { |
| /* .buf_size = 0x100000*16, |
| //4k2k , 0x100000 per buffer */ |
| /* 4096x2304 , 0x120000 per buffer */ |
| .buf_size = MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB * FRAME_BUFFERS, |
| }, |
| #endif |
| .rpm = { |
| .buf_size = 0x80*2, |
| }, |
| .lmem = { |
| .buf_size = 0x400 * 2, |
| } |
| |
| }, |
| { |
| .max_width = 8192, |
| .max_height = 4608, |
| .ipp = { |
| // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k |
| .buf_size = 0x4000, |
| }, |
| .sao_abv = { |
| .buf_size = 0x0, //0x30000, |
| }, |
| .sao_vb = { |
| .buf_size = 0x0, //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, |
| }, |
| .seg_map = { |
| // SEGMENT MAP AREA - 4096x2304/4/4 * 3 bits = 0x36000 Bytes * 16 = 0x360000 |
| .buf_size = 0xd80000, |
| }, |
| .daala_top = { |
| // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000 |
| .buf_size = 0x2000, |
| }, |
| .sao_up = { |
| // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes |
| .buf_size = 0x0, //0x2800, |
| }, |
| .swap_buf = { |
| // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid) |
| .buf_size = 0x800, |
| }, |
| .cdf_buf = { |
| // for context store/load 1024x256 x16 = 512K bytes 16*0x8000 |
| .buf_size = 0x80000, |
| }, |
| .gmc_buf = { |
| // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800 |
| .buf_size = 0x800, |
| }, |
| .scalelut = { |
| // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000) |
| .buf_size = 0x0, //0x8000, |
| }, |
| .dblk_para = { |
| // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000) |
| .buf_size = 0x3300, /*0x32a0*/ |
| }, |
| .dblk_data = { |
| .buf_size = 0xa4800, |
| }, |
| .cdef_data = { |
| .buf_size = 0x29200, |
| }, |
| .ups_data = { |
| .buf_size = 0xdb000, |
| }, |
| .fgs_table = { |
| .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits |
| }, |
| #ifdef AOM_AV1_MMU |
| .mmu_vbh = { |
| .buf_size = VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_8K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| .mmu_vbh_dw = { |
| .buf_size = DW_VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K |
| }, |
| .cm_header_dw = { |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| .buf_size = MMU_COMPRESS_HEADER_SIZE_8K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) |
| #else |
| .buf_size = 0, |
| #endif |
| }, |
| #endif |
| .mpred_above = { |
| .buf_size = 0xA800, /* 2 * size of hw*/ |
| }, |
| #ifdef MV_USE_FIXED_BUF |
| .mpred_mv = { |
| /* .buf_size = 0x100000*16, |
| //4k2k , 0x100000 per buffer */ |
| /* 4096x2304 , 0x120000 per buffer */ |
| .buf_size = MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB * FRAME_BUFFERS, |
| }, |
| #endif |
| .rpm = { |
| .buf_size = 0x80*2, |
| }, |
| .lmem = { |
| .buf_size = 0x400 * 2, |
| } |
| |
| } |
| }; |
| |
| |
| /* |
| * AUX DATA Process |
| */ |
| static u32 init_aux_size; |
| static int aux_data_is_avaible(struct AV1HW_s *hw) |
| { |
| u32 reg_val; |
| |
| reg_val = READ_VREG(HEVC_AUX_DATA_SIZE); |
| if (reg_val != 0 && reg_val != init_aux_size) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static void config_aux_buf(struct AV1HW_s *hw) |
| { |
| WRITE_VREG(HEVC_AUX_ADR, hw->aux_phy_addr); |
| init_aux_size = ((hw->prefix_aux_size >> 4) << 16) | |
| (hw->suffix_aux_size >> 4); |
| WRITE_VREG(HEVC_AUX_DATA_SIZE, init_aux_size); |
| } |
| |
| /* |
| * dv_meta_flag: 1, dolby meta (T35) only; 2, not include dolby meta (T35) |
| */ |
| static void set_aux_data(struct AV1HW_s *hw, |
| char **aux_data_buf, int *aux_data_size, |
| unsigned char suffix_flag, |
| unsigned char dv_meta_flag) |
| { |
| int i; |
| unsigned short *aux_adr; |
| unsigned int size_reg_val = |
| READ_VREG(HEVC_AUX_DATA_SIZE); |
| unsigned int aux_count = 0; |
| int aux_size = 0; |
| if (0 == aux_data_is_avaible(hw)) |
| return; |
| |
| if (hw->aux_data_dirty || |
| hw->m_ins_flag == 0) { |
| |
| hw->aux_data_dirty = 0; |
| } |
| |
| if (suffix_flag) { |
| aux_adr = (unsigned short *) |
| (hw->aux_addr + |
| hw->prefix_aux_size); |
| aux_count = |
| ((size_reg_val & 0xffff) << 4) |
| >> 1; |
| aux_size = |
| hw->suffix_aux_size; |
| } else { |
| aux_adr = |
| (unsigned short *)hw->aux_addr; |
| aux_count = |
| ((size_reg_val >> 16) << 4) |
| >> 1; |
| aux_size = |
| hw->prefix_aux_size; |
| } |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| av1_print(hw, 0, |
| "%s:old size %d count %d,suf %d dv_flag %d\r\n", |
| __func__, *aux_data_size, |
| aux_count, suffix_flag, dv_meta_flag); |
| } |
| if (aux_size > 0 && aux_count > 0) { |
| int heads_size = 0; |
| |
| for (i = 0; i < aux_count; i++) { |
| unsigned char tag = aux_adr[i] >> 8; |
| if (tag != 0 && tag != 0xff) { |
| if (dv_meta_flag == 0) |
| heads_size += 8; |
| else if (dv_meta_flag == 1 && tag == 0x14) |
| heads_size += 8; |
| else if (dv_meta_flag == 2 && tag != 0x14) |
| heads_size += 8; |
| } |
| } |
| |
| if (*aux_data_buf) { |
| unsigned char valid_tag = 0; |
| unsigned char *h = |
| *aux_data_buf + |
| *aux_data_size; |
| unsigned char *p = h + 8; |
| int len = 0; |
| int padding_len = 0; |
| |
| for (i = 0; i < aux_count; i += 4) { |
| int ii; |
| unsigned char tag = aux_adr[i + 3] >> 8; |
| if (tag != 0 && tag != 0xff) { |
| if (dv_meta_flag == 0) |
| valid_tag = 1; |
| else if (dv_meta_flag == 1 |
| && tag == 0x14) |
| valid_tag = 1; |
| else if (dv_meta_flag == 2 |
| && tag != 0x14) |
| valid_tag = 1; |
| else |
| valid_tag = 0; |
| if (valid_tag && len > 0) { |
| *aux_data_size += |
| (len + 8); |
| h[0] = (len >> 24) |
| & 0xff; |
| h[1] = (len >> 16) |
| & 0xff; |
| h[2] = (len >> 8) |
| & 0xff; |
| h[3] = (len >> 0) |
| & 0xff; |
| h[6] = |
| (padding_len >> 8) |
| & 0xff; |
| h[7] = (padding_len) |
| & 0xff; |
| h += (len + 8); |
| p += 8; |
| len = 0; |
| padding_len = 0; |
| } |
| if (valid_tag) { |
| h[4] = tag; |
| h[5] = 0; |
| h[6] = 0; |
| h[7] = 0; |
| } |
| } |
| if (valid_tag) { |
| for (ii = 0; ii < 4; ii++) { |
| unsigned short aa = |
| aux_adr[i + 3 |
| - ii]; |
| *p = aa & 0xff; |
| p++; |
| len++; |
| if ((aa >> 8) == 0xff) |
| padding_len++; |
| } |
| } |
| } |
| if (len > 0) { |
| *aux_data_size += (len + 8); |
| h[0] = (len >> 24) & 0xff; |
| h[1] = (len >> 16) & 0xff; |
| h[2] = (len >> 8) & 0xff; |
| h[3] = (len >> 0) & 0xff; |
| h[6] = (padding_len >> 8) & 0xff; |
| h[7] = (padding_len) & 0xff; |
| } |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| av1_print(hw, 0, |
| "aux: (size %d) suffix_flag %d\n", |
| *aux_data_size, suffix_flag); |
| for (i = 0; i < *aux_data_size; i++) { |
| av1_print_cont(hw, 0, |
| "%02x ", (*aux_data_buf)[i]); |
| if (((i + 1) & 0xf) == 0) |
| av1_print_cont(hw, 0, "\n"); |
| } |
| av1_print_cont(hw, 0, "\n"); |
| } |
| } |
| } |
| |
| } |
| |
| static void set_dv_data(struct AV1HW_s *hw) |
| { |
| set_aux_data(hw, &hw->dv_data_buf, |
| &hw->dv_data_size, 0, 1); |
| |
| } |
| |
| static void set_pic_aux_data(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic, unsigned char suffix_flag, |
| unsigned char dv_meta_flag) |
| { |
| if (pic == NULL) |
| return; |
| set_aux_data(hw, &pic->aux_data_buf, |
| &pic->aux_data_size, suffix_flag, dv_meta_flag); |
| } |
| |
| static void copy_dv_data(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic) |
| { |
| if (pic->aux_data_buf) { |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| av1_print(hw, 0, |
| "%s: (size %d) pic index %d\n", |
| __func__, |
| hw->dv_data_size, pic->index); |
| } |
| memcpy(pic->aux_data_buf + pic->aux_data_size, hw->dv_data_buf, hw->dv_data_size); |
| pic->aux_data_size += hw->dv_data_size; |
| memset(hw->dv_data_buf, 0, hw->aux_data_size); |
| hw->dv_data_size = 0; |
| } |
| } |
| |
| static void release_aux_data(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic) |
| { |
| #if 0 |
| if (pic->aux_data_buf) |
| vfree(pic->aux_data_buf); |
| pic->aux_data_buf = NULL; |
| pic->aux_data_size = 0; |
| #endif |
| } |
| |
| static void dump_aux_buf(struct AV1HW_s *hw) |
| { |
| int i; |
| unsigned short *aux_adr = |
| (unsigned short *) |
| hw->aux_addr; |
| unsigned int aux_size = |
| (READ_VREG(HEVC_AUX_DATA_SIZE) |
| >> 16) << 4; |
| |
| if (hw->prefix_aux_size > 0) { |
| av1_print(hw, 0, |
| "prefix aux: (size %d)\n", |
| aux_size); |
| for (i = 0; i < |
| (aux_size >> 1); i++) { |
| av1_print_cont(hw, 0, |
| "%04x ", |
| *(aux_adr + i)); |
| if (((i + 1) & 0xf) |
| == 0) |
| av1_print_cont(hw, |
| 0, "\n"); |
| } |
| } |
| if (hw->suffix_aux_size > 0) { |
| aux_adr = (unsigned short *) |
| (hw->aux_addr + |
| hw->prefix_aux_size); |
| aux_size = |
| (READ_VREG(HEVC_AUX_DATA_SIZE) & 0xffff) |
| << 4; |
| av1_print(hw, 0, |
| "suffix aux: (size %d)\n", |
| aux_size); |
| for (i = 0; i < |
| (aux_size >> 1); i++) { |
| av1_print_cont(hw, 0, |
| "%04x ", *(aux_adr + i)); |
| if (((i + 1) & 0xf) == 0) |
| av1_print_cont(hw, 0, "\n"); |
| } |
| } |
| } |
| |
| /* |
| * |
| */ |
| |
| /*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 & AV1_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 & AV1_DEBUG_BUFMGR_MORE) |
| pr_info("%s(%d,%d)=>%d\n", |
| __func__, width, height, |
| hsize); |
| |
| return hsize; |
| } |
| |
| #ifdef AOM_AV1_MMU_DW |
| static int compute_losless_comp_body_size_dw(int width, int height, |
| uint8_t is_bit_depth_10) |
| { |
| |
| return compute_losless_comp_body_size(width, height, is_bit_depth_10); |
| } |
| |
| /* Losless compression header buffer size 32bytes per 128x64 (jt)*/ |
| static int compute_losless_comp_header_size_dw(int width, int height) |
| { |
| return compute_losless_comp_header_size(width, height); |
| } |
| #endif |
| |
| static void init_buff_spec(struct AV1HW_s *hw, |
| 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->seg_map.buf_start = |
| WORKBUF_ALIGN(buf_spec->vps.buf_start + buf_spec->vps.buf_size); |
| buf_spec->daala_top.buf_start = |
| WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size); |
| buf_spec->sao_up.buf_start = |
| WORKBUF_ALIGN(buf_spec->daala_top.buf_start + buf_spec->daala_top.buf_size); |
| buf_spec->swap_buf.buf_start = |
| WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); |
| buf_spec->cdf_buf.buf_start = |
| WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); |
| buf_spec->gmc_buf.buf_start = |
| WORKBUF_ALIGN(buf_spec->cdf_buf.buf_start + buf_spec->cdf_buf.buf_size); |
| buf_spec->scalelut.buf_start = |
| WORKBUF_ALIGN(buf_spec->gmc_buf.buf_start + buf_spec->gmc_buf.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->cdef_data.buf_start = |
| WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); |
| buf_spec->ups_data.buf_start = |
| WORKBUF_ALIGN(buf_spec->cdef_data.buf_start + buf_spec->cdef_data.buf_size); |
| buf_spec->fgs_table.buf_start = |
| WORKBUF_ALIGN(buf_spec->ups_data.buf_start + buf_spec->ups_data.buf_size); |
| #ifdef AOM_AV1_MMU |
| buf_spec->mmu_vbh.buf_start = |
| WORKBUF_ALIGN(buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size); |
| buf_spec->cm_header.buf_start = |
| WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); |
| #ifdef AOM_AV1_MMU_DW |
| buf_spec->mmu_vbh_dw.buf_start = |
| WORKBUF_ALIGN(buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size); |
| buf_spec->cm_header_dw.buf_start = |
| WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); |
| buf_spec->mpred_above.buf_start = |
| WORKBUF_ALIGN(buf_spec->cm_header_dw.buf_start + buf_spec->cm_header_dw.buf_size); |
| #else |
| buf_spec->mpred_above.buf_start = |
| WORKBUF_ALIGN(buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size); |
| #endif |
| #else |
| buf_spec->mpred_above.buf_start = |
| WORKBUF_ALIGN(buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size); |
| #endif |
| #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 (!hw) |
| return; |
| |
| if (!vdec_secure(hw_to_vdec(hw))) { |
| 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("seg_map.buf_start :%x\n", |
| buf_spec->seg_map.buf_start); |
| pr_info("daala_top.buf_start :%x\n", |
| buf_spec->daala_top.buf_start); |
| pr_info("swap_buf.buf_start :%x\n", |
| buf_spec->swap_buf.buf_start); |
| pr_info("cdf_buf.buf_start :%x\n", |
| buf_spec->cdf_buf.buf_start); |
| pr_info("gmc_buf.buf_start :%x\n", |
| buf_spec->gmc_buf.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("cdef_data.buf_start :%x\n", |
| buf_spec->cdef_data.buf_start); |
| pr_info("ups_data.buf_start :%x\n", |
| buf_spec->ups_data.buf_start); |
| |
| #ifdef AOM_AV1_MMU |
| pr_info("mmu_vbh.buf_start :%x\n", |
| buf_spec->mmu_vbh.buf_start); |
| #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 & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0) { |
| pr_info("rpm.buf_start :%x\n", |
| buf_spec->rpm.buf_start); |
| } |
| } |
| } |
| |
| static void uninit_mmu_buffers(struct AV1HW_s *hw) |
| { |
| #ifndef MV_USE_FIXED_BUF |
| dealloc_mv_bufs(hw); |
| #endif |
| if (hw->mmu_box) |
| decoder_mmu_box_free(hw->mmu_box); |
| hw->mmu_box = NULL; |
| |
| #ifdef AOM_AV1_MMU_DW |
| if (hw->mmu_box_dw) |
| decoder_mmu_box_free(hw->mmu_box_dw); |
| hw->mmu_box_dw = NULL; |
| #endif |
| if (hw->bmmu_box) |
| decoder_bmmu_box_free(hw->bmmu_box); |
| hw->bmmu_box = NULL; |
| } |
| |
| static int calc_luc_quantity(int lcu_size, u32 w, u32 h) |
| { |
| 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 av1_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 av1_get_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; |
| } |
| |
| static void av1_put_video_frame(void *vdec_ctx, struct vframe_s *vf) |
| { |
| vav1_vf_put(vf, vdec_ctx); |
| } |
| |
| static void av1_get_video_frame(void *vdec_ctx, struct vframe_s **vf) |
| { |
| *vf = vav1_vf_get(vdec_ctx); |
| } |
| |
| static struct task_ops_s task_dec_ops = { |
| .type = TASK_TYPE_DEC, |
| .get_vframe = av1_get_video_frame, |
| .put_vframe = av1_put_video_frame, |
| }; |
| |
| static int v4l_alloc_and_config_pic(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic) |
| { |
| int ret = -1; |
| int i = pic->index; |
| int dw_mode = get_double_write_mode_init(hw); |
| int lcu_total = calc_luc_quantity(hw->current_lcu_size, |
| hw->frame_width, hw->frame_height); |
| #ifdef MV_USE_FIXED_BUF |
| u32 mpred_mv_end = hw->work_space_buf->mpred_mv.buf_start + |
| hw->work_space_buf->mpred_mv.buf_size; |
| //#ifdef USE_DYNAMIC_MV_BUFFER |
| // int32_t MV_MEM_UNIT = (lcu_size == 128) ? (19*4*16) : (19*16); |
| // int32_t mv_buffer_size = (lcu_total*MV_MEM_UNIT); |
| //#else |
| int32_t mv_buffer_size = hw->max_one_mv_buffer_size; |
| //#endif |
| #endif |
| struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)hw->v4l2_ctx; |
| struct vdec_v4l2_buffer *fb = NULL; |
| |
| if (i < 0) |
| return ret; |
| |
| ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); |
| if (ret < 0) { |
| av1_print(hw, 0, "[%d] AV1 get buffer fail.\n", ctx->id); |
| return ret; |
| } |
| |
| fb->task->attach(fb->task, &task_dec_ops, hw); |
| fb->status = FB_ST_DECODER; |
| |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(hw, fb); |
| |
| hw->m_BUF[i].header_addr = ibuf->header_addr; |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| pr_info("MMU header_adr %d: %ld\n", |
| i, hw->m_BUF[i].header_addr); |
| } |
| } |
| |
| if (get_double_write_mode(hw) & 0x20) { |
| struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(hw, fb); |
| |
| hw->m_BUF[i].header_dw_addr = ibuf->header_dw_addr; |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| pr_info("MMU header_adr %d: %ld\n", |
| i, hw->m_BUF[i].header_addr); |
| } |
| } |
| pic->repeat_pic = NULL; |
| pic->repeat_count = 0; |
| #ifdef MV_USE_FIXED_BUF |
| if ((hw->work_space_buf->mpred_mv.buf_start + |
| ((i + 1) * mv_buffer_size)) |
| <= mpred_mv_end) { |
| #endif |
| hw->m_BUF[i].v4l_ref_buf_addr = (ulong)fb; |
| pic->cma_alloc_addr = fb->m.mem[0].addr; |
| if (fb->num_planes == 1) { |
| hw->m_BUF[i].start_adr = fb->m.mem[0].addr; |
| hw->m_BUF[i].luma_size = fb->m.mem[0].offset; |
| hw->m_BUF[i].size = fb->m.mem[0].size; |
| fb->m.mem[0].bytes_used = fb->m.mem[0].size; |
| pic->dw_y_adr = hw->m_BUF[i].start_adr; |
| pic->dw_u_v_adr = pic->dw_y_adr + hw->m_BUF[i].luma_size; |
| } else if (fb->num_planes == 2) { |
| hw->m_BUF[i].start_adr = fb->m.mem[0].addr; |
| hw->m_BUF[i].size = fb->m.mem[0].size; |
| hw->m_BUF[i].chroma_addr = fb->m.mem[1].addr; |
| hw->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 = hw->m_BUF[i].start_adr; |
| pic->dw_u_v_adr = hw->m_BUF[i].chroma_addr; |
| } |
| |
| /* config frame buffer */ |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| pic->header_adr = hw->m_BUF[i].header_addr; |
| } |
| |
| if (get_double_write_mode(hw) & 0x20) { |
| pic->header_dw_adr = hw->m_BUF[i].header_dw_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 = |
| hw->work_space_buf->mpred_mv.buf_start + |
| (pic->index * mv_buffer_size); |
| #endif |
| |
| #ifdef DUMP_FILMGRAIN |
| if (pic->index == fg_dump_index) { |
| pic->fgs_table_adr = hw->fg_phy_addr; |
| pr_info("set buffer %d film grain table 0x%x\n", |
| pic->index, pic->fgs_table_adr); |
| } else { |
| #endif |
| if (hw->assit_task.use_sfgs) { |
| pic->sfgs_table_phy = hw->fg_phy_addr + (pic->index * FGS_TABLE_SIZE); |
| pic->sfgs_table_ptr = hw->fg_ptr + (pic->index * FGS_TABLE_SIZE); |
| } |
| pic->fgs_table_adr = hw->work_space_buf->fgs_table.buf_start + |
| (pic->index * FGS_TABLE_SIZE); |
| } |
| |
| 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 %d\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 AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| int ret = -1; |
| int i; |
| int pic_width = hw->init_pic_w; |
| int pic_height = hw->init_pic_h; |
| //int lcu_size = ((params->p.seq_flags >> 6) & 0x1) ? 128 : 64; |
| int lcu_size = hw->current_lcu_size; |
| |
| 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 = hw->work_space_buf->mpred_mv.buf_start + |
| hw->work_space_buf->mpred_mv.buf_size; |
| //#ifdef USE_DYNAMIC_MV_BUFFER |
| // int32_t MV_MEM_UNIT = (lcu_size == 128) ? (19*4*16) : (19*16); |
| // int32_t mv_buffer_size = (lcu_total*MV_MEM_UNIT); |
| //#else |
| int32_t mv_buffer_size = hw->max_one_mv_buffer_size; |
| //#endif |
| |
| #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(hw); |
| |
| hw->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 ((!hw->mmu_enable) && ((dw_mode & 0x10) == 0)) |
| buf_size += (mc_buffer_size_h << 16); |
| |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| if (hw->mmu_enable) { |
| pic_config->header_adr = |
| hw->work_space_buf->cm_header.buf_start + |
| (pic_config->index * vav1_mmu_compress_header_size(hw)); |
| |
| #ifdef AOM_AV1_MMU_DW |
| if (hw->dw_mmu_enable) { |
| pic_config->header_dw_adr = |
| hw->work_space_buf->cm_header_dw.buf_start + |
| (pic_config->index * vav1_mmu_compress_header_size(hw)); |
| |
| } |
| #endif |
| } |
| |
| #else |
| /*!USE_SPEC_BUF_FOR_MMU_HEAD*/ |
| if (hw->mmu_enable) { |
| pic_config->header_adr = decoder_bmmu_box_get_phy_addr( |
| hw->bmmu_box, HEADER_BUFFER_IDX(pic_config->index)); |
| |
| #ifdef AOM_AV1_MMU_DW |
| if (hw->dw_mmu_enable) { |
| pic_config->header_dw_adr = decoder_bmmu_box_get_phy_addr( |
| hw->bmmu_box, DW_HEADER_BUFFER_IDX(pic_config->index)); |
| |
| } |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| pr_info("MMU dw header_adr (%d, %d) %d: %d\n", |
| hw->dw_mmu_enable, |
| DW_HEADER_BUFFER_IDX(pic_config->index), |
| pic_config->index, |
| pic_config->header_dw_adr); |
| } |
| #endif |
| |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| pr_info("MMU header_adr %d: %d\n", |
| pic_config->index, pic_config->header_adr); |
| } |
| } |
| #endif |
| |
| i = pic_config->index; |
| #ifdef MV_USE_FIXED_BUF |
| if ((hw->work_space_buf->mpred_mv.buf_start + |
| ((i + 1) * mv_buffer_size)) |
| <= mpred_mv_end |
| ) { |
| #endif |
| if (buf_size > 0) { |
| ret = decoder_bmmu_box_alloc_buf_phy(hw->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 (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 = |
| hw->work_space_buf->mpred_mv.buf_start + |
| (pic_config->index * mv_buffer_size); |
| #endif |
| #ifdef DUMP_FILMGRAIN |
| if (pic_config->index == fg_dump_index) { |
| pic_config->fgs_table_adr = hw->fg_phy_addr; |
| pr_info("set buffer %d film grain table 0x%x\n", |
| pic_config->index, pic_config->fgs_table_adr); |
| } else { |
| #endif |
| if (hw->assit_task.use_sfgs) { |
| pic_config->sfgs_table_phy = hw->fg_phy_addr + (pic_config->index * FGS_TABLE_SIZE); |
| pic_config->sfgs_table_ptr = hw->fg_ptr + (pic_config->index * FGS_TABLE_SIZE); |
| } |
| pic_config->fgs_table_adr = |
| hw->work_space_buf->fgs_table.buf_start + |
| (pic_config->index * FGS_TABLE_SIZE); |
| } |
| |
| 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 %d\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; |
| } |
| |
| #ifndef USE_SPEC_BUF_FOR_MMU_HEAD |
| static int vav1_mmu_compress_header_size(struct AV1HW_s *hw) |
| { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
| IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) |
| return (MMU_COMPRESS_HEADER_SIZE_8K); |
| |
| if (IS_4K_SIZE(hw->max_pic_w, hw->max_pic_h)) |
| return MMU_COMPRESS_HEADER_SIZE_4K; |
| |
| return (MMU_COMPRESS_HEADER_SIZE_1080P); |
| } |
| #endif |
| /*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/ |
| static int vav1_frame_mmu_map_size(struct AV1HW_s *hw) |
| { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
| IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) |
| return (MAX_FRAME_8K_NUM * 4); |
| |
| return (MAX_FRAME_4K_NUM * 4); |
| } |
| |
| #ifdef AOM_AV1_MMU_DW |
| static int vaom_dw_frame_mmu_map_size(struct AV1HW_s *hw) |
| { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
| IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) |
| return (MAX_FRAME_8K_NUM * 4); |
| |
| return (MAX_FRAME_4K_NUM * 4); |
| } |
| #endif |
| |
| static void init_pic_list(struct AV1HW_s *hw) |
| { |
| int i; |
| struct AV1_Common_s *cm = &hw->common; |
| struct PIC_BUFFER_CONFIG_s *pic_config; |
| struct vdec_s *vdec = hw_to_vdec(hw); |
| |
| #ifndef USE_SPEC_BUF_FOR_MMU_HEAD |
| u32 header_size; |
| |
| if (!hw->is_used_v4l && (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| header_size = vav1_mmu_compress_header_size(hw); |
| /*alloc AV1 compress header first*/ |
| for (i = 0; i < hw->used_buf_num; i++) { |
| unsigned long buf_addr; |
| if (decoder_bmmu_box_alloc_buf_phy |
| (hw->bmmu_box, |
| HEADER_BUFFER_IDX(i), header_size, |
| DRIVER_HEADER_NAME, |
| &buf_addr) < 0) { |
| av1_print(hw, 0, "%s malloc compress header failed %d\n", |
| DRIVER_HEADER_NAME, i); |
| hw->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; |
| return; |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (hw->dw_mmu_enable) { |
| if (decoder_bmmu_box_alloc_buf_phy |
| (hw->bmmu_box, |
| DW_HEADER_BUFFER_IDX(i), header_size, |
| DRIVER_HEADER_NAME, |
| &buf_addr) < 0) { |
| av1_print(hw, 0, "%s malloc compress dw header failed %d\n", |
| DRIVER_HEADER_NAME, i); |
| hw->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; |
| return; |
| } |
| } |
| #endif |
| } |
| } |
| #endif |
| for (i = 0; i < hw->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 = hw->init_pic_w; |
| pic_config->y_crop_height = hw->init_pic_h; |
| pic_config->double_write_mode = get_double_write_mode(hw); |
| hw->buffer_wrap[i] = i; |
| |
| if (!hw->is_used_v4l) { |
| if (config_pic(hw, pic_config) < 0) { |
| if (debug) |
| av1_print(hw, 0, "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(hw, pic_config); |
| } |
| } |
| } |
| for (; i < hw->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; |
| hw->buffer_wrap[i] = i; |
| if (vdec->parallel_dec == 1) { |
| pic_config->y_canvas_index = -1; |
| pic_config->uv_canvas_index = -1; |
| } |
| } |
| av1_print(hw, AV1_DEBUG_BUFMGR, "%s ok, used_buf_num = %d\n", |
| __func__, hw->used_buf_num); |
| |
| } |
| |
| static void init_pic_list_hw(struct AV1HW_s *hw) |
| { |
| int i; |
| struct AV1_Common_s *cm = &hw->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 < hw->used_buf_num; i++) { |
| pic_config = &cm->buffer_pool->frame_bufs[i].buf; |
| if (pic_config->index < 0) |
| break; |
| |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| 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->dw_u_v_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); |
| |
| #ifdef CHANGE_REMOVED |
| /*Zero out canvas registers in IPP -- avoid simulation X*/ |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, |
| (0 << 8) | (0 << 1) | 1); |
| #else |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, |
| (1 << 8) | (0 << 1) | 1); |
| #endif |
| for (i = 0; i < 32; i++) |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); |
| } |
| |
| |
| static void dump_pic_list(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->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; |
| av1_print(hw, 0, |
| "Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d repeat_count %d dec_idx %d slice_type %d w/h %d/%d adr%ld\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->repeat_count, |
| pic_config->decode_idx, |
| pic_config->slice_type, |
| pic_config->y_crop_width, |
| pic_config->y_crop_height, |
| pic_config->cma_alloc_addr |
| ); |
| } |
| return; |
| } |
| |
| void av1_release_buf(AV1Decoder *pbi, RefCntBuffer *const buf) |
| { |
| |
| #if 0 |
| //def CHANGE_DONE |
| struct AV1HW_s *hw = (struct AV1HW_s *)(pbi->private_data); |
| if (!hw->mmu_enable) |
| return; |
| //release_buffer_4k(&av1_mmumgr_m, buf->buf.index); |
| decoder_mmu_box_free_idx(hw->mmu_box, buf->buf.index); |
| #ifdef AOM_AV1_MMU_DW |
| //release_buffer_4k(&av1_mmumgr_dw, buf->buf.index); |
| decoder_mmu_box_free_idx(hw->mmu_box_dw, buf->buf.index); |
| #endif |
| |
| #endif |
| } |
| |
| void av1_release_bufs(struct AV1HW_s *hw) |
| { |
| AV1_COMMON *cm = &hw->common; |
| RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; |
| int i; |
| |
| for (i = 0; i < FRAME_BUFFERS; ++i) { |
| if (frame_bufs[i].buf.vf_ref == 0 && |
| frame_bufs[i].ref_count == 0 && |
| frame_bufs[i].buf.index >= 0) { |
| if (frame_bufs[i].buf.aux_data_buf) |
| release_aux_data(hw, &frame_bufs[i].buf); |
| } |
| } |
| } |
| |
| #ifdef DEBUG_CMD |
| static void d_fill_zero(struct AV1HW_s *hw, unsigned int phyadr, int size) |
| { |
| WRITE_VREG(HEVC_DBG_LOG_ADR, phyadr); |
| WRITE_VREG(DEBUG_REG1, |
| 0x20000000 | size); |
| debug_cmd_wait_count = 0; |
| debug_cmd_wait_type = 1; |
| while ((READ_VREG(DEBUG_REG1) & 0x1) == 0 |
| && debug_cmd_wait_count < 0x7fffffff) { |
| debug_cmd_wait_count++; |
| } |
| |
| WRITE_VREG(DEBUG_REG1, 0); |
| debug_cmd_wait_type = 0; |
| } |
| |
| static void d_dump(struct AV1HW_s *hw, unsigned int phyadr, int size, |
| struct file *fp, loff_t *wr_off) |
| { |
| |
| int jj; |
| unsigned char *data = (unsigned char *) |
| (hw->ucode_log_addr); |
| WRITE_VREG(HEVC_DBG_LOG_ADR, hw->ucode_log_phy_addr); |
| |
| WRITE_VREG(HEVC_D_ADR, phyadr); |
| WRITE_VREG(DEBUG_REG1, |
| 0x10000000 | size); |
| |
| debug_cmd_wait_count = 0; |
| debug_cmd_wait_type = 3; |
| while ((READ_VREG(DEBUG_REG1) & 0x1) == 0 |
| && debug_cmd_wait_count < 0x7fffffff) { |
| debug_cmd_wait_count++; |
| } |
| |
| if (fp) { |
| vfs_write(fp, data, |
| size, wr_off); |
| |
| } else { |
| for (jj = 0; jj < size; jj++) { |
| if ((jj & 0xf) == 0) |
| av1_print(hw, 0, |
| "%06x:", jj); |
| av1_print_cont(hw, 0, |
| "%02x ", data[jj]); |
| if (((jj + 1) & 0xf) == 0) |
| av1_print_cont(hw, 0, |
| "\n"); |
| } |
| av1_print(hw, 0, "\n"); |
| } |
| |
| WRITE_VREG(DEBUG_REG1, 0); |
| debug_cmd_wait_type = 0; |
| |
| } |
| |
| static void mv_buffer_fill_zero(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| pr_info("fill dummy data pic index %d colocate addreses %x size %x\n", |
| pic_config->index, pic_config->mpred_mv_wr_start_addr, |
| hw->m_mv_BUF[pic_config->mv_buf_index].size); |
| d_fill_zero(hw, pic_config->mpred_mv_wr_start_addr, |
| hw->m_mv_BUF[pic_config->mv_buf_index].size); |
| } |
| |
| static void dump_mv_buffer(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| |
| unsigned int adr, size; |
| unsigned int adr_end = pic_config->mpred_mv_wr_start_addr + |
| hw->m_mv_BUF[pic_config->mv_buf_index].size; |
| mm_segment_t old_fs; |
| loff_t off = 0; |
| int mode = O_CREAT | O_WRONLY | O_TRUNC; |
| char file[64]; |
| struct file *fp; |
| sprintf(&file[0], "/data/tmp/colocate%d", hw->frame_count-1); |
| fp = filp_open(file, mode, 0666); |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| for (adr = pic_config->mpred_mv_wr_start_addr; |
| adr < adr_end; |
| adr += UCODE_LOG_BUF_SIZE) { |
| size = UCODE_LOG_BUF_SIZE; |
| if (size > (adr_end - adr)) |
| size = adr_end - adr; |
| pr_info("dump pic index %d colocate addreses %x size %x\n", |
| pic_config->index, adr, size); |
| d_dump(hw, adr, size, fp, &off); |
| } |
| set_fs(old_fs); |
| vfs_fsync(fp, 0); |
| |
| filp_close(fp, current->files); |
| } |
| |
| #endif |
| |
| static int config_pic_size(struct AV1HW_s *hw, unsigned short bit_depth) |
| { |
| uint32_t data32; |
| struct AV1_Common_s *cm = &hw->common; |
| struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf; |
| int losless_comp_header_size, losless_comp_body_size; |
| #ifdef AOM_AV1_MMU_DW |
| int losless_comp_header_size_dw, losless_comp_body_size_dw; |
| #endif |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " #### config_pic_size ####, bit_depth = %d\n", bit_depth); |
| |
| 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(hw); |
| |
| /* use fixed maximum size // 128x128/4/4*3-bits = 384 Bytes |
| seg_map_size = |
| ((frame_width + 127) >> 7) * ((frame_height + 127) >> 7) * 384 ; |
| */ |
| WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, |
| (frame_height << 16) | frame_width); |
| #ifdef DUAL_DECODE |
| #else |
| WRITE_VREG(HEVC_ASSIST_PIC_SIZE_FB_READ, |
| (frame_height << 16) | frame_width); |
| #endif |
| #ifdef AOM_AV1_MMU |
| |
| //alloc_mmu(&av1_mmumgr_m, cm->cur_frame->buf.index, frame_width, frame_height, bit_depth); |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| |
| //alloc_mmu(&av1_mmumgr_dw, cm->cur_frame->buf.index, frame_width, frame_height, bit_depth); |
| losless_comp_header_size_dw = |
| compute_losless_comp_header_size_dw(frame_width, frame_height); |
| losless_comp_body_size_dw = |
| compute_losless_comp_body_size_dw(frame_width, frame_height, |
| (bit_depth == AOM_BITS_10)); |
| #endif |
| |
| losless_comp_header_size = |
| compute_losless_comp_header_size |
| (frame_width, frame_height); |
| losless_comp_body_size = |
| compute_losless_comp_body_size(frame_width, |
| frame_height, (bit_depth == AOM_BITS_10)); |
| |
| cur_pic_config->comp_body_size = losless_comp_body_size; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s: width %d height %d depth %d head_size 0x%x body_size 0x%x\r\n", |
| __func__, frame_width, frame_height, bit_depth, |
| losless_comp_header_size, losless_comp_body_size); |
| #ifdef LOSLESS_COMPRESS_MODE |
| data32 = READ_VREG(HEVC_SAO_CTRL5); |
| if (bit_depth == AOM_BITS_10) |
| data32 &= ~(1<<9); |
| else |
| data32 |= (1<<9); |
| |
| WRITE_VREG(HEVC_SAO_CTRL5, data32); |
| |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,(0x1<< 4)); // bit[4] : paged_mem_mode |
| } else { |
| if (bit_depth == AOM_BITS_10) |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3)); // bit[3] smem mdoe |
| else |
| WRITE_VREG(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_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(hw) & 0x10) |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); |
| |
| #else |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,0x1 << 31); |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size_dw); |
| WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size_dw); |
| WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size_dw); |
| } |
| #endif |
| return 0; |
| |
| } |
| |
| static int config_mc_buffer(struct AV1HW_s *hw, unsigned short bit_depth, unsigned char inter_flag) |
| { |
| int32_t i; |
| AV1_COMMON *cm = &hw->common; |
| PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf; |
| uint8_t scale_enable = 0; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " #### config_mc_buffer %s ####\n", |
| inter_flag ? "inter" : "intra"); |
| |
| #ifdef DEBUG_PRINT |
| if (debug&AOM_AV1_DEBUG_BUFMGR) |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "config_mc_buffer entered .....\n"); |
| #endif |
| |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, |
| (0 << 8) | (0<<1) | 1); |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, |
| (cur_pic_config->order_hint<<24) | |
| (cur_pic_config->mc_canvas_u_v<<16) | |
| (cur_pic_config->mc_canvas_u_v<<8)| |
| cur_pic_config->mc_canvas_y); |
| for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| PIC_BUFFER_CONFIG *pic_config; //cm->frame_refs[i].buf; |
| if (inter_flag) |
| pic_config = av1_get_ref_frame_spec_buf(cm, i); |
| else |
| pic_config = cur_pic_config; |
| if (pic_config) { |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, |
| (pic_config->order_hint<<24) | |
| (pic_config->mc_canvas_u_v<<16) | |
| (pic_config->mc_canvas_u_v<<8) | |
| pic_config->mc_canvas_y); |
| if (inter_flag) |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "refid 0x%x mc_canvas_u_v 0x%x mc_canvas_y 0x%x order_hint 0x%x\n", |
| i, pic_config->mc_canvas_u_v, |
| pic_config->mc_canvas_y, pic_config->order_hint); |
| } else { |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); |
| } |
| } |
| |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, |
| (16 << 8) | (0 << 1) | 1); |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, |
| (cur_pic_config->order_hint << 24) | |
| (cur_pic_config->mc_canvas_u_v << 16) | |
| (cur_pic_config->mc_canvas_u_v << 8) | |
| cur_pic_config->mc_canvas_y); |
| for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| PIC_BUFFER_CONFIG *pic_config; |
| if (inter_flag) |
| pic_config = av1_get_ref_frame_spec_buf(cm, i); |
| else |
| pic_config = cur_pic_config; |
| |
| if (pic_config) { |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, |
| (pic_config->order_hint << 24)| |
| (pic_config->mc_canvas_u_v << 16) | |
| (pic_config->mc_canvas_u_v << 8) | |
| pic_config->mc_canvas_y); |
| } else { |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); |
| } |
| } |
| |
| WRITE_VREG(AV1D_MPP_REFINFO_TBL_ACCCONFIG, |
| (0x1 << 2) | (0x0 <<3)); // auto_inc start index:0 field:0 |
| for (i = 0; i <= ALTREF_FRAME; i++) { |
| int32_t ref_pic_body_size; |
| struct scale_factors * sf = NULL; |
| PIC_BUFFER_CONFIG *pic_config; |
| |
| if (inter_flag && i >= LAST_FRAME) |
| pic_config = av1_get_ref_frame_spec_buf(cm, i); |
| else |
| pic_config = cur_pic_config; |
| |
| if (pic_config) { |
| ref_pic_body_size = |
| compute_losless_comp_body_size(pic_config->y_crop_width, |
| pic_config->y_crop_height, (bit_depth == AOM_BITS_10)); |
| |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, pic_config->y_crop_width); |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, pic_config->y_crop_height); |
| if (inter_flag && i >= LAST_FRAME) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "refid %d: ref width/height(%d,%d), cur width/height(%d,%d) ref_pic_body_size 0x%x\n", |
| i, pic_config->y_crop_width, pic_config->y_crop_height, |
| cur_pic_config->y_crop_width, cur_pic_config->y_crop_height, |
| ref_pic_body_size); |
| } |
| } else { |
| ref_pic_body_size = 0; |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0); |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0); |
| } |
| |
| if (inter_flag && i >= LAST_FRAME) |
| sf = av1_get_ref_scale_factors(cm, i); |
| |
| if ((sf != NULL) && av1_is_scaled(sf)) { |
| scale_enable |= (1 << i); |
| } |
| |
| if (sf) { |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, sf->x_scale_fp); |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, sf->y_scale_fp); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "x_scale_fp %d, y_scale_fp %d\n", |
| sf->x_scale_fp, sf->y_scale_fp); |
| } else { |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, REF_NO_SCALE); //1<<14 |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, REF_NO_SCALE); |
| } |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0); |
| } else |
| WRITE_VREG(AV1D_MPP_REFINFO_DATA, ref_pic_body_size >> 5); |
| |
| } |
| WRITE_VREG(AV1D_MPP_REF_SCALE_ENBL, scale_enable); |
| WRITE_VREG(PARSER_REF_SCALE_ENBL, scale_enable); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "WRITE_VREG(PARSER_REF_SCALE_ENBL, 0x%x)\n", |
| scale_enable); |
| return 0; |
| } |
| |
| static void clear_mpred_hw(struct AV1HW_s *hw) |
| { |
| unsigned int data32; |
| |
| data32 = READ_VREG(HEVC_MPRED_CTRL4); |
| data32 &= (~(1 << 6)); |
| WRITE_VREG(HEVC_MPRED_CTRL4, data32); |
| } |
| |
| static void config_mpred_hw(struct AV1HW_s *hw, unsigned char inter_flag) |
| { |
| AV1_COMMON *cm = &hw->common; |
| PIC_BUFFER_CONFIG *cur_pic_config = &cm->cur_frame->buf; |
| //PIC_BUFFER_CONFIG *last_frame_pic_config = NULL; |
| int i, j, pos, reg_i; |
| int mv_cal_tpl_count = 0; |
| unsigned int mv_ref_id[MFMV_STACK_SIZE] = {0, 0, 0}; |
| unsigned ref_offset_reg[] = { |
| HEVC_MPRED_L0_REF06_POC, |
| HEVC_MPRED_L0_REF07_POC, |
| HEVC_MPRED_L0_REF08_POC, |
| HEVC_MPRED_L0_REF09_POC, |
| HEVC_MPRED_L0_REF10_POC, |
| HEVC_MPRED_L0_REF11_POC, |
| }; |
| unsigned ref_buf_reg[] = { |
| HEVC_MPRED_L0_REF03_POC, |
| HEVC_MPRED_L0_REF04_POC, |
| HEVC_MPRED_L0_REF05_POC |
| }; |
| unsigned ref_offset_val[6] = |
| {0, 0, 0, 0, 0, 0}; |
| unsigned ref_buf_val[3] = {0, 0, 0}; |
| |
| uint32_t data32; |
| int32_t mpred_curr_lcu_x; |
| int32_t mpred_curr_lcu_y; |
| //int32_t mpred_mv_rd_end_addr; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " #### config_mpred_hw ####\n"); |
| |
| /*if (cm->prev_frame) |
| last_frame_pic_config = &cm->prev_frame->buf; |
| mpred_mv_rd_end_addr = last_frame_pic_config->mpred_mv_wr_start_addr |
| + (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; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "cur pic index %d\n", cur_pic_config->index); |
| /*printk("cur pic index %d col pic index %d\n", |
| cur_pic_config->index, last_frame_pic_config->index);*/ |
| |
| //WRITE_VREG(HEVC_MPRED_CTRL3,0x24122412); |
| #ifdef CO_MV_COMPRESS |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { |
| WRITE_VREG(HEVC_MPRED_CTRL3,0x10151015); // 'd10, 'd21 for AV1 |
| } else { |
| WRITE_VREG(HEVC_MPRED_CTRL3,0x13151315); // 'd19, 'd21 for AV1 |
| } |
| #else |
| WRITE_VREG(HEVC_MPRED_CTRL3,0x13151315); // 'd19, 'd21 for AV1 |
| #endif |
| WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, |
| hw->pbi->work_space_buf->mpred_above.buf_start); |
| |
| #if 0 |
| data32 = READ_VREG(HEVC_MPRED_CTRL4); |
| data32 &= (~(1<<6)); |
| data32 |= (cm->use_prev_frame_mvs << 6); |
| WRITE_VREG(HEVC_MPRED_CTRL4, data32); |
| #endif |
| if (inter_flag) { |
| /* config sign_bias */ |
| //data32 = (cm->cur_frame_force_integer_mv & 0x1) << 9; |
| data32 = READ_VREG(HEVC_MPRED_CTRL4); |
| data32 &= (~(0xff << 12)); |
| //for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| /* HEVC_MPRED_CTRL4[bit 12] is for cm->ref_frame_sign_bias[0] |
| instead of cm->ref_frame_sign_bias[LAST_FRAME] */ |
| for (i = 0; i <= ALTREF_FRAME; i++) { |
| data32 |= ((cm->ref_frame_sign_bias[i] & 0x1) << (12 + i)); |
| } |
| WRITE_VREG(HEVC_MPRED_CTRL4, data32); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "WRITE_VREG(HEVC_MPRED_CTRL4, 0x%x)\n", data32); |
| } |
| #if 1 |
| data32 = ((cm->seq_params.order_hint_info.enable_order_hint << 27) | |
| (cm->seq_params.order_hint_info.order_hint_bits_minus_1 << 24) | |
| (cm->cur_frame->order_hint << 16 )); |
| #ifdef CO_MV_COMPRESS |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { |
| data32 |= (0x10 << 8) | (0x10 << 0); |
| } else { |
| data32 |= (0x13 << 8) | (0x13 << 0); |
| } |
| #else |
| data32 |= (0x13 << 8) | (0x13 << 0); |
| #endif |
| |
| #else |
| data32 = READ_VREG(HEVC_MPRED_L0_REF00_POC); |
| data32 &= (~(0xff << 16)); |
| data32 |= (cm->cur_frame->order_hint & 0xff); |
| data32 &= (~(1 << 27)); |
| data32 |= (cm->seq_params.order_hint_info.enable_order_hint << 27); |
| #endif |
| WRITE_VREG(HEVC_MPRED_L0_REF00_POC, data32); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "WRITE_VREG(HEVC_MPRED_L0_REF00_POC, 0x%x)\n", data32); |
| |
| if (inter_flag) { |
| /* config ref_buf id and order hint */ |
| data32 = 0; |
| pos = 25; |
| reg_i = 0; |
| for (i = ALTREF_FRAME; i >= LAST_FRAME; i--) { |
| PIC_BUFFER_CONFIG *pic_config = |
| av1_get_ref_frame_spec_buf(cm, i); |
| if (pic_config) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "pic_config for %d th ref: index %d, reg[%d] pos %d\n", |
| i, pic_config->index, reg_i, pos); |
| data32 |= ((pic_config->index < 0)? 0 : pic_config->index) << pos; |
| } else |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "pic_config is null for %d th ref\n", i); |
| if (pos == 0) { |
| //WRITE_VREG(ref_buf_reg[reg_i], data32); |
| ref_buf_val[reg_i] = data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n", |
| reg_i, ref_buf_reg[reg_i], data32); |
| reg_i++; |
| data32 = 0; |
| pos = 24; //for P_HEVC_MPRED_L0_REF04_POC |
| } else { |
| if (pos == 24) |
| pos -= 8; //for P_HEVC_MPRED_L0_REF04_POC |
| else |
| pos -= 5; //for P_HEVC_MPRED_L0_REF03_POC |
| } |
| } |
| for (i = ALTREF_FRAME; i >= LAST_FRAME; i--) { |
| PIC_BUFFER_CONFIG *pic_config = |
| av1_get_ref_frame_spec_buf(cm, i); |
| if (pic_config) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "pic_config for %d th ref: order_hint %d, reg[%d] pos %d\n", |
| i, pic_config->order_hint, reg_i, pos); |
| data32 |= ((pic_config->index < 0)? 0 : pic_config->order_hint) << pos; |
| } else |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "pic_config is null for %d th ref\n", i); |
| if (pos == 0) { |
| //WRITE_VREG(ref_buf_reg[reg_i], data32); |
| ref_buf_val[reg_i] = data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n", |
| reg_i, ref_buf_reg[reg_i], data32); |
| reg_i++; |
| data32 = 0; |
| pos = 24; |
| } else |
| pos -= 8; |
| } |
| if (pos != 24) { |
| //WRITE_VREG(ref_buf_reg[reg_i], data32); |
| ref_buf_val[reg_i] = data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n", |
| reg_i, ref_buf_reg[reg_i], data32); |
| } |
| /* config ref_offset */ |
| data32 = 0; |
| pos = 24; |
| mv_cal_tpl_count = 0; |
| reg_i = 0; |
| for (i = 0; i < cm->mv_ref_id_index; i++) { |
| if (cm->mv_cal_tpl_mvs[i]) { |
| mv_ref_id[mv_cal_tpl_count] = cm->mv_ref_id[i]; |
| mv_cal_tpl_count++; |
| for (j = LAST_FRAME; j <= ALTREF_FRAME; j++) { |
| /*offset can be negative*/ |
| unsigned char offval = |
| cm->mv_ref_offset[i][j] & 0xff; |
| data32 |= (offval << pos); |
| if (pos == 0) { |
| //WRITE_VREG(ref_offset_reg[reg_i], data32); |
| ref_offset_val[reg_i] = data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "ref_offset_reg[%d], WRITE_VREG(0x%x, 0x%x)\n", |
| reg_i, ref_offset_reg[reg_i], data32); |
| reg_i++; |
| data32 = 0; |
| pos = 24; |
| } else |
| pos -= 8; |
| } |
| } |
| } |
| if (pos != 24) { |
| //WRITE_VREG(ref_offset_reg[reg_i], data32); |
| ref_offset_val[reg_i] = data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "ref_offset_reg[%d], WRITE_VREG(0x%x, 0x%x)\n", |
| reg_i, ref_offset_reg[reg_i], data32); |
| } |
| |
| data32 = ref_offset_val[5] | //READ_VREG(HEVC_MPRED_L0_REF11_POC) | |
| mv_cal_tpl_count | (mv_ref_id[0] << 2) | |
| (mv_ref_id[1] << 5) | (mv_ref_id[2] << 8); |
| ref_offset_val[5] = data32; |
| //WRITE_VREG(HEVC_MPRED_L0_REF11_POC, data32); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "WRITE_VREG(HEVC_MPRED_L0_REF11_POC 0x%x, 0x%x)\n", |
| HEVC_MPRED_L0_REF11_POC, data32); |
| } |
| for (i = 0; i < 3; i++) |
| WRITE_VREG(ref_buf_reg[i], ref_buf_val[i]); |
| for (i = 0; i < 6; i++) |
| WRITE_VREG(ref_offset_reg[i], ref_offset_val[i]); |
| |
| 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); |
| |
| if (inter_flag) { |
| for (i = 0; i < mv_cal_tpl_count; i++) { |
| PIC_BUFFER_CONFIG *pic_config = |
| av1_get_ref_frame_spec_buf(cm, mv_ref_id[i]); |
| if (pic_config == NULL) |
| continue; |
| if (i == 0) { |
| WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR, |
| pic_config->mpred_mv_wr_start_addr); |
| WRITE_VREG(HEVC_MPRED_MV_RPTR, |
| pic_config->mpred_mv_wr_start_addr); |
| } else if (i == 1) { |
| WRITE_VREG(HEVC_MPRED_L0_REF01_POC, |
| pic_config->mpred_mv_wr_start_addr); |
| WRITE_VREG(HEVC_MPRED_MV_RPTR_1, |
| pic_config->mpred_mv_wr_start_addr); |
| } else if (i == 2) { |
| WRITE_VREG(HEVC_MPRED_L0_REF02_POC, |
| pic_config->mpred_mv_wr_start_addr); |
| WRITE_VREG(HEVC_MPRED_MV_RPTR_2, |
| pic_config->mpred_mv_wr_start_addr); |
| } else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s: mv_ref_id error\n", __func__); |
| } |
| } |
| } |
| data32 = READ_VREG(HEVC_MPRED_CTRL0); |
| data32 &= ~((1 << 10) | (1 << 11)); |
| data32 |= (1 << 10); /*write enable*/ |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "current_frame.frame_type=%d, cur_frame->frame_type=%d, allow_ref_frame_mvs=%d\n", |
| cm->current_frame.frame_type, cm->cur_frame->frame_type, |
| cm->allow_ref_frame_mvs); |
| |
| if (av1_frame_is_inter(&hw->common)) { |
| if (cm->allow_ref_frame_mvs) { |
| data32 |= (1 << 11); /*read enable*/ |
| } |
| } |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "WRITE_VREG(HEVC_MPRED_CTRL0 0x%x, 0x%x)\n", |
| HEVC_MPRED_CTRL0, data32); |
| WRITE_VREG(HEVC_MPRED_CTRL0, data32); |
| /* |
| printk("config_mpred: (%x) wr_start_addr %x from indx %d; |
| (%x) rd_start_addr %x from index %d\n", |
| cur_pic_config, cur_pic_config->mpred_mv_wr_start_addr, cur_pic_config->index, |
| last_frame_pic_config, last_frame_pic_config->mpred_mv_wr_start_addr, last_frame_pic_config->index); |
| 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 AV1HW_s *hw, union param_u *params) |
| { |
| /* |
| !!!!!!!!!!!!!!!!!!!!!!!!!TODO .... !!!!!!!!!!! |
| mem_map_mode, endian, get_double_write_mode |
| */ |
| AV1_COMMON *cm = &hw->common; |
| PIC_BUFFER_CONFIG* pic_config = &cm->cur_frame->buf; |
| uint32_t data32; |
| int32_t lcu_size = |
| ((params->p.seq_flags >> 6) & 0x1) ? 128 : 64; |
| int32_t mc_buffer_size_u_v = |
| pic_config->lcu_total*lcu_size*lcu_size/2; |
| int32_t mc_buffer_size_u_v_h = |
| (mc_buffer_size_u_v + 0xffff)>>16; //64k alignment |
| struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] #### config_sao_hw ####, lcu_size %d\n", lcu_size); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] lcu_total : %d\n", pic_config->lcu_total); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] mc_y_adr : 0x%x\n", pic_config->mc_y_adr); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] mc_u_v_adr : 0x%x\n", pic_config->mc_u_v_adr); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] header_adr : 0x%x\n", pic_config->header_adr); |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] header_dw_adr : 0x%x\n", pic_config->header_dw_adr); |
| #endif |
| data32 = READ_VREG(HEVC_SAO_CTRL9) | (1 << 1); |
| WRITE_VREG(HEVC_SAO_CTRL9, data32); |
| |
| data32 = READ_VREG(HEVC_SAO_CTRL5); |
| data32 |= (0x1 << 14); /* av1 mode */ |
| data32 |= (0xff << 16); /* dw {v1,v0,h1,h0} ctrl_y_cbus */ |
| WRITE_VREG(HEVC_SAO_CTRL5, data32); |
| |
| WRITE_VREG(HEVC_SAO_CTRL0, |
| lcu_size == 128 ? 0x7 : 0x6); /*lcu_size_log2*/ |
| #ifdef LOSLESS_COMPRESS_MODE |
| WRITE_VREG(HEVC_CM_BODY_START_ADDR, pic_config->mc_y_adr); |
| #ifdef AOM_AV1_MMU |
| WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->header_adr); |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, pic_config->header_dw_adr); |
| } |
| #endif |
| #else |
| /*!LOSLESS_COMPRESS_MODE*/ |
| WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->mc_y_adr); |
| #endif |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] sao_body_addr:%x\n", pic_config->mc_y_adr); |
| //printk("[config_sao_hw] sao_header_addr:%x\n", pic_config->mc_y_adr + losless_comp_body_size ); |
| |
| #ifdef VPU_FILMGRAIN_DUMP |
| // Let Microcode to increase |
| // WRITE_VREG(HEVC_FGS_TABLE_START, pic_config->fgs_table_adr); |
| #else |
| WRITE_VREG(HEVC_FGS_TABLE_START, pic_config->fgs_table_adr); |
| #endif |
| WRITE_VREG(HEVC_FGS_TABLE_LENGTH, FGS_TABLE_SIZE * 8); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[config_sao_hw] fgs_table adr:0x%x , length 0x%x bits\n", |
| pic_config->fgs_table_adr, FGS_TABLE_SIZE * 8); |
| |
| data32 = (mc_buffer_size_u_v_h<<16)<<1; |
| //printk("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); |
| |
| #ifndef LOSLESS_COMPRESS_MODE |
| WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->mc_u_v_adr); |
| #else |
| #endif |
| |
| data32 = (mc_buffer_size_u_v_h<<16); |
| WRITE_VREG(HEVC_SAO_C_LENGTH ,data32); |
| |
| #ifndef LOSLESS_COMPRESS_MODE |
| /* multi tile to do... */ |
| WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->mc_y_adr); |
| |
| WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->mc_u_v_adr); |
| #else |
| if (get_double_write_mode(hw) && |
| (get_double_write_mode(hw) & 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 { |
| //WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff); |
| //WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff); |
| } |
| #endif |
| |
| |
| #ifndef AOM_AV1_NV21 |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| } |
| #endif |
| #endif |
| |
| #ifdef AOM_AV1_NV21 |
| #ifdef DOS_PROJECT |
| data32 = READ_VREG(HEVC_SAO_CTRL1); |
| data32 &= (~0x3000); |
| data32 |= (hw->mem_map_mode << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 |
| data32 &= (~0x3); |
| data32 |= 0x1; // [1]:dw_disable [0]:cm_disable |
| WRITE_VREG(HEVC_SAO_CTRL1, data32); |
| |
| data32 = READ_VREG(HEVC_SAO_CTRL5); // [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl |
| data32 &= ~(0xff << 16); // set them all 0 for AOM_AV1_NV21 (no down-scale) |
| WRITE_VREG(HEVC_SAO_CTRL5, data32); |
| |
| data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); |
| data32 &= (~0x30); |
| data32 |= (hw->mem_map_mode << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 |
| WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); |
| #else |
| // m8baby test1902 |
| data32 = READ_VREG(HEVC_SAO_CTRL1); |
| data32 &= (~0x3000); |
| data32 |= (hw->mem_map_mode << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 |
| 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); |
| |
| data32 = READ_VREG(HEVC_SAO_CTRL5); // [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl |
| data32 &= ~(0xff << 16); // set them all 0 for AOM_AV1_NV21 (no down-scale) |
| WRITE_VREG(HEVC_SAO_CTRL5, data32); |
| |
| data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); |
| data32 &= (~0x30); |
| data32 |= (hw->mem_map_mode << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 |
| data32 &= (~0xF); |
| data32 |= 0x8; // Big-Endian per 64-bit |
| WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); |
| #endif |
| #else |
| /*CHANGE_DONE nnn*/ |
| data32 = READ_VREG(HEVC_SAO_CTRL1); |
| data32 &= (~0x3000); |
| data32 |= (hw->mem_map_mode << 12); /* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */ |
| data32 &= (~0xff0); |
| /* data32 |= 0x670; // Big-Endian per 64-bit */ |
| #ifdef AOM_AV1_MMU_DW |
| if ((get_double_write_mode(hw) & 0x20) == 0) |
| data32 |= ((hw->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */ |
| #else |
| data32 |= ((hw->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */ |
| #endif |
| data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ |
| if (get_double_write_mode(hw) == 0) |
| data32 |= 0x2; /*disable double write*/ |
| else if (get_double_write_mode(hw) & 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(hw) == 0) |
| data |= (0x1 << 8); /*enable first write*/ |
| else if (get_double_write_mode(hw) & 0x10) |
| data |= (0x1 << 9); /*double write only*/ |
| else |
| data |= ((0x1 << 8) |(0x1 << 9)); |
| WRITE_VREG(HEVC_DBLK_CFGB, data); |
| } |
| |
| /* swap uv */ |
| if (hw->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 */ |
| } |
| data32 &= (~(3 << 14)); |
| data32 |= (2 << 14); |
| /* |
| * [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(hw) & 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(hw) & 0xf) == 8) { |
| WRITE_VREG(HEVC_SAO_CTRL26, 0xf); |
| data32 |= (0xff << 16); |
| } else if ((get_double_write_mode(hw) & 0xf) == 2 || |
| (get_double_write_mode(hw) & 0xf) == 3) |
| data32 |= (0xff<<16); |
| else if ((get_double_write_mode(hw) & 0xf) == 4 || |
| (get_double_write_mode(hw) & 0xf) == 5) |
| 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 |= (hw->mem_map_mode << 4); |
| data32 &= (~0xf); |
| data32 |= (hw->endian & 0xf); /* valid only when double write only */ |
| |
| /* swap uv */ |
| if (hw->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); |
| /* |
| * [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 |
| |
| } |
| |
| |
| #ifdef AOM_AV1_DBLK_INIT |
| /* |
| * Defines, declarations, sub-functions for av1 de-block loop filter Thr/Lvl table update |
| * - struct segmentation_lf is for loop filter only (removed something) |
| * - function "av1_loop_filter_init" and "av1_loop_filter_frame_init" will be instantiated in C_Entry |
| * - av1_loop_filter_init run once before decoding start |
| * - av1_loop_filter_frame_init run before every frame decoding start |
| * - set video format to AOM_AV1 is in av1_loop_filter_init |
| */ |
| #define MAX_LOOP_FILTER 63 |
| #define MAX_MODE_LF_DELTAS 2 |
| #define MAX_SEGMENTS 8 |
| #define MAX_MB_PLANE 3 |
| |
| typedef enum { |
| SEG_LVL_ALT_Q, // Use alternate Quantizer .... |
| SEG_LVL_ALT_LF_Y_V, // Use alternate loop filter value on y plane vertical |
| SEG_LVL_ALT_LF_Y_H, // Use alternate loop filter value on y plane horizontal |
| SEG_LVL_ALT_LF_U, // Use alternate loop filter value on u plane |
| SEG_LVL_ALT_LF_V, // Use alternate loop filter value on v plane |
| SEG_LVL_REF_FRAME, // Optional Segment reference frame |
| SEG_LVL_SKIP, // Optional Segment (0,0) + skip mode |
| SEG_LVL_GLOBALMV, |
| SEG_LVL_MAX |
| } SEG_LVL_FEATURES; |
| |
| static const SEG_LVL_FEATURES seg_lvl_lf_lut[MAX_MB_PLANE][2] = { |
| { SEG_LVL_ALT_LF_Y_V, SEG_LVL_ALT_LF_Y_H }, |
| { SEG_LVL_ALT_LF_U, SEG_LVL_ALT_LF_U }, |
| { SEG_LVL_ALT_LF_V, SEG_LVL_ALT_LF_V } |
| }; |
| |
| struct segmentation_lf { // for loopfilter only |
| uint8_t enabled; |
| /* |
| SEG_LVL_ALT_LF_Y_V feature_enable: seg_lf_info_y[bit7] |
| SEG_LVL_ALT_LF_Y_V data: seg_lf_info_y[bit0~6] |
| SEG_LVL_ALT_LF_Y_H feature enable: seg_lf_info_y[bit15] |
| SEG_LVL_ALT_LF_Y_H data: seg_lf_info_y[bit8~14] |
| */ |
| uint16_t seg_lf_info_y[8]; |
| /* |
| SEG_LVL_ALT_LF_U feature_enable: seg_lf_info_c[bit7] |
| SEG_LVL_ALT_LF_U data: seg_lf_info_c[bit0~6] |
| SEG_LVL_ALT_LF_V feature enable: seg_lf_info_c[bit15] |
| SEG_LVL_ALT_LF_V data: seg_lf_info_c[bit8~14] |
| */ |
| uint16_t seg_lf_info_c[8]; |
| }; |
| |
| typedef struct { |
| uint8_t mblim; |
| uint8_t lim; |
| uint8_t hev_thr; |
| } loop_filter_thresh; |
| |
| typedef struct loop_filter_info_n_s { |
| loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1]; |
| uint8_t lvl[MAX_MB_PLANE][MAX_SEGMENTS][2][REF_FRAMES][MAX_MODE_LF_DELTAS]; |
| } loop_filter_info_n; |
| |
| struct loopfilter { |
| int32_t filter_level[2]; |
| int32_t filter_level_u; |
| int32_t filter_level_v; |
| |
| int32_t sharpness_level; |
| |
| uint8_t mode_ref_delta_enabled; |
| uint8_t mode_ref_delta_update; |
| |
| // 0 = Intra, Last, Last2+Last3, |
| // GF, BRF, ARF2, ARF |
| int8_t ref_deltas[REF_FRAMES]; |
| |
| // 0 = ZERO_MV, MV |
| int8_t mode_deltas[MAX_MODE_LF_DELTAS]; |
| |
| int32_t combine_vert_horz_lf; |
| |
| int32_t lf_pic_cnt; |
| |
| //#if LOOP_FILTER_BITMASK |
| //LoopFilterMask *lfm; |
| //size_t lfm_num; |
| //int lfm_stride; |
| //LpfSuperblockInfo neighbor_sb_lpf_info; |
| //#endif // LOOP_FILTER_BITMASK |
| }; |
| #ifdef DBG_LPF_DBLK_LVL |
| static int32_t myclamp(int32_t value, int32_t low, int32_t high) { |
| return value < low ? low : (value > high ? high : value); |
| } |
| #endif |
| /*static int8_t extend_sign_7bits(uint8_t value) { |
| return (((value>>6) & 0x1)<<7) | (value&0x7f); |
| }*/ |
| |
| // convert data to int8_t variable |
| // value : signed data (with any bitwidth<8) which is assigned to uint8_t variable as an input |
| // bw : bitwidth of signed data, (from 1 to 7) |
| static int8_t conv2int8 (uint8_t value, uint8_t bw) { |
| if (bw<1 || bw>7) return (int8_t)value; |
| else { |
| const uint8_t data_bits = value & ((1<<bw)-1); |
| const uint8_t sign_bit = (value>>(bw-1)) & 0x1; |
| const uint8_t sign_bit_ext = sign_bit | sign_bit<<1 | sign_bit<<2 | sign_bit<<3 | sign_bit<<4 | sign_bit<<5 | sign_bit<<6 | sign_bit<<7; |
| return (int8_t)((sign_bit_ext<<bw) | data_bits); |
| } |
| } |
| |
| static void av1_update_sharpness(loop_filter_info_n *lfi, int32_t sharpness_lvl) { |
| int32_t 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. |
| int32_t 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 av1_loop_filter_init(loop_filter_info_n *lfi, struct loopfilter *lf) { |
| int32_t i; |
| uint32_t data32; |
| |
| // init limits for given sharpness |
| av1_update_sharpness(lfi, lf->sharpness_level); |
| |
| // Write to register |
| for (i = 0; i < 32; i++) { |
| uint32_t 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 AOM_AV1 |
| data32 = (0x57 << 8) | // 1st/2nd write both enable |
| (0x4 << 0); // aom_av1 video format |
| WRITE_VREG(HEVC_DBLK_CFGB, data32); |
| av1_print2(AOM_DEBUG_HW_MORE, |
| "[DBLK DEBUG] CFGB : 0x%x\n", data32); |
| } |
| |
| // perform this function per frame |
| void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg, |
| loop_filter_info_n *lfi, |
| struct loopfilter *lf, |
| int32_t pic_width) { |
| BuffInfo_t* buf_spec = pbi->work_space_buf; |
| int32_t i; |
| #ifdef DBG_LPF_DBLK_LVL |
| int32_t dir; |
| int32_t filt_lvl[MAX_MB_PLANE], filt_lvl_r[MAX_MB_PLANE]; |
| int32_t plane; |
| int32_t seg_id; |
| #endif |
| // 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 |
| |
| // update limits if sharpness has changed |
| av1_update_sharpness(lfi, lf->sharpness_level); |
| |
| // Write to register |
| for (i = 0; i < 32; i++) { |
| uint32_t 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); |
| } |
| #ifdef DBG_LPF_DBLK_LVL |
| filt_lvl[0] = lf->filter_level[0]; |
| filt_lvl[1] = lf->filter_level_u; |
| filt_lvl[2] = lf->filter_level_v; |
| |
| filt_lvl_r[0] = lf->filter_level[1]; |
| filt_lvl_r[1] = lf->filter_level_u; |
| filt_lvl_r[2] = lf->filter_level_v; |
| |
| #ifdef DBG_LPF_PRINT |
| printk("LF_PRINT: pic_cnt(%d) base_filter_level(%d,%d,%d,%d)\n", |
| lf->lf_pic_cnt, lf->filter_level[0], |
| lf->filter_level[1], lf->filter_level_u, lf->filter_level_v); |
| #endif |
| |
| for (plane = 0; plane < 3; plane++) { |
| if (plane == 0 && !filt_lvl[0] && !filt_lvl_r[0]) |
| break; |
| else if (plane == 1 && !filt_lvl[1]) |
| continue; |
| else if (plane == 2 && !filt_lvl[2]) |
| continue; |
| |
| for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) { // MAX_SEGMENTS==8 |
| for (dir = 0; dir < 2; ++dir) { |
| int32_t lvl_seg = (dir == 0) ? filt_lvl[plane] : filt_lvl_r[plane]; |
| //assert(plane >= 0 && plane <= 2); |
| const uint8_t seg_lf_info_y0 = seg->seg_lf_info_y[seg_id] & 0xff; |
| const uint8_t seg_lf_info_y1 = (seg->seg_lf_info_y[seg_id]>>8) & 0xff; |
| const uint8_t seg_lf_info_u = seg->seg_lf_info_c[seg_id] & 0xff; |
| const uint8_t seg_lf_info_v = (seg->seg_lf_info_c[seg_id]>>8) & 0xff; |
| const uint8_t seg_lf_info = (plane==2) ? seg_lf_info_v : (plane==1) ? |
| seg_lf_info_u : ((dir==0) ? seg_lf_info_y0 : seg_lf_info_y1); |
| const int8_t seg_lf_active = ((seg->enabled) && ((seg_lf_info>>7) & 0x1)); |
| const int8_t seg_lf_data = conv2int8(seg_lf_info,7); |
| #ifdef DBG_LPF_PRINT |
| const int8_t seg_lf_data_clip = (seg_lf_data>63) ? 63 : |
| (seg_lf_data<-63) ? -63 : seg_lf_data; |
| #endif |
| if (seg_lf_active) { |
| lvl_seg = myclamp(lvl_seg + (int32_t)seg_lf_data, 0, MAX_LOOP_FILTER); |
| } |
| |
| #ifdef DBG_LPF_PRINT |
| printk("LF_PRINT:plane(%d) seg_id(%d) dir(%d) seg_lf_info(%d,0x%x),lvl_seg(0x%x)\n", |
| plane,seg_id,dir,seg_lf_active,seg_lf_data_clip,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[plane][seg_id][dir], lvl_seg, |
| sizeof(lfi->lvl[plane][seg_id][dir])); |
| } else { |
| int32_t ref, mode; |
| const int32_t scale = 1 << (lvl_seg >> 5); |
| const int32_t intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale; |
| lfi->lvl[plane][seg_id][dir][INTRA_FRAME][0] = |
| myclamp(intra_lvl, 0, MAX_LOOP_FILTER); |
| #ifdef DBG_LPF_PRINT |
| printk("LF_PRINT:ref_deltas[INTRA_FRAME](%d)\n",lf->ref_deltas[INTRA_FRAME]); |
| #endif |
| for (ref = LAST_FRAME; ref < REF_FRAMES; ++ref) { // LAST_FRAME==1 REF_FRAMES==8 |
| for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { // MAX_MODE_LF_DELTAS==2 |
| const int32_t inter_lvl = |
| lvl_seg + lf->ref_deltas[ref] * scale + |
| lf->mode_deltas[mode] * scale; |
| lfi->lvl[plane][seg_id][dir][ref][mode] = |
| myclamp(inter_lvl, 0, MAX_LOOP_FILTER); |
| #ifdef DBG_LPF_PRINT |
| printk("LF_PRINT:ref_deltas(%d) mode_deltas(%d)\n", |
| lf->ref_deltas[ref], lf->mode_deltas[mode]); |
| #endif |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| #ifdef DBG_LPF_PRINT |
| for (i = 0; i <= MAX_LOOP_FILTER; i++) { |
| printk("LF_PRINT:(%2d) thr=%d,blim=%3d,lim=%2d\n", |
| i, lfi->lfthr[i].hev_thr, |
| lfi->lfthr[i].mblim, lfi->lfthr[i].lim); |
| } |
| for (plane = 0; plane < 3; plane++) { |
| for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) { // MAX_SEGMENTS==8 |
| for (dir = 0; dir < 2; ++dir) { |
| int32_t mode; |
| for (mode = 0; mode < 2; ++mode) { |
| printk("assign {lvl[%d][%d][%d][0][%d],lvl[%d][%d][%d][1][%d],lvl[%d][%d][%d][2][%d],lvl[%d][%d][%d][3][%d],lvl[%d][%d][%d][4][%d],lvl[%d][%d][%d][5][%d],lvl[%d][%d][%d][6][%d],lvl[%d][%d][%d][7][%d]}={6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d};\n", |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| plane, seg_id, dir, mode, |
| lfi->lvl[plane][seg_id][dir][0][mode], |
| lfi->lvl[plane][seg_id][dir][1][mode], |
| lfi->lvl[plane][seg_id][dir][2][mode], |
| lfi->lvl[plane][seg_id][dir][3][mode], |
| lfi->lvl[plane][seg_id][dir][4][mode], |
| lfi->lvl[plane][seg_id][dir][5][mode], |
| lfi->lvl[plane][seg_id][dir][6][mode], |
| lfi->lvl[plane][seg_id][dir][7][mode]); |
| } |
| } |
| } |
| } |
| #endif |
| // Write to register |
| for (i = 0; i < 192; i++) { |
| uint32_t level; |
| level = ((lfi->lvl[i>>6&3][i>>3&7][1][i&7][1] & 0x3f)<<24) | |
| ((lfi->lvl[i>>6&3][i>>3&7][1][i&7][0] & 0x3f)<<16) | |
| ((lfi->lvl[i>>6&3][i>>3&7][0][i&7][1] & 0x3f)<<8) | |
| (lfi->lvl[i>>6&3][i>>3&7][0][i&7][0] & 0x3f); |
| if (!lf->filter_level[0] && !lf->filter_level[1]) |
| level = 0; |
| WRITE_VREG(HEVC_DBLK_CFGA, level); |
| } |
| #endif // DBG_LPF_DBLK_LVL |
| |
| #ifdef DBG_LPF_DBLK_FORCED_OFF |
| if (lf->lf_pic_cnt == 2) { |
| printk("LF_PRINT: pic_cnt(%d) dblk forced off !!!\n", lf->lf_pic_cnt); |
| WRITE_VREG(HEVC_DBLK_DBLK0, 0); |
| } else |
| WRITE_VREG(HEVC_DBLK_DBLK0, |
| lf->filter_level[0] | lf->filter_level[1] << 6 | |
| lf->filter_level_u << 12 | lf->filter_level_v << 18); |
| #else |
| WRITE_VREG(HEVC_DBLK_DBLK0, |
| lf->filter_level[0] | lf->filter_level[1]<<6 | |
| lf->filter_level_u<<12 | lf->filter_level_v<<18); |
| #endif |
| for (i =0; i < 10; i++) |
| WRITE_VREG(HEVC_DBLK_DBLK1, |
| ((i<2) ? lf->mode_deltas[i&1] : lf->ref_deltas[(i-2)&7])); |
| for (i = 0; i < 8; i++) |
| WRITE_VREG(HEVC_DBLK_DBLK2, |
| (uint32_t)(seg->seg_lf_info_y[i]) | (uint32_t)(seg->seg_lf_info_c[i]<<16)); |
| |
| // Set P_HEVC_DBLK_CFGB again |
| { |
| uint32_t lpf_data32 = READ_VREG(HEVC_DBLK_CFGB); |
| if (lf->mode_ref_delta_enabled) |
| lpf_data32 |= (0x1<<28); // mode_ref_delta_enabled |
| else |
| lpf_data32 &= ~(0x1<<28); |
| if (seg->enabled) |
| lpf_data32 |= (0x1<<29); // seg enable |
| else |
| lpf_data32 &= ~(0x1<<29); |
| if (pic_width >= 1280) |
| lpf_data32 |= (0x1 << 4); // dblk pipeline mode=1 for performance |
| else |
| lpf_data32 &= ~(0x3 << 4); |
| WRITE_VREG(HEVC_DBLK_CFGB, lpf_data32); |
| } |
| // Set CDEF |
| WRITE_VREG(HEVC_DBLK_CDEF0, buf_spec->cdef_data.buf_start); |
| { |
| uint32_t cdef_data32 = (READ_VREG(HEVC_DBLK_CDEF1) & 0xffffff00); |
| cdef_data32 |= 17; // TODO ERROR :: cdef temp dma address left offset |
| #ifdef DBG_LPF_CDEF_NO_PIPELINE |
| cdef_data32 |= (1<<17); // cdef test no pipeline for very small picture |
| #endif |
| WRITE_VREG(HEVC_DBLK_CDEF1, cdef_data32); |
| } |
| // Picture count |
| lf->lf_pic_cnt++; |
| } |
| #endif // #ifdef AOM_AV1_DBLK_INIT |
| |
| #ifdef AOM_AV1_UPSCALE_INIT |
| /* |
| * these functions here for upscaling updated in every picture |
| */ |
| #define RS_SUBPEL_BITS 6 |
| #define RS_SUBPEL_MASK ((1 << RS_SUBPEL_BITS) - 1) |
| #define RS_SCALE_SUBPEL_BITS 14 |
| #define RS_SCALE_SUBPEL_MASK ((1 << RS_SCALE_SUBPEL_BITS) - 1) |
| #define RS_SCALE_EXTRA_BITS (RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS) |
| #define RS_SCALE_EXTRA_OFF (1 << (RS_SCALE_EXTRA_BITS - 1)) |
| |
| static int32_t av1_get_upscale_convolve_step(int32_t in_length, int32_t out_length) { |
| return ((in_length << RS_SCALE_SUBPEL_BITS) + out_length / 2) / out_length; |
| } |
| |
| static int32_t get_upscale_convolve_x0(int32_t in_length, int32_t out_length, |
| int32_t x_step_qn) { |
| const int32_t err = out_length * x_step_qn - (in_length << RS_SCALE_SUBPEL_BITS); |
| const int32_t x0 = |
| (-((out_length - in_length) << (RS_SCALE_SUBPEL_BITS - 1)) + |
| out_length / 2) / |
| out_length + |
| RS_SCALE_EXTRA_OFF - err / 2; |
| return (int32_t)((uint32_t)x0 & RS_SCALE_SUBPEL_MASK); |
| } |
| |
| void av1_upscale_frame_init(AV1Decoder* pbi, AV1_COMMON *cm, param_t* params) |
| { |
| BuffInfo_t* buf_spec = pbi->work_space_buf; |
| //uint32_t data32; |
| const int32_t width = cm->dec_width; |
| const int32_t superres_upscaled_width = cm->superres_upscaled_width; |
| const int32_t x_step_qn_luma = av1_get_upscale_convolve_step(width, superres_upscaled_width); |
| const int32_t x0_qn_luma = get_upscale_convolve_x0(width, superres_upscaled_width, x_step_qn_luma); |
| const int32_t x_step_qn_chroma = av1_get_upscale_convolve_step((width+1)>>1, (superres_upscaled_width+1)>>1); |
| const int32_t x0_qn_chroma = get_upscale_convolve_x0((width+1)>>1, (superres_upscaled_width+1)>>1, x_step_qn_chroma); |
| av1_print2(AOM_DEBUG_HW_MORE, |
| "UPS_PRINT: width(%d -> %d)\n", |
| width, superres_upscaled_width); |
| av1_print2(AOM_DEBUG_HW_MORE, |
| "UPS_PRINT: xstep(%d,%d)(0x%X, 0x%X) x0qn(%d,%d)(0x%X, 0x%X)\n", |
| x_step_qn_luma,x_step_qn_chroma, |
| x_step_qn_luma,x_step_qn_chroma, |
| x0_qn_luma,x0_qn_chroma, |
| x0_qn_luma,x0_qn_chroma); |
| WRITE_VREG(HEVC_DBLK_UPS1, buf_spec->ups_data.buf_start); |
| WRITE_VREG(HEVC_DBLK_UPS2, x0_qn_luma); // x0_qn y |
| WRITE_VREG(HEVC_DBLK_UPS3, x0_qn_chroma); // x0_qn c |
| WRITE_VREG(HEVC_DBLK_UPS4, x_step_qn_luma); // x_step y |
| WRITE_VREG(HEVC_DBLK_UPS5, x_step_qn_chroma); // x_step c |
| WRITE_VREG(AV1_UPSCALE_X0_QN, (x0_qn_chroma<<16)|x0_qn_luma); |
| WRITE_VREG(AV1_UPSCALE_STEP_QN, (x_step_qn_chroma<<16)|x_step_qn_luma); |
| |
| /* |
| * TileR calculation here if cm needs an exactly accurate value |
| */ |
| //#define AV1_UPSCALE_TILER_CALCULATION |
| #ifdef AV1_UPSCALE_TILER_CALCULATION |
| uint32_t upscl_enabled = 1; // 1 just for example, actually this is use_superres flag |
| uint32_t tiler_x = 192; // 192 just for example, actually this is tile end |
| uint32_t ux; |
| uint32_t ux_tiler,ux_tiler_rnd32; |
| uint32_t xqn_y; |
| uint32_t xqn_c; |
| uint32_t tiler_x_y = tiler_x - 8 - 3; // dblk/cdef left-shift-8 plus upscaling extra-3 |
| uint32_t tiler_x_c = (tiler_x/2) - 4 - 3; // dblk/cdef left-shift-4 plus upscaling extra-3 |
| |
| xqn_y = x0_qn_luma; |
| xqn_c = x0_qn_chroma; |
| ux_tiler = 0; |
| ux_tiler_rnd32 = 0; |
| for (ux=0; ux<16384; ux+=8) { |
| uint32_t x1qn_y = xqn_y + x_step_qn_luma *( 7+3); // extra-3 is for lrf |
| uint32_t x1qn_c = xqn_c + x_step_qn_chroma*( 3+3); // extra-3 is for lrf |
| uint32_t x1qn_y_nxt = xqn_y + x_step_qn_luma *(8+7+3); // extra-3 is for lrf |
| uint32_t x1qn_c_nxt = xqn_c + x_step_qn_chroma*(4+3+3); // extra-3 is for lrf |
| |
| uint32_t x1_y = upscl_enabled ? (x1qn_y>>14) : ux +7+3; |
| uint32_t x1_c = upscl_enabled ? (x1qn_c>>14) : (ux/2)+3+3; |
| uint32_t x1_y_nxt = upscl_enabled ? (x1qn_y_nxt>>14) : ux +8+7+3; |
| uint32_t x1_c_nxt = upscl_enabled ? (x1qn_c_nxt>>14) : (ux/2)+4+3+3; |
| |
| if ((x1_y<tiler_x_y && x1_c<tiler_x_c) && |
| (x1_y_nxt>=tiler_x_y || x1_c_nxt>=tiler_x_c)) { |
| ux_tiler = ux; |
| ux_tiler_rnd32 = (ux_tiler/32 + (ux_tiler%32 ? 1 : 0)) * 32; |
| break; |
| } |
| |
| xqn_y += x_step_qn_luma*8; |
| xqn_c += x_step_qn_chroma*4; |
| } |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "UPS_PRINT: xqn_y(0x%x), xqn_c(0x%x), x1qn_y(0x%x), x1qn_c(0x%x)\n", |
| xqn_y, xqn_c, x1qn_y, x1qn_c); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "UPS_PRINT: ux_tiler(%d)(0x%x), ux_tiler_rnd32(%d)(0x%x)\n", |
| ux_tiler, ux_tiler, ux_tiler_rnd32, ux_tiler_rnd32); |
| #endif |
| |
| // TEMP write lrf register here |
| //WRITE_VREG(HEVC_DBLK_LRF0, 1<<0 | 1<<2); // LRF UNIT SIZE |
| //WRITE_VREG(HEVC_DBLK_LRF1, 3<<0 | 1<<8 | 1<<16 | 1<<24); // LRF UNIT NUMBER |
| |
| // TEMP Global Enables write here |
| /* |
| const uint32_t dblk_enable = (!cm->allow_intrabc && !cm->single_tile_decoding && (cm->lf.filter_level[0] || cm->lf.filter_level[1])); |
| const uint32_t cdef_enable = (!cm->allow_intrabc && !cm->single_tile_decoding && !cm->skip_loop_filter && !cm->coded_lossless && (cm->cdef_bits || cm->cdef_strengths[0] || cm->cdef_uv_strengths[0])); |
| printk("LPF_ENABLES : dblk(%d) cdef(%d)\n", dblk_enable, cdef_enable); |
| data32 = READ_VREG(HEVC_DBLK_CFGB ); |
| data32 &= ~(0xf<<20); |
| data32 |= (dblk_enable<<20); |
| data32 |= (cdef_enable<<23); |
| WRITE_VREG(HEVC_DBLK_CFGB, data32); |
| */ |
| } |
| |
| #endif // #ifdef AOM_AV1_UPSCALE_INIT |
| |
| static void release_dblk_struct(struct AV1HW_s *hw) |
| { |
| #ifdef AOM_AV1_DBLK_INIT |
| if (hw->lfi) |
| vfree(hw->lfi); |
| if (hw->lf) |
| vfree(hw->lf); |
| if (hw->seg_4lf) |
| vfree(hw->seg_4lf); |
| hw->lfi = NULL; |
| hw->lf = NULL; |
| hw->seg_4lf = NULL; |
| #endif |
| } |
| |
| static int init_dblk_struc(struct AV1HW_s *hw) |
| { |
| #ifdef AOM_AV1_DBLK_INIT |
| hw->lfi = vmalloc(sizeof(loop_filter_info_n)); |
| hw->lf = vmalloc(sizeof(struct loopfilter)); |
| hw->seg_4lf = vmalloc(sizeof(struct segmentation_lf)); |
| |
| if (hw->lfi == NULL || hw->lf == NULL || hw->seg_4lf == NULL) { |
| printk("[test.c] aom_loop_filter init malloc error!!!\n"); |
| release_dblk_struct(hw); |
| return -1; |
| } |
| |
| hw->lf->mode_ref_delta_enabled = 1; // set default here |
| hw->lf->mode_ref_delta_update = 1; // set default here |
| hw->lf->sharpness_level = 0; // init to 0 |
| hw->lf->lf_pic_cnt = 0; // init to 0 |
| #endif |
| return 0; |
| } |
| |
| static void config_dblk_hw(struct AV1HW_s *hw) |
| { |
| AV1Decoder *pbi = hw->pbi; |
| AV1_COMMON *cm = &hw->common; |
| loop_filter_info_n *lfi = hw->lfi; |
| struct loopfilter *lf = hw->lf; |
| struct segmentation_lf *seg_4lf = hw->seg_4lf; |
| BuffInfo_t* buf_spec = pbi->work_space_buf; |
| PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf; |
| PIC_BUFFER_CONFIG* prev_pic_config = &cm->prev_frame->buf; |
| int i; |
| |
| #ifdef AOM_AV1_DBLK_INIT |
| #ifdef DUAL_DECODE |
| #else |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c ref_delta] cur_frame : %p prev_frame : %p - %p \n", |
| cm->cur_frame, cm->prev_frame, |
| av1_get_primary_ref_frame_buf(cm)); |
| // get lf parameters from parser |
| lf->mode_ref_delta_enabled = |
| (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 1); |
| lf->mode_ref_delta_update = |
| ((hw->aom_param.p.loop_filter_mode_ref_delta_enabled >> 1) & 1); |
| lf->sharpness_level = |
| hw->aom_param.p.loop_filter_sharpness_level; |
| if (((hw->aom_param.p.loop_filter_mode_ref_delta_enabled)&3) == 3) { // enabled but and update |
| if (cm->prev_frame <= 0) { |
| // already initialized in Microcode |
| lf->ref_deltas[0] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0),7); |
| lf->ref_deltas[1] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0>>8),7); |
| lf->ref_deltas[2] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1),7); |
| lf->ref_deltas[3] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1>>8),7); |
| lf->ref_deltas[4] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2),7); |
| lf->ref_deltas[5] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2>>8),7); |
| lf->ref_deltas[6] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3),7); |
| lf->ref_deltas[7] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3>>8),7); |
| lf->mode_deltas[0] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0),7); |
| lf->mode_deltas[1] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0>>8),7); |
| } else { |
| lf->ref_deltas[0] = (hw->aom_param.p.loop_filter_ref_deltas_0 & 0x80) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0),7) : |
| cm->prev_frame->ref_deltas[0]; |
| lf->ref_deltas[1] = (hw->aom_param.p.loop_filter_ref_deltas_0 & 0x8000) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0>>8),7) : |
| cm->prev_frame->ref_deltas[1]; |
| lf->ref_deltas[2] = (hw->aom_param.p.loop_filter_ref_deltas_1 & 0x80) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1),7) : |
| cm->prev_frame->ref_deltas[2]; |
| lf->ref_deltas[3] = (hw->aom_param.p.loop_filter_ref_deltas_1 & 0x8000) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1>>8),7) : |
| cm->prev_frame->ref_deltas[3]; |
| lf->ref_deltas[4] = (hw->aom_param.p.loop_filter_ref_deltas_2 & 0x80) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2),7) : |
| cm->prev_frame->ref_deltas[4]; |
| lf->ref_deltas[5] = (hw->aom_param.p.loop_filter_ref_deltas_2 & 0x8000) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2>>8),7) : |
| cm->prev_frame->ref_deltas[5]; |
| lf->ref_deltas[6] = (hw->aom_param.p.loop_filter_ref_deltas_3 & 0x80) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3),7) : |
| cm->prev_frame->ref_deltas[6]; |
| lf->ref_deltas[7] = (hw->aom_param.p.loop_filter_ref_deltas_3 & 0x8000) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3>>8),7) : |
| cm->prev_frame->ref_deltas[7]; |
| lf->mode_deltas[0] = (hw->aom_param.p.loop_filter_mode_deltas_0 & 0x80) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0),7) : |
| cm->prev_frame->mode_deltas[0]; |
| lf->mode_deltas[1] = (hw->aom_param.p.loop_filter_mode_deltas_0 & 0x8000) ? |
| conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0>>8),7) : |
| cm->prev_frame->mode_deltas[1]; |
| } |
| } //else if (hw->aom_param.p.loop_filter_mode_ref_delta_enabled == 1) { // enabled but no update |
| else { // match c code -- not enabled, still need to copy prev to used for next |
| if ((cm->prev_frame <= 0) | (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 4)) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] mode_ref_delta set to default\n"); |
| lf->ref_deltas[0] = conv2int8((uint8_t)1,7); |
| lf->ref_deltas[1] = conv2int8((uint8_t)0,7); |
| lf->ref_deltas[2] = conv2int8((uint8_t)0,7); |
| lf->ref_deltas[3] = conv2int8((uint8_t)0,7); |
| lf->ref_deltas[4] = conv2int8((uint8_t)0xff,7); |
| lf->ref_deltas[5] = conv2int8((uint8_t)0,7); |
| lf->ref_deltas[6] = conv2int8((uint8_t)0xff,7); |
| lf->ref_deltas[7] = conv2int8((uint8_t)0xff,7); |
| lf->mode_deltas[0] = conv2int8((uint8_t)0,7); |
| lf->mode_deltas[1] = conv2int8((uint8_t)0,7); |
| } else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] mode_ref_delta copy from prev_frame\n"); |
| lf->ref_deltas[0] = cm->prev_frame->ref_deltas[0]; |
| lf->ref_deltas[1] = cm->prev_frame->ref_deltas[1]; |
| lf->ref_deltas[2] = cm->prev_frame->ref_deltas[2]; |
| lf->ref_deltas[3] = cm->prev_frame->ref_deltas[3]; |
| lf->ref_deltas[4] = cm->prev_frame->ref_deltas[4]; |
| lf->ref_deltas[5] = cm->prev_frame->ref_deltas[5]; |
| lf->ref_deltas[6] = cm->prev_frame->ref_deltas[6]; |
| lf->ref_deltas[7] = cm->prev_frame->ref_deltas[7]; |
| lf->mode_deltas[0] = cm->prev_frame->mode_deltas[0]; |
| lf->mode_deltas[1] = cm->prev_frame->mode_deltas[1]; |
| } |
| } |
| lf->filter_level[0] = hw->aom_param.p.loop_filter_level_0; |
| lf->filter_level[1] = hw->aom_param.p.loop_filter_level_1; |
| lf->filter_level_u = hw->aom_param.p.loop_filter_level_u; |
| lf->filter_level_v = hw->aom_param.p.loop_filter_level_v; |
| |
| cm->cur_frame->ref_deltas[0] = lf->ref_deltas[0]; |
| cm->cur_frame->ref_deltas[1] = lf->ref_deltas[1]; |
| cm->cur_frame->ref_deltas[2] = lf->ref_deltas[2]; |
| cm->cur_frame->ref_deltas[3] = lf->ref_deltas[3]; |
| cm->cur_frame->ref_deltas[4] = lf->ref_deltas[4]; |
| cm->cur_frame->ref_deltas[5] = lf->ref_deltas[5]; |
| cm->cur_frame->ref_deltas[6] = lf->ref_deltas[6]; |
| cm->cur_frame->ref_deltas[7] = lf->ref_deltas[7]; |
| cm->cur_frame->mode_deltas[0] = lf->mode_deltas[0]; |
| cm->cur_frame->mode_deltas[1] = lf->mode_deltas[1]; |
| |
| // get seg_4lf parameters from parser |
| seg_4lf->enabled = hw->aom_param.p.segmentation_enabled & 1; |
| cm->cur_frame->segmentation_enabled = hw->aom_param.p.segmentation_enabled & 1; |
| cm->cur_frame->intra_only = (hw->aom_param.p.segmentation_enabled >> 2) & 1; |
| cm->cur_frame->segmentation_update_map = (hw->aom_param.p.segmentation_enabled >> 3) & 1; |
| |
| if (hw->aom_param.p.segmentation_enabled & 1) { // segmentation_enabled |
| if (hw->aom_param.p.segmentation_enabled & 2) { // segmentation_update_data |
| for (i = 0; i < MAX_SEGMENTS; i++) { |
| seg_4lf->seg_lf_info_y[i] = hw->aom_param.p.seg_lf_info_y[i]; |
| seg_4lf->seg_lf_info_c[i] = hw->aom_param.p.seg_lf_info_c[i]; |
| #ifdef DBG_LPF_PRINT |
| printk(" read seg_lf_info [%d] : 0x%x, 0x%x\n", |
| i, seg_4lf->seg_lf_info_y[i], seg_4lf->seg_lf_info_c[i]); |
| #endif |
| } |
| } // segmentation_update_data |
| else { // no segmentation_update_data |
| if (cm->prev_frame <= 0) { |
| for (i=0;i<MAX_SEGMENTS;i++) { |
| seg_4lf->seg_lf_info_y[i] = 0; |
| seg_4lf->seg_lf_info_c[i] = 0; |
| } |
| } else { |
| for (i = 0; i < MAX_SEGMENTS; i++) { |
| seg_4lf->seg_lf_info_y[i] = cm->prev_frame->seg_lf_info_y[i]; |
| seg_4lf->seg_lf_info_c[i] = cm->prev_frame->seg_lf_info_c[i]; |
| #ifdef DBG_LPF_PRINT |
| printk(" Refrence seg_lf_info [%d] : 0x%x, 0x%x\n", |
| i, seg_4lf->seg_lf_info_y[i], seg_4lf->seg_lf_info_c[i]); |
| #endif |
| } |
| } |
| } // no segmentation_update_data |
| } // segmentation_enabled |
| else { |
| for (i=0;i<MAX_SEGMENTS;i++) { |
| seg_4lf->seg_lf_info_y[i] = 0; |
| seg_4lf->seg_lf_info_c[i] = 0; |
| } |
| } // NOT segmentation_enabled |
| for (i=0;i<MAX_SEGMENTS;i++) { |
| cm->cur_frame->seg_lf_info_y[i] = seg_4lf->seg_lf_info_y[i]; |
| cm->cur_frame->seg_lf_info_c[i] = seg_4lf->seg_lf_info_c[i]; |
| #ifdef DBG_LPF_PRINT |
| printk(" SAVE seg_lf_info [%d] : 0x%x, 0x%x\n", |
| i, cm->cur_frame->seg_lf_info_y[i], |
| cm->cur_frame->seg_lf_info_c[i]); |
| #endif |
| } |
| |
| /* |
| * Update loop filter Thr/Lvl table for every frame |
| */ |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] av1_loop_filter_frame_init (run before every frame decoding start)\n"); |
| av1_loop_filter_frame_init(pbi, seg_4lf, lfi, lf, cm->dec_width); |
| #endif // not DUAL_DECODE |
| #endif |
| |
| #ifdef AOM_AV1_UPSCALE_INIT |
| /* |
| * init for upscaling |
| */ |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] av1_upscale_frame_init (run before every frame decoding start)\n"); |
| av1_upscale_frame_init(pbi, |
| pbi->common, &hw->aom_param); |
| #endif // #ifdef AOM_AV1_UPSCALE_INIT |
| |
| //BuffInfo_t* buf_spec = pbi->work_space_buf; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] cur_frame : %p prev_frame : %p - %p \n", |
| cm->cur_frame, cm->prev_frame, av1_get_primary_ref_frame_buf(cm)); |
| if (cm->cur_frame <= 0) { |
| WRITE_VREG(AOM_AV1_CDF_BUFFER_W, buf_spec->cdf_buf.buf_start); |
| WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_W, buf_spec->seg_map.buf_start); |
| } |
| else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] Config WRITE CDF_BUF/SEG_MAP_BUF : %d\n", |
| cur_pic_config->index); |
| WRITE_VREG(AOM_AV1_CDF_BUFFER_W, |
| buf_spec->cdf_buf.buf_start + (0x8000*cur_pic_config->index)); |
| WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_W, |
| buf_spec->seg_map.buf_start + ((buf_spec->seg_map.buf_size / 16) * cur_pic_config->index)); |
| } |
| cm->cur_frame->seg_mi_rows = cm->cur_frame->mi_rows; |
| cm->cur_frame->seg_mi_cols = cm->cur_frame->mi_cols; |
| if (cm->prev_frame <= 0) { |
| WRITE_VREG(AOM_AV1_CDF_BUFFER_R, buf_spec->cdf_buf.buf_start); |
| WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_R, buf_spec->seg_map.buf_start); |
| } else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] Config READ CDF_BUF/SEG_MAP_BUF : %d\n", |
| prev_pic_config->index); |
| WRITE_VREG(AOM_AV1_CDF_BUFFER_R, |
| buf_spec->cdf_buf.buf_start + (0x8000*prev_pic_config->index)); |
| WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_R, |
| buf_spec->seg_map.buf_start + ((buf_spec->seg_map.buf_size / 16) * prev_pic_config->index)); |
| |
| // segmentation_enabled but no segmentation_update_data |
| if ((hw->aom_param.p.segmentation_enabled & 3) == 1) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] segfeatures_copy from prev_frame\n"); |
| for (i = 0; i < 8; i++) { |
| WRITE_VREG(AOM_AV1_SEGMENT_FEATURE, |
| cm->prev_frame->segment_feature[i]); |
| } |
| } |
| // segmentation_enabled but no segmentation_update_map |
| if ((hw->aom_param.p.segmentation_enabled & 9) == 1) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] seg_map_size copy from prev_frame\n"); |
| cm->cur_frame->seg_mi_rows = cm->prev_frame->seg_mi_rows; |
| cm->cur_frame->seg_mi_cols = cm->prev_frame->seg_mi_cols; |
| } |
| } |
| #ifdef PRINT_HEVC_DATA_PATH_MONITOR |
| { |
| uint32_t total_clk_count; |
| uint32_t path_transfer_count; |
| uint32_t path_wait_count; |
| float path_wait_ratio; |
| if (pbi->decode_idx > 1) { |
| WRITE_VREG(HEVC_PATH_MONITOR_CTRL, 0); // Disabble monitor and set rd_idx to 0 |
| total_clk_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| |
| WRITE_VREG(HEVC_PATH_MONITOR_CTRL, (1<<4)); // Disabble monitor and set rd_idx to 0 |
| |
| // parser --> iqit |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else |
| path_wait_ratio = |
| (float)path_wait_count/(float)path_transfer_count; |
| printk("[P%d HEVC PATH] Parser/IQIT/IPP/DBLK/OW/DDR/CMD WAITING \% : %.2f", |
| pbi->decode_idx - 2, |
| path_wait_ratio); |
| |
| // iqit --> ipp |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else |
| path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // dblk <-- ipp |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else |
| path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // dblk --> ow |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else path_wait_ratio = |
| (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // <--> DDR |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else path_wait_ratio = |
| (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // CMD |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) |
| path_wait_ratio = 0.0; |
| else |
| path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f\n", path_wait_ratio); |
| } |
| } |
| |
| #endif |
| |
| } |
| |
| static void aom_config_work_space_hw(struct AV1HW_s *hw, u32 mask) |
| { |
| struct BuffInfo_s *buf_spec = hw->work_space_buf; |
| unsigned int data32; |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| if (debug && hw->init_flag == 0) |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %x %x %x %x %x %x %x %x\n", |
| __func__, |
| buf_spec->ipp.buf_start, |
| buf_spec->start_adr, |
| buf_spec->short_term_rps.buf_start, |
| buf_spec->sao_up.buf_start, |
| buf_spec->swap_buf.buf_start, |
| buf_spec->scalelut.buf_start, |
| buf_spec->dblk_para.buf_start, |
| buf_spec->dblk_data.buf_start); |
| if (mask & HW_MASK_FRONT) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| if ((debug & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0) |
| WRITE_VREG(HEVC_RPM_BUFFER, (u32)hw->rpm_phy_addr); |
| |
| /*WRITE_VREG(HEVC_STREAM_SWAP_BUFFER, |
| buf_spec->swap_buf.buf_start);*/ |
| WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr); |
| |
| } |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| |
| WRITE_VREG(AOM_AV1_DAALA_TOP_BUFFER, |
| buf_spec->daala_top.buf_start); |
| WRITE_VREG(AV1_GMC_PARAM_BUFF_ADDR, |
| buf_spec->gmc_buf.buf_start); |
| |
| WRITE_VREG(HEVC_DBLK_CFG4, |
| buf_spec->dblk_para.buf_start); // cfg_addr_cif |
| WRITE_VREG(HEVC_DBLK_CFG5, |
| buf_spec->dblk_data.buf_start); // cfg_addr_xio |
| |
| if (mask & HW_MASK_BACK) { |
| #ifdef LOSLESS_COMPRESS_MODE |
| int losless_comp_header_size = |
| compute_losless_comp_header_size(hw->init_pic_w, |
| hw->init_pic_h); |
| int losless_comp_body_size = |
| compute_losless_comp_body_size(hw->init_pic_w, |
| hw->init_pic_h, buf_alloc_depth == 10); |
| #endif |
| #ifdef AOM_AV1_MMU_DW |
| int losless_comp_header_size_dw = |
| compute_losless_comp_header_size_dw(hw->init_pic_w, |
| hw->init_pic_h); |
| int losless_comp_body_size_dw = |
| compute_losless_comp_body_size_dw(hw->init_pic_w, |
| hw->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); |
| #ifdef CHANGE_REMOVED |
| 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 & AV1_DEBUG_BUFMGR_MORE) |
| pr_info("Write HEVC_DBLK_CFGE\n"); |
| } |
| #endif |
| /* 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) { |
| 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] |
| av1_print(hw, AV1_DEBUG_BUFMGR_MORE, |
| "HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3)); |
| } |
| |
| #ifdef LOSLESS_COMPRESS_MODE |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| /*bit[4] : paged_mem_mode*/ |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4)); |
| #ifdef CHANGE_REMOVED |
| if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) |
| #endif |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0); |
| } else { |
| /*if (cur_pic_config->bit_depth == AOM_BITS_10) |
| * WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3)); |
| */ |
| /*bit[3] smem mdoe*/ |
| /*else WRITE_VREG(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(hw) & 0x10) |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); |
| #else |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); |
| #endif |
| |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| 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(HEVC_SAO_CTRL9);*/ |
| /*data32 |= 0x1;*/ |
| /*WRITE_VREG(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 AOM_AV1_MMU_DW |
| data32 = READ_VREG(HEVC_SAO_CTRL5); |
| if (get_double_write_mode(hw) & 0x20) { |
| u32 data_tmp; |
| 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_dw); |
| WRITE_VREG(HEVC_CM_HEADER_OFFSET2,losless_comp_body_size_dw); |
| WRITE_VREG(HEVC_CM_HEADER_LENGTH2,losless_comp_header_size_dw); |
| |
| 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)); |
| |
| WRITE_VREG(HEVC_DW_VH0_ADDDR, buf_spec->mmu_vbh_dw.buf_start |
| + (2 * DW_VBH_BUF_SIZE(buf_spec))); |
| WRITE_VREG(HEVC_DW_VH1_ADDDR, buf_spec->mmu_vbh_dw.buf_start |
| + (3 * DW_VBH_BUF_SIZE(buf_spec))); |
| |
| /* use HEVC_CM_HEADER_START_ADDR */ |
| data32 |= (1<<15); |
| } else |
| data32 &= ~(1<<15); |
| WRITE_VREG(HEVC_SAO_CTRL5, data32); |
| #endif |
| |
| WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr); |
| #ifdef CHANGE_REMOVED |
| |
| WRITE_VREG(AV1_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start); |
| |
| /**/ |
| WRITE_VREG(AV1_PROB_SWAP_BUFFER, hw->prob_buffer_phy_addr); |
| WRITE_VREG(AV1_COUNT_SWAP_BUFFER, hw->count_buffer_phy_addr); |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) |
| WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, hw->frame_mmu_map_phy_addr); |
| else |
| WRITE_VREG(AV1_MMU_MAP_BUFFER, hw->frame_mmu_map_phy_addr); |
| } |
| #else |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL, hw->frame_mmu_map_phy_addr); |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, hw->dw_frame_mmu_map_phy_addr); |
| //default of 0xffffffff will disable dw |
| WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0); |
| WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); |
| } |
| #endif |
| #endif |
| #ifdef CO_MV_COMPRESS |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { |
| data32 = READ_VREG(HEVC_MPRED_CTRL4); |
| data32 |= (1 << 1); |
| WRITE_VREG(HEVC_MPRED_CTRL4, data32); |
| } |
| #endif |
| } |
| |
| config_aux_buf(hw); |
| } |
| |
| #ifdef MCRCC_ENABLE |
| static u32 mcrcc_cache_alg_flag = 1; |
| static void mcrcc_perfcount_reset(struct AV1HW_s *hw); |
| static void decomp_perfcount_reset(struct AV1HW_s *hw); |
| #endif |
| |
| static void aom_init_decoder_hw(struct AV1HW_s *hw, 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 & AV1_DEBUG_BUFMGR_MORE) |
| pr_info("%s\n", __func__);*/ |
| if (mask & HW_MASK_FRONT) { |
| data32 = READ_VREG(HEVC_PARSER_INT_CONTROL); |
| #ifdef CHANGE_REMOVED |
| #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*/ |
| ; |
| #else |
| data32 = data32 & 0x03ffffff; |
| data32 = data32 | |
| (3 << 29) | // stream_buffer_empty_int_ctl ( 0x200 interrupt) |
| (3 << 26) | // stream_fifo_empty_int_ctl ( 4 interrupt) |
| (1 << 24) | // stream_buffer_empty_int_amrisc_enable |
| (1 << 22) | // stream_fifo_empty_int_amrisc_enable |
| #ifdef AOM_AV1_HED_FB |
| #ifdef DUAL_DECODE |
| // For HALT CCPU test. Use Pull inside CCPU to generate interrupt |
| // (1 << 9) | // fed_fb_slice_done_int_amrisc_enable |
| #else |
| (1 << 10) | // fed_fb_slice_done_int_cpu_enable |
| #endif |
| #endif |
| (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 |
| ; |
| #endif |
| WRITE_VREG(HEVC_PARSER_INT_CONTROL, data32); |
| |
| data32 = READ_VREG(HEVC_SHIFT_STATUS); |
| data32 = data32 | |
| (0 << 1) |/*emulation_check_off AV1 |
| 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 AV1*/ |
| (1 << 9) | /*length_valid_startcode_en for AV1*/ |
| (3 << 6) | /*sft_valid_wr_position*/ |
| (2 << 4) | /*emulate_code_length_sub_1*/ |
| (3 << 1) | /*start_code_length_sub_1 |
| AV1 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(hw->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 (!hw->m_ins_flag) { |
| if (hw->low_latency_flag) |
| decode_mode = DECODE_MODE_SINGLE_LOW_LATENCY; |
| else |
| decode_mode = DECODE_MODE_SINGLE; |
| } else if (vdec_frame_based(hw_to_vdec(hw))) |
| decode_mode = hw->no_head ? |
| DECODE_MODE_MULTI_FRAMEBASE_NOHEAD : |
| DECODE_MODE_MULTI_FRAMEBASE; |
| else |
| decode_mode = DECODE_MODE_MULTI_STREAMBASE; |
| if (debug & AOM_DEBUG_BUFMGR_ONLY) |
| decode_mode |= (1 << 16); |
| 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*/ |
| ); |
| #ifdef CHANGE_REMOVED |
| WRITE_VREG(HEVCD_IPP_TOP_CNTL, |
| (1 << 1) | /*enable ipp*/ |
| (0 << 0) /*software reset ipp and mpp*/ |
| ); |
| #else |
| WRITE_VREG(HEVCD_IPP_TOP_CNTL, |
| (3 << 4) | // av1 |
| (1 << 1) | /*enable ipp*/ |
| (0 << 0) /*software reset ipp and mpp*/ |
| ); |
| #endif |
| if (get_double_write_mode(hw) & 0x10) { |
| /*Enable NV21 reference read mode for MC*/ |
| WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); |
| } |
| #ifdef MCRCC_ENABLE |
| /*Initialize mcrcc and decomp perf counters*/ |
| if (mcrcc_cache_alg_flag && |
| hw->init_flag == 0) { |
| mcrcc_perfcount_reset(hw); |
| decomp_perfcount_reset(hw); |
| } |
| #endif |
| } |
| #ifdef CHANGE_REMOVED |
| #else |
| // 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 |
| return; |
| } |
| |
| |
| #ifdef CONFIG_HEVC_CLK_FORCED_ON |
| static void config_av1_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 |
| |
| |
| static int vav1_mmu_map_alloc(struct AV1HW_s *hw) |
| { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| u32 mmu_map_size = vav1_frame_mmu_map_size(hw); |
| hw->frame_mmu_map_addr = |
| dma_alloc_coherent(amports_get_dma_device(), |
| mmu_map_size, |
| &hw->frame_mmu_map_phy_addr, GFP_KERNEL); |
| if (hw->frame_mmu_map_addr == NULL) { |
| pr_err("%s: failed to alloc count_buffer\n", __func__); |
| return -1; |
| } |
| memset(hw->frame_mmu_map_addr, 0, mmu_map_size); |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| u32 mmu_map_size = vaom_dw_frame_mmu_map_size(hw); |
| hw->dw_frame_mmu_map_addr = |
| dma_alloc_coherent(amports_get_dma_device(), |
| mmu_map_size, |
| &hw->dw_frame_mmu_map_phy_addr, GFP_KERNEL); |
| if (hw->dw_frame_mmu_map_addr == NULL) { |
| pr_err("%s: failed to alloc count_buffer\n", __func__); |
| return -1; |
| } |
| memset(hw->dw_frame_mmu_map_addr, 0, mmu_map_size); |
| } |
| #endif |
| return 0; |
| } |
| |
| |
| static void vav1_mmu_map_free(struct AV1HW_s *hw) |
| { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| u32 mmu_map_size = vav1_frame_mmu_map_size(hw); |
| if (hw->frame_mmu_map_addr) { |
| if (hw->frame_mmu_map_phy_addr) |
| dma_free_coherent(amports_get_dma_device(), |
| mmu_map_size, |
| hw->frame_mmu_map_addr, |
| hw->frame_mmu_map_phy_addr); |
| hw->frame_mmu_map_addr = NULL; |
| } |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| u32 mmu_map_size = vaom_dw_frame_mmu_map_size(hw); |
| if (hw->dw_frame_mmu_map_addr) { |
| if (hw->dw_frame_mmu_map_phy_addr) |
| dma_free_coherent(amports_get_dma_device(), |
| mmu_map_size, |
| hw->dw_frame_mmu_map_addr, |
| hw->dw_frame_mmu_map_phy_addr); |
| hw->dw_frame_mmu_map_addr = NULL; |
| } |
| } |
| #endif |
| } |
| |
| |
| static void av1_local_uninit(struct AV1HW_s *hw, bool reset_flag) |
| { |
| hw->rpm_ptr = NULL; |
| hw->lmem_ptr = NULL; |
| |
| if (!reset_flag) { |
| hw->fg_ptr = NULL; |
| if (hw->fg_addr) { |
| if (hw->fg_phy_addr) |
| codec_mm_dma_free_coherent(hw->fg_table_handle); |
| hw->fg_addr = NULL; |
| } |
| } |
| |
| if (hw->rpm_addr) { |
| dma_free_coherent(amports_get_dma_device(), |
| RPM_BUF_SIZE, |
| hw->rpm_addr, |
| hw->rpm_phy_addr); |
| hw->rpm_addr = NULL; |
| } |
| if (hw->aux_addr) { |
| dma_free_coherent(amports_get_dma_device(), |
| hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, |
| hw->aux_phy_addr); |
| hw->aux_addr = NULL; |
| } |
| #if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| if (hw->ucode_log_addr) { |
| dma_free_coherent(amports_get_dma_device(), |
| UCODE_LOG_BUF_SIZE, hw->ucode_log_addr, |
| hw->ucode_log_phy_addr); |
| hw->ucode_log_addr = NULL; |
| } |
| #endif |
| if (hw->lmem_addr) { |
| if (hw->lmem_phy_addr) |
| dma_free_coherent(amports_get_dma_device(), |
| LMEM_BUF_SIZE, hw->lmem_addr, |
| hw->lmem_phy_addr); |
| hw->lmem_addr = NULL; |
| } |
| |
| vav1_mmu_map_free(hw); |
| |
| if (hw->gvs) |
| vfree(hw->gvs); |
| hw->gvs = NULL; |
| } |
| |
| static int av1_local_init(struct AV1HW_s *hw, bool reset_flag) |
| { |
| int ret = -1; |
| /*int losless_comp_header_size, losless_comp_body_size;*/ |
| |
| struct BuffInfo_s *cur_buf_info = NULL; |
| |
| memset(&hw->param, 0, sizeof(union param_u)); |
| #ifdef MULTI_INSTANCE_SUPPORT |
| cur_buf_info = &hw->work_space_buf_store; |
| hw->pbi->work_space_buf = cur_buf_info; |
| #if 0 |
| if (vdec_is_support_4k()) { |
| memcpy(cur_buf_info, &aom_workbuff_spec[1], /* 8k */ |
| sizeof(struct BuffInfo_s)); |
| } else |
| memcpy(cur_buf_info, &aom_workbuff_spec[0],/* 1080p */ |
| sizeof(struct BuffInfo_s)); |
| #endif |
| memcpy(cur_buf_info, &aom_workbuff_spec[hw->buffer_spec_index], |
| sizeof(struct BuffInfo_s)); |
| |
| cur_buf_info->start_adr = hw->buf_start; |
| if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL) || |
| (get_double_write_mode(hw) == 0x10)) |
| hw->mc_buf_spec.buf_end = hw->buf_start + hw->buf_size; |
| |
| #else |
| /*! MULTI_INSTANCE_SUPPORT*/ |
| #if 0 |
| if (vdec_is_support_4k()) { |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) |
| cur_buf_info = &aom_workbuff_spec[1];/* 8k work space */ |
| else |
| cur_buf_info = &aom_workbuff_spec[1];/* 4k2k work space */ |
| } else |
| cur_buf_info = &aom_workbuff_spec[0];/* 1080p work space */ |
| #endif |
| memcpy(cur_buf_info, &aom_workbuff_spec[hw->buffer_spec_index], |
| sizeof(struct BuffInfo_s)); |
| #endif |
| |
| init_buff_spec(hw, cur_buf_info); |
| aom_bufmgr_init(hw, cur_buf_info, NULL); |
| |
| if (!vdec_is_support_4k() |
| && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) { |
| buf_alloc_width = 1920; |
| buf_alloc_height = 1088; |
| if (hw->max_pic_w > 1920 && hw->max_pic_h > 1088) { |
| hw->max_pic_w = 1920; |
| hw->max_pic_h = 1088; |
| } |
| } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { |
| buf_alloc_width = 8192; |
| buf_alloc_height = 4608; |
| } |
| |
| hw->init_pic_w = hw->max_pic_w ? hw->max_pic_w : |
| (hw->vav1_amstream_dec_info.width ? hw->vav1_amstream_dec_info.width : |
| (buf_alloc_width ? buf_alloc_width : hw->work_space_buf->max_width)); |
| hw->init_pic_h = hw->max_pic_h ? hw->max_pic_h : |
| (hw->vav1_amstream_dec_info.height ? hw->vav1_amstream_dec_info.height : |
| (buf_alloc_height ? buf_alloc_height : hw->work_space_buf->max_height)); |
| |
| hw->pbi->frame_width = hw->init_pic_w; |
| hw->pbi->frame_height = hw->init_pic_h; |
| |
| /* 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_SM1) && |
| (get_double_write_mode(hw) != 0) && |
| (((hw->max_pic_w % 64) != 0) || |
| (hw->vav1_amstream_dec_info.width % 64) != 0)) { |
| if (hw_to_vdec(hw)->canvas_mode != |
| CANVAS_BLKMODE_LINEAR) |
| hw->mem_map_mode = 2; |
| else { |
| hw->mem_map_mode = 0; |
| av1_print(hw, AOM_DEBUG_HW_MORE, "vdec blkmod linear, force mem_map_mode 0\n"); |
| } |
| } |
| |
| #if 0 |
| //ndef MV_USE_FIXED_BUF |
| if (init_mv_buf_list(hw) < 0) { |
| pr_err("%s: init_mv_buf_list fail\n", __func__); |
| return -1; |
| } |
| #endif |
| |
| hw->mv_buf_margin = mv_buf_margin; |
| |
| hw->pts_unstable = ((unsigned long)(hw->vav1_amstream_dec_info.param) |
| & 0x40) >> 6; |
| |
| if ((debug & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0) { |
| hw->rpm_addr = dma_alloc_coherent(amports_get_dma_device(), |
| RPM_BUF_SIZE, |
| &hw->rpm_phy_addr, GFP_KERNEL); |
| if (hw->rpm_addr == NULL) { |
| pr_err("%s: failed to alloc rpm buffer\n", __func__); |
| return -1; |
| } |
| hw->rpm_ptr = hw->rpm_addr; |
| } |
| |
| if (prefix_aux_buf_size > 0 || |
| suffix_aux_buf_size > 0) { |
| u32 aux_buf_size; |
| |
| hw->prefix_aux_size = AUX_BUF_ALIGN(prefix_aux_buf_size); |
| hw->suffix_aux_size = AUX_BUF_ALIGN(suffix_aux_buf_size); |
| aux_buf_size = hw->prefix_aux_size + hw->suffix_aux_size; |
| hw->aux_addr = dma_alloc_coherent(amports_get_dma_device(), |
| aux_buf_size, &hw->aux_phy_addr, GFP_KERNEL); |
| if (hw->aux_addr == NULL) { |
| pr_err("%s: failed to alloc rpm buffer\n", __func__); |
| goto dma_alloc_fail; |
| } |
| } |
| #if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| //if (udebug_flag & 0x8) { |
| hw->ucode_log_addr = dma_alloc_coherent(amports_get_dma_device(), |
| UCODE_LOG_BUF_SIZE, &hw->ucode_log_phy_addr, GFP_KERNEL); |
| if (hw->ucode_log_addr == NULL) { |
| hw->ucode_log_phy_addr = 0; |
| } |
| pr_info("%s: alloc ucode log buffer %p\n", |
| __func__, hw->ucode_log_addr); |
| //} |
| #endif |
| |
| if (!reset_flag) { |
| int alloc_num = 1; |
| if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_SC2) || |
| (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3) || |
| (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || |
| (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5W)) { |
| alloc_num = FRAME_BUFFERS; |
| } |
| hw->fg_addr = codec_mm_dma_alloc_coherent(&hw->fg_table_handle, |
| (ulong *)&hw->fg_phy_addr,FGS_TABLE_SIZE * alloc_num, MEM_NAME); |
| if (hw->fg_addr == NULL) { |
| pr_err("%s: failed to alloc fg buffer\n", __func__); |
| } |
| hw->fg_ptr = hw->fg_addr; |
| pr_info("%s, alloc fg table addr %lx, size 0x%x\n", __func__, |
| (ulong)hw->fg_phy_addr, FGS_TABLE_SIZE * alloc_num); |
| } |
| |
| hw->lmem_addr = dma_alloc_coherent(amports_get_dma_device(), |
| LMEM_BUF_SIZE, |
| &hw->lmem_phy_addr, GFP_KERNEL); |
| if (hw->lmem_addr == NULL) { |
| pr_err("%s: failed to alloc lmem buffer\n", __func__); |
| goto dma_alloc_fail; |
| } |
| hw->lmem_ptr = hw->lmem_addr; |
| |
| vdec_set_vframe_comm(hw_to_vdec(hw), DRIVER_NAME); |
| ret = vav1_mmu_map_alloc(hw); |
| if (ret < 0) |
| goto dma_alloc_fail; |
| |
| return ret; |
| |
| dma_alloc_fail: |
| av1_local_uninit(hw, reset_flag); |
| return -1; |
| } |
| |
| |
| #define spec2canvas(x) \ |
| (((x)->uv_canvas_index << 16) | \ |
| ((x)->uv_canvas_index << 8) | \ |
| ((x)->y_canvas_index << 0)) |
| |
| |
| static void set_canvas(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| struct vdec_s *vdec = hw_to_vdec(hw); |
| int canvas_w = ALIGN(pic_config->y_crop_width, 64)/4; |
| int canvas_h = ALIGN(pic_config->y_crop_height, 32)/4; |
| int blkmode = hw->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 config aligned with 64, so aligned with 64 same */ |
| 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, hw->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, hw->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 = hw->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 = hw->is_used_v4l ? 0 : 7; |
| #endif |
| } |
| } |
| |
| static void set_frame_info(struct AV1HW_s *hw, struct vframe_s *vf) |
| { |
| unsigned int ar; |
| vf->duration = hw->frame_dur; |
| vf->duration_pulldown = 0; |
| vf->flag = 0; |
| vf->prop.master_display_colour = hw->vf_dp; |
| vf->signal_type = hw->video_signal_type; |
| if (vf->compWidth && vf->compHeight) |
| hw->frame_ar = vf->compHeight * 0x100 / vf->compWidth; |
| ar = min_t(u32, hw->frame_ar, DISP_RATIO_ASPECT_RATIO_MAX); |
| vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); |
| |
| if (hw->is_used_v4l && (vf->signal_type != 0)) { |
| struct aml_vdec_hdr_infos hdr; |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| |
| memset(&hdr, 0, sizeof(hdr)); |
| hdr.signal_type = vf->signal_type; |
| hdr.color_parms = hw->vf_dp; |
| hdr.color_parms.luminance[0] = hdr.color_parms.luminance[0] / 1000; |
| vdec_v4l_set_hdr_infos(ctx, &hdr); |
| } |
| |
| vf->sidebind_type = hw->sidebind_type; |
| vf->sidebind_channel_id = hw->sidebind_channel_id; |
| } |
| |
| static int vav1_vf_states(struct vframe_states *states, void *op_arg) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; |
| |
| states->vf_pool_size = VF_POOL_SIZE; |
| states->buf_free_num = kfifo_len(&hw->newframe_q); |
| states->buf_avail_num = kfifo_len(&hw->display_q); |
| |
| if (step == 2) |
| states->buf_avail_num = 0; |
| return 0; |
| } |
| |
| static struct vframe_s *vav1_vf_peek(void *op_arg) |
| { |
| struct vframe_s *vf[2] = {0, 0}; |
| struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; |
| |
| if (step == 2) |
| return NULL; |
| |
| if (kfifo_out_peek(&hw->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 *vav1_vf_get(void *op_arg) |
| { |
| struct vframe_s *vf; |
| struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; |
| |
| if (step == 2) |
| return NULL; |
| else if (step == 1) |
| step = 2; |
| |
| if (kfifo_get(&hw->display_q, &vf)) { |
| struct vframe_s *next_vf = NULL; |
| uint8_t index = vf->index & 0xff; |
| ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); |
| if (index < hw->used_buf_num || |
| (vf->type & VIDTYPE_V4L_EOS)) { |
| vf->index_disp = atomic_read(&hw->vf_get_count); |
| atomic_add(1, &hw->vf_get_count); |
| if (debug & AOM_DEBUG_VFRAME) { |
| struct BufferPool_s *pool = hw->common.buffer_pool; |
| struct PIC_BUFFER_CONFIG_s *pic = |
| &pool->frame_bufs[index].buf; |
| unsigned long flags; |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| av1_print(hw, AOM_DEBUG_VFRAME, "%s vf %px index 0x%x type 0x%x w/h %d/%d, aux size %d, pts %d, %lld, ts: %llu\n", |
| __func__, vf, vf->index, vf->type, |
| vf->width, vf->height, |
| pic->aux_data_size, |
| vf->pts, |
| vf->pts_us64, |
| vf->timestamp); |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| } |
| |
| if (kfifo_peek(&hw->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; |
| #ifdef DUMP_FILMGRAIN |
| if (index == fg_dump_index) { |
| unsigned long flags; |
| int ii; |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| pr_info("FGS_TABLE for buffer %d:\n", index); |
| for (ii = 0; ii < FGS_TABLE_SIZE; ii++) { |
| pr_info("%02x ", hw->fg_ptr[ii]); |
| if (((ii+ 1) & 0xf) == 0) |
| pr_info("\n"); |
| } |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| } |
| #endif |
| |
| return vf; |
| } |
| } |
| return NULL; |
| } |
| |
| static void vav1_vf_put(struct vframe_s *vf, void *op_arg) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; |
| uint8_t index = vf->index & 0xff; |
| unsigned long flags; |
| |
| if ((vf == NULL) || (hw == NULL)) |
| return; |
| |
| kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); |
| ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); |
| atomic_add(1, &hw->vf_put_count); |
| if (debug & AOM_DEBUG_VFRAME) { |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| av1_print(hw, AOM_DEBUG_VFRAME, "%s index 0x%x type 0x%x w/h %d/%d, pts %d, %lld, ts: %llu\n", |
| __func__, vf->index, vf->type, |
| vf->width, vf->height, |
| vf->pts, |
| vf->pts_us64, |
| vf->timestamp); |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| } |
| |
| if (index < hw->used_buf_num) { |
| struct AV1_Common_s *cm = &hw->common; |
| struct BufferPool_s *pool = cm->buffer_pool; |
| PIC_BUFFER_CONFIG *pic = &pool->frame_bufs[index].buf; |
| |
| if (vf->v4l_mem_handle != |
| hw->m_BUF[pic->BUF_index].v4l_ref_buf_addr) { |
| av1_print(hw, PRINT_FLAG_V4L_DETAIL, |
| "AV1 update fb handle, old:%llx, new:%llx\n", |
| hw->m_BUF[pic->BUF_index].v4l_ref_buf_addr, |
| vf->v4l_mem_handle); |
| |
| hw->m_BUF[pic->BUF_index].v4l_ref_buf_addr = |
| vf->v4l_mem_handle; |
| } |
| |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| if (pic->repeat_pic) { |
| if (pic->repeat_pic->repeat_count > 0) |
| pic->repeat_pic->repeat_count --; |
| else |
| av1_print(hw, PRINT_FLAG_ERROR, "repeat_count <= 0 pic:%px\n", pic); |
| pic->repeat_pic = NULL; |
| } |
| if ((debug & AV1_DEBUG_IGNORE_VF_REF) == 0) { |
| if (pool->frame_bufs[index].buf.vf_ref > 0) |
| pool->frame_bufs[index].buf.vf_ref--; |
| } |
| if (hw->wait_buf) |
| WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); |
| |
| hw->last_put_idx = index; |
| hw->new_frame_displayed++; |
| |
| if (hw->wait_more_buf) { |
| hw->wait_more_buf = false; |
| hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; |
| vdec_schedule_work(&hw->work); |
| } |
| |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| } |
| } |
| |
| static int vav1_event_cb(int type, void *data, void *op_arg) |
| { |
| unsigned long flags; |
| struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; |
| struct AV1_Common_s *cm = &hw->common; |
| struct BufferPool_s *pool = cm->buffer_pool; |
| |
| if (type & VFRAME_EVENT_RECEIVER_RESET) { |
| #if 0 |
| unsigned long flags; |
| |
| amhevc_stop(); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_light_unreg_provider(&vav1_vf_prov); |
| #endif |
| spin_lock_irqsave(&hw->lock, flags); |
| vav1_local_init(); |
| vav1_prot_init(); |
| spin_unlock_irqrestore(&hw->lock, flags); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_reg_provider(&vav1_vf_prov); |
| #endif |
| amhevc_start(); |
| #endif |
| } else if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) { |
| struct provider_aux_req_s *req = |
| (struct provider_aux_req_s *)data; |
| unsigned char index; |
| |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| index = req->vf->index & 0xff; |
| req->aux_buf = NULL; |
| req->aux_size = 0; |
| if (req->bot_flag) |
| index = (req->vf->index >> 8) & 0xff; |
| if (index != 0xff |
| && index < hw->used_buf_num) { |
| struct PIC_BUFFER_CONFIG_s *pic_config = |
| &pool->frame_bufs[index].buf; |
| req->aux_buf = pic_config->aux_data_buf; |
| req->aux_size = pic_config->aux_data_size; |
| #if 0 |
| //def CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| if (hw->bypass_dvenl && !dolby_meta_with_el) |
| req->dv_enhance_exist = false; |
| else |
| req->dv_enhance_exist = |
| pic_config->dv_enhance_exist; |
| av1_print(hw, AOM_DEBUG_VFRAME, |
| "query dv_enhance_exist for pic (vf 0x%p, poc %d index %d) flag => %d, aux sizd 0x%x\n", |
| req->vf, |
| pic_config->POC, index, |
| req->dv_enhance_exist, req->aux_size); |
| #else |
| req->dv_enhance_exist = 0; |
| #endif |
| } |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| |
| if (debug & AOM_DEBUG_AUX_DATA) |
| av1_print(hw, 0, |
| "%s(type 0x%x vf index 0x%x)=>size 0x%x\n", |
| __func__, type, index, req->aux_size); |
| } 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(hw)); |
| else |
| req->req_result[0] = 0xffffffff; |
| } |
| return 0; |
| } |
| |
| void av1_inc_vf_ref(struct AV1HW_s *hw, int index) |
| { |
| struct AV1_Common_s *cm = &hw->common; |
| |
| if ((debug & AV1_DEBUG_IGNORE_VF_REF) == 0) { |
| cm->buffer_pool->frame_bufs[index].buf.vf_ref++; |
| |
| av1_print(hw, AV1_DEBUG_BUFMGR_MORE, "%s index = %d new vf_ref = %d\r\n", |
| __func__, index, |
| cm->buffer_pool->frame_bufs[index].buf.vf_ref); |
| } |
| } |
| #if 0 |
| static int frame_duration_adapt(struct AV1HW_s *hw, struct vframe_s *vf, u32 valid) |
| { |
| u32 old_duration, pts_duration = 0; |
| u32 pts = vf->pts; |
| |
| if (hw->get_frame_dur == true) |
| return true; |
| |
| hw->frame_cnt_window++; |
| if (!(hw->av1_first_pts_ready == 1)) { |
| if (valid) { |
| hw->pts1 = pts; |
| hw->frame_cnt_window = 0; |
| hw->duration_from_pts_done = 0; |
| hw->av1_first_pts_ready = 1; |
| } else { |
| return false; |
| } |
| } else { |
| if (pts < hw->pts1) { |
| if (hw->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) { |
| hw->pts1 = pts; |
| hw->frame_cnt_window = 0; |
| } |
| } |
| |
| if (valid && (hw->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) && |
| (pts > hw->pts1) && (hw->duration_from_pts_done == 0)) { |
| old_duration = hw->frame_dur; |
| hw->pts2 = pts; |
| pts_duration = (((hw->pts2 - hw->pts1) * 16) / |
| (hw->frame_cnt_window * 15)); |
| |
| if (close_to(pts_duration, old_duration, 2000)) { |
| hw->frame_dur = pts_duration; |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "use calc duration %d\n", pts_duration); |
| } |
| |
| if (hw->duration_from_pts_done == 0) { |
| if (close_to(pts_duration, old_duration, RATE_CORRECTION_THRESHOLD)) { |
| hw->duration_from_pts_done = 1; |
| } else { |
| if (!close_to(pts_duration, |
| old_duration, 1000) && |
| !close_to(pts_duration, |
| hw->frame_dur, 1000) && |
| close_to(pts_duration, |
| hw->last_duration, 200)) { |
| /* frame_dur must |
| * wrong,recover it. |
| */ |
| hw->frame_dur = pts_duration; |
| } |
| hw->pts1 = hw->pts2; |
| hw->frame_cnt_window = 0; |
| hw->duration_from_pts_done = 0; |
| } |
| } |
| hw->last_duration = pts_duration; |
| } |
| } |
| return true; |
| } |
| #endif |
| |
| static void update_vf_memhandle(struct AV1HW_s *hw, |
| struct vframe_s *vf, struct PIC_BUFFER_CONFIG_s *pic) |
| { |
| /* keeper not needed for v4l solution */ |
| if (hw->is_used_v4l) |
| return; |
| |
| if (pic->index < 0) { |
| vf->mem_handle = NULL; |
| vf->mem_head_handle = NULL; |
| vf->mem_dw_handle = NULL; |
| } else if (vf->type & VIDTYPE_SCATTER) { |
| #ifdef AOM_AV1_MMU_DW |
| if (pic->double_write_mode & 0x20 && |
| (debug & AOM_DEBUG_DW_DISP_MAIN) == 0) { |
| vf->mem_handle = |
| decoder_mmu_box_get_mem_handle( |
| hw->mmu_box_dw, pic->index); |
| vf->mem_head_handle = |
| decoder_bmmu_box_get_mem_handle( |
| hw->bmmu_box, |
| DW_HEADER_BUFFER_IDX(pic->BUF_index)); |
| vf->mem_dw_handle = NULL; |
| } else |
| #endif |
| { |
| vf->mem_handle = |
| decoder_mmu_box_get_mem_handle( |
| hw->mmu_box, pic->index); |
| vf->mem_head_handle = |
| decoder_bmmu_box_get_mem_handle( |
| hw->bmmu_box, |
| HEADER_BUFFER_IDX(pic->BUF_index)); |
| if (get_double_write_mode(hw) == 3) |
| vf->mem_dw_handle = |
| decoder_bmmu_box_get_mem_handle( |
| hw->bmmu_box, |
| VF_BUFFER_IDX(pic->BUF_index)); |
| else |
| vf->mem_dw_handle = NULL; |
| } |
| #ifdef USE_SPEC_BUF_FOR_MMU_HEAD |
| vf->mem_head_handle = NULL; |
| #endif |
| } else { |
| vf->mem_handle = |
| decoder_bmmu_box_get_mem_handle( |
| hw->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( |
| *hw->bmmu_box, VF_BUFFER_IDX(BUF_index)); |
| */ |
| } |
| } |
| |
| static inline void av1_update_gvs(struct AV1HW_s *hw, struct vframe_s *vf, |
| struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| if (hw->gvs->frame_height != pic_config->y_crop_height) { |
| hw->gvs->frame_width = pic_config->y_crop_width; |
| hw->gvs->frame_height = pic_config->y_crop_height; |
| } |
| if (hw->gvs->frame_dur != hw->frame_dur) { |
| hw->gvs->frame_dur = hw->frame_dur; |
| if (hw->frame_dur != 0) |
| hw->gvs->frame_rate = ((96000 * 10 / hw->frame_dur) % 10) < 5 ? |
| 96000 / hw->frame_dur : (96000 / hw->frame_dur +1); |
| else |
| hw->gvs->frame_rate = -1; |
| } |
| if (vf && hw->gvs->ratio_control != vf->ratio_control) |
| hw->gvs->ratio_control = vf->ratio_control; |
| |
| hw->gvs->status = hw->stat | hw->fatal_error; |
| hw->gvs->error_count = hw->gvs->error_frame_count; |
| |
| } |
| |
| static int prepare_display_buf(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *pic_config) |
| { |
| struct vframe_s *vf = NULL; |
| struct vdec_info tmp4x; |
| int stream_offset = pic_config->stream_offset; |
| struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; |
| struct vdec_v4l2_buffer *fb = NULL; |
| ulong nv_order = VIDTYPE_VIU_NV21; |
| u32 pts_valid = 0, pts_us64_valid = 0; |
| u32 frame_size; |
| int i, reclac_flag = 0; |
| |
| av1_print(hw, AOM_DEBUG_VFRAME, "%s index = %d\r\n", __func__, pic_config->index); |
| if (kfifo_get(&hw->newframe_q, &vf) == 0) { |
| av1_print(hw, 0, "fatal error, no available buffer slot."); |
| return -1; |
| } |
| |
| /* swap uv */ |
| if (hw->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(hw, pic_config); |
| |
| display_frame_count[hw->index]++; |
| if (vf) { |
| if (!force_pts_unstable && hw->av1_first_pts_ready) { |
| if ((pic_config->pts == 0) || ((pic_config->pts <= hw->last_pts) && |
| (pic_config->pts64 <= hw->last_pts_us64))) { |
| for (i = (FRAME_BUFFERS - 1); i > 0; i--) { |
| if ((hw->last_pts == hw->frame_mode_pts_save[i]) || |
| (hw->last_pts_us64 == hw->frame_mode_pts64_save[i])) { |
| pic_config->pts = hw->frame_mode_pts_save[i - 1]; |
| pic_config->pts64 = hw->frame_mode_pts64_save[i - 1]; |
| break; |
| } |
| } |
| |
| if ((i == 0) || (pic_config->pts <= hw->last_pts)) { |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "no found pts %d, set 0. %d, %d\n", |
| i, pic_config->pts, hw->last_pts); |
| pic_config->pts = 0; |
| pic_config->pts64 = 0; |
| } |
| } |
| } |
| |
| if (hw->is_used_v4l) { |
| vf->v4l_mem_handle |
| = hw->m_BUF[pic_config->v4l_buf_index].v4l_ref_buf_addr; |
| fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| vf->mm_box.bmmu_box = hw->bmmu_box; |
| vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->v4l_buf_index]); |
| vf->mm_box.mmu_box = hw->mmu_box; |
| vf->mm_box.mmu_idx = hw->buffer_wrap[pic_config->v4l_buf_index]; |
| } |
| } |
| |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (vdec_frame_based(hw_to_vdec(hw))) { |
| vf->pts = pic_config->pts; |
| vf->pts_us64 = pic_config->pts64; |
| |
| if (hw->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_us64 |
| (PTS_TYPE_VIDEO, stream_offset, &vf->pts, |
| &frame_size, 0, |
| &vf->pts_us64) != 0) { |
| #ifdef DEBUG_PTS |
| hw->pts_missed++; |
| #endif |
| vf->pts = 0; |
| vf->pts_us64 = 0; |
| pts_valid = 0; |
| pts_us64_valid = 0; |
| } else { |
| #ifdef DEBUG_PTS |
| hw->pts_hit++; |
| #endif |
| pts_valid = 1; |
| pts_us64_valid = 1; |
| } |
| |
| if (hw->av1_first_pts_ready) { |
| if (hw->frame_dur && ((vf->pts == 0) || (vf->pts_us64 == 0))) { |
| vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur); |
| vf->pts_us64 = hw->last_pts_us64 + |
| (DUR2PTS(hw->frame_dur) * 100 / 9); |
| reclac_flag = 1; |
| } |
| |
| if (!close_to(vf->pts, (hw->last_pts + DUR2PTS(hw->frame_dur)), 100)) { |
| vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur); |
| vf->pts_us64 = hw->last_pts_us64 + |
| (DUR2PTS(hw->frame_dur) * 100 / 9); |
| reclac_flag = 2; |
| } |
| |
| if (hw->is_used_v4l) |
| reclac_flag = 0; |
| |
| /* try find the closed pts in saved pts pool */ |
| if (reclac_flag) { |
| for (i = 0; i < FRAME_BUFFERS - 1; i++) { |
| if ((hw->frame_mode_pts_save[i] > vf->pts) && |
| (hw->frame_mode_pts_save[i + 1] < vf->pts)) { |
| if ((hw->frame_mode_pts_save[i] - vf->pts) > |
| (vf->pts - hw->frame_mode_pts_save[i + 1])) { |
| vf->pts = hw->frame_mode_pts_save[i + 1]; |
| vf->pts_us64 = hw->frame_mode_pts64_save[i + 1]; |
| } else { |
| vf->pts = hw->frame_mode_pts_save[i]; |
| vf->pts_us64 = hw->frame_mode_pts64_save[i]; |
| } |
| break; |
| } |
| } |
| if (i == (FRAME_BUFFERS - 1)) |
| hw->dur_recalc_flag = 1; |
| } |
| } else { |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "first pts %d change to save[%d] %d\n", |
| vf->pts, hw->first_pts_index - 1, |
| hw->frame_mode_pts_save[hw->first_pts_index - 1]); |
| vf->pts = hw->frame_mode_pts_save[hw->first_pts_index - 1]; |
| vf->pts_us64 = hw->frame_mode_pts64_save[hw->first_pts_index - 1]; |
| } |
| hw->last_pts = vf->pts; |
| hw->last_pts_us64 = vf->pts_us64; |
| hw->av1_first_pts_ready = true; |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "av1 output slice type %d, dur %d, pts %d, pts64 %lld, ts: %llu\n", |
| pic_config->slice_type, hw->frame_dur, vf->pts, vf->pts_us64, vf->timestamp); |
| |
| fill_frame_info(hw, pic_config, frame_size, vf->pts); |
| |
| vf->index = 0xff00 | pic_config->v4l_buf_index; |
| if (pic_config->double_write_mode & 0x10) { |
| /* double write only */ |
| vf->compBodyAddr = 0; |
| vf->compHeadAddr = 0; |
| #ifdef AOM_AV1_MMU_DW |
| vf->dwBodyAddr = 0; |
| vf->dwHeadAddr = 0; |
| #endif |
| } else { |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| vf->compBodyAddr = 0; |
| vf->compHeadAddr = pic_config->header_adr; |
| if (((get_debug_fgs() & DEBUG_FGS_BYPASS) == 0) |
| && hw->assit_task.use_sfgs) |
| vf->fgs_table_adr = pic_config->sfgs_table_phy; |
| else |
| vf->fgs_table_adr = pic_config->fgs_table_adr; |
| vf->fgs_valid = hw->fgs_valid; |
| #ifdef AOM_AV1_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 & AOM_DEBUG_DW_DISP_MAIN) == 0) { |
| vf->compHeadAddr = pic_config->header_dw_adr; |
| vf->fgs_valid = 0; |
| av1_print(hw, AOM_DEBUG_VFRAME, |
| "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 ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| vf->type |= VIDTYPE_SCATTER; |
| } |
| } |
| if (hw->is_used_v4l && pic_config->double_write_mode != 16 && |
| (!IS_8K_SIZE(pic_config->y_crop_width, |
| pic_config->y_crop_height))) { |
| if ((get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_S4 && |
| get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_S4D) |
| || (!hw->film_grain_present) || (get_double_write_mode(hw) != 1)) { |
| vf->type |= VIDTYPE_COMPRESS | VIDTYPE_SCATTER; |
| } |
| } |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (hw->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 ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| vf->type |= VIDTYPE_SCATTER; |
| } |
| } |
| |
| switch (pic_config->bit_depth) { |
| case AOM_BITS_8: |
| vf->bitdepth = BITDEPTH_Y8 | |
| BITDEPTH_U8 | BITDEPTH_V8; |
| break; |
| case AOM_BITS_10: |
| case AOM_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 == AOM_BITS_8) |
| vf->bitdepth |= BITDEPTH_SAVING_MODE; |
| |
| /* if ((vf->width!=pic_config->width)| |
| * (vf->height!=pic_config->height)) |
| */ |
| /* pr_info("aaa: %d/%d, %d/%d\n", |
| vf->width,vf->height, pic_config->width, |
| pic_config->height); */ |
| 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(hw, vf); |
| if (force_fps & 0x100) { |
| u32 rate = force_fps & 0xff; |
| |
| if (rate) |
| vf->duration = 96000/rate; |
| else |
| vf->duration = 0; |
| } |
| update_vf_memhandle(hw, vf, pic_config); |
| |
| av1_inc_vf_ref(hw, pic_config->v4l_buf_index); |
| |
| vdec_vframe_ready(hw_to_vdec(hw), vf); |
| if (pic_config->double_write_mode && |
| ((pic_config->double_write_mode & 0x20) == 0) && |
| (pic_config->v4l_buf_index != pic_config->BUF_index)) { |
| struct PIC_BUFFER_CONFIG_s *dst_pic = |
| &hw->common.buffer_pool->frame_bufs[pic_config->v4l_buf_index].buf; |
| struct PIC_BUFFER_CONFIG_s *src_pic = |
| &hw->common.buffer_pool->frame_bufs[pic_config->BUF_index].buf; |
| struct vdec_ge2d_info ge2d_info; |
| |
| av1_print(hw, PRINT_FLAG_V4L_DETAIL, |
| "ge2d copy start v4l_buf_index:%d repeat_buff_index:%d\n", |
| pic_config->v4l_buf_index, |
| pic_config->BUF_index); |
| ge2d_info.dst_vf = vf; |
| ge2d_info.src_canvas0Addr = ge2d_info.src_canvas1Addr = 0; |
| if (dst_pic->double_write_mode) { |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (hw->m_ins_flag) { |
| vf->canvas0Addr = vf->canvas1Addr = -1; |
| ge2d_info.src_canvas0Addr = ge2d_info.src_canvas1Addr = -1; |
| vf->plane_num = 2; |
| vf->canvas0_config[0] = |
| dst_pic->canvas_config[0]; |
| vf->canvas0_config[1] = |
| dst_pic->canvas_config[1]; |
| vf->canvas1_config[0] = |
| dst_pic->canvas_config[0]; |
| vf->canvas1_config[1] = |
| dst_pic->canvas_config[1]; |
| ge2d_info.src_canvas0_config[0] = |
| src_pic->canvas_config[0]; |
| ge2d_info.src_canvas0_config[1] = |
| src_pic->canvas_config[1]; |
| ge2d_info.src_canvas1_config[0] = |
| src_pic->canvas_config[0]; |
| ge2d_info.src_canvas1_config[1] = |
| src_pic->canvas_config[1]; |
| } else |
| #endif |
| { |
| vf->canvas0Addr = vf->canvas1Addr = |
| spec2canvas(dst_pic); |
| ge2d_info.src_canvas0Addr = ge2d_info.src_canvas1Addr = |
| spec2canvas(src_pic); |
| } |
| } |
| |
| if (!hw->ge2d) { |
| int mode = nv_order == VIDTYPE_VIU_NV21 ? GE2D_MODE_CONVERT_NV21 : GE2D_MODE_CONVERT_NV12; |
| mode |= GE2D_MODE_CONVERT_LE; |
| vdec_ge2d_init(&hw->ge2d, mode); |
| } |
| vdec_ge2d_copy_data(hw->ge2d, &ge2d_info); |
| av1_print(hw, PRINT_FLAG_V4L_DETAIL, "ge2d copy done\n"); |
| } |
| decoder_do_frame_check(hw_to_vdec(hw), vf); |
| kfifo_put(&hw->display_q, (const struct vframe_s *)vf); |
| ATRACE_COUNTER(hw->trace.pts_name, vf->timestamp); |
| ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); |
| ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); |
| |
| atomic_add(1, &hw->vf_pre_count); |
| /*count info*/ |
| hw->gvs->frame_dur = hw->frame_dur; |
| vdec_count_info(hw->gvs, 0, stream_offset); |
| hw_to_vdec(hw)->vdec_fps_detec(hw_to_vdec(hw)->id); |
| |
| #ifdef AUX_DATA_CRC |
| decoder_do_aux_data_check(hw_to_vdec(hw), pic_config->aux_data_buf, |
| pic_config->aux_data_size); |
| #endif |
| |
| av1_print(hw, AV1_DEBUG_SEI_DETAIL, "%s aux_data_size = %d\n", |
| __func__, pic_config->aux_data_size); |
| |
| if (debug & AV1_DEBUG_SEI_DETAIL) { |
| int i = 0; |
| PR_INIT(128); |
| for (i = 0; i < pic_config->aux_data_size; i++) { |
| PR_FILL("%02x ", pic_config->aux_data_buf[i]); |
| if (((i + 1) & 0xf) == 0) |
| PR_INFO(hw->index); |
| } |
| PR_INFO(hw->index); |
| } |
| |
| if (hw->is_used_v4l) { |
| if ((pic_config->aux_data_size == 0) && |
| (pic_config->slice_type == KEY_FRAME) && |
| (atomic_read(&hw->vf_pre_count) == 1)) { |
| hw->no_need_aux_data = true; |
| } |
| |
| if (hw->no_need_aux_data) { |
| v4l2_ctx->aux_infos.free_buffer(v4l2_ctx, DV_TYPE); |
| v4l2_ctx->aux_infos.free_one_sei_buffer(v4l2_ctx, |
| &pic_config->aux_data_buf, |
| &pic_config->aux_data_size, |
| pic_config->ctx_buf_idx); |
| } else { |
| v4l2_ctx->aux_infos.bind_dv_buffer(v4l2_ctx, &vf->src_fmt.comp_buf, |
| &vf->src_fmt.md_buf); |
| } |
| |
| update_vframe_src_fmt(vf, |
| pic_config->aux_data_buf, |
| pic_config->aux_data_size, |
| false, hw->provider_name, NULL); |
| } |
| |
| av1_update_gvs(hw, vf, pic_config); |
| memcpy(&tmp4x, hw->gvs, sizeof(struct vdec_info)); |
| tmp4x.bit_depth_luma = bit_depth_luma; |
| tmp4x.bit_depth_chroma = bit_depth_chroma; |
| tmp4x.double_write_mode = pic_config->double_write_mode; |
| vdec_fill_vdec_frame(hw_to_vdec(hw), &hw->vframe_qos, &tmp4x, vf, pic_config->hw_decode_time); |
| if (without_display_mode == 0) { |
| if (hw->is_used_v4l) { |
| if (v4l2_ctx->is_stream_off) { |
| vav1_vf_put(vav1_vf_get(hw), hw); |
| } else { |
| ATRACE_COUNTER("VC_OUT_DEC-submit", fb->buf_idx); |
| fb->task->submit(fb->task, TASK_TYPE_DEC); |
| } |
| } else { |
| vf_notify_receiver(hw->provider_name, |
| VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); |
| } |
| } else |
| vav1_vf_put(vav1_vf_get(hw), hw); |
| } |
| |
| return 0; |
| } |
| |
| void av1_raw_write_image(AV1Decoder *pbi, PIC_BUFFER_CONFIG *sd) |
| { |
| sd->stream_offset = pbi->pre_stream_offset; |
| prepare_display_buf((struct AV1HW_s *)(pbi->private_data), sd); |
| pbi->pre_stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT); |
| } |
| |
| static bool is_avaliable_buffer(struct AV1HW_s *hw); |
| |
| static int notify_v4l_eos(struct vdec_s *vdec) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_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) { |
| expires = jiffies + msecs_to_jiffies(2000); |
| while (!is_avaliable_buffer(hw)) { |
| if (time_after(jiffies, expires)) { |
| pr_err("[%d] AV1 isn't enough buff for notify eos.\n", ctx->id); |
| return 0; |
| } |
| } |
| |
| index = v4l_get_free_fb(hw); |
| if (INVALID_IDX == index) { |
| pr_err("[%d] AV1 EOS get free buff fail.\n", ctx->id); |
| return 0; |
| } |
| |
| fb = (struct vdec_v4l2_buffer *) |
| hw->m_BUF[index].v4l_ref_buf_addr; |
| |
| vf->type |= VIDTYPE_V4L_EOS; |
| vf->timestamp = ULONG_MAX; |
| vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; |
| vf->v4l_mem_handle = (ulong)fb; |
| |
| vdec_vframe_ready(vdec, vf); |
| kfifo_put(&hw->display_q, (const struct vframe_s *)vf); |
| |
| ATRACE_COUNTER("VC_OUT_DEC-submit", fb->buf_idx); |
| fb->task->submit(fb->task, TASK_TYPE_DEC); |
| |
| av1_print(hw, 0, "[%d] AV1 EOS notify.\n", ctx->id); |
| } |
| |
| return 0; |
| } |
| |
| static void get_rpm_param(union param_u *params) |
| { |
| int i; |
| unsigned int data32; |
| |
| if (debug & AV1_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 & AV1_DEBUG_BUFMGR) |
| pr_info("leave %s\r\n", __func__); |
| } |
| |
| #ifdef CHANGE_REMOVED |
| static int recycle_mmu_buf_tail(struct AV1HW_s *hw, |
| bool check_dma) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| |
| hw->used_4k_num = |
| READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; |
| |
| av1_print(hw, 0, "pic index %d page_start %d\n", |
| cm->cur_fb_idx_mmu, hw->used_4k_num); |
| |
| if (check_dma) |
| hevc_mmu_dma_check(hw_to_vdec(hw)); |
| |
| if (hw->is_used_v4l) { |
| int index = cm->cur_fb_idx_mmu; |
| struct internal_comp_buf *ibuf = |
| index_to_icomp_buf(hw, index); |
| |
| decoder_mmu_box_free_idx_tail( |
| ibuf->mmu_box, |
| ibuf->index, |
| hw->used_4k_num); |
| } else { |
| decoder_mmu_box_free_idx_tail( |
| hw->mmu_box, |
| cm->cur_fb_idx_mmu, |
| hw->used_4k_num); |
| } |
| |
| cm->cur_fb_idx_mmu = INVALID_IDX; |
| hw->used_4k_num = -1; |
| |
| return 0; |
| } |
| #endif |
| |
| #ifdef CHANGE_REMOVED |
| static void av1_recycle_mmu_buf_tail(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| if (get_double_write_mode(hw) & 0x10) |
| return; |
| |
| if (cm->cur_fb_idx_mmu != INVALID_IDX) { |
| recycle_mmu_buf_tail(hw, |
| ((hw->used_4k_num == -1) && |
| hw->m_ins_flag) ? 1 : 0); |
| } |
| } |
| #endif |
| |
| static void av1_recycle_mmu_buf(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| |
| if (hw->is_used_v4l) |
| return; |
| |
| if (get_double_write_mode(hw) & 0x10) |
| return; |
| if (cm->cur_fb_idx_mmu != INVALID_IDX) { |
| decoder_mmu_box_free_idx(hw->mmu_box, |
| cm->cur_fb_idx_mmu); |
| |
| cm->cur_fb_idx_mmu = INVALID_IDX; |
| hw->used_4k_num = -1; |
| } |
| } |
| |
| static void dec_again_process(struct AV1HW_s *hw) |
| { |
| amhevc_stop(); |
| hw->dec_result = DEC_RESULT_AGAIN; |
| if (hw->process_state == |
| PROC_STATE_DECODESLICE) { |
| hw->process_state = |
| PROC_STATE_SENDAGAIN; |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| av1_recycle_mmu_buf(hw); |
| } |
| } |
| reset_process_time(hw); |
| vdec_schedule_work(&hw->work); |
| } |
| |
| static void read_film_grain_reg(struct AV1HW_s *hw) |
| { |
| AV1_COMMON *cm = &hw->common; |
| int i; |
| if (cm->cur_frame == NULL) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s, cur_frame not exist!!!\n", __func__); |
| return; |
| } else |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s\n", __func__); |
| WRITE_VREG(HEVC_FGS_IDX, 0); |
| for (i = 0; i < FILM_GRAIN_REG_SIZE; i++) { |
| cm->cur_frame->film_grain_reg[i] = READ_VREG(HEVC_FGS_DATA); |
| } |
| cm->cur_frame->film_grain_reg_valid = 1; |
| cm->cur_frame->film_grain_ctrl = READ_VREG(HEVC_FGS_CTRL); |
| } |
| |
| static void config_film_grain_reg(struct AV1HW_s *hw, int film_grain_params_ref_idx) |
| { |
| AV1_COMMON *cm = &hw->common; |
| int i; |
| unsigned char found = 0; |
| RefCntBuffer *buf; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " ## %s frome reference idx %d\n", |
| __func__, film_grain_params_ref_idx); |
| for (i = 0; i < INTER_REFS_PER_FRAME; ++i) { |
| if (film_grain_params_ref_idx == cm->remapped_ref_idx[i]) { |
| found = 1; |
| break; |
| } |
| } |
| if (!found) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s Error, Invalid film grain reference idx %d\n", |
| __func__, film_grain_params_ref_idx); |
| return; |
| } |
| buf = cm->ref_frame_map[film_grain_params_ref_idx]; |
| |
| if (buf->film_grain_reg_valid == 0) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s Error, film grain register data invalid for reference idx %d\n", |
| __func__, film_grain_params_ref_idx); |
| return; |
| } |
| |
| if (cm->cur_frame == NULL) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s, cur_frame not exist!!!\n", __func__); |
| } |
| WRITE_VREG(HEVC_FGS_IDX, 0); |
| for (i = 0; i < FILM_GRAIN_REG_SIZE; i++) { |
| WRITE_VREG(HEVC_FGS_DATA, buf->film_grain_reg[i]); |
| if (cm->cur_frame) |
| cm->cur_frame->film_grain_reg[i] = buf->film_grain_reg[i]; |
| } |
| if (cm->cur_frame) |
| cm->cur_frame->film_grain_reg_valid = 1; |
| WRITE_VREG(HEVC_FGS_CTRL, READ_VREG(HEVC_FGS_CTRL) | 1); // set fil_grain_start |
| if (cm->cur_frame) |
| cm->cur_frame->film_grain_ctrl = READ_VREG(HEVC_FGS_CTRL); |
| } |
| |
| void config_next_ref_info_hw(struct AV1HW_s *hw) |
| { |
| int j; |
| AV1_COMMON *const cm = &hw->common; |
| |
| av1_set_next_ref_frame_map(hw->pbi); |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) |
| WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11a0); |
| else |
| WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1000); |
| |
| for (j = 0; j < 12; j++) { |
| unsigned int info = |
| av1_get_next_used_ref_info(cm, j); |
| |
| WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, info); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "config next ref info %d 0x%x\n", j, info); |
| } |
| } |
| |
| |
| |
| #ifdef PRINT_HEVC_DATA_PATH_MONITOR |
| void datapath_monitor(struct AV1HW_s *hw) |
| { |
| uint32_t total_clk_count; |
| uint32_t path_transfer_count; |
| uint32_t path_wait_count; |
| float path_wait_ratio; |
| if (pbi->decode_idx > 1) { |
| WRITE_VREG(HEVC_PATH_MONITOR_CTRL, 0); // Disabble monitor and set rd_idx to 0 |
| total_clk_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| |
| WRITE_VREG(HEVC_PATH_MONITOR_CTRL, (1<<4)); // Disabble monitor and set rd_idx to 0 |
| |
| // parser --> iqit |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk("[P%d HEVC PATH] Parser/IQIT/IPP/DBLK/OW/DDR/CMD WAITING \% : %.2f", |
| pbi->decode_idx - 2, path_wait_ratio); |
| |
| // iqit --> ipp |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // dblk <-- ipp |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // dblk --> ow |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // <--> DDR |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f", path_wait_ratio); |
| |
| // CMD |
| path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA); |
| if (path_transfer_count == 0) path_wait_ratio = 0.0; |
| else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count; |
| printk(" %.2f\n", path_wait_ratio); |
| } |
| } |
| |
| #endif |
| |
| #ifdef MCRCC_ENABLE |
| |
| static int mcrcc_hit_rate; |
| static int mcrcc_bypass_rate; |
| |
| #define C_Reg_Wr WRITE_VREG |
| static void C_Reg_Rd(unsigned int adr, unsigned int *val) |
| { |
| *val = READ_VREG(adr); |
| } |
| |
| static void mcrcc_perfcount_reset(struct AV1HW_s *hw) |
| { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, |
| "[cache_util.c] Entered mcrcc_perfcount_reset...\n"); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x1); |
| C_Reg_Wr(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(struct AV1HW_s *hw, 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; |
| } |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered mcrcc_get_hitrate...\n"); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x0<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &raw_mcr_cnt); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x1<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &hit_mcr_cnt); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x2<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &byp_mcr_cnt_nchoutwin); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x3<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &byp_mcr_cnt_nchcanv); |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "raw_mcr_cnt_total: %d\n",raw_mcr_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hit_mcr_cnt_total: %d\n",hit_mcr_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "byp_mcr_cnt_nchoutwin_total: %d\n",byp_mcr_cnt_nchoutwin); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "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; |
| |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "miss_mcr_0_cnt_total: %d\n",tmp); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x5<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "miss_mcr_1_cnt_total: %d\n",tmp); |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x6<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "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; |
| C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1)); |
| C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "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; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CANV0_HIT_RATE : %d\n", hitrate); |
| hitrate = 100 * delta_hit_mcr_1_cnt/delta_raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CANV1_HIT_RATE : %d\n", hitrate); |
| hitrate = 100 * delta_mcr_cnt_nchcanv/delta_raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "NONCACH_CANV_BYP_RATE : %d\n", hitrate); |
| hitrate = 100 * delta_mcr_cnt_nchoutwin/delta_raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CACHE_OUTWIN_BYP_RATE : %d\n", hitrate); |
| } |
| |
| if (raw_mcr_cnt != 0) |
| { |
| hitrate = 100*hit_mcr_cnt/raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : %d\n", hitrate); |
| hitrate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : %d\n", hitrate); |
| } else { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : na\n"); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : na\n"); |
| } |
| mcrcc_hit_rate = 100*hit_mcr_cnt/raw_mcr_cnt; |
| mcrcc_bypass_rate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt; |
| |
| return; |
| } |
| |
| static void decomp_perfcount_reset(struct AV1HW_s *hw) |
| { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_perfcount_reset...\n"); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x1); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x0); |
| return; |
| } |
| |
| static void decomp_get_hitrate(struct AV1HW_s *hw) |
| { |
| unsigned raw_mcr_cnt; |
| unsigned hit_mcr_cnt; |
| int hitrate; |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_get_hitrate...\n"); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x0<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_mcr_cnt); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x1<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &hit_mcr_cnt); |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hcache_raw_cnt_total: %d\n",raw_mcr_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hcache_hit_cnt_total: %d\n",hit_mcr_cnt); |
| |
| if ( raw_mcr_cnt != 0 ) { |
| hitrate = 100*hit_mcr_cnt/raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : %.2f\%\n", hitrate); |
| } else { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : na\n"); |
| } |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x2<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_mcr_cnt); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x3<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &hit_mcr_cnt); |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "dcache_raw_cnt_total: %d\n",raw_mcr_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "dcache_hit_cnt_total: %d\n",hit_mcr_cnt); |
| |
| if ( raw_mcr_cnt != 0 ) { |
| hitrate = 100*hit_mcr_cnt/raw_mcr_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_DCACHE_HIT_RATE : %d\n", hitrate); |
| |
| //hitrate = ((float)hit_mcr_cnt/(float)raw_mcr_cnt); |
| //hitrate = (mcrcc_hit_rate + (mcrcc_bypass_rate * hitrate))*100; |
| hitrate = mcrcc_hit_rate + (mcrcc_bypass_rate * hit_mcr_cnt/raw_mcr_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_DECOMP_DCACHE_EFFECTIVE_HIT_RATE : %d\n", hitrate); |
| |
| } else { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_DCACHE_HIT_RATE : na\n"); |
| } |
| |
| return; |
| } |
| |
| static void decomp_get_comprate(struct AV1HW_s *hw) |
| { |
| unsigned raw_ucomp_cnt; |
| unsigned fast_comp_cnt; |
| unsigned slow_comp_cnt; |
| int comprate; |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_get_comprate...\n"); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x4<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &fast_comp_cnt); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x5<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &slow_comp_cnt); |
| C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x6<<1)); |
| C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_ucomp_cnt); |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_fast_comp_total: %d\n",fast_comp_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_slow_comp_total: %d\n",slow_comp_cnt); |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_raw_uncomp_total: %d\n",raw_ucomp_cnt); |
| |
| if ( raw_ucomp_cnt != 0 ) |
| { |
| comprate = 100*(fast_comp_cnt + slow_comp_cnt)/raw_ucomp_cnt; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_COMP_RATIO : %d\n", comprate); |
| } else |
| { |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_COMP_RATIO : na\n"); |
| } |
| return; |
| } |
| |
| static void dump_hit_rate(struct AV1HW_s *hw) |
| { |
| if (debug & AV1_DEBUG_CACHE_HIT_RATE) { |
| mcrcc_get_hitrate(hw, hw->m_ins_flag); |
| decomp_get_hitrate(hw); |
| decomp_get_comprate(hw); |
| } |
| } |
| |
| static uint32_t mcrcc_get_abs_frame_distance(struct AV1HW_s *hw, uint32_t refid, uint32_t ref_ohint, uint32_t curr_ohint, uint32_t ohint_bits_min1) |
| { |
| int32_t diff_ohint0; |
| int32_t diff_ohint1; |
| uint32_t abs_dist; |
| uint32_t m; |
| uint32_t m_min1; |
| |
| diff_ohint0 = ref_ohint - curr_ohint; |
| |
| m = (1 << ohint_bits_min1); |
| m_min1 = m -1; |
| |
| diff_ohint1 = (diff_ohint0 & m_min1 ) - (diff_ohint0 & m); |
| |
| abs_dist = (diff_ohint1 < 0) ? -diff_ohint1 : diff_ohint1; |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, |
| "[cache_util.c] refid:%0x ref_orderhint:%0x curr_orderhint:%0x orderhint_bits_min1:%0x abd_dist:%0x\n", |
| refid, ref_ohint, curr_ohint, ohint_bits_min1,abs_dist); |
| |
| return abs_dist; |
| } |
| |
| static void config_mcrcc_axi_hw_nearest_ref(struct AV1HW_s *hw) |
| { |
| uint32_t i; |
| uint32_t rdata32; |
| uint32_t dist_array[8]; |
| uint32_t refcanvas_array[2]; |
| uint32_t orderhint_bits; |
| unsigned char is_inter; |
| AV1_COMMON *cm = &hw->common; |
| PIC_BUFFER_CONFIG *curr_pic_config; |
| int32_t curr_orderhint; |
| int cindex0 = LAST_FRAME; |
| uint32_t last_ref_orderhint_dist = 1023; // large distance |
| uint32_t curr_ref_orderhint_dist = 1023; // large distance |
| int cindex1; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, |
| "[test.c] #### config_mcrcc_axi_hw ####\n"); |
| |
| WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); // reset mcrcc |
| |
| is_inter = av1_frame_is_inter(&hw->common); //((pbi->common.frame_type != KEY_FRAME) && (!pbi->common.intra_only)) ? 1 : 0; |
| if ( !is_inter ) { // I-PIC |
| //WRITE_VREG(HEVCD_MCRCC_CTL1, 0x1); // remove reset -- disables clock |
| WRITE_VREG(HEVCD_MCRCC_CTL2, 0xffffffff); // Replace with current-frame canvas |
| WRITE_VREG(HEVCD_MCRCC_CTL3, 0xffffffff); // |
| WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); // enable mcrcc progressive-mode |
| return; |
| } |
| |
| #if 0 |
| //printk("before call mcrcc_get_hitrate\r\n"); |
| mcrcc_get_hitrate(hw); |
| decomp_get_hitrate(hw); |
| decomp_get_comprate(hw); |
| #endif |
| |
| // Find absolute orderhint delta |
| curr_pic_config = &cm->cur_frame->buf; |
| curr_orderhint = curr_pic_config->order_hint; |
| orderhint_bits = cm->seq_params.order_hint_info.order_hint_bits_minus_1; |
| for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| int32_t ref_orderhint = 0; |
| PIC_BUFFER_CONFIG *pic_config; |
| //int32_t tmp; |
| pic_config = av1_get_ref_frame_spec_buf(cm,i); |
| if (pic_config) |
| ref_orderhint = pic_config->order_hint; |
| //tmp = curr_orderhint - ref_orderhint; |
| //dist_array[i] = (tmp < 0) ? -tmp : tmp; |
| dist_array[i] = mcrcc_get_abs_frame_distance(hw, i,ref_orderhint, curr_orderhint, orderhint_bits); |
| } |
| // Get smallest orderhint distance refid |
| for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| PIC_BUFFER_CONFIG *pic_config; |
| pic_config = av1_get_ref_frame_spec_buf(cm, i); |
| curr_ref_orderhint_dist = dist_array[i]; |
| if ( curr_ref_orderhint_dist < last_ref_orderhint_dist) { |
| cindex0 = i; |
| last_ref_orderhint_dist = curr_ref_orderhint_dist; |
| } |
| } |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex0 << 8) | (1<<1) | 0); |
| refcanvas_array[0] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR) & 0xffff; |
| |
| last_ref_orderhint_dist = 1023; // large distance |
| curr_ref_orderhint_dist = 1023; // large distance |
| // Get 2nd smallest orderhint distance refid |
| cindex1 = LAST_FRAME; |
| for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) { |
| PIC_BUFFER_CONFIG *pic_config; |
| pic_config = av1_get_ref_frame_spec_buf(cm, i); |
| curr_ref_orderhint_dist = dist_array[i]; |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (i << 8) | (1<<1) | 0); |
| refcanvas_array[1] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR) & 0xffff; |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] curr_ref_orderhint_dist:%x last_ref_orderhint_dist:%x refcanvas_array[0]:%x refcanvas_array[1]:%x\n", |
| curr_ref_orderhint_dist, last_ref_orderhint_dist, refcanvas_array[0],refcanvas_array[1]); |
| if ((curr_ref_orderhint_dist < last_ref_orderhint_dist) && (refcanvas_array[0] != refcanvas_array[1])) { |
| cindex1 = i; |
| last_ref_orderhint_dist = curr_ref_orderhint_dist; |
| } |
| } |
| |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex0 << 8) | (1<<1) | 0); |
| refcanvas_array[0] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); |
| WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex1 << 8) | (1<<1) | 0); |
| refcanvas_array[1] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); |
| |
| av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] refcanvas_array[0](index %d):%x refcanvas_array[1](index %d):%x\n", |
| cindex0, refcanvas_array[0], cindex1, refcanvas_array[1]); |
| |
| // 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); |
| |
| WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); // enable mcrcc progressive-mode |
| return; |
| } |
| |
| |
| #endif |
| |
| int av1_continue_decoding(struct AV1HW_s *hw, int obu_type) |
| { |
| int ret = 0; |
| #ifdef SANITY_CHECK |
| param_t* params = &hw->aom_param; |
| #endif |
| #if 1 |
| //def CHANGE_DONE |
| AV1Decoder *pbi = hw->pbi; |
| AV1_COMMON *const cm = pbi->common; |
| struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| int i; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s: pbi %p cm %p cur_frame %p %d has_seq %d has_keyframe %d\n", |
| __func__, pbi, cm, cm->cur_frame, |
| pbi->bufmgr_proc_count, |
| hw->has_sequence, |
| hw->has_keyframe); |
| |
| if (hw->has_sequence == 0) { |
| av1_print(hw, 0, |
| "no sequence head, skip\n"); |
| if (!hw->m_ins_flag) |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| return -2; |
| } else if (hw->has_keyframe == 0 && |
| hw->aom_param.p.frame_type != KEY_FRAME){ |
| av1_print(hw, 0, |
| "no key frame, skip\n"); |
| on_no_keyframe_skiped++; |
| if (!hw->m_ins_flag) |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| return -2; |
| } |
| hw->has_keyframe = 1; |
| on_no_keyframe_skiped = 0; |
| |
| if (hw->is_used_v4l && ctx->param_sets_from_ucode) |
| hw->res_ch_flag = 0; |
| |
| //pre_decode_idx = pbi->decode_idx; |
| if (pbi->bufmgr_proc_count == 0 || |
| hw->one_compressed_data_done) { |
| hw->new_compressed_data = 1; |
| hw->one_compressed_data_done = 0; |
| } else { |
| hw->new_compressed_data = 0; |
| } |
| #ifdef SANITY_CHECK |
| ret = 0; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "Check Picture size, max (%d, %d), width/height (%d, %d), dec_width %d\n", |
| params->p.max_frame_width, |
| params->p.max_frame_height, |
| params->p.frame_width_scaled, |
| params->p.frame_height, |
| params->p.dec_frame_width |
| ); |
| |
| if (/*params->p.max_frame_width > MAX_PIC_WIDTH || |
| params->p.max_frame_height > MAX_PIC_HEIGHT ||*/ |
| (params->p.frame_width_scaled * params->p.frame_height) > MAX_SIZE_8K || |
| (params->p.dec_frame_width * params->p.frame_height) > MAX_SIZE_8K || |
| params->p.frame_width_scaled <= 0 || |
| params->p.dec_frame_width <= 0 || |
| params->p.frame_height <= 0) { |
| av1_print(hw, 0, "!!Picture size error, max (%d, %d), width/height (%d, %d), dec_width %d\n", |
| params->p.max_frame_width, |
| params->p.max_frame_height, |
| params->p.frame_width_scaled, |
| params->p.frame_height, |
| params->p.dec_frame_width |
| ); |
| ret = -1; |
| } |
| #endif |
| if (ret >= 0) { |
| ret = av1_bufmgr_process(pbi, &hw->aom_param, |
| hw->new_compressed_data, obu_type); |
| if (ret < 0) |
| return -1; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "%s: pbi %p cm %p cur_frame %p\n", |
| __func__, pbi, cm, cm->cur_frame); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "1+++++++++++++++++++++++++++++++++++%d %p\n", |
| ret, cm->cur_frame); |
| if (cm->cur_frame) { |
| init_waitqueue_head(&cm->cur_frame->wait_sfgs); |
| atomic_set(&cm->cur_frame->fgs_done, 1); |
| } |
| if (hw->new_compressed_data) |
| WRITE_VREG(PIC_END_LCU_COUNT, 0); |
| } |
| if (ret > 0) { |
| /* the case when cm->show_existing_frame is 1 */ |
| /*case 3016*/ |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "Decoding done (index=%d, show_existing_frame = %d)\n", |
| cm->cur_frame? cm->cur_frame->buf.index:-1, |
| cm->show_existing_frame |
| ); |
| |
| if (cm->cur_frame) { |
| PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf; |
| if (debug & |
| AV1_DEBUG_BUFMGR_MORE) |
| dump_aux_buf(hw); |
| set_pic_aux_data(hw, |
| cur_pic_config, 0, 0); |
| } |
| config_next_ref_info_hw(hw); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "aom_bufmgr_process=> %d,decode done, AOM_AV1_SEARCH_HEAD\r\n", ret); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| pbi->decode_idx++; |
| pbi->bufmgr_proc_count++; |
| hw->frame_decoded = 1; |
| return 0; |
| } else if (ret < 0) { |
| hw->frame_decoded = 1; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "aom_bufmgr_process=> %d, bufmgr e.r.r.o.r. %d, AOM_AV1_SEARCH_HEAD\r\n", |
| ret, cm->error.error_code); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| return 0; |
| } |
| else if (ret == 0) { |
| PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf; |
| PIC_BUFFER_CONFIG* prev_pic_config = &cm->prev_frame->buf; |
| //struct segmentation_lf *seg_4lf = &hw->seg_4lf_store; |
| if (debug & |
| AV1_DEBUG_BUFMGR_MORE) |
| dump_aux_buf(hw); |
| set_dv_data(hw); |
| if (cm->show_frame && |
| hw->dv_data_buf != NULL) |
| copy_dv_data(hw, cur_pic_config); |
| /* to do:.. |
| set_pic_aux_data(hw, |
| cur_pic_config, 0, 2);*/ |
| hw->frame_decoded = 0; |
| pbi->bufmgr_proc_count++; |
| if (hw->new_compressed_data == 0) { |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE); |
| return 0; |
| } |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " [PICTURE %d] cm->cur_frame->mi_size : (%d X %d) y_crop_size :(%d X %d)\n", |
| hw->frame_count, |
| cm->cur_frame->mi_cols, |
| cm->cur_frame->mi_rows, |
| cur_pic_config->y_crop_width, |
| cur_pic_config->y_crop_height); |
| if (cm->prev_frame > 0) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " [SEGMENT] cm->prev_frame->segmentation_enabled : %d\n", |
| cm->prev_frame->segmentation_enabled); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " [SEGMENT] cm->prev_frame->mi_size : (%d X %d)\n", |
| cm->prev_frame->mi_cols, cm->prev_frame->mi_rows); |
| } |
| cm->cur_frame->prev_segmentation_enabled = (cm->prev_frame > 0) ? |
| (cm->prev_frame->segmentation_enabled & (cm->prev_frame->segmentation_update_map |
| | cm->prev_frame->prev_segmentation_enabled) & |
| (cm->cur_frame->mi_rows == cm->prev_frame->mi_rows) & |
| (cm->cur_frame->mi_cols == cm->prev_frame->mi_cols)) : 0; |
| WRITE_VREG(AV1_SKIP_MODE_INFO, |
| (cm->cur_frame->prev_segmentation_enabled << 31) | |
| (((cm->prev_frame > 0) ? cm->prev_frame->intra_only : 0) << 30) | |
| (((cm->prev_frame > 0) ? prev_pic_config->index : 0x1f) << 24) | |
| (((cm->cur_frame > 0) ? cur_pic_config->index : 0x1f) << 16) | |
| (cm->current_frame.skip_mode_info.ref_frame_idx_0 & 0xf) | |
| ((cm->current_frame.skip_mode_info.ref_frame_idx_1 & 0xf) << 4) | |
| (cm->current_frame.skip_mode_info.skip_mode_allowed << 8)); |
| cur_pic_config->decode_idx = pbi->decode_idx; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "Decode Frame Data %d frame_type %d (%d) bufmgr_proc_count %d\n", |
| pbi->decode_idx, |
| cm->cur_frame->frame_type, |
| cm->current_frame.frame_type, |
| pbi->bufmgr_proc_count); |
| pbi->decode_idx++; |
| hw->frame_count++; |
| cur_pic_config->slice_type = cm->cur_frame->frame_type; |
| if (hw->chunk) { |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "%s, config pic pts %d, pts64 %lld, ts: %lld\n", |
| __func__, hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp); |
| cur_pic_config->pts = hw->chunk->pts; |
| cur_pic_config->pts64 = hw->chunk->pts64; |
| |
| if (hw->is_used_v4l && !v4l_bitstream_id_enable) { |
| cur_pic_config->pts64 = hw->chunk->timestamp; |
| hw->chunk->timestamp = 0; |
| } |
| |
| hw->chunk->pts = 0; |
| hw->chunk->pts64 = 0; |
| } |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_START); |
| #ifdef DUAL_DECODE |
| #else |
| config_pic_size(hw, hw->aom_param.p.bit_depth); |
| #endif |
| if (get_mv_buf(hw, &cm->cur_frame->buf) < 0) { |
| av1_print(hw, 0, |
| "%s: Error get_mv_buf fail\n", |
| __func__); |
| ret = -1; |
| } |
| |
| if (ret >= 0 && (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| ret = av1_alloc_mmu(hw, |
| cm->cur_frame->buf.index, |
| cur_pic_config->y_crop_width, |
| cur_pic_config->y_crop_height, |
| hw->aom_param.p.bit_depth, |
| hw->frame_mmu_map_addr); |
| if (ret >= 0) |
| cm->cur_fb_idx_mmu = cm->cur_frame->buf.index; |
| else |
| pr_err("can't alloc need mmu1,idx %d ret =%d\n", |
| cm->cur_frame->buf.index, ret); |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| ret = av1_alloc_mmu_dw(hw, |
| cm->cur_frame->buf.index, |
| cur_pic_config->y_crop_width, |
| cur_pic_config->y_crop_height, |
| hw->aom_param.p.bit_depth, |
| hw->dw_frame_mmu_map_addr); |
| if (ret >= 0) |
| cm->cur_fb_idx_mmu_dw = cm->cur_frame->buf.index; |
| else |
| pr_err("can't alloc need dw mmu1,idx %d ret =%d\n", |
| cm->cur_frame->buf.index, ret); |
| } |
| #endif |
| #ifdef DEBUG_CRC_ERROR |
| if (crc_debug_flag & 0x40) |
| mv_buffer_fill_zero(hw, &cm->cur_frame->buf); |
| #endif |
| } else { |
| ret = 0; |
| } |
| if (av1_frame_is_inter(&hw->common)) { |
| //if ((pbi->common.frame_type != KEY_FRAME) && (!pbi->common.intra_only)) { |
| #ifdef DUAL_DECODE |
| #else |
| config_mc_buffer(hw, hw->aom_param.p.bit_depth, 1); |
| #endif |
| config_mpred_hw(hw, 1); |
| } |
| else { |
| config_mc_buffer(hw, hw->aom_param.p.bit_depth, 0); |
| clear_mpred_hw(hw); |
| config_mpred_hw(hw, 0); |
| } |
| #ifdef DUAL_DECODE |
| #else |
| #ifdef MCRCC_ENABLE |
| config_mcrcc_axi_hw_nearest_ref(hw); |
| #endif |
| config_sao_hw(hw, &hw->aom_param); |
| #endif |
| |
| config_dblk_hw(hw); |
| |
| /* store segment_feature before shared sub-module run to fix mosaic on t5d */ |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) |
| WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11b0 + (cur_pic_config->index)); |
| else |
| WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index)); |
| if (hw->aom_param.p.segmentation_enabled & 1) // segmentation_enabled |
| WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, READ_VREG(AV1_REF_SEG_INFO)); |
| else |
| WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, 0); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "HEVC_DEC_STATUS_REG <= AOM_AV1_DECODE_SLICE\n"); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE); |
| |
| // Save segment_feature while hardware decoding |
| if (hw->seg_4lf->enabled) { |
| for (i = 0; i < 8; i++) { |
| cm->cur_frame->segment_feature[i] = READ_VREG(AOM_AV1_SEGMENT_FEATURE); |
| } |
| } else { |
| for (i = 0; i < 8; i++) { |
| cm->cur_frame->segment_feature[i] = (0x80000000 | (i << 22)); |
| } |
| } |
| } else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, "Sequence head, Search next start code\n"); |
| cm->prev_fb_idx = INVALID_IDX; |
| //skip, search next start code |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE); |
| } |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_END); |
| return ret; |
| |
| #else |
| |
| bit_depth_luma = av1_param.p.bit_depth; |
| bit_depth_chroma = av1_param.p.bit_depth; |
| |
| if (hw->process_state != PROC_STATE_SENDAGAIN) { |
| ret = av1_bufmgr_process(hw, &av1_param); |
| if (!hw->m_ins_flag) |
| hw->result_done_count++; |
| } else { |
| union param_u *params = &av1_param; |
| if (hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) { |
| ret = av1_alloc_mmu(hw, |
| cm->new_fb_idx, |
| params->p.width, |
| params->p.height, |
| params->p.bit_depth, |
| hw->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); |
| } else { |
| ret = 0; |
| } |
| WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, |
| (params->p.height << 16) | params->p.width); |
| } |
| if (ret < 0) { |
| pr_info("av1_bufmgr_process=> %d, AV1_10B_DISCARD_NAL\r\n", ret); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AV1_10B_DISCARD_NAL); |
| cm->show_frame = 0; |
| if (hw->mmu_enable) |
| av1_recycle_mmu_buf(hw); |
| |
| if (hw->m_ins_flag) { |
| hw->dec_result = DEC_RESULT_DONE; |
| amhevc_stop(); |
| vdec_schedule_work(&hw->work); |
| } |
| return ret; |
| } else if (ret == 0) { |
| struct PIC_BUFFER_CONFIG_s *cur_pic_config |
| = &cm->cur_frame->buf; |
| cur_pic_config->decode_idx = hw->frame_count; |
| |
| if (hw->process_state != PROC_STATE_SENDAGAIN) { |
| if (!hw->m_ins_flag) { |
| hw->frame_count++; |
| decode_frame_count[hw->index] |
| = hw->frame_count; |
| } |
| if (hw->chunk) { |
| cur_pic_config->pts = hw->chunk->pts; |
| cur_pic_config->pts64 = hw->chunk->pts64; |
| } |
| } |
| /*pr_info("Decode Frame Data %d\n", hw->frame_count);*/ |
| config_pic_size(hw, av1_param.p.bit_depth); |
| |
| if ((hw->common.frame_type != KEY_FRAME) |
| && (!hw->common.intra_only)) { |
| config_mc_buffer(hw, av1_param.p.bit_depth); |
| config_mpred_hw(hw); |
| } else { |
| clear_mpred_hw(hw); |
| } |
| #ifdef MCRCC_ENABLE |
| if (mcrcc_cache_alg_flag) |
| config_mcrcc_axi_hw_new(hw); |
| else |
| config_mcrcc_axi_hw(hw); |
| #endif |
| config_sao_hw(hw, &av1_param); |
| /*pr_info("HEVC_DEC_STATUS_REG <= AV1_10B_DECODE_SLICE\n");*/ |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AV1_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, AV1_10B_DECODE_SLICE); |
| } |
| hw->process_state = PROC_STATE_DECODESLICE; |
| if (hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) { |
| if (hw->last_put_idx < hw->used_buf_num) { |
| struct RefCntBuffer_s *frame_bufs = |
| cm->buffer_pool->frame_bufs; |
| int i = hw->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); |
| |
| decoder_mmu_box_free_idx(ibuf->mmu_box, i); |
| } else { |
| decoder_mmu_box_free_idx(pbi->mmu_box, i); |
| } |
| } |
| hw->last_put_idx = -1; |
| } |
| } |
| return ret; |
| #endif |
| } |
| |
| static void fill_frame_info(struct AV1HW_s *hw, |
| struct PIC_BUFFER_CONFIG_s *frame, |
| unsigned int framesize, |
| unsigned int pts) |
| { |
| struct vframe_qos_s *vframe_qos = &hw->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 |
| */ |
| vframe_qos->size = framesize; |
| vframe_qos->pts = pts; |
| #ifdef SHOW_QOS_INFO |
| av1_print(hw, 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 |
| av1_print(hw, 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 |
| av1_print(hw, 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 |
| av1_print(hw, 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++; |
| /* |
| if (hw->frameinfo_enable) |
| vdec_fill_frame_info(vframe_qos, 1); |
| */ |
| } |
| |
| /* 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 AV1HW_s *hw) |
| { |
| struct PIC_BUFFER_CONFIG_s *frame = &hw->cur_buf->buf; |
| |
| if (!frame) |
| return; |
| |
| 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]; |
| |
| av1_print(hw, AV1_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]; |
| |
| av1_print(hw, AV1_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]; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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) { |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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) { |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_DEBUG_QOS_INFO, |
| "[Picture %d Quality] Y QP min : %d\n", |
| pic_number, (rdata32>>0)&0xff); |
| |
| frame->min_qp = (rdata32>>0)&0xff; |
| |
| av1_print(hw, AV1_DEBUG_QOS_INFO, |
| "[Picture %d Quality] Y QP max : %d\n", |
| pic_number, (rdata32>>8)&0xff); |
| |
| frame->max_qp = (rdata32>>8)&0xff; |
| |
| av1_print(hw, AV1_DEBUG_QOS_INFO, |
| "[Picture %d Quality] C QP min : %d\n", |
| pic_number, (rdata32>>16)&0xff); |
| av1_print(hw, AV1_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) { |
| av1_print(hw, AV1_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 */ |
| av1_print(hw, AV1_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); |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_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; |
| |
| av1_print(hw, AV1_DEBUG_QOS_INFO, |
| "[Picture %d Quality] MVY_L1 MIN : %d\n", |
| pic_number, mv_lo); |
| |
| rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL); |
| |
| av1_print(hw, AV1_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 int load_param(struct AV1HW_s *hw, union param_u *params, uint32_t dec_status) |
| { |
| int i; |
| unsigned long flags; |
| int head_type = 0; |
| if (dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE) |
| head_type = OBU_SEQUENCE_HEADER; |
| else if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE) |
| head_type = OBU_FRAME_HEADER; |
| else if (dec_status == AOM_AV1_FRAME_PARSER_DONE) |
| head_type = OBU_FRAME; |
| else if (dec_status == AOM_AV1_REDUNDANT_FRAME_HEAD_PARSER_DONE) |
| head_type = OBU_REDUNDANT_FRAME_HEADER; |
| else { |
| //printf("Error, dec_status of 0x%x, not supported!!!\n", dec_status); |
| return -1; |
| } |
| av1_print2(AOM_DEBUG_HW_MORE, "load_param: ret 0x%x\n", head_type); |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_START); |
| if (debug&AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) { |
| get_rpm_param(params); |
| } |
| else { |
| for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { |
| int32_t ii; |
| for (ii = 0; ii < 4; ii++) { |
| params->l.data[i+ii]=hw->rpm_ptr[i+3-ii]; |
| } |
| } |
| } |
| ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_END); |
| params->p.enable_ref_frame_mvs = (params->p.seq_flags >> 7) & 0x1; |
| params->p.enable_superres = (params->p.seq_flags >> 15) & 0x1; |
| |
| if (debug & AV1_DEBUG_BUFMGR_MORE) { |
| lock_buffer_pool(hw->common.buffer_pool, flags); |
| pr_info("aom_param: (%d)\n", hw->pbi->decode_idx); |
| //pbi->slice_idx++; |
| for ( i = 0; i < (RPM_END-RPM_BEGIN); i++) { |
| pr_info("%04x ", params->l.data[i]); |
| if (((i + 1) & 0xf) == 0) |
| pr_info("\n"); |
| } |
| unlock_buffer_pool(hw->common.buffer_pool, flags); |
| } |
| return head_type; |
| } |
| |
| static int av1_postproc(struct AV1HW_s *hw) |
| { |
| if (hw->postproc_done) |
| return 0; |
| hw->postproc_done = 1; |
| return av1_bufmgr_postproc(hw->pbi, hw->frame_decoded); |
| } |
| |
| static void vav1_get_comp_buf_info(struct AV1HW_s *hw, |
| struct vdec_comp_buf_info *info) |
| { |
| u16 bit_depth = hw->param.p.bit_depth; |
| |
| info->max_size = av1_max_mmu_buf_size( |
| hw->max_pic_w, |
| hw->max_pic_h); |
| info->header_size = av1_get_header_size( |
| hw->frame_width, |
| hw->frame_height); |
| info->frame_buffer_size = av1_mmu_page_num( |
| hw, hw->frame_width, |
| hw->frame_height, |
| bit_depth == 0); |
| } |
| |
| static int vav1_get_ps_info(struct AV1HW_s *hw, struct aml_vdec_ps_infos *ps) |
| { |
| ps->visible_width = hw->frame_width; |
| ps->visible_height = hw->frame_height; |
| ps->coded_width = ALIGN(hw->frame_width, 64); |
| ps->coded_height = ALIGN(hw->frame_height, 64); |
| ps->dpb_size = hw->used_buf_num; |
| ps->dpb_margin = hw->dynamic_buf_num_margin; |
| if (hw->frame_width > 1920 && hw->frame_height > 1088) |
| ps->dpb_frames = 8; |
| else |
| ps->dpb_frames = 10; |
| |
| ps->dpb_frames += 2; |
| |
| if (ps->dpb_margin + ps->dpb_frames > MAX_BUF_NUM_NORMAL) { |
| u32 delta; |
| delta = ps->dpb_margin + ps->dpb_frames - MAX_BUF_NUM_NORMAL; |
| ps->dpb_margin -= delta; |
| hw->dynamic_buf_num_margin = ps->dpb_margin; |
| } |
| ps->field = V4L2_FIELD_NONE; |
| |
| return 0; |
| } |
| |
| static int v4l_res_change(struct AV1HW_s *hw) |
| { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| struct AV1_Common_s *const cm = &hw->common; |
| int ret = 0; |
| |
| if (ctx->param_sets_from_ucode && |
| hw->res_ch_flag == 0) { |
| struct aml_vdec_ps_infos ps; |
| struct vdec_comp_buf_info comp; |
| |
| if ((cm->width != 0 && |
| cm->height != 0) && |
| (hw->frame_width != cm->width || |
| hw->frame_height != cm->height)) { |
| |
| av1_print(hw, 0, |
| "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width, |
| cm->height, hw->frame_width, hw->frame_height); |
| |
| if (get_valid_double_write_mode(hw) != 16) { |
| vav1_get_comp_buf_info(hw, &comp); |
| vdec_v4l_set_comp_buf_info(ctx, &comp); |
| } |
| |
| vav1_get_ps_info(hw, &ps); |
| vdec_v4l_set_ps_infos(ctx, &ps); |
| vdec_v4l_res_ch_event(ctx); |
| hw->v4l_params_parsed = false; |
| hw->res_ch_flag = 1; |
| ctx->v4l_resolution_change = 1; |
| mutex_lock(&hw->assit_task.assit_mutex); |
| hw->eos = 1; |
| |
| av1_postproc(hw); |
| |
| ATRACE_COUNTER("V_ST_DEC-submit_eos", __LINE__); |
| notify_v4l_eos(hw_to_vdec(hw)); |
| ATRACE_COUNTER("V_ST_DEC-submit_eos", 0); |
| mutex_unlock(&hw->assit_task.assit_mutex); |
| ret = 1; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int work_space_size_update(struct AV1HW_s *hw) |
| { |
| int workbuf_size, cma_alloc_cnt, ret; |
| struct BuffInfo_s *p_buf_info = &hw->work_space_buf_store; |
| |
| /* only for 8k workspace update */ |
| if (!IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) |
| return 0; |
| |
| if (hw->cma_alloc_addr && hw->buf_size) { |
| memcpy(p_buf_info, &aom_workbuff_spec[2], |
| sizeof(struct BuffInfo_s)); |
| workbuf_size = (p_buf_info->end_adr - |
| p_buf_info->start_adr + 0xffff) & (~0xffff); |
| cma_alloc_cnt = PAGE_ALIGN(workbuf_size) / PAGE_SIZE; |
| if (hw->cma_alloc_count < cma_alloc_cnt) { |
| decoder_bmmu_box_free_idx(hw->bmmu_box, WORK_SPACE_BUF_ID); |
| hw->buffer_spec_index = 2; |
| hw->cma_alloc_count = cma_alloc_cnt; |
| ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, |
| WORK_SPACE_BUF_ID, hw->cma_alloc_count * PAGE_SIZE, |
| DRIVER_NAME, &hw->cma_alloc_addr); |
| if(ret < 0) { |
| hw->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; |
| pr_err("8k workspace recalloc failed\n"); |
| return ret; |
| } |
| hw->buf_start = hw->cma_alloc_addr; |
| hw->buf_size = workbuf_size; |
| pr_info("8k work_space_buf recalloc, size 0x%x\n", hw->buf_size); |
| p_buf_info->start_adr = hw->buf_start; |
| if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL) || |
| (get_double_write_mode(hw) == 0x10)) { |
| hw->mc_buf_spec.buf_end = hw->buf_start + hw->buf_size; |
| } |
| init_buff_spec(hw, p_buf_info); |
| hw->work_space_buf = p_buf_info; |
| hw->pbi->work_space_buf = p_buf_info; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static irqreturn_t vav1_isr_thread_fn(int irq, void *data) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *)data; |
| unsigned int dec_status = hw->dec_status; |
| int obu_type; |
| int ret = 0; |
| |
| if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE || |
| dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE || |
| dec_status == AOM_AV1_FRAME_PARSER_DONE) { |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); |
| } |
| else if (dec_status == AOM_AV1_DEC_PIC_END || |
| dec_status == AOM_NAL_DECODE_DONE) { |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); |
| } |
| |
| if (hw->eos) |
| return IRQ_HANDLED; |
| hw->wait_buf = 0; |
| if ((dec_status == AOM_NAL_DECODE_DONE) || |
| (dec_status == AOM_SEARCH_BUFEMPTY) || |
| (dec_status == AOM_DECODE_BUFEMPTY) |
| ) { |
| if (hw->m_ins_flag) { |
| reset_process_time(hw); |
| if (!vdec_frame_based(hw_to_vdec(hw))) |
| dec_again_process(hw); |
| else { |
| hw->dec_result = DEC_RESULT_DONE; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); |
| vdec_schedule_work(&hw->work); |
| } |
| } |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } else if (dec_status == AOM_AV1_DEC_PIC_END) { |
| struct AV1_Common_s *const cm = &hw->common; |
| struct PIC_BUFFER_CONFIG_s *frame = &cm->cur_frame->buf; |
| struct vdec_s *vdec = hw_to_vdec(hw); |
| #if 1 |
| u32 fg_reg0, fg_reg1, num_y_points, num_cb_points, num_cr_points; |
| WRITE_VREG(HEVC_FGS_IDX, 0); |
| fg_reg0 = READ_VREG(HEVC_FGS_DATA); |
| fg_reg1 = READ_VREG(HEVC_FGS_DATA); |
| num_y_points = fg_reg1 & 0xf; |
| num_cr_points = (fg_reg1 >> 8) & 0xf; |
| num_cb_points = (fg_reg1 >> 4) & 0xf; |
| if ((num_y_points > 0) || |
| ((num_cb_points > 0) | ((fg_reg0 >> 17) & 0x1)) || |
| ((num_cr_points > 0) | ((fg_reg0 >> 17) & 0x1))) |
| hw->fgs_valid = 1; |
| else |
| hw->fgs_valid = 0; |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "fg_data0 0x%x fg_data1 0x%x fg_valid %d\n", |
| fg_reg0, fg_reg1, hw->fgs_valid); |
| #else |
| if (READ_VREG(HEVC_FGS_CTRL) & |
| ((1 << 4) | (1 << 5) | (1 << 6))) |
| hw->fgs_valid = 1; |
| else |
| hw->fgs_valid = 0; |
| #endif |
| decode_frame_count[hw->index] = hw->frame_count; |
| if (hw->m_ins_flag) { |
| #ifdef USE_DEC_PIC_END |
| if (READ_VREG(PIC_END_LCU_COUNT) != 0) { |
| hw->frame_decoded = 1; |
| if (cm->cur_frame && vdec->mvfrm && frame) { |
| frame->hw_decode_time = |
| local_clock() - vdec->mvfrm->hw_decode_start; |
| frame->frame_size2 = vdec->mvfrm->frame_size; |
| } |
| hw->gvs->frame_count = hw->frame_count; |
| /* |
| In c module, multi obus are put in one packet, which is decoded |
| with av1_receive_compressed_data(). |
| For STREAM_MODE or SINGLE_MODE, there is no packet boundary, |
| we assume each packet must and only include one picture of data (LCUs) |
| or cm->show_existing_frame is 1 |
| */ |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "Decoding done (index %d), fgs_valid %d data_size 0x%x shiftbyte 0x%x\n", |
| cm->cur_frame? cm->cur_frame->buf.index:-1, |
| hw->fgs_valid, |
| hw->data_size, |
| READ_VREG(HEVC_SHIFT_BYTE_COUNT)); |
| hw->config_next_ref_info_flag = 1; /*to do: low_latency_flag case*/ |
| //config_next_ref_info_hw(hw); |
| } |
| #endif |
| |
| if (get_picture_qos) |
| get_picture_qos_info(hw); |
| |
| reset_process_time(hw); |
| |
| if (hw->m_ins_flag && |
| (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10) && |
| (debug & AOM_DEBUG_DIS_RECYCLE_MMU_TAIL) == 0) { |
| long used_4k_num = |
| (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); |
| if ((cm->cur_frame != NULL) && (cm->cur_fb_idx_mmu != INVALID_IDX)) { |
| hevc_mmu_dma_check(hw_to_vdec(hw)); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "mmu free tail, index %d used_num 0x%x\n", |
| cm->cur_fb_idx_mmu, used_4k_num); |
| if (hw->is_used_v4l) { |
| struct internal_comp_buf *ibuf = |
| index_to_icomp_buf(hw, cm->cur_fb_idx_mmu); |
| |
| decoder_mmu_box_free_idx_tail( |
| ibuf->mmu_box, |
| ibuf->index, |
| used_4k_num); |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| used_4k_num = |
| (READ_VREG(HEVC_SAO_MMU_STATUS2) >> 16); |
| decoder_mmu_box_free_idx_tail( |
| ibuf->mmu_box_dw, |
| ibuf->index, |
| used_4k_num); |
| av1_print(hw, AOM_DEBUG_HW_MORE, "dw mmu free tail, index %d used_num 0x%x\n", |
| cm->cur_frame->buf.index, used_4k_num); |
| } |
| #endif |
| cm->cur_fb_idx_mmu = INVALID_IDX; |
| } else { |
| decoder_mmu_box_free_idx_tail(hw->mmu_box, |
| cm->cur_frame->buf.index, used_4k_num); |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| used_4k_num = |
| (READ_VREG(HEVC_SAO_MMU_STATUS2) >> 16); |
| decoder_mmu_box_free_idx_tail(hw->mmu_box_dw, |
| cm->cur_frame->buf.index, used_4k_num); |
| av1_print(hw, AOM_DEBUG_HW_MORE, "dw mmu free tail, index %d used_num 0x%x\n", |
| cm->cur_frame->buf.index, used_4k_num); |
| } |
| #endif |
| } |
| } |
| } |
| |
| if (hw->assit_task.use_sfgs) { |
| ulong start_time; |
| start_time = local_clock(); |
| if (cm->cur_frame) |
| wait_event_interruptible_timeout(cm->cur_frame->wait_sfgs, |
| (atomic_read(&cm->cur_frame->fgs_done) == 1), msecs_to_jiffies(50)); |
| if (get_debug_fgs() & DEBUG_FGS_CONSUME_TIME) { |
| pr_info("%s, pic %d, fgs_valid %d, wait consume time %d us\n", __func__, |
| hw->frame_count - 1, hw->fgs_valid, |
| div64_u64(local_clock() - start_time, 1000)); |
| } |
| } |
| if (hw->low_latency_flag) |
| av1_postproc(hw); |
| |
| if (multi_frames_in_one_pack && |
| hw->frame_decoded && |
| READ_VREG(HEVC_SHIFT_BYTE_COUNT) < hw->data_size) { |
| if (enable_single_slice == 1) { |
| hw->consume_byte = READ_VREG(HEVC_SHIFT_BYTE_COUNT) - 4; |
| hw->dec_result = DEC_RESULT_UNFINISH; |
| amhevc_stop(); |
| #ifdef MCRCC_ENABLE |
| if (mcrcc_cache_alg_flag) |
| dump_hit_rate(hw); |
| #endif |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); |
| vdec_schedule_work(&hw->work); |
| }else { |
| #ifdef DEBUG_CRC_ERROR |
| if ((crc_debug_flag & 0x40) && cm->cur_frame) |
| dump_mv_buffer(hw, &cm->cur_frame->buf); |
| #endif |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "PIC_END, fgs_valid %d search head ...\n", |
| hw->fgs_valid); |
| if (hw->config_next_ref_info_flag) |
| config_next_ref_info_hw(hw); |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); |
| } |
| } else { |
| hw->data_size = 0; |
| hw->data_offset = 0; |
| #ifdef DEBUG_CRC_ERROR |
| if ((crc_debug_flag & 0x40) && cm->cur_frame) |
| dump_mv_buffer(hw, &cm->cur_frame->buf); |
| #endif |
| hw->dec_result = DEC_RESULT_DONE; |
| amhevc_stop(); |
| #ifdef MCRCC_ENABLE |
| if (mcrcc_cache_alg_flag) |
| dump_hit_rate(hw); |
| #endif |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); |
| vdec_schedule_work(&hw->work); |
| } |
| } else { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "PIC_END, fgs_valid %d search head ...\n", |
| hw->fgs_valid); |
| #ifdef USE_DEC_PIC_END |
| if (READ_VREG(PIC_END_LCU_COUNT) != 0) { |
| hw->frame_decoded = 1; |
| /* |
| In c module, multi obus are put in one packet, which is decoded |
| with av1_receive_compressed_data(). |
| For STREAM_MODE or SINGLE_MODE, there is no packet boundary, |
| we assume each packet must and only include one picture of data (LCUs) |
| or cm->show_existing_frame is 1 |
| */ |
| if (cm->cur_frame) |
| av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", |
| cm->cur_frame? cm->cur_frame->buf.index:-1); |
| config_next_ref_info_hw(hw); |
| } |
| #endif |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| /* |
| if (debug & |
| AV1_DEBUG_BUFMGR_MORE) |
| dump_aux_buf(hw); |
| set_aux_data(hw, |
| &cm->cur_frame->buf, 0, 0); |
| */ |
| if (hw->low_latency_flag) { |
| av1_postproc(hw); |
| vdec_profile(hw_to_vdec(hw), VDEC_PROFILE_EVENT_CB); |
| if (debug & PRINT_FLAG_VDEC_DETAIL) |
| pr_info("%s AV1 frame done \n", __func__); |
| } |
| } |
| |
| start_process_time(hw); |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } |
| |
| if (dec_status == AOM_EOS) { |
| if (hw->m_ins_flag) |
| reset_process_time(hw); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "AV1_EOS, flush buffer\r\n"); |
| |
| av1_postproc(hw); |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "send AV1_10B_DISCARD_NAL\r\n"); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DISCARD_NAL); |
| hw->process_busy = 0; |
| if (hw->m_ins_flag) { |
| hw->dec_result = DEC_RESULT_DONE; |
| amhevc_stop(); |
| vdec_schedule_work(&hw->work); |
| } |
| return IRQ_HANDLED; |
| } else if (dec_status == AOM_DECODE_OVER_SIZE) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, "av1 decode oversize !!\n"); |
| /*debug |= (AV1_DEBUG_DIS_LOC_ERROR_PROC | |
| AV1_DEBUG_DIS_SYS_ERROR_PROC);*/ |
| hw->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW; |
| hw->process_busy = 0; |
| if (hw->m_ins_flag) |
| reset_process_time(hw); |
| return IRQ_HANDLED; |
| } |
| |
| obu_type = load_param(hw, &hw->aom_param, dec_status); |
| if (obu_type < 0) { |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } |
| |
| if (obu_type == OBU_SEQUENCE_HEADER) { |
| int next_lcu_size; |
| |
| av1_bufmgr_process(hw->pbi, &hw->aom_param, 0, obu_type); |
| |
| if ((hw->max_pic_w < hw->aom_param.p.max_frame_width) || |
| (hw->max_pic_h < hw->aom_param.p.max_frame_height)) { |
| av1_print(hw, 0, "%s, max size change (%d, %d) -> (%d, %d)\n", |
| __func__, hw->max_pic_w, hw->max_pic_h, |
| hw->aom_param.p.max_frame_width, hw->aom_param.p.max_frame_height); |
| |
| vav1_mmu_map_free(hw); |
| |
| hw->max_pic_w = hw->aom_param.p.max_frame_width; |
| hw->max_pic_h = hw->aom_param.p.max_frame_height; |
| hw->init_pic_w = hw->max_pic_w; |
| hw->init_pic_h = hw->max_pic_h; |
| hw->pbi->frame_width = hw->init_pic_w; |
| hw->pbi->frame_height = hw->init_pic_h; |
| |
| vav1_mmu_map_alloc(hw); |
| |
| if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL, hw->frame_mmu_map_phy_addr); |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, hw->dw_frame_mmu_map_phy_addr); |
| //default of 0xffffffff will disable dw |
| WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0); |
| WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); |
| } |
| #endif |
| |
| /*v4l2 alloc new mv when max size changed */ |
| if (hw->is_used_v4l && IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) { |
| /* now less than 8k use fix mv buf size */ |
| if (hw->pic_list_init_done) { |
| if (init_mv_buf_list(hw) < 0) |
| pr_err("%s: !!!!Error, reinit_mv_buf_list fail\n", __func__); |
| } |
| } |
| } |
| |
| bit_depth_luma = hw->aom_param.p.bit_depth; |
| bit_depth_chroma = hw->aom_param.p.bit_depth; |
| hw->film_grain_present = hw->aom_param.p.film_grain_present_flag; |
| |
| next_lcu_size = ((hw->aom_param.p.seq_flags >> 6) & 0x1) ? 128 : 64; |
| hw->video_signal_type = (hw->aom_param.p.video_signal_type << 16 |
| | hw->aom_param.p.color_description); |
| |
| if (next_lcu_size != hw->current_lcu_size) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| " ## lcu_size changed from %d to %d\n", |
| hw->current_lcu_size, next_lcu_size); |
| hw->current_lcu_size = next_lcu_size; |
| } |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "AOM_AV1_SEQ_HEAD_PARSER_DONE, search head ...\n"); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); |
| |
| hw->process_busy = 0; |
| hw->has_sequence = 1; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); |
| return IRQ_HANDLED; |
| } |
| |
| if (hw->is_used_v4l) { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| |
| hw->frame_width = hw->common.seq_params.max_frame_width; |
| hw->frame_height = hw->common.seq_params.max_frame_height; |
| |
| if (hw->frame_width == 0 || hw->frame_height == 0) { |
| hw->dec_result = DEC_RESULT_DISCARD_DATA; |
| hw->process_busy = 0; |
| amhevc_stop(); |
| vdec_schedule_work(&hw->work); |
| return IRQ_HANDLED; |
| } |
| |
| if (!v4l_res_change(hw)) { |
| if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { |
| struct aml_vdec_ps_infos ps; |
| struct vdec_comp_buf_info comp; |
| |
| pr_info("set ucode parse\n"); |
| |
| ctx->film_grain_present = hw->film_grain_present; |
| if (ctx->film_grain_present && |
| !disable_fg && |
| (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_S4 || |
| get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_S4D)) { |
| #ifdef AOM_AV1_MMU_DW |
| ctx->config.parm.dec.cfg.double_write_mode = 0x21; |
| pr_info("AV1 has fg, use dw 0x21!\n"); |
| if (hw->dw_frame_mmu_map_addr == NULL) { |
| u32 mmu_map_size = vaom_dw_frame_mmu_map_size(hw); |
| hw->dw_frame_mmu_map_addr = |
| dma_alloc_coherent(amports_get_dma_device(), |
| mmu_map_size, |
| &hw->dw_frame_mmu_map_phy_addr, GFP_KERNEL); |
| if (hw->dw_frame_mmu_map_addr == NULL) { |
| pr_err("%s: failed to alloc count_buffer\n", __func__); |
| return -1; |
| } |
| memset(hw->dw_frame_mmu_map_addr, 0, mmu_map_size); |
| } |
| #endif |
| } |
| if (get_valid_double_write_mode(hw) != 16) { |
| vav1_get_comp_buf_info(hw, &comp); |
| vdec_v4l_set_comp_buf_info(ctx, &comp); |
| } |
| vav1_get_ps_info(hw, &ps); |
| /*notice the v4l2 codec.*/ |
| vdec_v4l_set_ps_infos(ctx, &ps); |
| hw->v4l_params_parsed = true; |
| work_space_size_update(hw); |
| hw->postproc_done = 0; |
| hw->process_busy = 0; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); |
| dec_again_process(hw); |
| return IRQ_HANDLED; |
| } else { |
| struct vdec_pic_info pic; |
| |
| if (!hw->pic_list_init_done) { |
| vdec_v4l_get_pic_info(ctx, &pic); |
| hw->used_buf_num = pic.dpb_frames + |
| pic.dpb_margin; |
| |
| if (IS_4K_SIZE(hw->init_pic_w, hw->init_pic_h)) { |
| hw->used_buf_num = MAX_BUF_NUM_LESS + pic.dpb_margin; |
| if (hw->used_buf_num > REF_FRAMES_4K) |
| hw->mv_buf_margin = hw->used_buf_num - REF_FRAMES_4K + 1; |
| } |
| |
| if (IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) { |
| hw->double_write_mode = 4; |
| hw->used_buf_num = MAX_BUF_NUM_LESS; |
| if (hw->used_buf_num > REF_FRAMES_4K) |
| hw->mv_buf_margin = hw->used_buf_num - REF_FRAMES_4K + 1; |
| if (((hw->max_pic_w % 64) != 0) && |
| (hw_to_vdec(hw)->canvas_mode != CANVAS_BLKMODE_LINEAR)) |
| hw->mem_map_mode = 2; |
| av1_print(hw, 0, |
| "force 8k double write 4, mem_map_mode %d\n", hw->mem_map_mode); |
| } |
| |
| if (hw->used_buf_num > MAX_BUF_NUM) |
| hw->used_buf_num = MAX_BUF_NUM; |
| |
| init_pic_list(hw); |
| init_pic_list_hw(hw); |
| #ifndef MV_USE_FIXED_BUF |
| if (init_mv_buf_list(hw) < 0) { |
| pr_err("%s: !!!!Error, init_mv_buf_list fail\n", __func__); |
| } |
| #endif |
| hw->pic_list_init_done = true; |
| } |
| } |
| } else { |
| hw->postproc_done = 0; |
| hw->process_busy = 0; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); |
| dec_again_process(hw); |
| return IRQ_HANDLED; |
| } |
| } |
| |
| #ifndef USE_DEC_PIC_END |
| //if (pbi->wait_buf) { |
| if (pbi->bufmgr_proc_count > 0) { |
| if (READ_VREG(PIC_END_LCU_COUNT) != 0) { |
| hw->frame_decoded = 1; |
| /* |
| In c module, multi obus are put in one packet, which is decoded |
| with av1_receive_compressed_data(). |
| For STREAM_MODE or SINGLE_MODE, there is no packet boundary, |
| we assume each packet must and only include one picture of data (LCUs) |
| or cm->show_existing_frame is 1 |
| */ |
| if (cm->cur_frame) |
| av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", |
| cm->cur_frame? cm->cur_frame->buf.index:-1); |
| } |
| } |
| #endif |
| #if 1 |
| /*def CHECK_OBU_REDUNDANT_FRAME_HEADER*/ |
| if (debug & AOM_DEBUG_BUFMGR_ONLY) { |
| if (READ_VREG(PIC_END_LCU_COUNT) != 0) |
| hw->obu_frame_frame_head_come_after_tile = 0; |
| |
| if (obu_type == OBU_FRAME_HEADER || |
| obu_type == OBU_FRAME) { |
| hw->obu_frame_frame_head_come_after_tile = 1; |
| } else if (obu_type == OBU_REDUNDANT_FRAME_HEADER && |
| hw->obu_frame_frame_head_come_after_tile == 0) { |
| if (hw->frame_decoded == 1) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "Warning, OBU_REDUNDANT_FRAME_HEADER come without OBU_FRAME or OBU_FRAME_HEAD\n"); |
| hw->frame_decoded = 0; |
| } |
| } |
| } |
| #endif |
| if (hw->frame_decoded) |
| hw->one_compressed_data_done = 1; |
| |
| if (hw->m_ins_flag) |
| reset_process_time(hw); |
| |
| if (hw->process_state != PROC_STATE_SENDAGAIN |
| ) { |
| if (hw->one_compressed_data_done) { |
| av1_postproc(hw); |
| av1_release_bufs(hw); |
| #ifndef MV_USE_FIXED_BUF |
| put_un_used_mv_bufs(hw); |
| #endif |
| } |
| } |
| |
| if (hw->one_package_frame_cnt) { |
| if (get_free_buf_count(hw) <= 0) { |
| hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; |
| hw->cur_obu_type = obu_type; |
| hw->process_busy = 0; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); |
| vdec_schedule_work(&hw->work); |
| return IRQ_HANDLED; |
| } |
| } |
| hw->one_package_frame_cnt++; |
| |
| ret = av1_continue_decoding(hw, obu_type); |
| hw->postproc_done = 0; |
| hw->process_busy = 0; |
| |
| if (hw->m_ins_flag) { |
| if (ret >= 0) |
| start_process_time(hw); |
| else { |
| hw->dec_result = DEC_RESULT_DONE; |
| amhevc_stop(); |
| vdec_schedule_work(&hw->work); |
| } |
| } |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); |
| return IRQ_HANDLED; |
| } |
| |
| static irqreturn_t vav1_isr(int irq, void *data) |
| { |
| int i; |
| unsigned int dec_status; |
| struct AV1HW_s *hw = (struct AV1HW_s *)data; |
| //struct AV1_Common_s *const cm = &hw->common; |
| uint debug_tag; |
| |
| WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1); |
| |
| dec_status = READ_VREG(HEVC_DEC_STATUS_REG) & 0xff; |
| |
| if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE || |
| dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE || |
| dec_status == AOM_AV1_FRAME_PARSER_DONE) { |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_HEAD_DONE); |
| } |
| else if (dec_status == AOM_AV1_DEC_PIC_END || |
| dec_status == AOM_NAL_DECODE_DONE) { |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_PIC_DONE); |
| } |
| if (!hw) |
| return IRQ_HANDLED; |
| if (hw->init_flag == 0) |
| return IRQ_HANDLED; |
| if (hw->process_busy) {/*on process.*/ |
| pr_err("err: %s, process busy\n", __func__); |
| return IRQ_HANDLED; |
| } |
| |
| ATRACE_COUNTER("V_ST_DEC-decode_state", dec_status); |
| |
| hw->dec_status = dec_status; |
| hw->process_busy = 1; |
| if (debug & AV1_DEBUG_BUFMGR) |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "av1 isr (%d) dec status = 0x%x (0x%x), lcu 0x%x shiftbyte 0x%x shifted_data 0x%x (%x %x lev %x, wr %x, rd %x) log %x\n", |
| irq, |
| dec_status, READ_VREG(HEVC_DEC_STATUS_REG), |
| READ_VREG(HEVC_PARSER_LCU_START), |
| READ_VREG(HEVC_SHIFT_BYTE_COUNT), |
| READ_VREG(HEVC_SHIFTED_DATA), |
| 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 DEBUG_UCODE_LOG |
| READ_VREG(HEVC_DBG_LOG_ADR) |
| #else |
| 0 |
| #endif |
| ); |
| #ifdef DEBUG_UCODE_LOG |
| if ((udebug_flag & 0x8) && |
| (hw->ucode_log_addr != 0) && |
| (READ_VREG(HEVC_DEC_STATUS_REG) & 0x100)) { |
| unsigned long flags; |
| unsigned short *log_adr = |
| (unsigned short *)hw->ucode_log_addr; |
| lock_buffer_pool(hw->pbi->common.buffer_pool, flags); |
| while (*(log_adr + 3)) { |
| pr_info("dbg%04x %04x %04x %04x\n", |
| *(log_adr + 3), *(log_adr + 2), *(log_adr + 1), *(log_adr + 0) |
| ); |
| log_adr += 4; |
| } |
| unlock_buffer_pool(hw->pbi->common.buffer_pool, flags); |
| } |
| #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 ", |
| hw->lmem_ptr[i + 3 - ii]); |
| } |
| if (((i + ii) & 0xf) == 0) |
| pr_info("\n"); |
| } |
| if (((udebug_pause_pos & 0xffff) |
| == (debug_tag & 0xffff)) && |
| (udebug_pause_decode_idx == 0 || |
| udebug_pause_decode_idx == hw->result_done_count) && |
| (udebug_pause_val == 0 || |
| udebug_pause_val == READ_HREG(DEBUG_REG2))) { |
| udebug_pause_pos &= 0xffff; |
| hw->ucode_pause_pos = udebug_pause_pos; |
| } |
| else if (debug_tag & 0x20000) |
| hw->ucode_pause_pos = 0xffffffff; |
| if (hw->ucode_pause_pos) |
| reset_process_time(hw); |
| 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 & 0xffff) |
| == (debug_tag & 0xffff)) && |
| (udebug_pause_decode_idx == 0 || |
| udebug_pause_decode_idx == hw->result_done_count) && |
| (udebug_pause_val == 0 || |
| udebug_pause_val == READ_HREG(DEBUG_REG2))) { |
| udebug_pause_pos &= 0xffff; |
| hw->ucode_pause_pos = udebug_pause_pos; |
| } |
| if (hw->ucode_pause_pos) |
| reset_process_time(hw); |
| else |
| WRITE_HREG(DEBUG_REG1, 0); |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } |
| |
| //if (READ_VREG(HEVC_FG_STATUS) == AOM_AV1_FGS_PARAM) { |
| if (hw->dec_status == AOM_AV1_FGS_PARAM) { |
| uint32_t status_val = READ_VREG(HEVC_FG_STATUS); |
| WRITE_VREG(HEVC_FG_STATUS, AOM_AV1_FGS_PARAM_CONT); |
| WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_FGS_PARAM_CONT); |
| // Bit[11] - 0 Read, 1 - Write |
| // Bit[10:8] - film_grain_params_ref_idx // For Write request |
| if ((status_val >> 11) & 0x1) { |
| uint32_t film_grain_params_ref_idx = (status_val >> 8) & 0x7; |
| config_film_grain_reg(hw, film_grain_params_ref_idx); |
| } |
| else |
| read_film_grain_reg(hw); |
| |
| film_grain_task_wakeup(hw); |
| |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } |
| |
| if (!hw->m_ins_flag) { |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "error flag = %d\n", hw->error_flag); |
| if (hw->error_flag == 1) { |
| hw->error_flag = 2; |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } else if (hw->error_flag == 3) { |
| hw->process_busy = 0; |
| return IRQ_HANDLED; |
| } |
| if (get_free_buf_count(hw) <= 0) { |
| /* |
| if (hw->wait_buf == 0) |
| pr_info("set wait_buf to 1\r\n"); |
| */ |
| hw->wait_buf = 1; |
| hw->process_busy = 0; |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "free buf not enough = %d\n", |
| get_free_buf_count(hw)); |
| return IRQ_HANDLED; |
| } |
| } |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_END); |
| return IRQ_WAKE_THREAD; |
| } |
| |
| static void av1_set_clk(struct work_struct *work) |
| { |
| struct AV1HW_s *hw = container_of(work, |
| struct AV1HW_s, set_clk_work); |
| int fps = 96000 / hw->frame_dur; |
| |
| if (hevc_source_changed(VFORMAT_AV1, |
| frame_width, frame_height, fps) > 0) |
| hw->saved_resolution = frame_width * |
| frame_height * fps; |
| } |
| |
| static void vav1_put_timer_func(struct timer_list *timer) |
| { |
| struct AV1HW_s *hw = container_of(timer, |
| struct AV1HW_s, timer); |
| uint8_t empty_flag; |
| unsigned int buf_level; |
| |
| enum receviver_start_e state = RECEIVER_INACTIVE; |
| |
| if (hw->m_ins_flag) { |
| if (hw_to_vdec(hw)->next_status |
| == VDEC_STATUS_DISCONNECTED) { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| if (!hw->is_used_v4l || ctx->is_stream_off) { |
| hw->dec_result = DEC_RESULT_FORCE_EXIT; |
| vdec_schedule_work(&hw->work); |
| pr_debug("vdec requested to be disconnected\n"); |
| return; |
| } |
| } |
| } |
| if (hw->init_flag == 0) { |
| if (hw->stat & STAT_TIMER_ARM) { |
| timer->expires = jiffies + PUT_INTERVAL; |
| add_timer(&hw->timer); |
| } |
| return; |
| } |
| if (hw->m_ins_flag == 0) { |
| if (vf_get_receiver(hw->provider_name)) { |
| state = |
| vf_notify_receiver(hw->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 & AV1_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(&hw->display_q) && |
| buf_level > 0x200) |
| ) { |
| WRITE_VREG |
| (HEVC_ASSIST_MBOX0_IRQ_REG, |
| 0x1); |
| } |
| } |
| |
| } |
| } |
| #ifdef MULTI_INSTANCE_SUPPORT |
| else { |
| av1_print(hw, AV1_DEBUG_TIMEOUT_INFO, "timeout!!!start_process_time %ld\n", |
| hw->start_process_time); |
| if ( |
| (decode_timeout_val > 0) && |
| (hw->start_process_time > 0) && |
| ((1000 * (jiffies - hw->start_process_time) / HZ) |
| > decode_timeout_val) |
| ) { |
| int current_lcu_idx = |
| READ_VREG(HEVC_PARSER_LCU_START) |
| & 0xffffff; |
| av1_print(hw, AV1_DEBUG_TIMEOUT_INFO, "timeout!!!current_lcu_idx = %u last_lcu_idx = %u decode_timeout_count = %d\n", |
| current_lcu_idx, hw->last_lcu_idx, hw->decode_timeout_count); |
| if (hw->last_lcu_idx == current_lcu_idx) { |
| if (hw->decode_timeout_count > 0) |
| hw->decode_timeout_count--; |
| if (hw->decode_timeout_count == 0) { |
| if (input_frame_based( |
| hw_to_vdec(hw)) || |
| (READ_VREG(HEVC_STREAM_LEVEL) > 0x200)) |
| timeout_process(hw); |
| else { |
| av1_print(hw, 0, |
| "timeout & empty, again\n"); |
| dec_again_process(hw); |
| } |
| } |
| } else { |
| start_process_time(hw); |
| hw->last_lcu_idx = current_lcu_idx; |
| } |
| } |
| } |
| #endif |
| |
| if ((hw->ucode_pause_pos != 0) && |
| (hw->ucode_pause_pos != 0xffffffff) && |
| udebug_pause_pos != hw->ucode_pause_pos) { |
| hw->ucode_pause_pos = 0; |
| WRITE_HREG(DEBUG_REG1, 0); |
| } |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (debug & AV1_DEBUG_DUMP_DATA) { |
| debug &= ~AV1_DEBUG_DUMP_DATA; |
| av1_print(hw, 0, |
| "%s: chunk size 0x%x off 0x%x sum 0x%x\n", |
| __func__, |
| hw->data_size, |
| hw->data_offset, |
| get_data_check_sum(hw, hw->data_size) |
| ); |
| dump_data(hw, hw->data_size); |
| } |
| #endif |
| if (debug & AV1_DEBUG_DUMP_PIC_LIST) { |
| /*dump_pic_list(hw);*/ |
| av1_dump_state(hw_to_vdec(hw)); |
| debug &= ~AV1_DEBUG_DUMP_PIC_LIST; |
| } |
| if (debug & AV1_DEBUG_TRIG_SLICE_SEGMENT_PROC) { |
| WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); |
| debug &= ~AV1_DEBUG_TRIG_SLICE_SEGMENT_PROC; |
| } |
| /*if (debug & AV1_DEBUG_HW_RESET) { |
| }*/ |
| |
| if (radr != 0) { |
| if ((radr >> 24) != 0) { |
| int count = radr >> 24; |
| int adr = radr & 0xffffff; |
| int i; |
| for (i = 0; i < count; i++) |
| pr_info("READ_VREG(%x)=%x\n", adr+i, READ_VREG(adr+i)); |
| } else 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(hw) == 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 (hw->get_frame_dur && hw->show_frame_num > 60 && |
| hw->frame_dur > 0 && hw->saved_resolution != |
| frame_width * frame_height * |
| (96000 / hw->frame_dur)) |
| vdec_schedule_work(&hw->set_clk_work); |
| |
| timer->expires = jiffies + PUT_INTERVAL; |
| add_timer(timer); |
| } |
| |
| |
| int vav1_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) |
| { |
| struct AV1HW_s *av1 = |
| (struct AV1HW_s *)vdec->private; |
| |
| if (!av1) |
| return -1; |
| |
| vstatus->frame_width = frame_width; |
| vstatus->frame_height = frame_height; |
| if (av1->frame_dur != 0) |
| vstatus->frame_rate = 96000 / av1->frame_dur; |
| else |
| vstatus->frame_rate = -1; |
| vstatus->error_count = 0; |
| vstatus->status = av1->stat | av1->fatal_error; |
| vstatus->frame_dur = av1->frame_dur; |
| //#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC |
| vstatus->bit_rate = av1->gvs->bit_rate; |
| vstatus->frame_data = av1->gvs->frame_data; |
| vstatus->total_data = av1->gvs->total_data; |
| vstatus->frame_count = av1->gvs->frame_count; |
| vstatus->error_frame_count = av1->gvs->error_frame_count; |
| vstatus->drop_frame_count = av1->gvs->drop_frame_count; |
| vstatus->samp_cnt = av1->gvs->samp_cnt; |
| vstatus->offset = av1->gvs->offset; |
| snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), |
| "%s", DRIVER_NAME); |
| //#endif |
| return 0; |
| } |
| |
| int vav1_set_isreset(struct vdec_s *vdec, int isreset) |
| { |
| is_reset = isreset; |
| return 0; |
| } |
| |
| #if 0 |
| static void AV1_DECODE_INIT(void) |
| { |
| /* enable av1 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 vav1_prot_init(struct AV1HW_s *hw, u32 mask) |
| { |
| unsigned int data32; |
| /* AV1_DECODE_INIT(); */ |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| |
| aom_config_work_space_hw(hw, mask); |
| if (mask & HW_MASK_BACK) { |
| //to do: .. for single instance, called after init_pic_list() |
| if (hw->m_ins_flag) |
| init_pic_list_hw(hw); |
| } |
| |
| aom_init_decoder_hw(hw, mask); |
| |
| #ifdef AOM_AV1_DBLK_INIT |
| av1_print(hw, AOM_DEBUG_HW_MORE, |
| "[test.c] av1_loop_filter_init (run once before decoding start)\n"); |
| av1_loop_filter_init(hw->lfi, hw->lf); |
| #endif |
| if ((mask & HW_MASK_FRONT) == 0) |
| return; |
| #if 1 |
| if (debug & AV1_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 & AV1_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("av1 prot init error %d\n", __LINE__); |
| return; |
| } |
| data32 = READ_VREG(HEVC_SHIFT_EMULATECODE); |
| if (data32 != 0x00000300) { |
| pr_info("av1 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("av1 prot init error %d\n", __LINE__); |
| return; |
| } |
| data32 = READ_VREG(HEVC_SHIFT_EMULATECODE); |
| if (data32 != 0x9abcdef0) { |
| pr_info("av1 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); |
| //#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD) |
| // WRITE_VREG(HEVC_DBG_LOG_ADR, hw->ucode_log_phy_addr); |
| //#endif |
| } |
| |
| static int vav1_local_init(struct AV1HW_s *hw, bool reset_flag) |
| { |
| int i; |
| int ret; |
| int width, height; |
| |
| hw->gvs = vzalloc(sizeof(struct vdec_info)); |
| if (NULL == hw->gvs) { |
| pr_info("the struct of vdec status malloc failed.\n"); |
| return -1; |
| } |
| #ifdef DEBUG_PTS |
| hw->pts_missed = 0; |
| hw->pts_hit = 0; |
| #endif |
| hw->new_frame_displayed = 0; |
| hw->last_put_idx = -1; |
| hw->saved_resolution = 0; |
| hw->get_frame_dur = false; |
| on_no_keyframe_skiped = 0; |
| hw->first_pts_index = 0; |
| hw->dur_recalc_flag = 0; |
| hw->av1_first_pts_ready = false; |
| width = hw->vav1_amstream_dec_info.width; |
| height = hw->vav1_amstream_dec_info.height; |
| hw->frame_dur = |
| (hw->vav1_amstream_dec_info.rate == |
| 0) ? 3200 : hw->vav1_amstream_dec_info.rate; |
| if (width && height) |
| hw->frame_ar = height * 0x100 / width; |
| /* |
| *TODO:FOR VERSION |
| */ |
| pr_info("av1: ver (%d,%d) decinfo: %dx%d rate=%d\n", av1_version, |
| 0, width, height, hw->frame_dur); |
| |
| if (hw->frame_dur == 0) |
| hw->frame_dur = 96000 / 24; |
| |
| INIT_KFIFO(hw->display_q); |
| INIT_KFIFO(hw->newframe_q); |
| |
| for (i = 0; i < FRAME_BUFFERS; i++) { |
| hw->buffer_wrap[i] = i; |
| } |
| |
| for (i = 0; i < VF_POOL_SIZE; i++) { |
| const struct vframe_s *vf = &hw->vfpool[i]; |
| |
| hw->vfpool[i].index = -1; |
| kfifo_put(&hw->newframe_q, vf); |
| } |
| |
| ret = av1_local_init(hw, reset_flag); |
| |
| if (force_pts_unstable) { |
| if (!hw->pts_unstable) { |
| hw->pts_unstable = |
| (hw->vav1_amstream_dec_info.rate == 0)?1:0; |
| pr_info("set pts unstable\n"); |
| } |
| } |
| |
| return ret; |
| } |
| |
| |
| #ifdef MULTI_INSTANCE_SUPPORT |
| static s32 vav1_init(struct vdec_s *vdec) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *)vdec->private; |
| #else |
| static s32 vav1_init(struct AV1HW_s *hw) |
| { |
| #endif |
| int ret; |
| int i; |
| int fw_size = 0x1000 * 16; |
| struct firmware_s *fw = NULL; |
| |
| hw->stat |= STAT_TIMER_INIT; |
| |
| if (vav1_local_init(hw, false) < 0) |
| return -EBUSY; |
| |
| fw = vmalloc(sizeof(struct firmware_s) + fw_size); |
| if (IS_ERR_OR_NULL(fw)) |
| return -ENOMEM; |
| |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| if (get_firmware_data(VIDEO_DEC_VP9_MMU, fw->data) < 0) { |
| #else |
| if (get_firmware_data(VIDEO_DEC_AV1_MMU, fw->data) < 0) { |
| #endif |
| pr_err("get firmware fail.\n"); |
| printk("%s %d\n", __func__, __LINE__); |
| vfree(fw); |
| return -1; |
| } |
| av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__); |
| fw->len = fw_size; |
| |
| INIT_WORK(&hw->set_clk_work, av1_set_clk); |
| timer_setup(&hw->timer, vav1_put_timer_func, 0); |
| |
| for (i = 0; i < FILM_GRAIN_REG_SIZE; i++) { |
| WRITE_VREG(HEVC_FGS_DATA, 0); |
| } |
| WRITE_VREG(HEVC_FGS_CTRL, 0); |
| |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (hw->m_ins_flag) { |
| hw->timer.expires = jiffies + PUT_INTERVAL; |
| |
| /*add_timer(&hw->timer); |
| |
| hw->stat |= STAT_TIMER_ARM; |
| hw->stat |= STAT_ISR_REG;*/ |
| |
| INIT_WORK(&hw->work, av1_work); |
| hw->fw = fw; |
| |
| return 0; /*multi instance return */ |
| } |
| #endif |
| amhevc_enable(); |
| |
| ret = amhevc_loadmc_ex(VFORMAT_AV1, NULL, fw->data); |
| if (ret < 0) { |
| amhevc_disable(); |
| vfree(fw); |
| pr_err("AV1: the %s fw loading failed, err: %x\n", |
| tee_enabled() ? "TEE" : "local", ret); |
| return -EBUSY; |
| } |
| |
| vfree(fw); |
| |
| hw->stat |= STAT_MC_LOAD; |
| |
| /* enable AMRISC side protocol */ |
| vav1_prot_init(hw, HW_MASK_FRONT | HW_MASK_BACK); |
| |
| if (vdec_request_threaded_irq(VDEC_IRQ_0, |
| vav1_isr, |
| vav1_isr_thread_fn, |
| IRQF_ONESHOT,/*run thread on this irq disabled*/ |
| "vav1-irq", (void *)hw)) { |
| pr_info("vav1 irq register error.\n"); |
| amhevc_disable(); |
| return -ENOENT; |
| } |
| |
| hw->stat |= STAT_ISR_REG; |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| if (force_dv_enable) |
| hw->provider_name = DV_PROVIDER_NAME; |
| else |
| #endif |
| hw->provider_name = PROVIDER_NAME; |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (!hw->is_used_v4l) { |
| vf_provider_init(&vav1_vf_prov, hw->provider_name, |
| &vav1_vf_provider, hw); |
| vf_reg_provider(&vav1_vf_prov); |
| vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL); |
| if (hw->frame_dur != 0) { |
| if (!is_reset) |
| vf_notify_receiver(hw->provider_name, |
| VFRAME_EVENT_PROVIDER_FR_HINT, |
| (void *) |
| ((unsigned long)hw->frame_dur)); |
| } |
| } |
| #else |
| vf_provider_init(&vav1_vf_prov, hw->provider_name, &vav1_vf_provider, |
| hw); |
| vf_reg_provider(&vav1_vf_prov); |
| vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL); |
| if (!is_reset) |
| vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_FR_HINT, |
| (void *)((unsigned long)hw->frame_dur)); |
| #endif |
| hw->stat |= STAT_VF_HOOK; |
| |
| hw->timer.expires = jiffies + PUT_INTERVAL; |
| add_timer(&hw->timer); |
| |
| hw->stat |= STAT_VDEC_RUN; |
| hw->stat |= STAT_TIMER_ARM; |
| |
| amhevc_start(); |
| |
| hw->init_flag = 1; |
| hw->process_busy = 0; |
| pr_info("%d, vav1_init, RP=0x%x\n", |
| __LINE__, READ_VREG(HEVC_STREAM_RD_PTR)); |
| return 0; |
| } |
| |
| static int vmav1_stop(struct AV1HW_s *hw) |
| { |
| hw->init_flag = 0; |
| |
| if (hw->stat & STAT_VDEC_RUN) { |
| amhevc_stop(); |
| hw->stat &= ~STAT_VDEC_RUN; |
| } |
| if (hw->stat & STAT_ISR_REG) { |
| vdec_free_irq(VDEC_IRQ_0, (void *)hw); |
| hw->stat &= ~STAT_ISR_REG; |
| } |
| if (hw->stat & STAT_TIMER_ARM) { |
| del_timer_sync(&hw->timer); |
| hw->stat &= ~STAT_TIMER_ARM; |
| } |
| |
| if (!hw->is_used_v4l && (hw->stat & STAT_VF_HOOK)) { |
| if (!is_reset) |
| vf_notify_receiver(hw->provider_name, |
| VFRAME_EVENT_PROVIDER_FR_END_HINT, |
| NULL); |
| |
| vf_unreg_provider(&vav1_vf_prov); |
| hw->stat &= ~STAT_VF_HOOK; |
| } |
| av1_local_uninit(hw, false); |
| reset_process_time(hw); |
| cancel_work_sync(&hw->work); |
| cancel_work_sync(&hw->set_clk_work); |
| uninit_mmu_buffers(hw); |
| if (hw->fw) |
| vfree(hw->fw); |
| hw->fw = NULL; |
| return 0; |
| } |
| |
| static int amvdec_av1_mmu_init(struct AV1HW_s *hw) |
| { |
| int tvp_flag = vdec_secure(hw_to_vdec(hw)) ? |
| CODEC_MM_FLAGS_TVP : 0; |
| int buf_size = 48; |
| |
| if ((hw->max_pic_w * hw->max_pic_h > 1280*736) && |
| (hw->max_pic_w * hw->max_pic_h <= 1920*1088)) { |
| buf_size = 12; |
| } else if ((hw->max_pic_w * hw->max_pic_h > 0) && |
| (hw->max_pic_w * hw->max_pic_h <= 1280*736)) { |
| buf_size = 4; |
| } |
| hw->need_cache_size = buf_size * SZ_1M; |
| hw->sc_start_time = get_jiffies_64(); |
| if (hw->mmu_enable && !hw->is_used_v4l) { |
| int count = FRAME_BUFFERS; |
| hw->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, |
| hw->index /* * 2*/, count, |
| hw->need_cache_size, |
| tvp_flag |
| ); |
| if (!hw->mmu_box) { |
| pr_err("av1 alloc mmu box failed!!\n"); |
| return -1; |
| } |
| #ifdef AOM_AV1_MMU_DW |
| if (get_double_write_mode(hw) & 0x20) { |
| hw->mmu_box_dw = decoder_mmu_box_alloc_box(DRIVER_NAME, |
| hw->index /** 2 + 1*/, count, |
| hw->need_cache_size, |
| tvp_flag |
| ); |
| if (!hw->mmu_box_dw) { |
| pr_err("av1 alloc dw mmu box failed!!\n"); |
| return -1; |
| } |
| } |
| #endif |
| |
| } |
| hw->bmmu_box = decoder_bmmu_box_alloc_box( |
| DRIVER_NAME, |
| hw->index, |
| MAX_BMMU_BUFFER_NUM, |
| 4 + PAGE_SHIFT, |
| CODEC_MM_FLAGS_CMA_CLEAR | |
| CODEC_MM_FLAGS_FOR_VDECODER | |
| tvp_flag); |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "%s, MAX_BMMU_BUFFER_NUM = %d\n", |
| __func__, |
| MAX_BMMU_BUFFER_NUM); |
| if (!hw->bmmu_box) { |
| pr_err("av1 alloc bmmu box failed!!\n"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| /****************************************/ |
| #ifdef CONFIG_PM |
| static int av1_suspend(struct device *dev) |
| { |
| amhevc_suspend(to_platform_device(dev), dev->power.power_state); |
| return 0; |
| } |
| |
| static int av1_resume(struct device *dev) |
| { |
| amhevc_resume(to_platform_device(dev)); |
| return 0; |
| } |
| |
| static const struct dev_pm_ops av1_pm_ops = { |
| SET_SYSTEM_SLEEP_PM_OPS(av1_suspend, av1_resume) |
| }; |
| #endif |
| |
| static struct codec_profile_t amvdec_av1_profile = { |
| .name = "AV1-V4L", |
| .profile = "" |
| }; |
| |
| static unsigned int get_data_check_sum |
| (struct AV1HW_s *hw, int size) |
| { |
| int sum = 0; |
| u8 *data = NULL; |
| |
| if (!hw->chunk->block->is_mapped) |
| data = codec_mm_vmap(hw->chunk->block->start + |
| hw->data_offset, size); |
| else |
| data = ((u8 *)hw->chunk->block->start_virt) + |
| hw->data_offset; |
| |
| sum = crc32_le(0, data, size); |
| |
| if (!hw->chunk->block->is_mapped) |
| codec_mm_unmap_phyaddr(data); |
| return sum; |
| } |
| |
| static void dump_data(struct AV1HW_s *hw, int size) |
| { |
| int jj; |
| u8 *data = NULL; |
| int padding_size = hw->data_offset & |
| (VDEC_FIFO_ALIGN - 1); |
| |
| if (!hw->chunk->block->is_mapped) |
| data = codec_mm_vmap(hw->chunk->block->start + |
| hw->data_offset, size); |
| else |
| data = ((u8 *)hw->chunk->block->start_virt) + |
| hw->data_offset; |
| |
| av1_print(hw, 0, "padding: "); |
| for (jj = padding_size; jj > 0; jj--) |
| av1_print_cont(hw, |
| 0, |
| "%02x ", *(data - jj)); |
| av1_print_cont(hw, 0, "data adr %p\n", |
| data); |
| |
| for (jj = 0; jj < size; jj++) { |
| if ((jj & 0xf) == 0) |
| av1_print(hw, |
| 0, |
| "%06x:", jj); |
| av1_print_cont(hw, |
| 0, |
| "%02x ", data[jj]); |
| if (((jj + 1) & 0xf) == 0) |
| av1_print(hw, |
| 0, |
| "\n"); |
| } |
| av1_print(hw, |
| 0, |
| "\n"); |
| |
| if (!hw->chunk->block->is_mapped) |
| codec_mm_unmap_phyaddr(data); |
| } |
| |
| static int av1_wait_cap_buf(void *args) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *) args; |
| struct AV1_Common_s *const cm = &hw->common; |
| struct aml_vcodec_ctx * ctx = |
| (struct aml_vcodec_ctx *)hw->v4l2_ctx; |
| ulong flags; |
| int ret = 0; |
| |
| ret = wait_event_interruptible_timeout(ctx->cap_wq, |
| (ctx->is_stream_off || (get_free_buf_count(hw) > 0)), |
| msecs_to_jiffies(300)); |
| if (ret <= 0){ |
| av1_print(hw, PRINT_FLAG_V4L_DETAIL, "%s, wait cap buf timeout or err %d\n", |
| __func__, ret); |
| } |
| |
| lock_buffer_pool(cm->buffer_pool, flags); |
| if (hw->wait_more_buf) { |
| hw->wait_more_buf = false; |
| hw->dec_result = ctx->is_stream_off ? |
| DEC_RESULT_FORCE_EXIT : |
| AOM_AV1_RESULT_NEED_MORE_BUFFER; |
| vdec_schedule_work(&hw->work); |
| } |
| unlock_buffer_pool(cm->buffer_pool, flags); |
| |
| av1_print(hw, PRINT_FLAG_V4L_DETAIL, |
| "%s wait capture buffer end, ret:%d\n", |
| __func__, ret); |
| return 0; |
| } |
| |
| static void av1_work(struct work_struct *work) |
| { |
| struct AV1HW_s *hw = container_of(work, |
| struct AV1HW_s, work); |
| struct vdec_s *vdec = hw_to_vdec(hw); |
| /* finished decoding one frame or error, |
| * notify vdec core to switch context |
| */ |
| if (hw->dec_result == DEC_RESULT_AGAIN) |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_AGAIN); |
| if (hw->dec_result != AOM_AV1_RESULT_NEED_MORE_BUFFER) |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_START); |
| av1_print(hw, PRINT_FLAG_VDEC_DETAIL, |
| "%s dec_result %d %x %x %x\n", |
| __func__, |
| hw->dec_result, |
| READ_VREG(HEVC_STREAM_LEVEL), |
| READ_VREG(HEVC_STREAM_WR_PTR), |
| READ_VREG(HEVC_STREAM_RD_PTR)); |
| |
| ATRACE_COUNTER("V_ST_DEC-work_state", hw->dec_result); |
| |
| if (hw->dec_result == AOM_AV1_RESULT_NEED_MORE_BUFFER) { |
| reset_process_time(hw); |
| if (get_free_buf_count(hw) <= 0) { |
| struct AV1_Common_s *const cm = &hw->common; |
| ulong flags; |
| int ret; |
| |
| lock_buffer_pool(cm->buffer_pool, flags); |
| |
| hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; |
| if (vdec->next_status == VDEC_STATUS_DISCONNECTED) { |
| hw->dec_result = DEC_RESULT_AGAIN; |
| vdec_schedule_work(&hw->work); |
| } else { |
| hw->wait_more_buf = true; |
| } |
| unlock_buffer_pool(cm->buffer_pool, flags); |
| |
| if (hw->wait_more_buf) { |
| ATRACE_COUNTER("V_ST_DEC-wait_more_buff", __LINE__); |
| ret = vdec_post_task(av1_wait_cap_buf, hw); |
| if (ret != 0) { |
| pr_err("post task create failed!!!! ret %d\n", ret); |
| lock_buffer_pool(cm->buffer_pool, flags); |
| hw->wait_more_buf = false; |
| hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; |
| vdec_schedule_work(&hw->work); |
| unlock_buffer_pool(cm->buffer_pool, flags); |
| } |
| } |
| |
| } else { |
| ATRACE_COUNTER("V_ST_DEC-wait_more_buff", 0); |
| av1_release_bufs(hw); |
| av1_continue_decoding(hw, hw->cur_obu_type); |
| hw->postproc_done = 0; |
| start_process_time(hw); |
| } |
| return; |
| } |
| |
| if (((hw->dec_result == DEC_RESULT_GET_DATA) || |
| (hw->dec_result == DEC_RESULT_GET_DATA_RETRY)) |
| && (hw_to_vdec(hw)->next_status != |
| VDEC_STATUS_DISCONNECTED)) { |
| if (!vdec_has_more_input(vdec)) { |
| hw->dec_result = DEC_RESULT_EOS; |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| |
| if (hw->dec_result == DEC_RESULT_GET_DATA) { |
| av1_print(hw, 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, hw->chunk); |
| vdec_clean_input(vdec); |
| } |
| |
| if (get_free_buf_count(hw) >= |
| hw->run_ready_min_buf_num) { |
| int r; |
| int decode_size; |
| r = vdec_prepare_input(vdec, &hw->chunk); |
| if (r < 0) { |
| hw->dec_result = DEC_RESULT_GET_DATA_RETRY; |
| |
| av1_print(hw, |
| PRINT_FLAG_VDEC_DETAIL, |
| "amvdec_vh265: Insufficient data\n"); |
| |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| hw->dec_result = DEC_RESULT_NONE; |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s: chunk size 0x%x sum 0x%x\n", |
| __func__, r, |
| (debug & PRINT_FLAG_VDEC_STATUS) ? |
| get_data_check_sum(hw, r) : 0 |
| ); |
| |
| if (debug & PRINT_FLAG_VDEC_DATA) |
| dump_data(hw, hw->data_size); |
| |
| decode_size = hw->data_size + |
| (hw->data_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(hw); |
| |
| } else { |
| hw->dec_result = DEC_RESULT_GET_DATA_RETRY; |
| |
| av1_print(hw, PRINT_FLAG_VDEC_DETAIL, |
| "amvdec_vh265: Insufficient data\n"); |
| |
| vdec_schedule_work(&hw->work); |
| } |
| return; |
| } else if (hw->dec_result == DEC_RESULT_DONE) { |
| /* if (!hw->ctx_valid) |
| hw->ctx_valid = 1; */ |
| hw->result_done_count++; |
| hw->process_state = PROC_STATE_INIT; |
| |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s (===> %d) dec_result %d (%d) %x %x %x shiftbytes 0x%x decbytes 0x%x\n", |
| __func__, |
| hw->frame_count, |
| hw->dec_result, |
| hw->result_done_count, |
| 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) - |
| hw->start_shift_bytes |
| ); |
| vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); |
| } else if (hw->dec_result == DEC_RESULT_AGAIN) { |
| /* |
| stream base: stream buf empty or timeout |
| frame base: vdec_prepare_input fail |
| */ |
| if (!vdec_has_more_input(vdec)) { |
| hw->dec_result = DEC_RESULT_EOS; |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| } else if (hw->dec_result == DEC_RESULT_EOS) { |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s: end of stream\n", __func__); |
| mutex_lock(&hw->assit_task.assit_mutex); |
| hw->eos = 1; |
| av1_postproc(hw); |
| |
| if (hw->is_used_v4l) { |
| ATRACE_COUNTER("V_ST_DEC-submit_eos", __LINE__); |
| notify_v4l_eos(hw_to_vdec(hw)); |
| ATRACE_COUNTER("V_ST_DEC-submit_eos", 0); |
| } |
| mutex_unlock(&hw->assit_task.assit_mutex); |
| |
| vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); |
| } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s: force exit\n", |
| __func__); |
| if (hw->stat & STAT_VDEC_RUN) { |
| amhevc_stop(); |
| hw->stat &= ~STAT_VDEC_RUN; |
| } |
| |
| if (hw->stat & STAT_ISR_REG) { |
| #ifdef MULTI_INSTANCE_SUPPORT |
| if (!hw->m_ins_flag) |
| #endif |
| WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0); |
| vdec_free_irq(VDEC_IRQ_0, (void *)hw); |
| hw->stat &= ~STAT_ISR_REG; |
| } |
| } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) { |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s (===> %d) dec_result %d (%d) %x %x %x shiftbytes 0x%x decbytes 0x%x discard pic!\n", |
| __func__, |
| hw->frame_count, |
| hw->dec_result, |
| hw->result_done_count, |
| 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) - |
| hw->start_shift_bytes |
| ); |
| vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); |
| } else if (hw->dec_result == DEC_RESULT_UNFINISH) { |
| hw->result_done_count++; |
| hw->process_state = PROC_STATE_INIT; |
| |
| av1_print(hw, PRINT_FLAG_VDEC_STATUS, |
| "%s (===> %d) dec_result %d (%d) %x %x %x shiftbytes 0x%x decbytes 0x%x\n", |
| __func__, |
| hw->frame_count, |
| hw->dec_result, |
| hw->result_done_count, |
| 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) - hw->start_shift_bytes); |
| amhevc_stop(); |
| } |
| |
| if (hw->stat & STAT_VDEC_RUN) { |
| amhevc_stop(); |
| hw->stat &= ~STAT_VDEC_RUN; |
| } |
| |
| if (hw->stat & STAT_TIMER_ARM) { |
| del_timer_sync(&hw->timer); |
| hw->stat &= ~STAT_TIMER_ARM; |
| } |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_END); |
| /* mark itself has all HW resource released and input released */ |
| if (vdec->parallel_dec == 1) |
| vdec_core_finish_run(vdec, CORE_MASK_HEVC); |
| else |
| vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1 |
| | CORE_MASK_HEVC); |
| trigger_schedule(hw); |
| } |
| |
| static int av1_hw_ctx_restore(struct AV1HW_s *hw) |
| { |
| vav1_prot_init(hw, HW_MASK_FRONT | HW_MASK_BACK); |
| return 0; |
| } |
| |
| static bool is_avaliable_buffer(struct AV1HW_s *hw) |
| { |
| AV1_COMMON *cm = &hw->common; |
| RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| int i, free_count = 0; |
| int used_count = 0; |
| |
| if ((hw->used_buf_num == 0) || |
| (ctx->cap_pool.dec < hw->used_buf_num)) { |
| if (ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) { |
| free_count = |
| v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) + 1; |
| } |
| } |
| |
| for (i = 0; i < hw->used_buf_num; ++i) { |
| if ((frame_bufs[i].ref_count == 0) && |
| (frame_bufs[i].buf.vf_ref == 0) && |
| (frame_bufs[i].buf.repeat_count == 0) && |
| (frame_bufs[i].buf.index >= 0) && |
| frame_bufs[i].buf.cma_alloc_addr) { |
| free_count++; |
| } else if (frame_bufs[i].buf.cma_alloc_addr) |
| used_count++; |
| } |
| |
| ATRACE_COUNTER("av1_free_buff_count", free_count); |
| ATRACE_COUNTER("av1_used_buff_count", used_count); |
| |
| return free_count >= hw->run_ready_min_buf_num ? 1 : 0; |
| } |
| |
| static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| int tvp = vdec_secure(hw_to_vdec(hw)) ? |
| CODEC_MM_FLAGS_TVP : 0; |
| unsigned long ret = 0; |
| |
| if (!hw->pic_list_init_done2 || hw->eos) |
| return ret; |
| |
| if (!hw->first_sc_checked && |
| (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && |
| (get_double_write_mode(hw) != 0x10)) { |
| int size; |
| void * mmu_box; |
| |
| if (hw->is_used_v4l) { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| mmu_box = ctx->mmu_box; |
| } else |
| mmu_box = hw->mmu_box; |
| |
| size = decoder_mmu_box_sc_check(mmu_box, tvp); |
| hw->first_sc_checked = 1; |
| av1_print(hw, 0, "av1 cached=%d need_size=%d speed= %d ms\n", |
| size, (hw->need_cache_size >> PAGE_SHIFT), |
| (int)(get_jiffies_64() - hw->sc_start_time) * 1000/HZ); |
| #ifdef AOM_AV1_MMU_DW |
| /*!!!!!! To do ... */ |
| if (get_double_write_mode(hw) & 0x20) { |
| |
| } |
| #endif |
| } |
| |
| if (hw->is_used_v4l) { |
| struct aml_vcodec_ctx *ctx = |
| (struct aml_vcodec_ctx *)(hw->v4l2_ctx); |
| |
| if (hw->v4l_params_parsed) { |
| if (is_avaliable_buffer(hw)) |
| ret = CORE_MASK_HEVC; |
| else |
| ret = 0; |
| } else { |
| if (ctx->v4l_resolution_change) |
| ret = 0; |
| else |
| ret = CORE_MASK_HEVC; |
| } |
| } |
| |
| if (ret) |
| not_run_ready[hw->index] = 0; |
| else |
| not_run_ready[hw->index]++; |
| |
| /*av1_print(hw, |
| PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx\r\n", |
| __func__, mask, ret);*/ |
| return ret; |
| } |
| |
| static void av1_frame_mode_pts_save(struct AV1HW_s *hw) |
| { |
| u64 i, valid_pts_diff_cnt, pts_diff_sum; |
| u64 in_pts_diff, last_valid_pts_diff, calc_dur; |
| |
| if (hw->chunk == NULL) |
| return; |
| /* no return when first pts is 0 */ |
| if (!hw->is_used_v4l && hw->first_pts_index) { |
| /* filtration pts 0 and continuous same pts */ |
| if ((hw->chunk->pts == 0) || |
| (hw->frame_mode_pts_save[0] == hw->chunk->pts)) |
| return; |
| |
| /* fps change, frame dur change to lower or higher, |
| * can't find closed pts in saved pool */ |
| if (hw->dur_recalc_flag || |
| (hw->last_pts > hw->chunk->pts)) { |
| hw->av1_first_pts_ready = 0; |
| hw->first_pts_index = 0; |
| hw->get_frame_dur = 0; |
| hw->dur_recalc_flag = 0; |
| memset(hw->frame_mode_pts_save, 0, |
| sizeof(hw->frame_mode_pts_save)); |
| memset(hw->frame_mode_pts64_save, 0, |
| sizeof(hw->frame_mode_pts64_save)); |
| } |
| } |
| av1_print(hw, AV1_DEBUG_OUT_PTS, |
| "run_front: pts %d, pts64 %lld, ts: %lld\n", |
| hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp); |
| |
| for (i = (FRAME_BUFFERS - 1); i > 0; i--) { |
| hw->frame_mode_pts_save[i] = hw->frame_mode_pts_save[i - 1]; |
| hw->frame_mode_pts64_save[i] = hw->frame_mode_pts64_save[i - 1]; |
| } |
| hw->frame_mode_pts_save[0] = hw->chunk->pts; |
| hw->frame_mode_pts64_save[0] = hw->chunk->pts64; |
| |
| if (hw->is_used_v4l && !v4l_bitstream_id_enable) |
| hw->frame_mode_pts64_save[0] = hw->chunk->timestamp; |
| |
| if (hw->first_pts_index < ARRAY_SIZE(hw->frame_mode_pts_save)) |
| hw->first_pts_index++; |
| /* frame duration check, vdec_secure return for nts problem */ |
| if ((!hw->first_pts_index) || |
| hw->get_frame_dur || |
| vdec_secure(hw_to_vdec(hw))) |
| return; |
| valid_pts_diff_cnt = 0; |
| pts_diff_sum = 0; |
| |
| for (i = 0; i < FRAME_BUFFERS - 1; i++) { |
| if ((hw->frame_mode_pts_save[i] > hw->frame_mode_pts_save[i + 1]) && |
| (hw->frame_mode_pts_save[i + 1] != 0)) |
| in_pts_diff = hw->frame_mode_pts_save[i] |
| - hw->frame_mode_pts_save[i + 1]; |
| else |
| in_pts_diff = 0; |
| |
| if (in_pts_diff < 100 || |
| (valid_pts_diff_cnt && (!close_to(in_pts_diff, last_valid_pts_diff, 100)))) |
| in_pts_diff = 0; |
| else { |
| last_valid_pts_diff = in_pts_diff; |
| valid_pts_diff_cnt++; |
| } |
| |
| pts_diff_sum += in_pts_diff; |
| } |
| |
| if (!valid_pts_diff_cnt) { |
| av1_print(hw, AV1_DEBUG_OUT_PTS, "checked no avaliable pts\n"); |
| return; |
| } |
| |
| calc_dur = PTS2DUR_u64(div_u64(pts_diff_sum, valid_pts_diff_cnt)); |
| |
| if ((!close_to(calc_dur, hw->frame_dur, 10)) && |
| (calc_dur < 4800) && (calc_dur > 800)) { |
| av1_print(hw, 0, "change to calc dur %llu, old dur %u\n", calc_dur, hw->frame_dur); |
| hw->frame_dur = calc_dur; |
| hw->get_frame_dur = true; |
| } else { |
| if (hw->frame_count > FRAME_BUFFERS) |
| hw->get_frame_dur = true; |
| } |
| } |
| |
| static void run_front(struct vdec_s *vdec) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| int ret, size; |
| |
| run_count[hw->index]++; |
| /* hw->chunk = vdec_prepare_input(vdec); */ |
| hevc_reset_core(vdec); |
| |
| if ((vdec_frame_based(vdec)) && |
| (hw->dec_result == DEC_RESULT_UNFINISH)) { |
| u32 res_byte = hw->data_size - hw->consume_byte; |
| |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "%s before, consume 0x%x, size 0x%x, offset 0x%x, res 0x%x\n", __func__, |
| hw->consume_byte, hw->data_size, hw->data_offset + hw->consume_byte, res_byte); |
| |
| hw->data_invalid = vdec_offset_prepare_input(vdec, hw->consume_byte, hw->data_offset, hw->data_size); |
| hw->data_offset -= (hw->data_invalid - hw->consume_byte); |
| hw->data_size += (hw->data_invalid - hw->consume_byte); |
| size = hw->data_size; |
| WRITE_VREG(HEVC_ASSIST_SCRATCH_C, hw->data_invalid); |
| |
| av1_print(hw, AV1_DEBUG_BUFMGR, |
| "%s after, consume 0x%x, size 0x%x, offset 0x%x, invalid 0x%x, res 0x%x\n", __func__, |
| hw->consume_byte, hw->data_size, hw->data_offset, hw->data_invalid, res_byte); |
| } else { |
| size = vdec_prepare_input(vdec, &hw->chunk); |
| if (size < 0) { |
| input_empty[hw->index]++; |
| |
| hw->dec_result = DEC_RESULT_AGAIN; |
| |
| av1_print(hw, PRINT_FLAG_VDEC_DETAIL, |
| "ammvdec_av1: Insufficient data\n"); |
| |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| if ((vdec_frame_based(vdec)) && |
| (hw->chunk != NULL)) { |
| hw->data_offset = hw->chunk->offset; |
| hw->data_size = size; |
| } |
| WRITE_VREG(HEVC_ASSIST_SCRATCH_C, 0); |
| } |
| |
| ATRACE_COUNTER("V_ST_DEC-chunk_size", size); |
| |
| input_empty[hw->index] = 0; |
| hw->dec_result = DEC_RESULT_NONE; |
| hw->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT); |
| |
| av1_frame_mode_pts_save(hw); |
| if (debug & PRINT_FLAG_VDEC_STATUS) { |
| if (vdec_frame_based(vdec) && hw->chunk && !vdec_secure(vdec)) { |
| u8 *data = NULL; |
| |
| if (!hw->chunk->block->is_mapped) |
| data = codec_mm_vmap(hw->chunk->block->start + |
| hw->data_offset, size); |
| else |
| data = ((u8 *)hw->chunk->block->start_virt) + |
| hw->data_offset; |
| |
| //print_hex_debug(data, size, size > 64 ? 64 : size); |
| av1_print(hw, 0, |
| "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", |
| __func__, size, get_data_check_sum(hw, size), |
| data[0], data[1], data[2], data[3], |
| data[4], data[5], data[size - 4], |
| data[size - 3], data[size - 2], |
| data[size - 1]); |
| av1_print(hw, 0, |
| "%s frm cnt (%d): chunk (0x%x 0x%x) (%x %x %x %x %x) bytes 0x%x\n", |
| __func__, hw->frame_count, hw->data_size, hw->data_offset, |
| 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), |
| hw->start_shift_bytes); |
| |
| if (!hw->chunk->block->is_mapped) |
| codec_mm_unmap_phyaddr(data); |
| } else { |
| av1_print(hw, 0, |
| "%s (%d): size 0x%x (0x%x 0x%x) (%x %x %x %x %x) bytes 0x%x\n", |
| __func__, |
| hw->frame_count, size, |
| hw->chunk ? hw->data_size : 0, |
| hw->chunk ? hw->data_offset : 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), |
| hw->start_shift_bytes); |
| } |
| } |
| ATRACE_COUNTER(hw->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 { |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, hw->fw->data); |
| #else |
| ret = amhevc_loadmc_ex(VFORMAT_AV1, NULL, hw->fw->data); |
| #endif |
| if (ret < 0) { |
| amhevc_disable(); |
| av1_print(hw, PRINT_FLAG_ERROR, |
| "AV1: the %s fw loading failed, err: %x\n", |
| tee_enabled() ? "TEE" : "local", ret); |
| hw->dec_result = DEC_RESULT_FORCE_EXIT; |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| vdec->mc_loaded = 1; |
| #ifdef DEBUG_USE_VP9_DEVICE_NAME |
| vdec->mc_type = VFORMAT_VP9; |
| #else |
| vdec->mc_type = VFORMAT_AV1; |
| #endif |
| } |
| ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END); |
| |
| ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START); |
| if (av1_hw_ctx_restore(hw) < 0) { |
| vdec_schedule_work(&hw->work); |
| return; |
| } |
| ATRACE_COUNTER(hw->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(hw, hw->data_size); |
| |
| WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0); |
| size = hw->data_size + |
| (hw->data_offset & (VDEC_FIFO_ALIGN - 1)); |
| if (vdec->mvfrm) |
| vdec->mvfrm->frame_size = hw->data_size; |
| } |
| hw->data_size = size; |
| WRITE_VREG(HEVC_DECODE_SIZE, size); |
| WRITE_VREG(HEVC_DECODE_COUNT, hw->result_done_count); |
| WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr); |
| if (hw->config_next_ref_info_flag) |
| config_next_ref_info_hw(hw); |
| hw->config_next_ref_info_flag = 0; |
| hw->init_flag = 1; |
| |
| av1_print(hw, PRINT_FLAG_VDEC_DETAIL, |
| "%s: start hw (%x %x %x) HEVC_DECODE_SIZE 0x%x\n", |
| __func__, |
| READ_VREG(HEVC_DEC_STATUS_REG), |
| READ_VREG(HEVC_MPC_E), |
| READ_VREG(HEVC_MPSR), |
| READ_VREG(HEVC_DECODE_SIZE)); |
| |
| start_process_time(hw); |
| mod_timer(&hw->timer, jiffies); |
| hw->stat |= STAT_TIMER_ARM; |
| hw->stat |= STAT_ISR_REG; |
| amhevc_start(); |
| hw->stat |= STAT_VDEC_RUN; |
| } |
| |
| static void run(struct vdec_s *vdec, unsigned long mask, |
| void (*callback)(struct vdec_s *, void *), void *arg) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_START); |
| av1_print(hw, |
| PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n", |
| __func__, mask); |
| |
| run_count[hw->index]++; |
| if (vdec->mvfrm) |
| vdec->mvfrm->hw_decode_start = local_clock(); |
| hw->vdec_cb_arg = arg; |
| hw->vdec_cb = callback; |
| hw->one_package_frame_cnt = 0; |
| run_front(vdec); |
| ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_END); |
| } |
| |
| static void av1_decode_ctx_reset(struct AV1HW_s *hw) |
| { |
| struct AV1_Common_s *const cm = &hw->common; |
| struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; |
| int i; |
| |
| for (i = 0; i < FRAME_BUFFERS; ++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.index = i; |
| frame_bufs[i].buf.BUF_index = -1; |
| frame_bufs[i].buf.mv_buf_index = -1; |
| frame_bufs[i].buf.repeat_pic = NULL; |
| frame_bufs[i].buf.repeat_count = 0; |
| } |
| |
| for (i = 0; i < MV_BUFFER_NUM; i++) { |
| if (hw->m_mv_BUF[i].start_adr) { |
| if (mv_buf_dynamic_alloc) { |
| decoder_bmmu_box_free_idx(hw->bmmu_box, MV_BUFFER_IDX(i)); |
| hw->m_mv_BUF[i].start_adr = 0; |
| hw->m_mv_BUF[i].size = 0; |
| } |
| hw->m_mv_BUF[i].used_flag = 0; |
| } |
| } |
| |
| hw->one_compressed_data_done = 0; |
| hw->config_next_ref_info_flag = 0; |
| hw->init_flag = 0; |
| hw->first_sc_checked = 0; |
| hw->fatal_error = 0; |
| hw->show_frame_num = 0; |
| hw->postproc_done = 0; |
| hw->process_busy = 0; |
| hw->process_state = 0; |
| hw->frame_decoded = 0; |
| hw->eos = 0; |
| hw->dec_result = DEC_RESULT_NONE; |
| } |
| |
| static void reset(struct vdec_s *vdec) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| |
| cancel_work_sync(&hw->work); |
| cancel_work_sync(&hw->set_clk_work); |
| |
| if (hw->stat & STAT_VDEC_RUN) { |
| amhevc_stop(); |
| hw->stat &= ~STAT_VDEC_RUN; |
| } |
| |
| if (hw->stat & STAT_TIMER_ARM) { |
| del_timer_sync(&hw->timer); |
| hw->stat &= ~STAT_TIMER_ARM; |
| } |
| |
| reset_process_time(hw); |
| |
| av1_bufmgr_ctx_reset(hw->pbi, &hw->av1_buffer_pool, &hw->common); |
| hw->pbi->private_data = hw; |
| mutex_lock(&hw->assit_task.assit_mutex); |
| av1_local_uninit(hw, true); |
| if (vav1_local_init(hw, true) < 0) |
| av1_print(hw, 0, "%s local_init failed \r\n", __func__); |
| mutex_unlock(&hw->assit_task.assit_mutex); |
| |
| av1_decode_ctx_reset(hw); |
| |
| atomic_set(&hw->vf_pre_count, 0); |
| atomic_set(&hw->vf_get_count, 0); |
| atomic_set(&hw->vf_put_count, 0); |
| |
| if (hw->ge2d) { |
| vdec_ge2d_destroy(hw->ge2d); |
| hw->ge2d = NULL; |
| } |
| |
| av1_print(hw, PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__); |
| } |
| |
| static irqreturn_t av1_irq_cb(struct vdec_s *vdec, int irq) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| return vav1_isr(0, hw); |
| } |
| |
| static irqreturn_t av1_threaded_irq_cb(struct vdec_s *vdec, int irq) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| return vav1_isr_thread_fn(0, hw); |
| } |
| |
| static void av1_dump_state(struct vdec_s *vdec) |
| { |
| struct AV1HW_s *hw = |
| (struct AV1HW_s *)vdec->private; |
| struct AV1_Common_s *const cm = &hw->common; |
| int i; |
| av1_print(hw, 0, "====== %s\n", __func__); |
| |
| av1_print(hw, 0, |
| "width/height (%d/%d), used_buf_num %d\n", |
| cm->width, |
| cm->height, |
| hw->used_buf_num |
| ); |
| |
| av1_print(hw, 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), |
| hw->eos, |
| hw->dec_result, |
| decode_frame_count[hw->index], |
| display_frame_count[hw->index], |
| run_count[hw->index], |
| not_run_ready[hw->index], |
| input_empty[hw->index], |
| hw->low_latency_flag, |
| hw->no_head |
| ); |
| |
| if (!hw->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); |
| av1_print(hw, 0, |
| "\nreceiver(%s) state %d\n", |
| vdec->vf_provider_name, |
| state); |
| } |
| |
| av1_print(hw, 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(&hw->newframe_q), |
| VF_POOL_SIZE, |
| kfifo_len(&hw->display_q), |
| VF_POOL_SIZE, |
| hw->vf_pre_count, |
| hw->vf_get_count, |
| hw->vf_put_count, |
| get_free_buf_count(hw), |
| hw->run_ready_min_buf_num |
| ); |
| |
| dump_pic_list(hw); |
| |
| for (i = 0; i < MAX_BUF_NUM; i++) { |
| av1_print(hw, 0, |
| "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", |
| i, |
| hw->m_mv_BUF[i].start_adr, |
| hw->m_mv_BUF[i].size, |
| hw->m_mv_BUF[i].used_flag); |
| } |
| |
| av1_print(hw, 0, |
| "HEVC_DEC_STATUS_REG=0x%x\n", |
| READ_VREG(HEVC_DEC_STATUS_REG)); |
| av1_print(hw, 0, |
| "HEVC_MPC_E=0x%x\n", |
| READ_VREG(HEVC_MPC_E)); |
| av1_print(hw, 0, |
| "DECODE_MODE=0x%x\n", |
| READ_VREG(DECODE_MODE)); |
| av1_print(hw, 0, |
| "NAL_SEARCH_CTL=0x%x\n", |
| READ_VREG(NAL_SEARCH_CTL)); |
| av1_print(hw, 0, |
| "HEVC_PARSER_LCU_START=0x%x\n", |
| READ_VREG(HEVC_PARSER_LCU_START)); |
| av1_print(hw, 0, |
| "HEVC_DECODE_SIZE=0x%x\n", |
| READ_VREG(HEVC_DECODE_SIZE)); |
| av1_print(hw, 0, |
| "HEVC_SHIFT_BYTE_COUNT=0x%x\n", |
| READ_VREG(HEVC_SHIFT_BYTE_COUNT)); |
| av1_print(hw, 0, |
| "HEVC_SHIFTED_DATA=0x%x\n", |
| READ_VREG(HEVC_SHIFTED_DATA)); |
| av1_print(hw, 0, |
| "HEVC_STREAM_START_ADDR=0x%x\n", |
| READ_VREG(HEVC_STREAM_START_ADDR)); |
| av1_print(hw, 0, |
| "HEVC_STREAM_END_ADDR=0x%x\n", |
| READ_VREG(HEVC_STREAM_END_ADDR)); |
| av1_print(hw, 0, |
| "HEVC_STREAM_LEVEL=0x%x\n", |
| READ_VREG(HEVC_STREAM_LEVEL)); |
| av1_print(hw, 0, |
| "HEVC_STREAM_WR_PTR=0x%x\n", |
| READ_VREG(HEVC_STREAM_WR_PTR)); |
| av1_print(hw, 0, |
| "HEVC_STREAM_RD_PTR=0x%x\n", |
| READ_VREG(HEVC_STREAM_RD_PTR)); |
| av1_print(hw, 0, |
| "PARSER_VIDEO_RP=0x%x\n", |
| STBUF_READ(&vdec->vbuf, get_rp)); |
| av1_print(hw, 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 (hw->chunk && hw->chunk->block && |
| hw->data_size > 0) { |
| u8 *data = NULL; |
| |
| if (!hw->chunk->block->is_mapped) |
| data = codec_mm_vmap( |
| hw->chunk->block->start + |
| hw->data_offset, |
| hw->data_size); |
| else |
| data = ((u8 *)hw->chunk->block->start_virt) |
| + hw->data_offset; |
| av1_print(hw, 0, |
| "frame data size 0x%x\n", |
| hw->data_size); |
| for (jj = 0; jj < hw->data_size; jj++) { |
| if ((jj & 0xf) == 0) |
| av1_print(hw, 0, |
| "%06x:", jj); |
| av1_print_cont(hw, 0, |
| "%02x ", data[jj]); |
| if (((jj + 1) & 0xf) == 0) |
| av1_print_cont(hw, 0, |
| "\n"); |
| } |
| |
| if (!hw->chunk->block->is_mapped) |
| codec_mm_unmap_phyaddr(data); |
| } |
| } |
| |
| } |
| |
| static int ammvdec_av1_probe(struct platform_device *pdev) |
| { |
| struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; |
| int ret; |
| int config_val; |
| int i; |
| struct vframe_content_light_level_s content_light_level; |
| struct vframe_master_display_colour_s vf_dp; |
| u32 work_buf_size; |
| struct BuffInfo_s *p_buf_info; |
| struct AV1HW_s *hw = NULL; |
| |
| if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TM2) || |
| (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) || |
| ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) && !is_meson_rev_b())) { |
| pr_err("av1 unsupported on cpu %d, is_tm2_revb %d\n", |
| get_cpu_major_id(), is_cpu_tm2_revb()); |
| return -EINVAL; |
| } |
| |
| if (pdata == NULL) { |
| av1_print(hw, 0, "\nammvdec_av1 memory resource undefined.\n"); |
| return -EFAULT; |
| } |
| memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s)); |
| |
| hw = vzalloc(sizeof(struct AV1HW_s)); |
| if (hw == NULL) { |
| av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n"); |
| return -ENOMEM; |
| } |
| |
| if (init_dblk_struc(hw) < 0) { |
| av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n"); |
| vfree(hw); |
| return -ENOMEM; |
| } |
| |
| hw->pbi = av1_decoder_create(&hw->av1_buffer_pool, &hw->common); //&aom_decoder; |
| if (hw->pbi == NULL) { |
| av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n"); |
| release_dblk_struct(hw); |
| vfree(hw); |
| return -ENOMEM; |
| } |
| |
| hw->pbi->private_data = hw; |
| /* the ctx from v4l2 driver. */ |
| hw->v4l2_ctx = pdata->private; |
| |
| pdata->private = hw; |
| pdata->dec_status = vav1_dec_status; |
| /* pdata->set_trickmode = set_trickmode; */ |
| pdata->run_ready = run_ready; |
| pdata->run = run; |
| pdata->reset = reset; |
| pdata->irq_handler = av1_irq_cb; |
| pdata->threaded_irq_handler = av1_threaded_irq_cb; |
| pdata->dump_state = av1_dump_state; |
| |
| hw->index = pdev->id; |
| if (is_rdma_enable()) { |
| hw->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &hw->rdma_phy_adr, GFP_KERNEL); |
| for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { |
| hw->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; |
| hw->rdma_adr[i * 4 + 1] = i; |
| hw->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; |
| hw->rdma_adr[i * 4 + 3] = 0; |
| if (i == SCALELUT_DATA_WRITE_NUM - 1) { |
| hw->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; |
| } |
| } |
| } |
| snprintf(hw->trace.vdec_name, sizeof(hw->trace.vdec_name), |
| "av1-%d", hw->index); |
| snprintf(hw->trace.pts_name, sizeof(hw->trace.pts_name), |
| "%s-timestamp", hw->trace.vdec_name); |
| snprintf(hw->trace.new_q_name, sizeof(hw->trace.new_q_name), |
| "%s-newframe_q", hw->trace.vdec_name); |
| snprintf(hw->trace.disp_q_name, sizeof(hw->trace.disp_q_name), |
| "%s-dispframe_q", hw->trace.vdec_name); |
| snprintf(hw->trace.decode_time_name, sizeof(hw->trace.decode_time_name), |
| "decoder_time%d", pdev->id); |
| snprintf(hw->trace.decode_run_time_name, sizeof(hw->trace.decode_run_time_name), |
| "decoder_run_time%d", pdev->id); |
| snprintf(hw->trace.decode_header_memory_time_name, sizeof(hw->trace.decode_header_memory_time_name), |
| "decoder_header_time%d", pdev->id); |
| snprintf(hw->trace.decode_work_time_name, sizeof(hw->trace.decode_work_time_name), |
| "decoder_work_time%d", pdev->id); |
| if (pdata->use_vfm_path) |
| snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, |
| VFM_DEC_PROVIDER_NAME); |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| else if (vdec_dual(pdata)) { |
| struct AV1HW_s *hevc_pair = NULL; |
| |
| if (dv_toggle_prov_name) /*debug purpose*/ |
| snprintf(pdata->vf_provider_name, |
| VDEC_PROVIDER_NAME_SIZE, |
| (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME : |
| VFM_DEC_DVEL_PROVIDER_NAME); |
| else |
| snprintf(pdata->vf_provider_name, |
| VDEC_PROVIDER_NAME_SIZE, |
| (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME : |
| VFM_DEC_DVBL_PROVIDER_NAME); |
| if (pdata->master) |
| hevc_pair = (struct AV1HW_s *)pdata->master->private; |
| else if (pdata->slave) |
| hevc_pair = (struct AV1HW_s *)pdata->slave->private; |
| |
| if (hevc_pair) |
| hw->shift_byte_count_lo = hevc_pair->shift_byte_count_lo; |
| } |
| #endif |
| else |
| snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, |
| MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); |
| |
| hw->provider_name = pdata->vf_provider_name; |
| platform_set_drvdata(pdev, pdata); |
| |
| hw->platform_dev = pdev; |
| hw->video_signal_type = 0; |
| hw->m_ins_flag = 1; |
| |
| film_grain_task_create(hw); |
| |
| if (pdata->sys_info) { |
| hw->vav1_amstream_dec_info = *pdata->sys_info; |
| if ((unsigned long) hw->vav1_amstream_dec_info.param |
| & 0x08) { |
| hw->low_latency_flag = 1; |
| } else |
| hw->low_latency_flag = 0; |
| } else { |
| hw->vav1_amstream_dec_info.width = 0; |
| hw->vav1_amstream_dec_info.height = 0; |
| hw->vav1_amstream_dec_info.rate = 30; |
| } |
| |
| if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 && |
| pdata->config_len) { |
| #ifdef MULTI_INSTANCE_SUPPORT |
| int av1_buf_width = 0; |
| int av1_buf_height = 0; |
| /*use ptr config for doubel_write_mode, etc*/ |
| av1_print(hw, 0, "pdata->config=%s\n", pdata->config); |
| if (get_config_int(pdata->config, "av1_double_write_mode", |
| &config_val) == 0) |
| hw->double_write_mode = config_val; |
| else |
| hw->double_write_mode = double_write_mode; |
| |
| if (get_config_int(pdata->config, "save_buffer_mode", |
| &config_val) == 0) |
| hw->save_buffer_mode = config_val; |
| else |
| hw->save_buffer_mode = 0; |
| if (get_config_int(pdata->config, "av1_buf_width", |
| &config_val) == 0) { |
| av1_buf_width = config_val; |
| } |
| if (get_config_int(pdata->config, "av1_buf_height", |
| &config_val) == 0) { |
| av1_buf_height = config_val; |
| } |
| |
| if (get_config_int(pdata->config, "no_head", |
| &config_val) == 0) |
| hw->no_head = config_val; |
| else |
| hw->no_head = no_head; |
| |
| /*use ptr config for max_pic_w, etc*/ |
| if (get_config_int(pdata->config, "av1_max_pic_w", |
| &config_val) == 0) { |
| hw->max_pic_w = config_val; |
| } |
| if (get_config_int(pdata->config, "av1_max_pic_h", |
| &config_val) == 0) { |
| hw->max_pic_h = config_val; |
| } |
| if ((hw->max_pic_w * hw->max_pic_h) |
| < (av1_buf_width * av1_buf_height)) { |
| hw->max_pic_w = av1_buf_width; |
| hw->max_pic_h = av1_buf_height; |
| av1_print(hw, 0, "use buf resolution\n"); |
| } |
| |
| if (get_config_int(pdata->config, "sidebind_type", |
| &config_val) == 0) |
| hw->sidebind_type = config_val; |
| |
| if (get_config_int(pdata->config, "sidebind_channel_id", |
| &config_val) == 0) |
| hw->sidebind_channel_id = config_val; |
| |
| if (get_config_int(pdata->config, |
| "parm_v4l_codec_enable", |
| &config_val) == 0) |
| hw->is_used_v4l = config_val; |
| |
| if (get_config_int(pdata->config, |
| "parm_v4l_buffer_margin", |
| &config_val) == 0) |
| hw->dynamic_buf_num_margin = config_val; |
| |
| if (get_config_int(pdata->config, |
| "parm_v4l_canvas_mem_mode", |
| &config_val) == 0) |
| hw->mem_map_mode = config_val; |
| |
| if (get_config_int(pdata->config, |
| "parm_v4l_low_latency_mode", |
| &config_val) == 0) |
| hw->low_latency_flag = config_val; |
| /*if (get_config_int(pdata->config, |
| "parm_v4l_duration", |
| &config_val) == 0) |
| vdec_frame_rate_uevent(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", |
| &hw->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); |
| vf_dp.content_light_level = content_light_level; |
| if (!hw->video_signal_type) { |
| hw->video_signal_type = (1 << 29) |
| | (5 << 26) /* unspecified */ |
| | (0 << 25) /* limit */ |
| | (1 << 24) /* color available */ |
| | (9 << 16) /* 2020 */ |
| | (16 << 8) /* 2084 */ |
| | (9 << 0); /* 2020 */ |
| } |
| } |
| hw->vf_dp = vf_dp; |
| } else { |
| u32 force_w, force_h; |
| if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { |
| force_w = 1920; |
| force_h = 1088; |
| } else { |
| force_w = 8192; |
| force_h = 4608; |
| } |
| if (hw->vav1_amstream_dec_info.width) |
| hw->max_pic_w = hw->vav1_amstream_dec_info.width; |
| else |
| hw->max_pic_w = force_w; |
| |
| if (hw->vav1_amstream_dec_info.height) |
| hw->max_pic_h = hw->vav1_amstream_dec_info.height; |
| else |
| hw->max_pic_h = force_h; |
| hw->double_write_mode = double_write_mode; |
| } |
| |
| hw->endian = HEVC_CONFIG_LITTLE_ENDIAN; |
| if (endian) |
| hw->endian = endian; |
| |
| if (is_oversize(hw->max_pic_w, hw->max_pic_h)) { |
| pr_err("over size: %dx%d, probe failed\n", |
| hw->max_pic_w, hw->max_pic_h); |
| return -1; |
| } |
| if (force_bufspec) { |
| hw->buffer_spec_index = force_bufspec & 0xf; |
| pr_info("force buffer spec %d\n", force_bufspec & 0xf); |
| } else if (vdec_is_support_4k()) { |
| hw->buffer_spec_index = 1; |
| } else |
| hw->buffer_spec_index = 0; |
| |
| if (hw->buffer_spec_index == 0) |
| hw->max_one_mv_buffer_size = |
| (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ? |
| MAX_ONE_MV_BUFFER_SIZE_1080P : MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB; |
| else if (hw->buffer_spec_index == 1) |
| hw->max_one_mv_buffer_size = |
| (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ? |
| MAX_ONE_MV_BUFFER_SIZE_4K : MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB; |
| else |
| hw->max_one_mv_buffer_size = |
| (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ? |
| MAX_ONE_MV_BUFFER_SIZE_8K : MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB; |
| |
| p_buf_info = &aom_workbuff_spec[hw->buffer_spec_index]; |
| work_buf_size = (p_buf_info->end_adr - p_buf_info->start_adr |
| + 0xffff) & (~0xffff); |
| |
| if (vdec_is_support_4k() && |
| (hw->max_pic_w * hw->max_pic_h < MAX_SIZE_4K)) { |
| hw->max_pic_w = 4096; |
| hw->max_pic_h = 2304; |
| } |
| av1_print(hw, 0, |
| "vdec_is_support_4k() %d max_pic_w %d max_pic_h %d buffer_spec_index %d work_buf_size 0x%x\n", |
| vdec_is_support_4k(), hw->max_pic_w, hw->max_pic_h, |
| hw->buffer_spec_index, work_buf_size); |
| |
| if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL || |
| hw->double_write_mode == 0x10) |
| hw->mmu_enable = 0; |
| else |
| hw->mmu_enable = 1; |
| |
| video_signal_type = hw->video_signal_type; |
| |
| if (pdata->sys_info) { |
| hw->vav1_amstream_dec_info = *pdata->sys_info; |
| if ((unsigned long) hw->vav1_amstream_dec_info.param |
| & 0x08) { |
| hw->low_latency_flag = 1; |
| } else |
| hw->low_latency_flag = 0; |
| } else { |
| hw->vav1_amstream_dec_info.width = 0; |
| hw->vav1_amstream_dec_info.height = 0; |
| hw->vav1_amstream_dec_info.rate = 30; |
| } |
| |
| #ifdef AOM_AV1_MMU_DW |
| hw->dw_mmu_enable = |
| get_double_write_mode_init(hw) & 0x20 ? 1 : 0; |
| |
| #endif |
| av1_print(hw, 0, |
| "no_head %d low_latency %d video_signal_type 0x%x\n", |
| hw->no_head, hw->low_latency_flag, hw->video_signal_type); |
| #if 0 |
| hw->buf_start = pdata->mem_start; |
| hw->buf_size = pdata->mem_end - pdata->mem_start + 1; |
| #else |
| if (amvdec_av1_mmu_init(hw) < 0) { |
| pr_err("av1 alloc bmmu box failed!!\n"); |
| /* devm_kfree(&pdev->dev, (void *)hw); */ |
| vfree((void *)hw); |
| pdata->dec_status = NULL; |
| return -1; |
| } |
| |
| hw->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE; |
| ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, WORK_SPACE_BUF_ID, |
| hw->cma_alloc_count * PAGE_SIZE, DRIVER_NAME, |
| &hw->cma_alloc_addr); |
| if (ret < 0) { |
| uninit_mmu_buffers(hw); |
| /* devm_kfree(&pdev->dev, (void *)hw); */ |
| vfree((void *)hw); |
| pdata->dec_status = NULL; |
| return ret; |
| } |
| hw->buf_start = hw->cma_alloc_addr; |
| hw->buf_size = work_buf_size; |
| #endif |
| |
| hw->init_flag = 0; |
| hw->first_sc_checked = 0; |
| hw->fatal_error = 0; |
| hw->show_frame_num = 0; |
| hw->run_ready_min_buf_num = run_ready_min_buf_num; |
| |
| if (hw->is_used_v4l && (hw->v4l2_ctx != NULL)) { |
| struct aml_vcodec_ctx *ctx = hw->v4l2_ctx; |
| |
| ctx->aux_infos.alloc_buffer(ctx, SEI_TYPE | DV_TYPE); |
| } |
| |
| hw->aux_data_size = AUX_BUF_ALIGN(prefix_aux_buf_size) + |
| AUX_BUF_ALIGN(suffix_aux_buf_size); |
| hw->dv_data_buf = vmalloc(hw->aux_data_size); |
| hw->dv_data_size = 0; |
| |
| if (debug) { |
| av1_print(hw, AOM_DEBUG_HW_MORE, "===AV1 decoder mem resource 0x%lx size 0x%x\n", |
| hw->buf_start, |
| hw->buf_size); |
| } |
| |
| hw->cma_dev = pdata->cma_dev; |
| if (vav1_init(pdata) < 0) { |
| av1_print(hw, 0, "\namvdec_av1 init failed.\n"); |
| av1_local_uninit(hw, false); |
| uninit_mmu_buffers(hw); |
| /* devm_kfree(&pdev->dev, (void *)hw); */ |
| vfree((void *)hw); |
| pdata->dec_status = NULL; |
| return -ENODEV; |
| } |
| |
| #ifdef AUX_DATA_CRC |
| vdec_aux_data_check_init(pdata); |
| #endif |
| |
| vdec_set_prepare_level(pdata, start_decode_buf_level); |
| hevc_source_changed(VFORMAT_AV1, 4096, 2048, 60); |
| |
| 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); |
| |
| hw->pic_list_init_done2 = true; |
| return 0; |
| } |
| |
| static int ammvdec_av1_remove(struct platform_device *pdev) |
| { |
| struct AV1HW_s *hw = (struct AV1HW_s *) |
| (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); |
| struct vdec_s *vdec = hw_to_vdec(hw); |
| int i; |
| if (debug) |
| av1_print(hw, AOM_DEBUG_HW_MORE, "amvdec_av1_remove\n"); |
| |
| #ifdef AUX_DATA_CRC |
| vdec_aux_data_check_exit(vdec); |
| #endif |
| |
| if (hw->dv_data_buf != NULL) { |
| vfree(hw->dv_data_buf); |
| hw->dv_data_buf = NULL; |
| } |
| |
| vmav1_stop(hw); |
| |
| film_grain_task_exit(hw); |
| |
| if (hw->ge2d) { |
| vdec_ge2d_destroy(hw->ge2d); |
| hw->ge2d = NULL; |
| } |
| |
| if (vdec->parallel_dec == 1) |
| vdec_core_release(hw_to_vdec(hw), CORE_MASK_HEVC); |
| else |
| vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); |
| |
| vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED); |
| |
| if (vdec->parallel_dec == 1) { |
| for (i = 0; i < FRAME_BUFFERS; i++) { |
| vdec->free_canvas_ex |
| (hw->common.buffer_pool->frame_bufs[i].buf.y_canvas_index, |
| vdec->id); |
| vdec->free_canvas_ex |
| (hw->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", |
| hw->pts_missed, hw->pts_hit, hw->frame_dur); |
| #endif |
| /* devm_kfree(&pdev->dev, (void *)hw); */ |
| if (is_rdma_enable()) |
| dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, hw->rdma_adr, hw->rdma_phy_adr); |
| vfree(hw->pbi); |
| release_dblk_struct(hw); |
| vfree((void *)hw); |
| return 0; |
| } |
| |
| static struct platform_driver ammvdec_av1_driver = { |
| .probe = ammvdec_av1_probe, |
| .remove = ammvdec_av1_remove, |
| .driver = { |
| .name = MULTI_DRIVER_NAME, |
| #ifdef CONFIG_PM |
| .pm = &av1_pm_ops, |
| #endif |
| } |
| }; |
| #endif |
| static struct mconfig av1_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_width", &buf_alloc_width), |
| MC_PU32("buf_alloc_height", &buf_alloc_height), |
| 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("av1_max_pic_w", &av1_max_pic_w), |
| MC_PU32("av1_max_pic_h", &av1_max_pic_h), |
| }; |
| static struct mconfig_node av1_node; |
| |
| static int __init amvdec_av1_driver_init_module(void) |
| { |
| //struct BuffInfo_s *p_buf_info; |
| int i; |
| #ifdef BUFMGR_ONLY_OLD_CHIP |
| debug |= AOM_DEBUG_BUFMGR_ONLY; |
| #endif |
| /* |
| if (vdec_is_support_4k()) { |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) |
| p_buf_info = &aom_workbuff_spec[1]; |
| else |
| p_buf_info = &aom_workbuff_spec[1]; |
| } else |
| p_buf_info = &aom_workbuff_spec[0]; |
| |
| init_buff_spec(NULL, p_buf_info); |
| work_buf_size = |
| (p_buf_info->end_adr - p_buf_info->start_adr |
| + 0xffff) & (~0xffff); |
| */ |
| for (i = 0; i < WORK_BUF_SPEC_NUM; i++) |
| init_buff_spec(NULL, &aom_workbuff_spec[i]); |
| |
| pr_debug("amvdec_av1 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; |
| |
| if (platform_driver_register(&ammvdec_av1_driver)) { |
| pr_err("failed to register ammvdec_av1 driver\n"); |
| return -ENODEV; |
| } |
| if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { |
| amvdec_av1_profile.profile = |
| "10bit, dwrite, compressed, no_head, uvm"; |
| } else if (((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) || is_cpu_tm2_revb()) |
| && (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5)) { |
| amvdec_av1_profile.profile = |
| "8k, 10bit, dwrite, compressed, no_head, frame_dv, uvm"; |
| } else { |
| amvdec_av1_profile.name = "av1_unsupport"; |
| } |
| |
| vcodec_profile_register(&amvdec_av1_profile); |
| |
| INIT_REG_NODE_CONFIGS("media.decoder", &av1_node, |
| "av1-v4l", av1_configs, CONFIG_FOR_RW); |
| vcodec_feature_register(VFORMAT_AV1, 1); |
| |
| return 0; |
| } |
| |
| static void __exit amvdec_av1_driver_remove_module(void) |
| { |
| pr_debug("amvdec_av1 module remove.\n"); |
| |
| platform_driver_unregister(&ammvdec_av1_driver); |
| } |
| |
| /****************************************/ |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| module_param(force_dv_enable, uint, 0664); |
| MODULE_PARM_DESC(force_dv_enable, "\n amvdec_av1 force_dv_enable\n"); |
| #endif |
| |
| module_param(bit_depth_luma, uint, 0664); |
| MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_av1 bit_depth_luma\n"); |
| |
| module_param(bit_depth_chroma, uint, 0664); |
| MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_av1 bit_depth_chroma\n"); |
| |
| module_param(frame_width, uint, 0664); |
| MODULE_PARM_DESC(frame_width, "\n amvdec_av1 frame_width\n"); |
| |
| module_param(frame_height, uint, 0664); |
| MODULE_PARM_DESC(frame_height, "\n amvdec_av1 frame_height\n"); |
| |
| module_param(multi_frames_in_one_pack, uint, 0664); |
| MODULE_PARM_DESC(multi_frames_in_one_pack, "\n multi_frames_in_one_pack\n"); |
| |
| module_param(debug, uint, 0664); |
| MODULE_PARM_DESC(debug, "\n amvdec_av1 debug\n"); |
| |
| module_param(disable_fg, uint, 0664); |
| MODULE_PARM_DESC(disable_fg, "\n amvdec_av1 disable_fg\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(disable_repeat, uint, 0664); |
| MODULE_PARM_DESC(disable_repeat, "\n disable_repeat\n"); |
| |
| module_param(step, uint, 0664); |
| MODULE_PARM_DESC(step, "\n amvdec_av1 step\n"); |
| |
| module_param(decode_pic_begin, uint, 0664); |
| MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_av1 decode_pic_begin\n"); |
| |
| module_param(slice_parse_begin, uint, 0664); |
| MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_av1 slice_parse_begin\n"); |
| |
| module_param(i_only_flag, uint, 0664); |
| MODULE_PARM_DESC(i_only_flag, "\n amvdec_av1 i_only_flag\n"); |
| |
| module_param(low_latency_flag, uint, 0664); |
| MODULE_PARM_DESC(low_latency_flag, "\n amvdec_av1 low_latency_flag\n"); |
| |
| module_param(no_head, uint, 0664); |
| MODULE_PARM_DESC(no_head, "\n amvdec_av1 no_head\n"); |
| |
| module_param(error_handle_policy, uint, 0664); |
| MODULE_PARM_DESC(error_handle_policy, "\n amvdec_av1 error_handle_policy\n"); |
| |
| module_param(buf_alloc_width, uint, 0664); |
| MODULE_PARM_DESC(buf_alloc_width, "\n buf_alloc_width\n"); |
| |
| module_param(buf_alloc_height, uint, 0664); |
| MODULE_PARM_DESC(buf_alloc_height, "\n buf_alloc_height\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(force_max_one_mv_buffer_size, uint, 0664); |
| MODULE_PARM_DESC(force_max_one_mv_buffer_size, "\n force_max_one_mv_buffer_size\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"); |
| |
| #ifdef MCRCC_ENABLE |
| module_param(mcrcc_cache_alg_flag, uint, 0664); |
| MODULE_PARM_DESC(mcrcc_cache_alg_flag, "\n mcrcc_cache_alg_flag\n"); |
| #endif |
| |
| #ifdef MULTI_INSTANCE_SUPPORT |
| module_param(start_decode_buf_level, int, 0664); |
| MODULE_PARM_DESC(start_decode_buf_level, |
| "\n av1 start_decode_buf_level\n"); |
| |
| module_param(decode_timeout_val, uint, 0664); |
| MODULE_PARM_DESC(decode_timeout_val, |
| "\n av1 decode_timeout_val\n"); |
| |
| module_param(av1_max_pic_w, uint, 0664); |
| MODULE_PARM_DESC(av1_max_pic_w, "\n av1_max_pic_w\n"); |
| |
| module_param(av1_max_pic_h, uint, 0664); |
| MODULE_PARM_DESC(av1_max_pic_h, "\n av1_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); |
| |
| #ifdef AOM_AV1_MMU_DW |
| module_param_array(dw_mmu_enable, uint, |
| &max_decode_instance_num, 0664); |
| #endif |
| |
| module_param(prefix_aux_buf_size, uint, 0664); |
| MODULE_PARM_DESC(prefix_aux_buf_size, "\n prefix_aux_buf_size\n"); |
| |
| module_param(suffix_aux_buf_size, uint, 0664); |
| MODULE_PARM_DESC(suffix_aux_buf_size, "\n suffix_aux_buf_size\n"); |
| |
| #endif |
| |
| #ifdef DUMP_FILMGRAIN |
| module_param(fg_dump_index, uint, 0664); |
| MODULE_PARM_DESC(fg_dump_index, "\n fg_dump_index\n"); |
| #endif |
| |
| module_param(get_picture_qos, uint, 0664); |
| MODULE_PARM_DESC(get_picture_qos, "\n amvdec_av1 get_picture_qos\n"); |
| |
| 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"); |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION |
| module_param(dv_toggle_prov_name, uint, 0664); |
| MODULE_PARM_DESC(dv_toggle_prov_name, "\n dv_toggle_prov_name\n"); |
| #endif |
| |
| 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"); |
| |
| #ifdef DEBUG_CRC_ERROR |
| module_param(crc_debug_flag, uint, 0664); |
| MODULE_PARM_DESC(crc_debug_flag, "\n crc_debug_flag\n"); |
| #endif |
| |
| #ifdef DEBUG_CMD |
| module_param(debug_cmd_wait_type, uint, 0664); |
| MODULE_PARM_DESC(debug_cmd_wait_type, "\n debug_cmd_wait_type\n"); |
| |
| module_param(debug_cmd_wait_count, uint, 0664); |
| MODULE_PARM_DESC(debug_cmd_wait_count, "\n debug_cmd_wait_count\n"); |
| |
| module_param(header_dump_size, uint, 0664); |
| MODULE_PARM_DESC(header_dump_size, "\n header_dump_size\n"); |
| #endif |
| |
| module_param(force_pts_unstable, uint, 0664); |
| MODULE_PARM_DESC(force_pts_unstable, "\n force_pts_unstable\n"); |
| |
| module_param(without_display_mode, uint, 0664); |
| MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n"); |
| |
| module_param(v4l_bitstream_id_enable, uint, 0664); |
| MODULE_PARM_DESC(v4l_bitstream_id_enable, "\n v4l_bitstream_id_enable\n"); |
| |
| module_param(enable_single_slice, uint, 0664); |
| MODULE_PARM_DESC(enable_single_slice, "\n enable_single_slice\n"); |
| |
| module_init(amvdec_av1_driver_init_module); |
| module_exit(amvdec_av1_driver_remove_module); |
| |
| MODULE_DESCRIPTION("AMLOGIC av1 Video Decoder Driver"); |
| MODULE_LICENSE("GPL"); |
| |