| /* |
| * drivers/amlogic/amports/vh264_4k2k.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. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/errno.h> |
| #include <linux/interrupt.h> |
| #include <linux/timer.h> |
| #include <linux/kfifo.h> |
| #include <linux/platform_device.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.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/delay.h> |
| |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/media/video_sink/video_keeper.h> |
| #include "../utils/firmware.h" |
| #include <linux/amlogic/tee.h> |
| #include "../../../common/chips/decoder_cpu_ver_info.h" |
| |
| |
| |
| #define MEM_NAME "codec_264_4k" |
| |
| /* #include <mach/am_regs.h> */ |
| #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
| |
| #include <linux/amlogic/media/vpu/vpu.h> |
| #endif |
| |
| #include <linux/amlogic/media/utils/vdec_reg.h> |
| #include "../../../stream_input/amports/amports_priv.h" |
| #include "../utils/vdec.h" |
| #include "../utils/amvdec.h" |
| #include "../utils/decoder_mmu_box.h" |
| #include "../utils/decoder_bmmu_box.h" |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/media/codec_mm/configs.h> |
| |
| |
| |
| #if 0 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6TVD */ |
| #define DOUBLE_WRITE |
| #endif |
| |
| #define DRIVER_NAME "amvdec_h264_4k2k" |
| #define MODULE_NAME "amvdec_h264_4k2k" |
| |
| #define PUT_INTERVAL (HZ/100) |
| #define ERROR_RESET_COUNT 500 |
| #define DECODE_BUFFER_NUM_MAX 32 |
| #define DISPLAY_BUFFER_NUM 6 |
| #define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + DISPLAY_BUFFER_NUM) |
| #define VF_BUFFER_IDX(n) (2 + n) |
| #define DECODER_WORK_SPACE_SIZE 0x800000 |
| |
| #if 1 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESONG9TV */ |
| #define H264_4K2K_SINGLE_CORE 1 |
| #else |
| #define H264_4K2K_SINGLE_CORE IS_MESON_M8M2_CPU |
| #endif |
| |
| #define SLICE_TYPE_I 2 |
| |
| static int vh264_4k2k_vf_states(struct vframe_states *states, void *); |
| static struct vframe_s *vh264_4k2k_vf_peek(void *); |
| static struct vframe_s *vh264_4k2k_vf_get(void *); |
| static void vh264_4k2k_vf_put(struct vframe_s *, void *); |
| static int vh264_4k2k_event_cb(int type, void *data, void *private_data); |
| |
| static void vh264_4k2k_prot_init(void); |
| static int vh264_4k2k_local_init(void); |
| static void vh264_4k2k_put_timer_func(unsigned long arg); |
| |
| static const char vh264_4k2k_dec_id[] = "vh264_4k2k-dev"; |
| static const char vh264_4k2k_dec_id2[] = "vh264_4k2k-vdec2-dev"; |
| |
| #define PROVIDER_NAME "decoder.h264_4k2k" |
| |
| static const struct vframe_operations_s vh264_4k2k_vf_provider = { |
| .peek = vh264_4k2k_vf_peek, |
| .get = vh264_4k2k_vf_get, |
| .put = vh264_4k2k_vf_put, |
| .event_cb = vh264_4k2k_event_cb, |
| .vf_states = vh264_4k2k_vf_states, |
| }; |
| static void *mm_blk_handle; |
| static struct vframe_provider_s vh264_4k2k_vf_prov; |
| |
| static u32 mb_width_old, mb_height_old; |
| static u32 frame_width, frame_height, frame_dur, frame_ar; |
| static u32 saved_resolution; |
| static struct timer_list recycle_timer; |
| static u32 stat; |
| static u32 error_watchdog_count; |
| static uint error_recovery_mode; |
| static u32 sync_outside; |
| static u32 vh264_4k2k_rotation; |
| static u32 first_i_received; |
| static struct vframe_s *p_last_vf; |
| static struct work_struct set_clk_work; |
| |
| #ifdef DEBUG_PTS |
| static unsigned long pts_missed, pts_hit; |
| #endif |
| |
| static struct dec_sysinfo vh264_4k2k_amstream_dec_info; |
| static dma_addr_t mc_dma_handle; |
| static void *mc_cpu_addr; |
| |
| #define AMVDEC_H264_4K2K_CANVAS_INDEX 0x80 |
| #define AMVDEC_H264_4K2K_CANVAS_MAX 0xc6 |
| static DEFINE_SPINLOCK(lock); |
| static int fatal_error; |
| |
| static atomic_t vh264_4k2k_active = ATOMIC_INIT(0); |
| |
| static DEFINE_MUTEX(vh264_4k2k_mutex); |
| |
| static void (*probe_callback)(void); |
| static void (*remove_callback)(void); |
| static struct device *cma_dev; |
| |
| /* bit[3:0] command : */ |
| /* 0 - command finished */ |
| /* (DATA0 - {level_idc_mmco, max_reference_frame_num, width, height} */ |
| /* 1 - alloc view_0 display_buffer and reference_data_area */ |
| /* 2 - alloc view_1 display_buffer and reference_data_area */ |
| #define MAILBOX_COMMAND AV_SCRATCH_0 |
| #define MAILBOX_DATA_0 AV_SCRATCH_1 |
| #define MAILBOX_DATA_1 AV_SCRATCH_2 |
| #define MAILBOX_DATA_2 AV_SCRATCH_3 |
| #define MAILBOX_DATA_3 AV_SCRATCH_4 |
| #define MAILBOX_DATA_4 AV_SCRATCH_5 |
| #define CANVAS_START AV_SCRATCH_6 |
| #define BUFFER_RECYCLE AV_SCRATCH_7 |
| #define PICTURE_COUNT AV_SCRATCH_9 |
| #define DECODE_STATUS AV_SCRATCH_A |
| #define SPS_STATUS AV_SCRATCH_B |
| #define PPS_STATUS AV_SCRATCH_C |
| #define MS_ID AV_SCRATCH_D |
| #define WORKSPACE_START AV_SCRATCH_E |
| #define DECODED_PIC_NUM AV_SCRATCH_F |
| #define DECODE_ERROR_CNT AV_SCRATCH_G |
| #define CURRENT_UCODE AV_SCRATCH_H |
| /* bit[15:9]-SPS, bit[8:0]-PPS */ |
| #define CURRENT_SPS_PPS AV_SCRATCH_I |
| #define DECODE_SKIP_PICTURE AV_SCRATCH_J |
| #define DECODE_MODE AV_SCRATCH_K |
| #define RESERVED_REG_L AV_SCRATCH_L |
| #define REF_START_VIEW_0 AV_SCRATCH_M |
| #define REF_START_VIEW_1 AV_SCRATCH_N |
| |
| #define VDEC2_MAILBOX_COMMAND VDEC2_AV_SCRATCH_0 |
| #define VDEC2_MAILBOX_DATA_0 VDEC2_AV_SCRATCH_1 |
| #define VDEC2_MAILBOX_DATA_1 VDEC2_AV_SCRATCH_2 |
| #define VDEC2_MAILBOX_DATA_2 VDEC2_AV_SCRATCH_3 |
| #define VDEC2_MAILBOX_DATA_3 VDEC2_AV_SCRATCH_4 |
| #define VDEC2_MAILBOX_DATA_4 VDEC2_AV_SCRATCH_5 |
| #define VDEC2_CANVAS_START VDEC2_AV_SCRATCH_6 |
| #define VDEC2_BUFFER_RECYCLE VDEC2_AV_SCRATCH_7 |
| #define VDEC2_PICTURE_COUNT VDEC2_AV_SCRATCH_9 |
| #define VDEC2_DECODE_STATUS VDEC2_AV_SCRATCH_A |
| #define VDEC2_SPS_STATUS VDEC2_AV_SCRATCH_B |
| #define VDEC2_PPS_STATUS VDEC2_AV_SCRATCH_C |
| #define VDEC2_MS_ID VDEC2_AV_SCRATCH_D |
| #define VDEC2_WORKSPACE_START VDEC2_AV_SCRATCH_E |
| #define VDEC2_DECODED_PIC_NUM VDEC2_AV_SCRATCH_F |
| #define VDEC2_DECODE_ERROR_CNT VDEC2_AV_SCRATCH_G |
| #define VDEC2_CURRENT_UCODE VDEC2_AV_SCRATCH_H |
| /* bit[15:9]-SPS, bit[8:0]-PPS */ |
| #define VDEC2_CURRENT_SPS_PPS VDEC2_AV_SCRATCH_I |
| #define VDEC2_DECODE_SKIP_PICTURE VDEC2_AV_SCRATCH_J |
| #define VDEC2_RESERVED_REG_K VDEC2_AV_SCRATCH_K |
| #define VDEC2_RESERVED_REG_L VDEC2_AV_SCRATCH_L |
| #define VDEC2_REF_START_VIEW_0 VDEC2_AV_SCRATCH_M |
| #define VDEC2_REF_START_VIEW_1 VDEC2_AV_SCRATCH_N |
| |
| /******************************************** |
| * DECODE_STATUS Define |
| ******************************************* |
| */ |
| #define DECODE_IDLE 0 |
| #define DECODE_START_HEADER 1 |
| #define DECODE_HEADER 2 |
| #define DECODE_START_MMCO 3 |
| #define DECODE_MMCO 4 |
| #define DECODE_START_SLICE 5 |
| #define DECODE_SLICE 6 |
| #define DECODE_WAIT_BUFFER 7 |
| |
| /******************************************** |
| * Dual Core Communication |
| ******************************************** |
| */ |
| #define FATAL_ERROR DOS_SCRATCH16 |
| #define PRE_MASTER_UPDATE_TIMES DOS_SCRATCH20 |
| /* bit[31] - REQUEST */ |
| /* bit[30:0] - MASTER_UPDATE_TIMES */ |
| #define SLAVE_WAIT_DPB_UPDATE DOS_SCRATCH21 |
| /* [15:8] - current_ref, [7:0] current_dpb (0x80 means no buffer found) */ |
| #define SLAVE_REF_DPB DOS_SCRATCH22 |
| #define SAVE_MVC_ENTENSION_0 DOS_SCRATCH23 |
| #define SAVE_I_POC DOS_SCRATCH24 |
| /* bit[31:30] - core_status 0-idle, 1-mmco, 2-decoding, 3-finished */ |
| /* bit[29:0] - core_pic_count */ |
| #define CORE_STATUS_M DOS_SCRATCH25 |
| #define CORE_STATUS_S DOS_SCRATCH26 |
| #define SAVE_ref_status_view_0 DOS_SCRATCH27 |
| #define SAVE_ref_status_view_1 DOS_SCRATCH28 |
| #define ALLOC_INFO_0 DOS_SCRATCH29 |
| #define ALLOC_INFO_1 DOS_SCRATCH30 |
| |
| /******************************************** |
| * Mailbox command |
| ********************************************/ |
| #define CMD_FINISHED 0 |
| #define CMD_ALLOC_VIEW 1 |
| #define CMD_FRAME_DISPLAY 3 |
| #define CMD_DEBUG 10 |
| |
| #define MC_TOTAL_SIZE (28*SZ_1K) |
| #define MC_SWAP_SIZE (4*SZ_1K) |
| |
| static unsigned long work_space_adr, ref_start_addr; |
| static unsigned long reserved_buffer; |
| |
| |
| #define video_domain_addr(adr) (adr&0x7fffffff) |
| |
| |
| struct buffer_spec_s { |
| unsigned int y_addr; |
| unsigned int uv_addr; |
| #ifdef DOUBLE_WRITE |
| unsigned int y_dw_addr; |
| unsigned int uv_dw_addr; |
| #endif |
| |
| int y_canvas_index; |
| int uv_canvas_index; |
| #ifdef DOUBLE_WRITE |
| int y_dw_canvas_index; |
| int uv_dw_canvas_index; |
| #endif |
| |
| struct page *alloc_pages; |
| unsigned long phy_addr; |
| int alloc_count; |
| }; |
| |
| static struct buffer_spec_s buffer_spec[MAX_BMMU_BUFFER_NUM]; |
| |
| #ifdef DOUBLE_WRITE |
| #define spec2canvas(x) \ |
| (((x)->uv_dw_canvas_index << 16) | \ |
| ((x)->uv_dw_canvas_index << 8) | \ |
| ((x)->y_dw_canvas_index << 0)) |
| #else |
| #define spec2canvas(x) \ |
| (((x)->uv_canvas_index << 16) | \ |
| ((x)->uv_canvas_index << 8) | \ |
| ((x)->y_canvas_index << 0)) |
| #endif |
| |
| #define VF_POOL_SIZE 32 |
| |
| static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); |
| static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); |
| static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); |
| |
| static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX]; |
| static struct vframe_s vfpool[VF_POOL_SIZE]; |
| |
| static struct work_struct alloc_work; |
| static struct vdec_info *gvs; |
| |
| static void set_frame_info(struct vframe_s *vf) |
| { |
| unsigned int ar; |
| |
| #ifdef DOUBLE_WRITE |
| vf->width = frame_width / 2; |
| vf->height = frame_height / 2; |
| #else |
| vf->width = frame_width; |
| vf->height = frame_height; |
| #endif |
| vf->duration = frame_dur; |
| vf->duration_pulldown = 0; |
| vf->flag = 0; |
| |
| ar = min_t(u32, frame_ar, DISP_RATIO_ASPECT_RATIO_MAX); |
| vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); |
| vf->orientation = vh264_4k2k_rotation; |
| |
| } |
| |
| static int vh264_4k2k_vf_states(struct vframe_states *states, void *op_arg) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&lock, flags); |
| |
| states->vf_pool_size = VF_POOL_SIZE; |
| states->buf_free_num = kfifo_len(&newframe_q); |
| states->buf_avail_num = kfifo_len(&display_q); |
| states->buf_recycle_num = kfifo_len(&recycle_q); |
| |
| spin_unlock_irqrestore(&lock, flags); |
| return 0; |
| } |
| |
| static struct vframe_s *vh264_4k2k_vf_peek(void *op_arg) |
| { |
| struct vframe_s *vf; |
| |
| if (kfifo_peek(&display_q, &vf)) |
| return vf; |
| |
| return NULL; |
| } |
| |
| static struct vframe_s *vh264_4k2k_vf_get(void *op_arg) |
| { |
| struct vframe_s *vf; |
| |
| if (kfifo_get(&display_q, &vf)) |
| return vf; |
| |
| return NULL; |
| } |
| |
| static void vh264_4k2k_vf_put(struct vframe_s *vf, void *op_arg) |
| { |
| kfifo_put(&recycle_q, (const struct vframe_s *)vf); |
| } |
| |
| static int vh264_4k2k_event_cb(int type, void *data, void *private_data) |
| { |
| if (type & VFRAME_EVENT_RECEIVER_RESET) { |
| unsigned long flags; |
| |
| amvdec_stop(); |
| |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_stop(); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_light_unreg_provider(&vh264_4k2k_vf_prov); |
| #endif |
| spin_lock_irqsave(&lock, flags); |
| vh264_4k2k_local_init(); |
| vh264_4k2k_prot_init(); |
| spin_unlock_irqrestore(&lock, flags); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_reg_provider(&vh264_4k2k_vf_prov); |
| #endif |
| amvdec_start(); |
| |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_start(); |
| } |
| |
| return 0; |
| } |
| |
| static int init_canvas(int refbuf_size, long dpb_size, int dpb_number, |
| int mb_width, int mb_height, |
| struct buffer_spec_s *buffer_spec) |
| { |
| unsigned long addr; |
| int i, j, ret = -1; |
| int mb_total; |
| int canvas_addr = ANC0_CANVAS_ADDR; |
| int vdec2_canvas_addr = VDEC2_ANC0_CANVAS_ADDR; |
| int index = AMVDEC_H264_4K2K_CANVAS_INDEX; |
| |
| mb_total = mb_width * mb_height; |
| mutex_lock(&vh264_4k2k_mutex); |
| |
| for (j = 0; j < (dpb_number + 1); j++) { |
| int page_count; |
| if (j == 0) { |
| ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 1, |
| refbuf_size, DRIVER_NAME, &ref_start_addr); |
| if (ret < 0) { |
| mutex_unlock(&vh264_4k2k_mutex); |
| return ret; |
| } |
| continue; |
| } |
| |
| WRITE_VREG(canvas_addr++, index | ((index + 1) << 8) | |
| ((index + 1) << 16)); |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(vdec2_canvas_addr++, |
| index | ((index + 1) << 8) | |
| ((index + 1) << 16)); |
| } |
| |
| i = j - 1; |
| #ifdef DOUBLE_WRITE |
| page_count = |
| PAGE_ALIGN((mb_total << 8) + (mb_total << 7) + |
| (mb_total << 6) + (mb_total << 5)) / PAGE_SIZE; |
| #else |
| page_count = |
| PAGE_ALIGN((mb_total << 8) + (mb_total << 7)) / PAGE_SIZE; |
| #endif |
| |
| ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, |
| VF_BUFFER_IDX(i), page_count << PAGE_SHIFT, |
| DRIVER_NAME, &buffer_spec[i].phy_addr); |
| |
| if (ret < 0) { |
| buffer_spec[i].alloc_count = 0; |
| mutex_unlock(&vh264_4k2k_mutex); |
| return ret; |
| } |
| addr = buffer_spec[i].phy_addr; |
| buffer_spec[i].alloc_count = page_count; |
| buffer_spec[i].y_addr = addr; |
| buffer_spec[i].y_canvas_index = index; |
| canvas_config(index, |
| addr, |
| mb_width << 4, |
| mb_height << 4, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); |
| |
| addr += mb_total << 8; |
| index++; |
| |
| buffer_spec[i].uv_addr = addr; |
| buffer_spec[i].uv_canvas_index = index; |
| canvas_config(index, |
| addr, |
| mb_width << 4, |
| mb_height << 3, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); |
| |
| addr += mb_total << 7; |
| index++; |
| |
| #ifdef DOUBLE_WRITE |
| buffer_spec[i].y_dw_addr = addr; |
| buffer_spec[i].y_dw_canvas_index = index; |
| canvas_config(index, |
| addr, |
| mb_width << 3, |
| mb_height << 3, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); |
| |
| addr += mb_total << 6; |
| index++; |
| |
| buffer_spec[i].uv_dw_addr = addr; |
| buffer_spec[i].uv_dw_canvas_index = index; |
| canvas_config(index, |
| addr, |
| mb_width << 3, |
| mb_height << 2, |
| CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); |
| |
| index++; |
| #endif |
| } |
| |
| mutex_unlock(&vh264_4k2k_mutex); |
| |
| pr_info |
| ("H264 4k2k decoder canvas allocation successful, "); |
| |
| return 0; |
| } |
| |
| static int get_max_dec_frame_buf_size(int level_idc, |
| int max_reference_frame_num, int mb_width, |
| int mb_height) |
| { |
| int pic_size = mb_width * mb_height * 384; |
| |
| int size = 0; |
| |
| switch (level_idc) { |
| case 9: |
| size = 152064; |
| break; |
| case 10: |
| size = 152064; |
| break; |
| case 11: |
| size = 345600; |
| break; |
| case 12: |
| size = 912384; |
| break; |
| case 13: |
| size = 912384; |
| break; |
| case 20: |
| size = 912384; |
| break; |
| case 21: |
| size = 1824768; |
| break; |
| case 22: |
| size = 3110400; |
| break; |
| case 30: |
| size = 3110400; |
| break; |
| case 31: |
| size = 6912000; |
| break; |
| case 32: |
| size = 7864320; |
| break; |
| case 40: |
| size = 12582912; |
| break; |
| case 41: |
| size = 12582912; |
| break; |
| case 42: |
| size = 13369344; |
| break; |
| case 50: |
| size = 42393600; |
| break; |
| case 51: |
| case 52: |
| default: |
| size = 70778880; |
| break; |
| } |
| |
| size /= pic_size; |
| size = size + 1; /* need one more buffer */ |
| |
| if (max_reference_frame_num > size) |
| size = max_reference_frame_num; |
| |
| if (size > DECODE_BUFFER_NUM_MAX) |
| size = DECODE_BUFFER_NUM_MAX; |
| |
| return size; |
| } |
| |
| static void do_alloc_work(struct work_struct *work) |
| { |
| int level_idc, max_reference_frame_num, mb_width, mb_height, |
| frame_mbs_only_flag; |
| int dpb_size, ref_size, refbuf_size; |
| int max_dec_frame_buffering, |
| total_dec_frame_buffering; |
| unsigned int chroma444; |
| unsigned int crop_infor, crop_bottom, crop_right; |
| int ret = READ_VREG(MAILBOX_COMMAND); |
| |
| |
| ret = READ_VREG(MAILBOX_DATA_0); |
| /* MAILBOX_DATA_1 : |
| * bit15 : frame_mbs_only_flag |
| * bit 0-7 : chroma_format_idc |
| * MAILBOX_DATA_2: |
| * bit31-16: (left << 8 | right ) << 1 |
| * bit15-0 : (top << 8 | bottom ) << (2 - frame_mbs_only_flag) |
| */ |
| frame_mbs_only_flag = READ_VREG(MAILBOX_DATA_1); |
| crop_infor = READ_VREG(MAILBOX_DATA_2); |
| level_idc = (ret >> 24) & 0xff; |
| max_reference_frame_num = (ret >> 16) & 0xff; |
| mb_width = (ret >> 8) & 0xff; |
| if (mb_width == 0) |
| mb_width = 256; |
| mb_height = (ret >> 0) & 0xff; |
| max_dec_frame_buffering = |
| get_max_dec_frame_buf_size(level_idc, max_reference_frame_num, |
| mb_width, mb_height); |
| total_dec_frame_buffering = |
| max_dec_frame_buffering + DISPLAY_BUFFER_NUM; |
| |
| chroma444 = ((frame_mbs_only_flag&0xffff) == 3) ? 1 : 0; |
| frame_mbs_only_flag = (frame_mbs_only_flag >> 16) & 0x01; |
| crop_bottom = (crop_infor & 0xff) >> (2 - frame_mbs_only_flag); |
| crop_right = ((crop_infor >> 16) & 0xff) >> 1; |
| pr_info("crop_right = 0x%x crop_bottom = 0x%x chroma_format_idc = 0x%x\n", |
| crop_right, crop_bottom, chroma444); |
| |
| if ((frame_width == 0) || (frame_height == 0) || crop_infor || |
| mb_width != mb_width_old || |
| mb_height != mb_height_old) { |
| frame_width = mb_width << 4; |
| frame_height = mb_height << 4; |
| mb_width_old = mb_width; |
| mb_height_old = mb_height; |
| if (frame_mbs_only_flag) { |
| frame_height -= (2 >> chroma444) * |
| min(crop_bottom, |
| (unsigned int)((8 << chroma444) - 1)); |
| frame_width -= (2 >> chroma444) * |
| min(crop_right, |
| (unsigned int)((8 << chroma444) - 1)); |
| } else { |
| frame_height -= (4 >> chroma444) * |
| min(crop_bottom, |
| (unsigned int)((8 << chroma444) - 1)); |
| frame_width -= (4 >> chroma444) * |
| min(crop_right, |
| (unsigned int)((8 << chroma444) - 1)); |
| } |
| pr_info("frame_mbs_only_flag %d, crop_bottom %d frame_height %d, mb_height %d crop_right %d, frame_width %d, mb_width %d\n", |
| frame_mbs_only_flag, crop_bottom, frame_height, |
| mb_height, crop_right, frame_width, mb_height); |
| } |
| |
| mb_width = (mb_width + 3) & 0xfffffffc; |
| mb_height = (mb_height + 3) & 0xfffffffc; |
| |
| dpb_size = mb_width * mb_height * 384; |
| ref_size = mb_width * mb_height * 96; |
| refbuf_size = ref_size * (max_reference_frame_num + 1) * 2; |
| |
| |
| pr_info("mb_width=%d, mb_height=%d\n", |
| mb_width, mb_height); |
| |
| ret = init_canvas(refbuf_size, dpb_size, |
| total_dec_frame_buffering, mb_width, mb_height, |
| buffer_spec); |
| |
| if (ret == -1) { |
| pr_info(" Un-expected memory alloc problem\n"); |
| return; |
| } |
| |
| if (frame_width == 0) |
| frame_width = mb_width << 4; |
| if (frame_height == 0) |
| frame_height = mb_height << 4; |
| |
| WRITE_VREG(REF_START_VIEW_0, video_domain_addr(ref_start_addr)); |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(VDEC2_REF_START_VIEW_0, |
| video_domain_addr(ref_start_addr)); |
| } |
| |
| WRITE_VREG(MAILBOX_DATA_0, |
| (max_dec_frame_buffering << 8) | |
| (total_dec_frame_buffering << 0)); |
| WRITE_VREG(MAILBOX_DATA_1, ref_size); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| |
| /* ///////////// FAKE FIRST PIC */ |
| |
| } |
| |
| static irqreturn_t vh264_4k2k_isr(int irq, void *dev_id) |
| { |
| int drop_status, display_buff_id, display_POC, slice_type, error; |
| unsigned int stream_offset; |
| struct vframe_s *vf = NULL; |
| int ret = READ_VREG(MAILBOX_COMMAND); |
| u32 frame_size; |
| |
| switch (ret & 0xff) { |
| case CMD_ALLOC_VIEW: |
| schedule_work(&alloc_work); |
| break; |
| |
| case CMD_FRAME_DISPLAY: |
| ret >>= 8; |
| display_buff_id = (ret >> 0) & 0x3f; |
| drop_status = (ret >> 8) & 0x1; |
| slice_type = (ret >> 9) & 0x7; |
| error = (ret >> 12) & 0x1; |
| display_POC = READ_VREG(MAILBOX_DATA_0); |
| stream_offset = READ_VREG(MAILBOX_DATA_1); |
| |
| smp_rmb();/* rmb smp */ |
| |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| |
| if (kfifo_get(&newframe_q, &vf) == 0) { |
| pr_info("fatal error, no available buffer slot."); |
| return IRQ_HANDLED; |
| } |
| |
| if (vf) { |
| vfbuf_use[display_buff_id]++; |
| |
| vf->pts = 0; |
| vf->pts_us64 = 0; |
| |
| if ((!sync_outside) |
| || (sync_outside && |
| (slice_type == SLICE_TYPE_I))) { |
| ret = pts_lookup_offset_us64(PTS_TYPE_VIDEO, |
| stream_offset, |
| &vf->pts, |
| &frame_size, |
| 0, |
| &vf->pts_us64); |
| if (ret != 0) |
| pr_debug(" vpts lookup failed\n"); |
| } |
| #ifdef H264_4K2K_SINGLE_CORE |
| if (READ_VREG(DECODE_MODE) & 1) { |
| /* for I only mode, ignore the PTS information |
| * and only uses 10fps for each |
| * I frame decoded |
| */ |
| if (p_last_vf) { |
| vf->pts = 0; |
| vf->pts_us64 = 0; |
| } |
| frame_dur = 96000 / 10; |
| } |
| #endif |
| vf->signal_type = 0; |
| vf->index = display_buff_id; |
| vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; |
| vf->type |= VIDTYPE_VIU_NV21; |
| vf->canvas0Addr = vf->canvas1Addr = |
| spec2canvas(&buffer_spec[display_buff_id]); |
| set_frame_info(vf); |
| |
| if (error) |
| gvs->drop_frame_count++; |
| |
| gvs->frame_dur = frame_dur; |
| vdec_count_info(gvs, error, stream_offset); |
| |
| if (((error_recovery_mode & 2) && error) |
| || (!first_i_received |
| && (slice_type != SLICE_TYPE_I))) { |
| kfifo_put(&recycle_q, |
| (const struct vframe_s *)vf); |
| } else { |
| p_last_vf = vf; |
| first_i_received = 1; |
| vf->mem_handle = |
| decoder_bmmu_box_get_mem_handle( |
| mm_blk_handle, |
| VF_BUFFER_IDX(display_buff_id)); |
| kfifo_put(&display_q, |
| (const struct vframe_s *)vf); |
| ATRACE_COUNTER(MODULE_NAME, vf->pts); |
| |
| vf_notify_receiver(PROVIDER_NAME, |
| VFRAME_EVENT_PROVIDER_VFRAME_READY, |
| NULL); |
| } |
| } |
| break; |
| |
| case CMD_DEBUG: |
| pr_info("M: core_status 0x%08x 0x%08x; ", |
| READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S)); |
| switch (READ_VREG(MAILBOX_DATA_0)) { |
| case 1: |
| pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n", |
| READ_VREG(MAILBOX_DATA_1)); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 2: |
| pr_info("H264_BUFFER_INFO_DATA = 0x%x\n", |
| READ_VREG(MAILBOX_DATA_1)); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 3: |
| pr_info("REC_CANVAS_ADDR = 0x%x\n", |
| READ_VREG(MAILBOX_DATA_1)); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 4: |
| pr_info("after DPB_MMCO\n"); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 5: |
| pr_info("MBY = 0x%x, S_MBXY = 0x%x\n", |
| READ_VREG(MAILBOX_DATA_1), |
| READ_VREG(0x2c07)); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 6: |
| pr_info("after FIFO_OUT_FRAME\n"); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 7: |
| pr_info("after RELEASE_EXCEED_REF_BUFF\n"); |
| WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 0x5a: |
| pr_info("\n"); |
| break; |
| default: |
| pr_info("\n"); |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return IRQ_HANDLED; |
| } |
| |
| #if 1 /*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/ |
| static irqreturn_t vh264_4k2k_vdec2_isr(int irq, void *dev_id) |
| { |
| int ret = READ_VREG(VDEC2_MAILBOX_COMMAND); |
| |
| switch (ret & 0xff) { |
| case CMD_DEBUG: |
| pr_info("S: core_status 0x%08x 0x%08x; ", |
| READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S)); |
| switch (READ_VREG(VDEC2_MAILBOX_DATA_0)) { |
| case 1: |
| pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n", |
| READ_VREG(VDEC2_MAILBOX_DATA_1)); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 2: |
| pr_info("H264_BUFFER_INFO_DATA = 0x%x\n", |
| READ_VREG(VDEC2_MAILBOX_DATA_1)); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 3: |
| pr_info("REC_CANVAS_ADDR = 0x%x\n", |
| READ_VREG(VDEC2_MAILBOX_DATA_1)); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 4: |
| pr_info("after DPB_MMCO\n"); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 5: |
| pr_info("MBY = 0x%x, M/S_MBXY = 0x%x-0x%x\n", |
| READ_VREG(VDEC2_MAILBOX_DATA_1), |
| READ_VREG(0xc07), READ_VREG(0x2c07)); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 6: |
| pr_info("after FIFO_OUT_FRAME\n"); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 7: |
| pr_info("after RELEASE_EXCEED_REF_BUFF\n"); |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); |
| break; |
| case 0x5a: |
| pr_info("\n"); |
| break; |
| default: |
| pr_info("\n"); |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return IRQ_HANDLED; |
| } |
| #endif |
| |
| static void vh264_4k2k_set_clk(struct work_struct *work) |
| { |
| if (first_i_received &&/*do switch after first i frame ready.*/ |
| frame_dur > 0 && saved_resolution != |
| frame_width * frame_height * (96000 / frame_dur)) { |
| int fps = 96000 / frame_dur; |
| |
| pr_info("H264 4k2k resolution changed!!\n"); |
| if (vdec_source_changed(VFORMAT_H264_4K2K, |
| frame_width, frame_height, fps) > 0)/*changed clk ok*/ |
| saved_resolution = frame_width * frame_height * fps; |
| } |
| } |
| |
| static void vh264_4k2k_put_timer_func(unsigned long arg) |
| { |
| struct timer_list *timer = (struct timer_list *)arg; |
| enum receviver_start_e state = RECEIVER_INACTIVE; |
| |
| if (vf_get_receiver(PROVIDER_NAME)) { |
| state = vf_notify_receiver(PROVIDER_NAME, |
| VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL); |
| if ((state == RECEIVER_STATE_NULL) |
| || (state == RECEIVER_STATE_NONE)) |
| state = RECEIVER_INACTIVE; |
| } else |
| state = RECEIVER_INACTIVE; |
| |
| /* error watchdog */ |
| if (((READ_VREG(VLD_MEM_VIFIFO_CONTROL) & 0x100) == 0) &&/* dec has in*/ |
| (state == RECEIVER_INACTIVE) && /* rec has no buf to recycle */ |
| (kfifo_is_empty(&display_q)) && /* no buf in display queue */ |
| (kfifo_is_empty(&recycle_q)) && /* no buf to recycle */ |
| (READ_VREG(MS_ID) & 0x100) |
| #ifdef CONFIG_H264_2K4K_SINGLE_CORE |
| && (READ_VREG(VDEC2_MS_ID) & 0x100) |
| |
| /* with both decoder |
| * have started decoding |
| */ |
| #endif |
| && first_i_received) { |
| if (++error_watchdog_count == ERROR_RESET_COUNT) { |
| /* and it lasts for a while */ |
| pr_info("H264 4k2k decoder fatal error watchdog.\n"); |
| fatal_error = DECODER_FATAL_ERROR_UNKNOWN; |
| } |
| } else |
| error_watchdog_count = 0; |
| |
| if (READ_VREG(FATAL_ERROR) != 0) { |
| pr_info("H264 4k2k decoder ucode fatal error.\n"); |
| fatal_error = DECODER_FATAL_ERROR_UNKNOWN; |
| WRITE_VREG(FATAL_ERROR, 0); |
| } |
| |
| while (!kfifo_is_empty(&recycle_q) && |
| (READ_VREG(BUFFER_RECYCLE) == 0)) { |
| struct vframe_s *vf; |
| |
| if (kfifo_get(&recycle_q, &vf)) { |
| if ((vf->index < DECODE_BUFFER_NUM_MAX) |
| && (--vfbuf_use[vf->index] == 0)) { |
| WRITE_VREG(BUFFER_RECYCLE, vf->index + 1); |
| vf->index = DECODE_BUFFER_NUM_MAX; |
| } |
| |
| kfifo_put(&newframe_q, (const struct vframe_s *)vf); |
| } |
| } |
| |
| schedule_work(&set_clk_work); |
| |
| timer->expires = jiffies + PUT_INTERVAL; |
| |
| add_timer(timer); |
| } |
| |
| int vh264_4k2k_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) |
| { |
| vstatus->frame_width = frame_width; |
| vstatus->frame_height = frame_height; |
| if (frame_dur != 0) |
| vstatus->frame_rate = 96000 / frame_dur; |
| else |
| vstatus->frame_rate = -1; |
| vstatus->error_count = 0; |
| vstatus->status = stat | fatal_error; |
| vstatus->frame_dur = frame_dur; |
| vstatus->frame_data = gvs->frame_data; |
| vstatus->total_data = gvs->total_data; |
| vstatus->frame_count = gvs->frame_count; |
| vstatus->error_frame_count = gvs->error_frame_count; |
| vstatus->drop_frame_count = gvs->drop_frame_count; |
| vstatus->total_data = gvs->total_data; |
| vstatus->samp_cnt = gvs->samp_cnt; |
| vstatus->offset = gvs->offset; |
| snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), |
| "%s", DRIVER_NAME); |
| |
| return 0; |
| } |
| |
| static int vh264_4k2k_vdec_info_init(void) |
| { |
| gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL); |
| if (NULL == gvs) { |
| pr_info("the struct of vdec status malloc failed.\n"); |
| return -ENOMEM; |
| } |
| return 0; |
| } |
| |
| int vh264_4k2k_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) |
| { |
| if (trickmode == TRICKMODE_I) { |
| WRITE_VREG(DECODE_MODE, 1); |
| trickmode_i = 1; |
| } else if (trickmode == TRICKMODE_NONE) { |
| WRITE_VREG(DECODE_MODE, 0); |
| trickmode_i = 0; |
| } |
| |
| return 0; |
| } |
| |
| static void H264_DECODE_INIT(void) |
| { |
| int i; |
| |
| WRITE_VREG(GCLK_EN, 0x3ff); |
| |
| WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); |
| WRITE_VREG(DOS_SW_RESET0, 0); |
| |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| |
| WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); |
| WRITE_VREG(DOS_SW_RESET0, 0); |
| |
| WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); |
| WRITE_VREG(DOS_SW_RESET0, 0); |
| |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| |
| /* fill_weight_pred */ |
| WRITE_VREG(MC_MPORT_CTRL, 0x0300); |
| for (i = 0; i < 192; i++) |
| WRITE_VREG(MC_MPORT_DAT, 0x100); |
| WRITE_VREG(MC_MPORT_CTRL, 0); |
| |
| WRITE_VREG(MB_WIDTH, 0xff); /* invalid mb_width */ |
| |
| /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */ |
| WRITE_VREG(SLICE_START_BYTE_01, 0x00000000); |
| WRITE_VREG(SLICE_START_BYTE_23, 0x01010000); |
| /* set to mpeg2 to enable mismatch logic */ |
| WRITE_VREG(MPEG1_2_REG, 1); |
| WRITE_VREG(VLD_ERROR_MASK, |
| 0x1011); |
| |
| /* Config MCPU Amrisc interrupt */ |
| WRITE_VREG(ASSIST_AMR1_INT0, 0x1); /* viu_vsync_int */ |
| WRITE_VREG(ASSIST_AMR1_INT1, 0x5); /* mbox_isr */ |
| WRITE_VREG(ASSIST_AMR1_INT2, 0x8); /* vld_isr */ |
| /* WRITE_VREG(ASSIST_AMR1_INT3, 0x15); // vififo_empty */ |
| WRITE_VREG(ASSIST_AMR1_INT4, 0xd); /* rv_ai_mb_finished_int */ |
| WRITE_VREG(ASSIST_AMR1_INT7, 0x14); /* dcac_dma_done */ |
| WRITE_VREG(ASSIST_AMR1_INT8, 0x15); /* vififo_empty */ |
| |
| /* Config MCPU Amrisc interrupt */ |
| WRITE_VREG(ASSIST_AMR1_INT5, 0x9); /* MCPU interrupt */ |
| WRITE_VREG(ASSIST_AMR1_INT6, 0x17); /* CCPU interrupt */ |
| |
| WRITE_VREG(CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */ |
| WRITE_VREG(CINT_VEC_BASE, (0xc20 >> 5)); |
| WRITE_VREG(POWER_CTL_VLD, (1 << 10) | /* disable cabac_step_2 */ |
| (1 << 9) | /* viff_drop_flag_en */ |
| (1 << 6)); /* h264_000003_en */ |
| WRITE_VREG(M4_CONTROL_REG, (1 << 13)); /* H264_DECODE_INFO - h264_en */ |
| |
| WRITE_VREG(CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX); |
| /* Start Address of Workspace (UCODE, temp_data...) */ |
| WRITE_VREG(WORKSPACE_START, |
| video_domain_addr(work_space_adr)); |
| /* Clear all sequence parameter set available */ |
| WRITE_VREG(SPS_STATUS, 0); |
| /* Clear all picture parameter set available */ |
| WRITE_VREG(PPS_STATUS, 0); |
| /* Set current microcode to NULL */ |
| WRITE_VREG(CURRENT_UCODE, 0xff); |
| /* Set current SPS/PPS to NULL */ |
| WRITE_VREG(CURRENT_SPS_PPS, 0xffff); |
| /* Set decode status to DECODE_START_HEADER */ |
| WRITE_VREG(DECODE_STATUS, 1); |
| } |
| |
| static void H264_DECODE2_INIT(void) |
| { |
| int i; |
| |
| WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); |
| |
| WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4)); |
| WRITE_VREG(DOS_SW_RESET2, 0); |
| |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| |
| WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4)); |
| WRITE_VREG(DOS_SW_RESET2, 0); |
| |
| WRITE_VREG(DOS_SW_RESET2, (1 << 9) | (1 << 8)); |
| WRITE_VREG(DOS_SW_RESET2, 0); |
| |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| |
| /* fill_weight_pred */ |
| WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0x0300); |
| for (i = 0; i < 192; i++) |
| WRITE_VREG(VDEC2_MC_MPORT_DAT, 0x100); |
| WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0); |
| |
| WRITE_VREG(VDEC2_MB_WIDTH, 0xff); /* invalid mb_width */ |
| |
| /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */ |
| WRITE_VREG(VDEC2_SLICE_START_BYTE_01, 0x00000000); |
| WRITE_VREG(VDEC2_SLICE_START_BYTE_23, 0x01010000); |
| /* set to mpeg2 to enable mismatch logic */ |
| WRITE_VREG(VDEC2_MPEG1_2_REG, 1); |
| /* disable COEF_GT_64 , error_m4_table and voff_rw_err */ |
| WRITE_VREG(VDEC2_VLD_ERROR_MASK, |
| 0x1011); |
| |
| /* Config MCPU Amrisc interrupt */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT0, 0x1);/* viu_vsync_int */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT1, 0x5);/* mbox_isr */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT2, 0x8);/* vld_isr */ |
| /* WRITE_VREG(VDEC2_ASSIST_AMR1_INT3, 0x15); // vififo_empty */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT4, 0xd);/* rv_ai_mb_finished_int */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT7, 0x14);/* dcac_dma_done */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT8, 0x15);/* vififo_empty */ |
| |
| /* Config MCPU Amrisc interrupt */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT5, 0x9);/* MCPU interrupt */ |
| WRITE_VREG(VDEC2_ASSIST_AMR1_INT6, 0x17);/* CCPU interrupt */ |
| |
| WRITE_VREG(VDEC2_CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */ |
| WRITE_VREG(VDEC2_CINT_VEC_BASE, (0xc20 >> 5)); |
| WRITE_VREG(VDEC2_POWER_CTL_VLD, (1 << 10) |/* disable cabac_step_2 */ |
| (1 << 9) | /* viff_drop_flag_en */ |
| (1 << 6)); /* h264_000003_en */ |
| /* H264_DECODE_INFO - h264_en */ |
| WRITE_VREG(VDEC2_M4_CONTROL_REG, (1 << 13)); |
| |
| WRITE_VREG(VDEC2_CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX); |
| /* Start Address of Workspace (UCODE, temp_data...) */ |
| WRITE_VREG(VDEC2_WORKSPACE_START, |
| video_domain_addr(work_space_adr)); |
| /* Clear all sequence parameter set available */ |
| WRITE_VREG(VDEC2_SPS_STATUS, 0); |
| /* Clear all picture parameter set available */ |
| WRITE_VREG(VDEC2_PPS_STATUS, 0); |
| /* Set current microcode to NULL */ |
| WRITE_VREG(VDEC2_CURRENT_UCODE, 0xff); |
| /* Set current SPS/PPS to NULL */ |
| WRITE_VREG(VDEC2_CURRENT_SPS_PPS, 0xffff); |
| /* Set decode status to DECODE_START_HEADER */ |
| WRITE_VREG(VDEC2_DECODE_STATUS, 1); |
| } |
| |
| static void vh264_4k2k_prot_init(void) |
| { |
| /* clear mailbox interrupt */ |
| #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_ASSIST_MBOX0_CLR_REG, 1); |
| #endif |
| WRITE_VREG(VDEC_ASSIST_MBOX1_CLR_REG, 1); |
| |
| /* enable mailbox interrupt */ |
| #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 1); |
| #endif |
| WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 1); |
| |
| /* disable PSCALE for hardware sharing */ |
| WRITE_VREG(PSCALE_CTRL, 0); |
| |
| H264_DECODE_INIT(); |
| if (!H264_4K2K_SINGLE_CORE) |
| H264_DECODE2_INIT(); |
| |
| WRITE_VREG(DOS_SW_RESET0, (1 << 11)); |
| WRITE_VREG(DOS_SW_RESET0, 0); |
| |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| READ_VREG(DOS_SW_RESET0); |
| |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(DOS_SW_RESET2, (1 << 11)); |
| WRITE_VREG(DOS_SW_RESET2, 0); |
| |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| READ_VREG(DOS_SW_RESET2); |
| } |
| |
| WRITE_VREG(MAILBOX_COMMAND, 0); |
| WRITE_VREG(BUFFER_RECYCLE, 0); |
| |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(VDEC2_MAILBOX_COMMAND, 0); |
| WRITE_VREG(VDEC2_BUFFER_RECYCLE, 0); |
| } |
| |
| CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); |
| if (!H264_4K2K_SINGLE_CORE) |
| CLEAR_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17); |
| |
| /* set VDEC Master/ID 0 */ |
| WRITE_VREG(MS_ID, (1 << 7) | (0 << 0)); |
| if (!H264_4K2K_SINGLE_CORE) { |
| /* set VDEC2 Slave/ID 0 */ |
| WRITE_VREG(VDEC2_MS_ID, (0 << 7) | (1 << 0)); |
| } |
| WRITE_VREG(DECODE_SKIP_PICTURE, 0); |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_DECODE_SKIP_PICTURE, 0); |
| |
| WRITE_VREG(PRE_MASTER_UPDATE_TIMES, 0); |
| WRITE_VREG(SLAVE_WAIT_DPB_UPDATE, 0); |
| WRITE_VREG(SLAVE_REF_DPB, 0); |
| WRITE_VREG(SAVE_MVC_ENTENSION_0, 0); |
| WRITE_VREG(SAVE_I_POC, 0); |
| WRITE_VREG(CORE_STATUS_M, 0); |
| WRITE_VREG(CORE_STATUS_S, 0); |
| WRITE_VREG(SAVE_ref_status_view_0, 0); |
| WRITE_VREG(SAVE_ref_status_view_1, 0); |
| WRITE_VREG(ALLOC_INFO_0, 0); |
| WRITE_VREG(ALLOC_INFO_1, 0); |
| WRITE_VREG(FATAL_ERROR, 0); |
| |
| SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); |
| if (!H264_4K2K_SINGLE_CORE) |
| SET_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17); |
| |
| WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(VDEC2_MDEC_PIC_DC_THRESH, 0x404038aa); |
| } |
| #ifdef DOUBLE_WRITE |
| WRITE_VREG(MDEC_DOUBLEW_CFG0, (0 << 31) | /* half y address */ |
| (1 << 30) | /* 0:No Merge 1:Automatic Merge */ |
| (0 << 28) | |
| |
| /* Field Picture, 0x:no skip |
| * 10:top only |
| * 11:bottom only |
| */ |
| (0 << 27) | /* Source from, 1:MCW 0:DBLK */ |
| (0 << 24) | /* Endian Control for Chroma */ |
| (0 << 18) | /* DMA ID */ |
| (0 << 12) | /* DMA Burst Number */ |
| (0 << 11) | /* DMA Urgent */ |
| (0 << 10) | /* 1:Round 0:Truncation */ |
| (1 << 9) | |
| |
| /* Size by vertical, 0:original size |
| * 1: 1/2 shrunken size |
| */ |
| (1 << 8) | |
| |
| /* Size by horizontal, 0:original size |
| * 1: 1/2 shrunken size |
| */ |
| (0 << 6) | |
| |
| /* Pixel sel by vertical, 0x:1/2 |
| * 10:up |
| * 11:down |
| */ |
| (0 << 4) | |
| |
| /* Pixel sel by horizontal, 0x:1/2 |
| * 10:left |
| * 11:right |
| */ |
| (0 << 1) | /* Endian Control for Luma */ |
| (1 << 0)); /* Double Write Enable */ |
| if (!H264_4K2K_SINGLE_CORE) { |
| WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0, |
| (0 << 31) | /* half y address */ |
| (1 << 30) | |
| |
| /* 0:No Merge |
| * 1:Automatic Merge |
| */ |
| (0 << 28) | |
| |
| /* Field Picture, 0x:no skip |
| * 10:top only |
| * 11:bottom only |
| */ |
| (0 << 27) | /* Source from, 1:MCW 0:DBLK */ |
| (0 << 24) | /* Endian Control for Chroma */ |
| (0 << 18) | /* DMA ID */ |
| (0 << 12) | /* DMA Burst Number */ |
| (0 << 11) | /* DMA Urgent */ |
| (0 << 10) | /* 1:Round 0:Truncation */ |
| (1 << 9) | |
| |
| /* Size by vertical, |
| * 0:original size |
| * 1: 1/2 shrunken size |
| */ |
| (1 << 8) | |
| |
| /* Size by horizontal, |
| * 0:original size |
| * 1: 1/2 shrunken size |
| */ |
| (0 << 6) | |
| |
| /* Pixel sel by vertical, |
| * 0x:1/2 |
| * 10:up |
| * 11:down |
| */ |
| (0 << 4) | |
| |
| /* Pixel sel by horizontal, |
| * 0x:1/2 |
| * 10:left |
| * 11:right |
| */ |
| (0 << 1) | /* Endian Control for Luma */ |
| (1 << 0)); /* Double Write Enable */ |
| } |
| #endif |
| } |
| |
| static int vh264_4k2k_local_init(void) |
| { |
| int i, size, ret; |
| |
| #ifdef DEBUG_PTS |
| pts_missed = 0; |
| pts_hit = 0; |
| #endif |
| mb_width_old = 0; |
| mb_height_old = 0; |
| saved_resolution = 0; |
| vh264_4k2k_rotation = |
| (((unsigned long) vh264_4k2k_amstream_dec_info.param) >> 16) |
| & 0xffff; |
| frame_width = vh264_4k2k_amstream_dec_info.width; |
| frame_height = vh264_4k2k_amstream_dec_info.height; |
| frame_dur = |
| (vh264_4k2k_amstream_dec_info.rate == |
| 0) ? 3600 : vh264_4k2k_amstream_dec_info.rate; |
| if (frame_width && frame_height) |
| frame_ar = frame_height * 0x100 / frame_width; |
| sync_outside = ((unsigned long) vh264_4k2k_amstream_dec_info.param |
| & 0x02) >> 1; |
| error_watchdog_count = 0; |
| |
| pr_info("H264_4K2K: decinfo: %dx%d rate=%d\n", |
| frame_width, frame_height, |
| frame_dur); |
| |
| if (frame_dur == 0) |
| frame_dur = 96000 / 24; |
| |
| INIT_KFIFO(display_q); |
| INIT_KFIFO(recycle_q); |
| INIT_KFIFO(newframe_q); |
| |
| for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) |
| vfbuf_use[i] = 0; |
| |
| for (i = 0; i < VF_POOL_SIZE; i++) { |
| const struct vframe_s *vf = &vfpool[i]; |
| |
| vfpool[i].index = DECODE_BUFFER_NUM_MAX; |
| kfifo_put(&newframe_q, vf); |
| } |
| |
| reserved_buffer = 0; |
| p_last_vf = NULL; |
| first_i_received = 0; |
| INIT_WORK(&alloc_work, do_alloc_work); |
| |
| if (mm_blk_handle) { |
| decoder_bmmu_box_free(mm_blk_handle); |
| mm_blk_handle = NULL; |
| } |
| |
| mm_blk_handle = decoder_bmmu_box_alloc_box( |
| DRIVER_NAME, |
| 0, |
| MAX_BMMU_BUFFER_NUM, |
| 4 + PAGE_SHIFT, |
| CODEC_MM_FLAGS_CMA_CLEAR | |
| CODEC_MM_FLAGS_FOR_VDECODER); |
| |
| size = DECODER_WORK_SPACE_SIZE; |
| ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 0, |
| size, DRIVER_NAME, &work_space_adr); |
| return ret; |
| } |
| |
| static s32 vh264_4k2k_init(void) |
| { |
| int ret = -1, size = -1; |
| char *buf = vmalloc(0x1000 * 16); |
| |
| if (buf == NULL) |
| return -ENOMEM; |
| |
| pr_info("\nvh264_4k2k_init\n"); |
| |
| init_timer(&recycle_timer); |
| |
| stat |= STAT_TIMER_INIT; |
| |
| ret = vh264_4k2k_local_init(); |
| if (ret < 0) { |
| vfree(buf); |
| return ret; |
| } |
| amvdec_enable(); |
| |
| /* -- ucode loading (amrisc and swap code) */ |
| mc_cpu_addr = dma_alloc_coherent(amports_get_dma_device(), |
| MC_TOTAL_SIZE, &mc_dma_handle, GFP_KERNEL); |
| if (!mc_cpu_addr) { |
| amvdec_disable(); |
| vfree(buf); |
| pr_err("vh264_4k2k init: Can not allocate mc memory.\n"); |
| return -ENOMEM; |
| } |
| |
| WRITE_VREG(AV_SCRATCH_L, mc_dma_handle); |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_AV_SCRATCH_L, mc_dma_handle); |
| |
| if (H264_4K2K_SINGLE_CORE) |
| size = get_firmware_data(VIDEO_DEC_H264_4k2K_SINGLE, buf); |
| else |
| size = get_firmware_data(VIDEO_DEC_H264_4k2K, buf); |
| |
| if (size < 0) { |
| pr_err("get firmware fail."); |
| vfree(buf); |
| return -1; |
| } |
| |
| if (H264_4K2K_SINGLE_CORE) |
| ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, "single_core", buf); |
| else |
| ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf); |
| |
| if (ret < 0) { |
| amvdec_disable(); |
| dma_free_coherent(amports_get_dma_device(), |
| MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); |
| mc_cpu_addr = NULL; |
| pr_err("H264_4K2K: the %s fw loading failed, err: %x\n", |
| tee_enabled() ? "TEE" : "local", ret); |
| return -EBUSY; |
| } |
| |
| if (!H264_4K2K_SINGLE_CORE) { |
| amvdec2_enable(); |
| |
| if (amvdec2_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf) < 0) { |
| amvdec_disable(); |
| amvdec2_disable(); |
| dma_free_coherent(amports_get_dma_device(), |
| MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); |
| mc_cpu_addr = NULL; |
| return -EBUSY; |
| } |
| } |
| |
| /*header*/ |
| memcpy((u8 *) mc_cpu_addr, buf + 0x1000, 0x1000); |
| |
| /*mmco*/ |
| memcpy((u8 *) mc_cpu_addr + 0x1000, buf + 0x2000, 0x2000); |
| |
| /*slice*/ |
| memcpy((u8 *) mc_cpu_addr + 0x3000, buf + 0x4000, 0x3000); |
| |
| stat |= STAT_MC_LOAD; |
| |
| /* enable AMRISC side protocol */ |
| vh264_4k2k_prot_init(); |
| |
| if (vdec_request_irq(VDEC_IRQ_1, vh264_4k2k_isr, |
| "vh264_4k2k-irq", (void *)vh264_4k2k_dec_id)) { |
| pr_info("vh264_4k2k irq register error.\n"); |
| amvdec_disable(); |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_disable(); |
| |
| return -ENOENT; |
| } |
| #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
| if (!H264_4K2K_SINGLE_CORE) { |
| if (vdec_request_irq(VDEC_IRQ_0, vh264_4k2k_vdec2_isr, |
| "vh264_4k2k-vdec2-irq", |
| (void *)vh264_4k2k_dec_id2)) { |
| pr_info("vh264_4k2k irq register error.\n"); |
| vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id); |
| amvdec_disable(); |
| amvdec2_disable(); |
| return -ENOENT; |
| } |
| } |
| #endif |
| |
| stat |= STAT_ISR_REG; |
| |
| vf_provider_init(&vh264_4k2k_vf_prov, PROVIDER_NAME, |
| &vh264_4k2k_vf_provider, NULL); |
| vf_reg_provider(&vh264_4k2k_vf_prov); |
| vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); |
| |
| vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT, |
| (void *)((unsigned long) |
| vh264_4k2k_amstream_dec_info.rate)); |
| |
| stat |= STAT_VF_HOOK; |
| |
| recycle_timer.data = (ulong) (&recycle_timer); |
| recycle_timer.function = vh264_4k2k_put_timer_func; |
| recycle_timer.expires = jiffies + PUT_INTERVAL; |
| |
| add_timer(&recycle_timer); |
| |
| stat |= STAT_TIMER_ARM; |
| |
| amvdec_start(); |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_start(); |
| |
| stat |= STAT_VDEC_RUN; |
| |
| ret = vh264_4k2k_vdec_info_init(); |
| if (0 != ret) |
| return -ret; |
| |
| return 0; |
| } |
| |
| static int vh264_4k2k_stop(void) |
| { |
| |
| if (stat & STAT_VDEC_RUN) { |
| amvdec_stop(); |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_stop(); |
| stat &= ~STAT_VDEC_RUN; |
| } |
| |
| if (stat & STAT_ISR_REG) { |
| WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 0); |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 0); |
| |
| vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id); |
| #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
| if (!H264_4K2K_SINGLE_CORE) |
| vdec_free_irq(VDEC_IRQ_0, (void *)vh264_4k2k_dec_id2); |
| #endif |
| stat &= ~STAT_ISR_REG; |
| } |
| |
| if (stat & STAT_TIMER_ARM) { |
| del_timer_sync(&recycle_timer); |
| stat &= ~STAT_TIMER_ARM; |
| } |
| |
| if (stat & STAT_VF_HOOK) { |
| vf_notify_receiver(PROVIDER_NAME, |
| VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); |
| |
| vf_unreg_provider(&vh264_4k2k_vf_prov); |
| stat &= ~STAT_VF_HOOK; |
| } |
| #ifdef DOUBLE_WRITE |
| WRITE_VREG(MDEC_DOUBLEW_CFG0, 0); |
| if (!H264_4K2K_SINGLE_CORE) |
| WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0, 0); |
| #endif |
| |
| if (stat & STAT_MC_LOAD) { |
| if (mc_cpu_addr != NULL) { |
| dma_free_coherent(amports_get_dma_device(), |
| MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); |
| mc_cpu_addr = NULL; |
| } |
| |
| stat &= ~STAT_MC_LOAD; |
| } |
| |
| amvdec_disable(); |
| if (!H264_4K2K_SINGLE_CORE) |
| amvdec2_disable(); |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| msleep(100); |
| #endif |
| if (mm_blk_handle) { |
| decoder_bmmu_box_free(mm_blk_handle); |
| mm_blk_handle = NULL; |
| } |
| |
| return 0; |
| } |
| |
| void vh264_4k_free_cmabuf(void) |
| { |
| int i; |
| |
| if (atomic_read(&vh264_4k2k_active)) |
| return; |
| mutex_lock(&vh264_4k2k_mutex); |
| for (i = 0; i < ARRAY_SIZE(buffer_spec); i++) { |
| if (buffer_spec[i].phy_addr) { |
| codec_mm_free_for_dma(MEM_NAME, |
| buffer_spec[i].phy_addr); |
| buffer_spec[i].phy_addr = 0; |
| buffer_spec[i].alloc_pages = NULL; |
| buffer_spec[i].alloc_count = 0; |
| pr_info("force free CMA buffer %d\n", i); |
| } |
| } |
| mutex_unlock(&vh264_4k2k_mutex); |
| } |
| |
| static int amvdec_h264_4k2k_probe(struct platform_device *pdev) |
| { |
| struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; |
| |
| pr_info("amvdec_h264_4k2k probe start.\n"); |
| |
| mutex_lock(&vh264_4k2k_mutex); |
| |
| fatal_error = 0; |
| |
| if (pdata == NULL) { |
| pr_info("\namvdec_h264_4k2k memory resource undefined.\n"); |
| mutex_unlock(&vh264_4k2k_mutex); |
| return -EFAULT; |
| } |
| |
| if (pdata->sys_info) |
| vh264_4k2k_amstream_dec_info = *pdata->sys_info; |
| cma_dev = pdata->cma_dev; |
| |
| pr_info(" sysinfo: %dx%d, rate = %d, param = 0x%lx\n", |
| vh264_4k2k_amstream_dec_info.width, |
| vh264_4k2k_amstream_dec_info.height, |
| vh264_4k2k_amstream_dec_info.rate, |
| (unsigned long) vh264_4k2k_amstream_dec_info.param); |
| |
| if (!H264_4K2K_SINGLE_CORE) { |
| if (vdec_on(VDEC_2)) { /* ++++ */ |
| vdec_poweroff(VDEC_2); /* ++++ */ |
| mdelay(10); |
| } |
| vdec_poweron(VDEC_2); |
| } |
| |
| |
| if (!H264_4K2K_SINGLE_CORE) |
| vdec2_power_mode(1); |
| |
| pdata->dec_status = vh264_4k2k_dec_status; |
| if (H264_4K2K_SINGLE_CORE) |
| pdata->set_trickmode = vh264_4k2k_set_trickmode; |
| |
| if (vh264_4k2k_init() < 0) { |
| pr_info("\namvdec_h264_4k2k init failed.\n"); |
| mutex_unlock(&vh264_4k2k_mutex); |
| kfree(gvs); |
| gvs = NULL; |
| |
| return -ENODEV; |
| } |
| #if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/ |
| request_vpu_clk_vmod(360000000, VPU_VIU_VD1); |
| #endif |
| |
| if (probe_callback) |
| probe_callback(); |
| /*set the max clk for smooth playing...*/ |
| vdec_source_changed(VFORMAT_H264_4K2K, |
| 4096, 2048, 30); |
| INIT_WORK(&set_clk_work, vh264_4k2k_set_clk); |
| |
| atomic_set(&vh264_4k2k_active, 1); |
| mutex_unlock(&vh264_4k2k_mutex); |
| |
| return 0; |
| } |
| |
| static int amvdec_h264_4k2k_remove(struct platform_device *pdev) |
| { |
| cancel_work_sync(&alloc_work); |
| cancel_work_sync(&set_clk_work); |
| mutex_lock(&vh264_4k2k_mutex); |
| atomic_set(&vh264_4k2k_active, 0); |
| |
| vh264_4k2k_stop(); |
| |
| vdec_source_changed(VFORMAT_H264_4K2K, 0, 0, 0); |
| |
| if (!H264_4K2K_SINGLE_CORE) { |
| vdec_poweroff(VDEC_2); |
| } |
| #ifdef DEBUG_PTS |
| pr_info("pts missed %ld, pts hit %ld, duration %d\n", |
| pts_missed, pts_hit, frame_dur); |
| #endif |
| |
| if (remove_callback) |
| remove_callback(); |
| |
| mutex_unlock(&vh264_4k2k_mutex); |
| |
| kfree(gvs); |
| gvs = NULL; |
| |
| pr_info("amvdec_h264_4k2k_remove\n"); |
| return 0; |
| } |
| |
| void vh264_4k2k_register_module_callback(void (*enter_func)(void), |
| void (*remove_func)(void)) |
| { |
| probe_callback = enter_func; |
| remove_callback = remove_func; |
| } |
| EXPORT_SYMBOL(vh264_4k2k_register_module_callback); |
| |
| /****************************************/ |
| |
| static struct platform_driver amvdec_h264_4k2k_driver = { |
| .probe = amvdec_h264_4k2k_probe, |
| .remove = amvdec_h264_4k2k_remove, |
| #ifdef CONFIG_PM |
| .suspend = amvdec_suspend, |
| .resume = amvdec_resume, |
| #endif |
| .driver = { |
| .name = DRIVER_NAME, |
| } |
| }; |
| |
| static struct codec_profile_t amvdec_h264_4k2k_profile = { |
| .name = "h264_4k2k", |
| .profile = "" |
| }; |
| static struct mconfig h264_4k2k_configs[] = { |
| MC_PU32("stat", &stat), |
| MC_PU32("error_recovery_mode", &error_recovery_mode), |
| }; |
| static struct mconfig_node h264_4k2k_node; |
| |
| static int __init amvdec_h264_4k2k_driver_init_module(void) |
| { |
| pr_debug("amvdec_h264_4k2k module init\n"); |
| |
| if (platform_driver_register(&amvdec_h264_4k2k_driver)) { |
| pr_err("failed to register amvdec_h264_4k2k driver\n"); |
| return -ENODEV; |
| } |
| if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXTVBB) |
| vcodec_profile_register(&amvdec_h264_4k2k_profile); |
| INIT_REG_NODE_CONFIGS("media.decoder", &h264_4k2k_node, |
| "h264_4k2k", h264_4k2k_configs, CONFIG_FOR_RW); |
| return 0; |
| } |
| |
| static void __exit amvdec_h264_4k2k_driver_remove_module(void) |
| { |
| pr_debug("amvdec_h264_4k2k module remove.\n"); |
| |
| platform_driver_unregister(&amvdec_h264_4k2k_driver); |
| } |
| |
| /****************************************/ |
| |
| module_param(stat, uint, 0664); |
| MODULE_PARM_DESC(stat, "\n amvdec_h264_4k2k stat\n"); |
| |
| module_param(error_recovery_mode, uint, 0664); |
| MODULE_PARM_DESC(error_recovery_mode, "\n amvdec_h264 error_recovery_mode\n"); |
| |
| module_init(amvdec_h264_4k2k_driver_init_module); |
| module_exit(amvdec_h264_4k2k_driver_remove_module); |
| |
| MODULE_DESCRIPTION("AMLOGIC h264_4k2k Video Decoder Driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>"); |