author | shihong.zheng <shihong.zheng@amlogic.com> | 2018-08-27 07:14:58 (GMT) |
---|---|---|
committer | Zhi Zhou <zhi.zhou@amlogic.com> | 2018-08-27 13:29:24 (GMT) |
commit | 87046a60037e23f3a1fc9355d4e58d7455694833 (patch) | |
tree | fd7afc859a4904a5e8b497e4aeafbef4f615adc9 | |
parent | 5e17d9a802240a4a0f2eff059347188861b36a5c (diff) | |
download | media_modules-87046a60037e23f3a1fc9355d4e58d7455694833.zip media_modules-87046a60037e23f3a1fc9355d4e58d7455694833.tar.gz media_modules-87046a60037e23f3a1fc9355d4e58d7455694833.tar.bz2 |
decoder: optimize code and sync from iptv
PD#170744: decoder:
1. fix mh264 mosaic when play mjpeg at sametime in frame mode;
2. sync the mjpeg multi play code;
3. add the mpeg2&mpeg4 multi play code;
4. force exit when load ucode fail;
5. set time out for vdec_disconnet wait_for_completion;
6. reset core when active vdec to disconnect list and before run;
7. fix some coverity error;
8. remove ucode load when mmu enable in vmh264 init.
Change-Id: Ic8f296526ddac5b3904a323ce2850b1d9178a284
Signed-off-by: shihong.zheng <shihong.zheng@amlogic.com>
-rw-r--r-- | Media.mk | 1 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/avs2/vavs2.c | 2 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h264_multi/vmh264.c | 55 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h265/vh265.c | 3 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c | 486 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/mpeg12/Makefile | 3 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c | 1889 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c | 947 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/amvdec.c | 30 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.c | 83 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.h | 2 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec_input.c | 3 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/vp9/vvp9.c | 5 |
13 files changed, 3189 insertions, 320 deletions
@@ -5,6 +5,7 @@ KERNEL_ARCH := arm64 endif CONFIGS := CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12=m \ + CONFIG_AMLOGIC_MEDIA_VDEC_MPEG2_MULTI=m \ CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4=m \ CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI=m \ CONFIG_AMLOGIC_MEDIA_VDEC_VC1=m \ diff --git a/drivers/frame_provider/decoder/avs2/vavs2.c b/drivers/frame_provider/decoder/avs2/vavs2.c index 0039864..a06be39 100644 --- a/drivers/frame_provider/decoder/avs2/vavs2.c +++ b/drivers/frame_provider/decoder/avs2/vavs2.c @@ -5411,6 +5411,8 @@ static void run(struct vdec_s *vdec, unsigned long mask, amhevc_disable(); avs2_print(dec, 0, "%s: Error amvdec_loadmc fail\n", __func__); + dec->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&dec->work); return; } else vdec->mc_loaded = 1; diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c index 24fa32e..1c68204 100644 --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c @@ -770,8 +770,10 @@ struct vdec_h264_hw_s { struct mh264_ud_record_wait_node_t free_nodes[MAX_FREE_USERDATA_NODES]; int wait_for_udr_send; #endif + u32 no_mem_count; bool is_used_v4l; void *v4l2_ctx; + wait_queue_head_t wait_q; }; static u32 again_threshold = 0x40; @@ -1514,6 +1516,9 @@ static int alloc_one_buf_spec(struct vdec_h264_hw_s *hw, int i) PAGE_ALIGN(buf_size), DRIVER_NAME, &hw->buffer_spec[i].cma_alloc_addr) < 0) { hw->buffer_spec[i].cma_alloc_addr = 0; + if (hw->no_mem_count++ > 3) { + hw->stat |= DECODER_FATAL_ERROR_NO_MEM; + } dpb_print(DECODE_ID(hw), 0, "%s, fail to alloc buf for bufspec%d, try later\n", __func__, i @@ -4084,6 +4089,7 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) if (dec_dpb_status == H264_CONFIG_REQUEST) { WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE); reset_process_time(hw); + hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); hw->dec_result = DEC_RESULT_CONFIG_PARAM; vdec_schedule_work(&hw->work); } else if (dec_dpb_status == H264_SLICE_HEAD_DONE) { @@ -4663,6 +4669,7 @@ send_again: "%s H264_DATA_REQUEST (%d)\n", __func__, hw->get_data_count); hw->dec_result = DEC_RESULT_GET_DATA; + hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); hw->get_data_start_time = jiffies; hw->get_data_count++; if (hw->get_data_count >= frame_max_data_packet) @@ -5279,6 +5286,7 @@ static void vh264_local_init(struct vdec_h264_hw_s *hw) hw->reg_rv_ai_mb_count = 0; hw->vld_dec_control = 0; hw->decode_timeout_count = 0; + hw->no_mem_count = 0; hw->vh264_ratio = hw->vh264_amstream_dec_info.ratio; /* vh264_ratio = 0x100; */ @@ -5345,12 +5353,14 @@ static void vh264_local_init(struct vdec_h264_hw_s *hw) hw->vh264_stream_switching_state = SWITCHING_STATE_OFF; hw->hevc_cur_buf_idx = 0xffff; + init_waitqueue_head(&hw->wait_q); + return; } static s32 vh264_init(struct vdec_h264_hw_s *hw) { - int ret = 0, size = -1; + int size = -1; int fw_size = 0x1000 * 16; int fw_mmu_size = 0x1000 * 16; struct firmware_s *fw = NULL, *fw_mmu = NULL; @@ -5471,28 +5481,6 @@ static s32 vh264_init(struct vdec_h264_hw_s *hw) /*slice*/ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN + 0x3000, fw->data + 0x5000, 0x1000); - - if (hw->mmu_enable) - ret = amhevc_loadmc_ex(VFORMAT_HEVC, - NULL, fw_mmu->data); - - if (ret < 0) { - amvdec_disable(); - if (hw->mmu_enable) - amhevc_disable(); - if (hw->mc_cpu_addr) { - dma_free_coherent(amports_get_dma_device(), - MC_TOTAL_SIZE, hw->mc_cpu_addr, - hw->mc_dma_handle); - hw->mc_cpu_addr = NULL; - } - - dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, - "MH264: the %s fw loading failed, err: %x\n", - tee_enabled() ? "TEE" : "local", ret); - - return -EBUSY; - } } #if 1 /* #ifdef BUFFER_MGR_IN_C */ @@ -6541,7 +6529,7 @@ result_done: /* mark itself has all HW resource released and input released */ vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC); - + wake_up_interruptible(&hw->wait_q); if (hw->vdec_cb) hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); } @@ -6575,6 +6563,9 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) if (hw->eos) return 0; + if (hw->stat & DECODER_FATAL_ERROR_NO_MEM) + return 0; + if (disp_vframe_valve_level && kfifo_len(&hw->display_q) >= disp_vframe_valve_level) { @@ -6628,6 +6619,7 @@ static void run(struct vdec_s *vdec, unsigned long mask, int size, ret = -1; run_count[DECODE_ID(hw)]++; + vdec_reset_core(vdec); if (hw->mmu_enable) hevc_reset_core(vdec); hw->vdec_cb_arg = arg; @@ -6743,6 +6735,8 @@ static void run(struct vdec_s *vdec, unsigned long mask, dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, "MH264 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; } @@ -6756,6 +6750,8 @@ static void run(struct vdec_s *vdec, unsigned long mask, dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, "MH264_MMU 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; } } @@ -7254,6 +7250,17 @@ static int ammvdec_h264_remove(struct platform_device *pdev) (struct vdec_h264_hw_s *) (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); int i; + struct vdec_s *vdec = hw_to_vdec(hw); + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED + && (vdec->status == VDEC_STATUS_ACTIVE)) { + pr_info("%s force exit %d\n", __func__, __LINE__); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + wait_event_interruptible_timeout(hw->wait_q, + (vdec->status == VDEC_STATUS_CONNECTED), + msecs_to_jiffies(50)); /* wait for work done */ + } for (i = 0; i < BUFSPEC_POOL_SIZE; i++) release_aux_data(hw, i); diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c index 0077ba5..5369b9e 100644 --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c @@ -10009,6 +10009,8 @@ static void run(struct vdec_s *vdec, unsigned long mask, amhevc_disable(); hevc_print(hevc, 0, "H265: the %s fw loading failed, err: %x\n", tee_enabled() ? "TEE" : "local", loadr); + hevc->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hevc->work); return; } @@ -10142,7 +10144,6 @@ static int amvdec_h265_probe(struct platform_device *pdev) work_buf_size, DRIVER_NAME, &hevc->buf_start); if (ret < 0) { uninit_mmu_buffers(hevc); - devm_kfree(&pdev->dev, (void *)hevc); vfree(hevc); mutex_unlock(&vh265_mutex); return ret; diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c index 7fb7920..001f14c 100644 --- a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c +++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c @@ -22,6 +22,7 @@ #include <linux/timer.h> #include <linux/kfifo.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/canvas/canvas.h> @@ -59,7 +60,10 @@ #define MREG_TO_AMRISC AV_SCRATCH_8 #define MREG_FROM_AMRISC AV_SCRATCH_9 #define MREG_FRAME_OFFSET AV_SCRATCH_A -#define DEC_STATUS_REG AV_SCRATCH_J +#define DEC_STATUS_REG AV_SCRATCH_F +#define MREG_PIC_WIDTH AV_SCRATCH_B +#define MREG_PIC_HEIGHT AV_SCRATCH_C +#define DECODE_STOP_POS AV_SCRATCH_K #define PICINFO_BUF_IDX_MASK 0x0007 #define PICINFO_AVI1 0x0080 @@ -73,8 +77,15 @@ #define DEFAULT_MEM_SIZE (32*SZ_1M) static int debug_enable; +static u32 udebug_flag; #define DECODE_ID(hw) (hw_to_vdec(hw)->id) +static unsigned int radr; +static unsigned int rval; +#define VMJPEG_DEV_NUM 9 +static unsigned int max_decode_instance_num = VMJPEG_DEV_NUM; +static unsigned int max_process_time[VMJPEG_DEV_NUM]; +static unsigned int decode_timeout_val = 200; static struct vframe_s *vmjpeg_vf_peek(void *); static struct vframe_s *vmjpeg_vf_get(void *); static void vmjpeg_vf_put(struct vframe_s *, void *); @@ -82,6 +93,36 @@ static int vmjpeg_vf_states(struct vframe_states *states, void *); static int vmjpeg_event_cb(int type, void *data, void *private_data); static void vmjpeg_work(struct work_struct *work); static int pre_decode_buf_level = 0x800; +#undef pr_info +#define pr_info printk +unsigned int mmjpeg_debug_mask = 0xff; +#define PRINT_FLAG_ERROR 0x0 +#define PRINT_FLAG_RUN_FLOW 0X0001 +#define PRINT_FLAG_TIMEINFO 0x0002 +#define PRINT_FLAG_UCODE_DETAIL 0x0004 +#define PRINT_FLAG_VLD_DETAIL 0x0008 +#define PRINT_FLAG_DEC_DETAIL 0x0010 +#define PRINT_FLAG_BUFFER_DETAIL 0x0020 +#define PRINT_FLAG_RESTORE 0x0040 +#define PRINT_FRAME_NUM 0x0080 +#define PRINT_FLAG_FORCE_DONE 0x0100 +#define PRINT_FRAMEBASE_DATA 0x0400 +int mmjpeg_debug_print(int index, int debug_flag, const char *fmt, ...) +{ + if (((debug_enable & debug_flag) && + ((1 << index) & mmjpeg_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) { + unsigned char buf[512]; + int len = 0; + va_list args; + va_start(args, fmt); + len = sprintf(buf, "%d: ", index); + vsnprintf(buf + len, 512-len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} static const char vmjpeg_dec_id[] = "vmmjpeg-dev"; @@ -152,15 +193,33 @@ struct vdec_mjpeg_hw_s { void *vdec_cb_arg; struct firmware_s *fw; struct timer_list check_timer; - unsigned decode_timeout_count; + u32 decode_timeout_count; + u32 start_process_time; + u32 last_vld_level; u8 eos; - u32 frame_num, put_num; + u32 frame_num; + u32 put_num; + u32 run_count; + u32 not_run_ready; + u32 input_empty; + u32 peek_num; + u32 get_num; }; +static void reset_process_time(struct vdec_mjpeg_hw_s *hw); static void set_frame_info(struct vdec_mjpeg_hw_s *hw, struct vframe_s *vf) { - vf->width = hw->frame_width; - vf->height = hw->frame_height; + u32 temp; + temp = READ_VREG(MREG_PIC_WIDTH); + if (temp > 1920) + vf->width = hw->frame_width = 1920; + else if (temp > 0) + vf->width = hw->frame_width = temp; + temp = READ_VREG(MREG_PIC_HEIGHT); + if (temp > 1088) + vf->height = hw->frame_height = 1088; + else if (temp > 0) + vf->height = hw->frame_height = temp; vf->duration = hw->frame_dur; vf->ratio_control = 0; vf->duration_pulldown = 0; @@ -186,15 +245,21 @@ static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq) u32 index, offset = 0, pts; u64 pts_us64; - if (debug_enable & 0x1) - pr_info("%s: %d\n", __func__, __LINE__); - - WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - if (!hw) return IRQ_HANDLED; + if (hw->eos) return IRQ_HANDLED; + reset_process_time(hw); + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + if (READ_VREG(AV_SCRATCH_D) != 0 && + (debug_enable & PRINT_FLAG_UCODE_DETAIL)) { + pr_info("dbg%x: %x\n", READ_VREG(AV_SCRATCH_D), + READ_VREG(AV_SCRATCH_E)); + WRITE_VREG(AV_SCRATCH_D, 0); + return IRQ_HANDLED; + } + reg = READ_VREG(MREG_FROM_AMRISC); index = READ_VREG(AV_SCRATCH_5); @@ -237,13 +302,17 @@ static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq) kfifo_put(&hw->display_q, (const struct vframe_s *)vf); hw->frame_num++; + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "%s:frame num:%d,pts=%d,pts64=%lld. dur=%d\n", + __func__, hw->frame_num, + vf->pts, vf->pts_us64, vf->duration); vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); hw->dec_result = DEC_RESULT_DONE; - schedule_work(&hw->work); + vdec_schedule_work(&hw->work); return IRQ_HANDLED; } @@ -256,7 +325,7 @@ static struct vframe_s *vmjpeg_vf_peek(void *op_arg) if (!hw) return NULL; - + hw->peek_num++; if (kfifo_peek(&hw->display_q, &vf)) return vf; @@ -271,7 +340,7 @@ static struct vframe_s *vmjpeg_vf_get(void *op_arg) if (!hw) return NULL; - + hw->get_num++; if (kfifo_get(&hw->display_q, &vf)) return vf; @@ -282,7 +351,8 @@ static void vmjpeg_vf_put(struct vframe_s *vf, void *op_arg) { struct vdec_s *vdec = op_arg; struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private; - + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "%s:put_num:%d\n", __func__, hw->put_num); hw->vfbuf_use[vf->index]--; kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); hw->put_num++; @@ -499,12 +569,120 @@ static void init_scaler(void) WRITE_VREG(PSCALE_RST, 0x0); } +static void vmjpeg_dump_state(struct vdec_s *vdec) +{ + struct vdec_mjpeg_hw_s *hw = + (struct vdec_mjpeg_hw_s *)(vdec->private); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "====== %s\n", __func__); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "width/height (%d/%d)\n", + hw->frame_width, + hw->frame_height + ); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d put_frm %d run %d not_run_ready %d input_empty %d\n", + input_frame_based(vdec), + hw->eos, + hw->stat, + hw->dec_result, + hw->frame_num, + hw->put_num, + hw->run_count, + hw->not_run_ready, + hw->input_empty + ); + if (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); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + mmjpeg_debug_print(DECODE_ID(hw), 0, + "%s, newq(%d/%d), dispq(%d/%d) vf peek/get/put (%d/%d/%d)\n", + __func__, + kfifo_len(&hw->newframe_q), + VF_POOL_SIZE, + kfifo_len(&hw->display_q), + VF_POOL_SIZE, + hw->peek_num, + hw->get_num, + hw->put_num + ); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "VIFF_BIT_CNT=0x%x\n", + READ_VREG(VIFF_BIT_CNT)); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_LEVEL=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_WP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_RP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_RP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_RP)); + mmjpeg_debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_WP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_WP)); + if (input_frame_based(vdec) && + debug_enable & PRINT_FRAMEBASE_DATA + ) { + int jj; + if (hw->chunk && hw->chunk->block && + hw->chunk->size > 0) { + u8 *data = + ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + mmjpeg_debug_print(DECODE_ID(hw), 0, + "frame data size 0x%x\n", + hw->chunk->size); + for (jj = 0; jj < hw->chunk->size; jj++) { + if ((jj & 0xf) == 0) + mmjpeg_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + mmjpeg_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + mmjpeg_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + } + } +} +static void reset_process_time(struct vdec_mjpeg_hw_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[DECODE_ID(hw)]) + max_process_time[DECODE_ID(hw)] = process_time; + } +} + +static void start_process_time(struct vdec_mjpeg_hw_s *hw) +{ + hw->decode_timeout_count = 2; + hw->start_process_time = jiffies; +} + static void timeout_process(struct vdec_mjpeg_hw_s *hw) { amvdec_stop(); - pr_info("%s decoder timeout\n", __func__); + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s decoder timeout\n", __func__); hw->dec_result = DEC_RESULT_DONE; - + reset_process_time(hw); vdec_schedule_work(&hw->work); } @@ -512,31 +690,43 @@ static void check_timer_func(unsigned long arg) { struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)arg; struct vdec_s *vdec = hw_to_vdec(hw); - if ((debug_enable & 0x2) != 0) { - pr_info("%s: status:nstatus=%d:%d\n", + int timeout_val = decode_timeout_val; + + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "%s: status:nstatus=%d:%d\n", __func__, vdec->status, vdec->next_status); - pr_info("%s: %d,buftl=%x:%x:%x:%x\n", + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "%s: %d,buftl=%x:%x:%x:%x\n", __func__, __LINE__, READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL), READ_PARSER_REG(PARSER_VIDEO_WP), READ_VREG(VLD_MEM_VIFIFO_LEVEL), READ_VREG(VLD_MEM_VIFIFO_WP)); - } - if ((debug_enable & 0x100) != 0) { - hw->dec_result = DEC_RESULT_DONE; - vdec_schedule_work(&hw->work); - pr_info("vdec %d is forced to be disconnected\n", - debug_enable & 0xff); - debug_enable = 0; - return; + + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; } - if (input_stream_based(vdec) - && READ_VREG(VLD_MEM_VIFIFO_LEVEL) <= 0x80) { - if (hw->decode_timeout_count > 0) - hw->decode_timeout_count--; - if (hw->decode_timeout_count == 0) - timeout_process(hw); + if ((debug_enable == 0) && + (input_frame_based(vdec) || + (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x100)) && + (timeout_val > 0) && + (hw->start_process_time > 0) && + ((1000 * (jiffies - hw->start_process_time) / HZ) + > timeout_val)) { + if (hw->last_vld_level == READ_VREG(VLD_MEM_VIFIFO_LEVEL)) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + timeout_process(hw); + } + hw->last_vld_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); } if (READ_VREG(DEC_STATUS_REG) == DEC_DECODE_TIMEOUT) { @@ -556,6 +746,7 @@ static void check_timer_func(unsigned long arg) } mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); } + static void vmjpeg_hw_ctx_restore(struct vdec_s *vdec, int index) { struct vdec_mjpeg_hw_s *hw = @@ -614,12 +805,18 @@ static s32 vmjpeg_init(struct vdec_s *vdec) hw->frame_width = hw->vmjpeg_amstream_dec_info.width; hw->frame_height = hw->vmjpeg_amstream_dec_info.height; - hw->frame_dur = hw->vmjpeg_amstream_dec_info.rate; + hw->frame_dur = ((hw->vmjpeg_amstream_dec_info.rate) ? + hw->vmjpeg_amstream_dec_info.rate : 3840); hw->saved_resolution = 0; hw->eos = 0; hw->init_flag = 0; hw->frame_num = 0; hw->put_num = 0; + hw->run_count = 0; + hw->not_run_ready = 0; + hw->input_empty = 0; + hw->peek_num = 0; + hw->get_num = 0; for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) hw->vfbuf_use[i] = 0; @@ -653,16 +850,20 @@ static s32 vmjpeg_init(struct vdec_s *vdec) hw->check_timer.expires = jiffies + CHECK_INTERVAL; /*add_timer(&hw->check_timer);*/ hw->stat |= STAT_TIMER_ARM; + hw->stat |= STAT_ISR_REG; + WRITE_VREG(DECODE_STOP_POS, udebug_flag); INIT_WORK(&hw->work, vmjpeg_work); - + pr_info("w:h=%d:%d\n", hw->frame_width, hw->frame_height); return 0; } -static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) +static unsigned long run_ready(struct vdec_s *vdec, + unsigned long mask) { struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private; + hw->not_run_ready++; if (hw->eos) return 0; if (vdec_stream_based(vdec) && (hw->init_flag == 0) @@ -679,6 +880,7 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) if (level < pre_decode_buf_level) return 0; } + hw->not_run_ready = 0; return CORE_MASK_VDEC_1 | CORE_MASK_HEVC; } @@ -687,11 +889,13 @@ static void run(struct vdec_s *vdec, unsigned long mask, { struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private; - int i,ret = -1; + int i, ret; hw->vdec_cb_arg = arg; hw->vdec_cb = callback; + hw->run_count++; + vdec_reset_core(vdec); for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { if (hw->vfbuf_use[i] == 0) break; @@ -699,30 +903,33 @@ static void run(struct vdec_s *vdec, unsigned long mask, if (i == DECODE_BUFFER_NUM_MAX) { hw->dec_result = DEC_RESULT_AGAIN; - schedule_work(&hw->work); + vdec_schedule_work(&hw->work); return; } ret = vdec_prepare_input(vdec, &hw->chunk); - if (ret < 0) { - if (debug_enable & 0x1) { - pr_info("%s: %d,r=%d,buftl=%x:%x:%x\n", + if (ret <= 0) { + hw->input_empty++; + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "%s: %d,r=%d,buftl=%x:%x:%x\n", __func__, __LINE__, ret, READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL), READ_PARSER_REG(PARSER_VIDEO_WP), READ_VREG(VLD_MEM_VIFIFO_WP)); - } + hw->dec_result = DEC_RESULT_AGAIN; - schedule_work(&hw->work); + vdec_schedule_work(&hw->work); return; } - + hw->input_empty = 0; hw->dec_result = DEC_RESULT_NONE; ret = amvdec_vdec_loadmc_ex(VFORMAT_MJPEG, "mmjpeg", vdec, hw->fw->data); if (ret < 0) { pr_err("[%d] MMJPEG: the %s fw loading failed, err: %x\n", vdec->id, tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); return; } /* if (amvdec_vdec_loadmc_buf_ex(vdec, hw->fw->data, hw->fw->len) < 0) { @@ -735,42 +942,63 @@ static void run(struct vdec_s *vdec, unsigned long mask, vdec_enable_input(vdec); mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); #endif + hw->stat |= STAT_MC_LOAD; + start_process_time(hw); + hw->last_vld_level = 0; + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); amvdec_start(); vdec_enable_input(vdec); - mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); - hw->decode_timeout_count = 2; + hw->stat |= STAT_VDEC_RUN; hw->init_flag = 1; - if (debug_enable&0x1) { - pr_info("%s (0x%x 0x%x 0x%x) vldcrl 0x%x bitcnt 0x%x powerctl 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - __func__, - READ_VREG(VLD_MEM_VIFIFO_LEVEL), - READ_VREG(VLD_MEM_VIFIFO_WP), - READ_VREG(VLD_MEM_VIFIFO_RP), - READ_VREG(VLD_DECODE_CONTROL), - READ_VREG(VIFF_BIT_CNT), - READ_VREG(POWER_CTL_VLD), - READ_VREG(VLD_MEM_VIFIFO_START_PTR), - READ_VREG(VLD_MEM_VIFIFO_CURR_PTR), - READ_VREG(VLD_MEM_VIFIFO_CONTROL), - READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL), - READ_VREG(VLD_MEM_VIFIFO_END_PTR)); + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "%s (0x%x 0x%x 0x%x) vldcrl 0x%x bitcnt 0x%x powerctl 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VLD_DECODE_CONTROL), + READ_VREG(VIFF_BIT_CNT), + READ_VREG(POWER_CTL_VLD), + READ_VREG(VLD_MEM_VIFIFO_START_PTR), + READ_VREG(VLD_MEM_VIFIFO_CURR_PTR), + READ_VREG(VLD_MEM_VIFIFO_CONTROL), + READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL), + READ_VREG(VLD_MEM_VIFIFO_END_PTR)); +} +static void wait_vmjpeg_search_done(struct vdec_mjpeg_hw_s *hw) +{ + u32 vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + int count = 0; - } + do { + usleep_range(100, 500); + if (vld_rp == READ_VREG(VLD_MEM_VIFIFO_RP)) + break; + if (count > 1000) { + mmjpeg_debug_print(DECODE_ID(hw), 0, + "%s, count %d vld_rp 0x%x VLD_MEM_VIFIFO_RP 0x%x\n", + __func__, count, vld_rp, READ_VREG(VLD_MEM_VIFIFO_RP)); + break; + } else + vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + count++; + } while (1); } static void vmjpeg_work(struct work_struct *work) { struct vdec_mjpeg_hw_s *hw = container_of(work, struct vdec_mjpeg_hw_s, work); - if (debug_enable & 0x2) - pr_info("%s: result=%d,len=%d:%d\n", + + mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, + "%s: result=%d,len=%d:%d\n", __func__, hw->dec_result, kfifo_len(&hw->newframe_q), kfifo_len(&hw->display_q)); - if (hw->dec_result == DEC_RESULT_DONE) + if (hw->dec_result == DEC_RESULT_DONE) { vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); - else if (hw->dec_result == DEC_RESULT_AGAIN) { + } else if (hw->dec_result == DEC_RESULT_AGAIN) { /* stream base: stream buf empty or timeout frame base: vdec_prepare_input fail @@ -783,16 +1011,29 @@ static void vmjpeg_work(struct work_struct *work) return; } } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { - pr_info("%s: force exit\n", - __func__); + pr_info("%s: force exit\n", __func__); + if (hw->stat & STAT_ISR_REG) { + amvdec_stop(); + /*disable mbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } } else if (hw->dec_result == DEC_RESULT_EOS) { - /*pr_info("%s: end of stream\n", - __func__);*/ - if (READ_VREG(VLD_MEM_VIFIFO_LEVEL) < 0x100) - hw->eos = 1; + pr_info("%s: end of stream\n", __func__); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + hw->eos = 1; vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); } - amvdec_stop(); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + wait_vmjpeg_search_done(hw); /* mark itself has all HW resource released and input released */ vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); @@ -803,13 +1044,48 @@ static void vmjpeg_work(struct work_struct *work) hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); } -static int amvdec_mjpeg_probe(struct platform_device *pdev) +static int vmjpeg_stop(struct vdec_mjpeg_hw_s *hw) +{ + pr_info("%s ...count = %d\n", __func__, hw->frame_num); + + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + pr_info("%s amvdec_stop\n", __func__); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + cancel_work_sync(&hw->work); + hw->init_flag = 0; + + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + + if (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + + return 0; +} + +static int ammvdec_mjpeg_probe(struct platform_device *pdev) { struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; struct vdec_mjpeg_hw_s *hw = NULL; if (pdata == NULL) { - pr_info("amvdec_mjpeg memory resource undefined.\n"); + pr_info("ammvdec_mjpeg memory resource undefined.\n"); return -EFAULT; } @@ -826,6 +1102,7 @@ static int amvdec_mjpeg_probe(struct platform_device *pdev) pdata->run = run; pdata->run_ready = run_ready; pdata->irq_handler = vmjpeg_isr; + pdata->dump_state = vmjpeg_dump_state; if (pdata->use_vfm_path) @@ -845,8 +1122,11 @@ static int amvdec_mjpeg_probe(struct platform_device *pdev) if (pdata->sys_info) hw->vmjpeg_amstream_dec_info = *pdata->sys_info; + vdec_source_changed(VFORMAT_MJPEG, + 1920, 1080, 60); if (vmjpeg_init(pdata) < 0) { - pr_info("amvdec_mjpeg init failed.\n"); + pr_info("ammvdec_mjpeg init failed.\n"); + devm_kfree(&pdev->dev, (void *)hw); return -ENODEV; } @@ -856,37 +1136,26 @@ static int amvdec_mjpeg_probe(struct platform_device *pdev) return 0; } -static int amvdec_mjpeg_remove(struct platform_device *pdev) +static int ammvdec_mjpeg_remove(struct platform_device *pdev) { struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *) (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); - - if (hw->stat & STAT_TIMER_ARM) { - del_timer_sync(&hw->check_timer); - hw->stat &= ~STAT_TIMER_ARM; - } - cancel_work_sync(&hw->work); - if (hw->mm_blk_handle) { - decoder_bmmu_box_free(hw->mm_blk_handle); - hw->mm_blk_handle = NULL; - } - - vfree(hw->fw); - hw->fw = NULL; + vmjpeg_stop(hw); vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED); + pr_info("%s\n", __func__); return 0; } /****************************************/ -static struct platform_driver amvdec_mjpeg_driver = { - .probe = amvdec_mjpeg_probe, - .remove = amvdec_mjpeg_remove, +static struct platform_driver ammvdec_mjpeg_driver = { + .probe = ammvdec_mjpeg_probe, + .remove = ammvdec_mjpeg_remove, #ifdef CONFIG_PM .suspend = amvdec_suspend, .resume = amvdec_resume, @@ -896,24 +1165,24 @@ static struct platform_driver amvdec_mjpeg_driver = { } }; -static struct codec_profile_t amvdec_mjpeg_profile = { +static struct codec_profile_t ammvdec_mjpeg_profile = { .name = "mmjpeg", .profile = "" }; -static int __init amvdec_mjpeg_driver_init_module(void) +static int __init ammvdec_mjpeg_driver_init_module(void) { - if (platform_driver_register(&amvdec_mjpeg_driver)) { - pr_err("failed to register amvdec_mjpeg driver\n"); + if (platform_driver_register(&ammvdec_mjpeg_driver)) { + pr_err("failed to register ammvdec_mjpeg driver\n"); return -ENODEV; } - vcodec_profile_register(&amvdec_mjpeg_profile); + vcodec_profile_register(&ammvdec_mjpeg_profile); return 0; } -static void __exit amvdec_mjpeg_driver_remove_module(void) +static void __exit ammvdec_mjpeg_driver_remove_module(void) { - platform_driver_unregister(&amvdec_mjpeg_driver); + platform_driver_unregister(&ammvdec_mjpeg_driver); } /****************************************/ @@ -922,8 +1191,23 @@ MODULE_PARM_DESC(debug_enable, "\n debug enable\n"); module_param(pre_decode_buf_level, int, 0664); MODULE_PARM_DESC(pre_decode_buf_level, "\n ammvdec_h264 pre_decode_buf_level\n"); -module_init(amvdec_mjpeg_driver_init_module); -module_exit(amvdec_mjpeg_driver_remove_module); +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n amvdec_mmpeg12 udebug_flag\n"); + + +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mjpeg decode_timeout_val\n"); + +module_param_array(max_process_time, uint, &max_decode_instance_num, 0664); + +module_param(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_init(ammvdec_mjpeg_driver_init_module); +module_exit(ammvdec_mjpeg_driver_remove_module); MODULE_DESCRIPTION("AMLOGIC MJMPEG Video Decoder Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/frame_provider/decoder/mpeg12/Makefile b/drivers/frame_provider/decoder/mpeg12/Makefile index 9a07229..34f78c4 100644 --- a/drivers/frame_provider/decoder/mpeg12/Makefile +++ b/drivers/frame_provider/decoder/mpeg12/Makefile @@ -1,2 +1,5 @@ obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12) += amvdec_mpeg12.o amvdec_mpeg12-objs += vmpeg12.o + +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG2_MULTI) += amvdec_mmpeg12.o +amvdec_mmpeg12-objs += vmpeg12_multi.o diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c new file mode 100644 index 0000000..865c248 --- a/dev/null +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c @@ -0,0 +1,1889 @@ +/* + * drivers/amlogic/amports/vmpeg12.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/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/random.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/utils/amstream.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/amlogic/tee.h> + +#include <linux/amlogic/media/utils/vdec_reg.h> +#include <linux/amlogic/media/registers/register.h> +#include "../../../stream_input/amports/amports_priv.h" + +#include "../utils/vdec_input.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> +#include "../utils/firmware.h" + + +#define MEM_NAME "codec_mmpeg12" +#define CHECK_INTERVAL (HZ/100) + +#define DRIVER_NAME "ammvdec_mpeg12" +#define MODULE_NAME "ammvdec_mpeg12" +#define MREG_REF0 AV_SCRATCH_2 +#define MREG_REF1 AV_SCRATCH_3 +/* protocol registers */ +#define MREG_SEQ_INFO AV_SCRATCH_4 +#define MREG_PIC_INFO AV_SCRATCH_5 +#define MREG_PIC_WIDTH AV_SCRATCH_6 +#define MREG_PIC_HEIGHT AV_SCRATCH_7 +#define MREG_INPUT AV_SCRATCH_8 /*input_type*/ +#define MREG_BUFFEROUT AV_SCRATCH_9 /*FROM_AMRISC_REG*/ + +#define MREG_CMD AV_SCRATCH_A +#define MREG_CO_MV_START AV_SCRATCH_B +#define MREG_ERROR_COUNT AV_SCRATCH_C +#define MREG_FRAME_OFFSET AV_SCRATCH_D +#define MREG_WAIT_BUFFER AV_SCRATCH_E +#define MREG_FATAL_ERROR AV_SCRATCH_F + +#define PICINFO_ERROR 0x80000000 +#define PICINFO_TYPE_MASK 0x00030000 +#define PICINFO_TYPE_I 0x00000000 +#define PICINFO_TYPE_P 0x00010000 +#define PICINFO_TYPE_B 0x00020000 + +#define GET_SLICE_TYPE(type) ("IPB###"[(type&PICINFO_TYPE_MASK)>>16]) +#define PICINFO_PROG 0x8000 +#define PICINFO_RPT_FIRST 0x4000 +#define PICINFO_TOP_FIRST 0x2000 +#define PICINFO_FRAME 0x1000 +#define TOP_FIELD 0x1000 +#define BOTTOM_FIELD 0x2000 +#define FRAME_PICTURE 0x3000 +#define FRAME_PICTURE_MASK 0x3000 + +#define SEQINFO_EXT_AVAILABLE 0x80000000 +#define SEQINFO_PROG 0x00010000 +#define CCBUF_SIZE (5*1024) + +#define VF_POOL_SIZE 32 +#define DECODE_BUFFER_NUM_MAX 8 +#define PUT_INTERVAL (HZ/100) +#define WORKSPACE_SIZE (4*SZ_64K) /*swap&ccbuf&matirx&MV*/ +#define CTX_LMEM_SWAP_OFFSET 0 +#define CTX_CCBUF_OFFSET 0x800 +#define CTX_QUANT_MATRIX_OFFSET (CTX_CCBUF_OFFSET + 5*1024) +#define CTX_CO_MV_OFFSET (CTX_QUANT_MATRIX_OFFSET + 1*1024) +#define CTX_DECBUF_OFFSET (CTX_CO_MV_OFFSET + 0x11000) + +#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1) +#define DEFAULT_MEM_SIZE (32*SZ_1M) +static u32 buf_size = 32 * 1024 * 1024; +static int pre_decode_buf_level = 0x800; +static u32 dec_control; +static u32 error_frame_skip_level; +static u32 stat; +static u32 udebug_flag; +static unsigned int radr; +static unsigned int rval; + +#define VMPEG12_DEV_NUM 9 +static unsigned int max_decode_instance_num = VMPEG12_DEV_NUM; +static unsigned int max_process_time[VMPEG12_DEV_NUM]; +static unsigned int decode_timeout_val = 100; +#define INCPTR(p) ptr_atomic_wrap_inc(&p) + +#define DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE 0x0002 +#define DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE 0x0004 +#define DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE 0x0008 +#define DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE 0x0010 +#define DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE 0x0020 +#define DEC_CONTROL_INTERNAL_MASK 0x0fff +#define DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE 0x1000 + +#define INTERLACE_SEQ_ALWAYS + +#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ +#define NV21 +#endif + + +enum { + FRAME_REPEAT_TOP, + FRAME_REPEAT_BOT, + FRAME_REPEAT_NONE +}; +#define DEC_RESULT_NONE 0 +#define DEC_RESULT_DONE 1 +#define DEC_RESULT_AGAIN 2 +#define DEC_RESULT_ERROR 3 +#define DEC_RESULT_FORCE_EXIT 4 +#define DEC_RESULT_EOS 5 +#define DEC_RESULT_GET_DATA 6 +#define DEC_RESULT_GET_DATA_RETRY 7 + +#define DEC_DECODE_TIMEOUT 0x21 +#define DECODE_ID(hw) (hw_to_vdec(hw)->id) +#define DECODE_STOP_POS AV_SCRATCH_K + +static struct vframe_s *vmpeg_vf_peek(void *); +static struct vframe_s *vmpeg_vf_get(void *); +static void vmpeg_vf_put(struct vframe_s *, void *); +static int vmpeg_vf_states(struct vframe_states *states, void *); +static int vmpeg_event_cb(int type, void *data, void *private_data); + +struct vdec_mpeg12_hw_s { + spinlock_t lock; + struct platform_device *platform_dev; + DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); + struct vframe_s vfpool[VF_POOL_SIZE]; + s32 vfbuf_use[DECODE_BUFFER_NUM_MAX]; + u32 frame_width; + u32 frame_height; + u32 frame_dur; + u32 frame_prog; + u32 seqinfo; + u32 ctx_valid; + u32 dec_control; + void *mm_blk_handle; + struct vframe_chunk_s *chunk; + u32 stat; + u8 init_flag; + unsigned long buf_start; + u32 buf_size; + u32 reg_pic_width; + u32 reg_pic_height; + u32 reg_mpeg1_2_reg; + u32 reg_pic_head_info; + u32 reg_f_code_reg; + u32 reg_slice_ver_pos_pic_type; + u32 reg_vcop_ctrl_reg; + u32 reg_mb_info; + u32 reg_signal_type; + u32 frame_num; + struct timer_list check_timer; + u32 decode_timeout_count; + u32 start_process_time; + u32 last_vld_level; + u32 eos; + u32 buffer_info[DECODE_BUFFER_NUM_MAX]; + u32 pts[DECODE_BUFFER_NUM_MAX]; + u64 pts64[DECODE_BUFFER_NUM_MAX]; + bool pts_valid[DECODE_BUFFER_NUM_MAX]; + u32 canvas_spec[DECODE_BUFFER_NUM_MAX]; + struct canvas_config_s canvas_config[DECODE_BUFFER_NUM_MAX][2]; + struct dec_sysinfo vmpeg12_amstream_dec_info; + + s32 refs[2]; + int dec_result; + struct work_struct work; + struct work_struct notify_work; + void (*vdec_cb)(struct vdec_s *, void *); + void *vdec_cb_arg; + unsigned long ccbuf_phyAddress; + void *ccbuf_phyAddress_virt; + unsigned long ccbuf_phyAddress_is_remaped_nocache; + u32 frame_rpt_state; +/* for error handling */ + s32 frame_force_skip_flag; + s32 error_frame_skip_level; + s32 wait_buffer_counter; + u32 first_i_frame_ready; + u32 run_count; + u32 not_run_ready; + u32 input_empty; + u32 put_num; + u32 peek_num; + u32 get_num; + u32 drop_frame_count; + u32 buffer_not_ready; + int frameinfo_enable; + struct firmware_s *fw; +}; +static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw); +static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw); +static void reset_process_time(struct vdec_mpeg12_hw_s *hw); +static struct vdec_info gvs; +static int debug_enable; +/*static struct work_struct userdata_push_work;*/ +#undef pr_info +#define pr_info printk +unsigned int mpeg12_debug_mask = 0xff; +/*static int counter_max = 5;*/ + +#define PRINT_FLAG_ERROR 0x0 +#define PRINT_FLAG_RUN_FLOW 0X0001 +#define PRINT_FLAG_TIMEINFO 0x0002 +#define PRINT_FLAG_UCODE_DETAIL 0x0004 +#define PRINT_FLAG_VLD_DETAIL 0x0008 +#define PRINT_FLAG_DEC_DETAIL 0x0010 +#define PRINT_FLAG_BUFFER_DETAIL 0x0020 +#define PRINT_FLAG_RESTORE 0x0040 +#define PRINT_FRAME_NUM 0x0080 +#define PRINT_FLAG_FORCE_DONE 0x0100 +#define PRINT_FLAG_COUNTER 0X0200 +#define PRINT_FRAMEBASE_DATA 0x0400 +#define PRINT_FLAG_VDEC_STATUS 0x0800 +#define PRINT_FLAG_PARA_DATA 0x1000 + + +int debug_print(int index, int debug_flag, const char *fmt, ...) +{ + if (((debug_enable & debug_flag) && + ((1 << index) & mpeg12_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) { + unsigned char buf[512]; + int len = 0; + va_list args; + va_start(args, fmt); + len = sprintf(buf, "%d: ", index); + vsnprintf(buf + len, 512-len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + + +/*static bool is_reset;*/ +#define PROVIDER_NAME "vdec.mpeg12" +static const struct vframe_operations_s vf_provider_ops = { + .peek = vmpeg_vf_peek, + .get = vmpeg_vf_get, + .put = vmpeg_vf_put, + .event_cb = vmpeg_event_cb, + .vf_states = vmpeg_vf_states, +}; + + +static const u32 frame_rate_tab[16] = { + 96000 / 30, 96000000 / 23976, 96000 / 24, 96000 / 25, + 9600000 / 2997, 96000 / 30, 96000 / 50, 9600000 / 5994, + 96000 / 60, + /* > 8 reserved, use 24 */ + 96000 / 24, 96000 / 24, 96000 / 24, 96000 / 24, + 96000 / 24, 96000 / 24, 96000 / 24 +}; + + +static u32 find_buffer(struct vdec_mpeg12_hw_s *hw) +{ + u32 i; + + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + if (hw->vfbuf_use[i] == 0) + return i; + } + + return DECODE_BUFFER_NUM_MAX; +} + +static u32 spec_to_index(struct vdec_mpeg12_hw_s *hw, u32 spec) +{ + u32 i; + + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + if (hw->canvas_spec[i] == spec) + return i; + } + + return DECODE_BUFFER_NUM_MAX; +} + +static void set_frame_info(struct vdec_mpeg12_hw_s *hw, struct vframe_s *vf) +{ + unsigned ar_bits; + u32 temp; + u32 buffer_index = vf->index; +#ifdef CONFIG_AM_VDEC_MPEG12_LOG + bool first = (hw->frame_width == 0) && (hw->frame_height == 0); +#endif + + temp = READ_VREG(MREG_PIC_WIDTH); + if (temp > 1920 || temp == 0) + vf->width = hw->frame_width = 1920; + else + vf->width = hw->frame_width = temp; + + temp = READ_VREG(MREG_PIC_HEIGHT); + if (temp > 1088 || temp == 0) + vf->height = hw->frame_height = 1088; + else + vf->height = hw->frame_height = temp; + + if (hw->frame_dur > 0) + vf->duration = hw->frame_dur; + else { + vf->duration = hw->frame_dur = + frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf]; + schedule_work(&hw->notify_work); + } + + ar_bits = READ_VREG(MREG_SEQ_INFO) & 0xf; + + if (ar_bits == 0x2) + vf->ratio_control = 0xc0 << DISP_RATIO_ASPECT_RATIO_BIT; + + else if (ar_bits == 0x3) + vf->ratio_control = 0x90 << DISP_RATIO_ASPECT_RATIO_BIT; + + else if (ar_bits == 0x4) + vf->ratio_control = 0x74 << DISP_RATIO_ASPECT_RATIO_BIT; + else + vf->ratio_control = 0; + + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + + vf->canvas0_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas0_config[1] = hw->canvas_config[buffer_index][1]; + + vf->canvas1_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas1_config[1] = hw->canvas_config[buffer_index][1]; + + + debug_print(DECODE_ID(hw), PRINT_FLAG_PARA_DATA, + "mpeg2dec: w(%d), h(%d), dur(%d), dur-ES(%d)\n", + hw->frame_width, hw->frame_height, hw->frame_dur, + frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf]); +} + +static bool error_skip(struct vdec_mpeg12_hw_s *hw, + u32 info, struct vframe_s *vf) +{ + if (hw->error_frame_skip_level) { + /* skip error frame */ + if ((info & PICINFO_ERROR) || (hw->frame_force_skip_flag)) { + if ((info & PICINFO_ERROR) == 0) { + if ((info & PICINFO_TYPE_MASK) == + PICINFO_TYPE_I) + hw->frame_force_skip_flag = 0; + } else { + if (hw->error_frame_skip_level >= 2) + hw->frame_force_skip_flag = 1; + } + if ((info & PICINFO_ERROR) + || (hw->frame_force_skip_flag)) + return true; + } + } + return false; +} + +static inline void vmpeg12_save_hw_context(struct vdec_mpeg12_hw_s *hw) +{ + hw->seqinfo = READ_VREG(MREG_SEQ_INFO); + hw->reg_pic_width = READ_VREG(MREG_PIC_WIDTH); + hw->reg_pic_height = READ_VREG(MREG_PIC_HEIGHT); + hw->reg_mpeg1_2_reg = READ_VREG(MPEG1_2_REG); + hw->reg_pic_head_info = READ_VREG(PIC_HEAD_INFO); + hw->reg_f_code_reg = READ_VREG(F_CODE_REG); + hw->reg_slice_ver_pos_pic_type = READ_VREG(SLICE_VER_POS_PIC_TYPE); + hw->reg_vcop_ctrl_reg = READ_VREG(VCOP_CTRL_REG); + hw->reg_mb_info = READ_VREG(MB_INFO); + hw->reg_signal_type = READ_VREG(AV_SCRATCH_H); + debug_print(DECODE_ID(hw), PRINT_FLAG_PARA_DATA, + "signal_type = %x", hw->reg_signal_type); +} +#if 0 +static void userdata_push_do_work(struct work_struct *work) +{ + u32 reg; + + struct userdata_poc_info_t user_data_poc; +/* struct vdec_mpeg12_hw_s *hw = + container_of(work, struct vdec_mpeg12_hw_s, work);*/ + user_data_poc.poc_info = 0; + user_data_poc.poc_number = 0; + reg = READ_VREG(MREG_BUFFEROUT); + /*pr_info("%s,%d\n",__func__,__LINE__);*/ + + if (!hw->ccbuf_phyAddress_is_remaped_nocache && + hw->ccbuf_phyAddress && + hw->ccbuf_phyAddress_virt) { + codec_mm_dma_flush( + hw->ccbuf_phyAddress_virt, + CCBUF_SIZE, + DMA_FROM_DEVICE); + } + wakeup_userdata_poll(user_data_poc, + reg & 0xffff, + (unsigned long)hw->ccbuf_phyAddress_virt, + CCBUF_SIZE, 0); + + WRITE_VREG(MREG_BUFFEROUT, 0); +} +#endif +static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) +{ + u32 reg, info, seqinfo, offset, pts, pts_valid = 0; + struct vframe_s *vf = NULL; + u32 index; + u64 pts_us64 = 0; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + + if (READ_VREG(AV_SCRATCH_M) != 0 && + (debug_enable & PRINT_FLAG_UCODE_DETAIL)) { + + debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "dbg %x: %x, level %x, wp %x, rp %x, cnt %x\n", + READ_VREG(AV_SCRATCH_M), READ_VREG(AV_SCRATCH_N), + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VIFF_BIT_CNT)); + WRITE_VREG(AV_SCRATCH_M, 0); + return IRQ_HANDLED; + } + + reg = READ_VREG(MREG_BUFFEROUT); + + if ((reg >> 16) == 0xfe) { + /*pr_info("%s,%d\n",__func__,__LINE__);*/ + /*vdec_schedule_work(&userdata_push_work);*/ + WRITE_VREG(MREG_BUFFEROUT, 0); + } else if (reg == 2) { + /*timeout when decoding next frame*/ + + debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "ammvdec_mpeg12: Insufficient data\n"); + debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "level=%x, vtl=%x,bcnt=%d\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_CONTROL), + READ_VREG(VIFF_BIT_CNT)); + if (input_frame_based(vdec)) + vmpeg12_save_hw_context(hw); + else { + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } + return IRQ_HANDLED; + } else { + reset_process_time(hw); + info = READ_VREG(MREG_PIC_INFO); + offset = READ_VREG(MREG_FRAME_OFFSET); + index = spec_to_index(hw, READ_VREG(REC_CANVAS_ADDR)); + seqinfo = READ_VREG(MREG_SEQ_INFO); + if ((info & PICINFO_PROG) == 0 && + (info & FRAME_PICTURE_MASK) != FRAME_PICTURE) + hw->first_i_frame_ready = 1; /* for field struct case*/ + debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "struct: %d %x\n", (info & PICINFO_FRAME), info); + if (index >= DECODE_BUFFER_NUM_MAX) { + + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "invalid buffer index,index=%d\n", + index); + hw->dec_result = DEC_RESULT_ERROR; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + + hw->dec_result = DEC_RESULT_DONE; + + /*debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "ammvdec_mpeg12: error = 0x%x, offset = 0x%x\n", + info & PICINFO_ERROR, offset);*/ + + if (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) || + ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P)) { + if (hw->chunk) { + hw->pts_valid[index] = hw->chunk->pts_valid; + hw->pts[index] = hw->chunk->pts; + hw->pts64[index] = hw->chunk->pts64; + + debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "!!!cpts=%d,pts64=%lld,size=%d,offset=%d\n", + hw->pts[index], hw->pts64[index], + hw->chunk->size, hw->chunk->offset); + } else { + if (pts_lookup_offset_us64(PTS_TYPE_VIDEO, + offset, &pts, 0, &pts_us64) == 0) { + hw->pts_valid[index] = true; + hw->pts[index] = pts; + hw->pts64[index] = pts_us64; + } else { + hw->pts_valid[index] = false; + } + } + } else { + hw->pts_valid[index] = false; + } + /*if (frame_prog == 0) */ + { + hw->frame_prog = info & PICINFO_PROG; + if ((seqinfo & SEQINFO_EXT_AVAILABLE) + && (!(seqinfo & SEQINFO_PROG))) + hw->frame_prog = 0; + } + if ((hw->dec_control & + DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE) && + (hw->frame_width == 720) && + (hw->frame_height == 576) && + (hw->frame_dur == 3840)) { + hw->frame_prog = 0; + } else if ((hw->dec_control + & DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE) && + (hw->frame_width == 704) && + (hw->frame_height == 480) && + (hw->frame_dur == 3200)) { + hw->frame_prog = 0; + } else if ((hw->dec_control + & DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE) && + (hw->frame_width == 704) && + (hw->frame_height == 576) && + (hw->frame_dur == 3840)) { + hw->frame_prog = 0; + } else if ((hw->dec_control + & DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE) && + (hw->frame_width == 544) && + (hw->frame_height == 576) && + (hw->frame_dur == 3840)) { + hw->frame_prog = 0; + } else if ((hw->dec_control + & DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE) && + (hw->frame_width == 480) && + (hw->frame_height == 576) && + (hw->frame_dur == 3840)) { + hw->frame_prog = 0; + } else if (hw->dec_control + & DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE) { + hw->frame_prog = 0; + } + + hw->buffer_info[index] = info; + + debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "ammvdec_mpeg12: decoded buffer %d, frame_type %c\n", + index, GET_SLICE_TYPE(info)); + + /* Buffer management + todo: add sequence-end flush */ + if (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) || + ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P)) { + hw->vfbuf_use[index]++; + if (hw->refs[1] == -1) { + hw->refs[1] = index; + index = DECODE_BUFFER_NUM_MAX; + } else if (hw->refs[0] == -1) { + hw->refs[0] = hw->refs[1]; + hw->refs[1] = index; + index = hw->refs[0]; + } else { + hw->vfbuf_use[hw->refs[0]]--; + hw->refs[0] = hw->refs[1]; + hw->refs[1] = index; + index = hw->refs[0]; + } + } else { + /* if this is a B frame, then drop + (depending on if there are two reference frames) + or display immediately*/ + if (hw->refs[0] == -1) + index = DECODE_BUFFER_NUM_MAX; + + } + + vmpeg12_save_hw_context(hw); + + if (index >= DECODE_BUFFER_NUM_MAX) { + debug_print(DECODE_ID(hw), 0, + "invalid buffer index,index=%d\n", index); + hw->dec_result = DEC_RESULT_ERROR; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + + info = hw->buffer_info[index]; + pts_valid = hw->pts_valid[index]; + pts = hw->pts[index]; + pts_us64 = hw->pts64[index]; + + if ((hw->first_i_frame_ready == 0) && + ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) && + ((info & PICINFO_ERROR) == 0)) + hw->first_i_frame_ready = 1; + debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "ammvdec_mpeg12: display buffer %d, frame_type %c\n", + index, GET_SLICE_TYPE(info)); + if (hw->frame_prog & PICINFO_PROG) { + + seqinfo = READ_VREG(MREG_SEQ_INFO); + + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "fatal error, no available buffer slot."); + hw->dec_result = DEC_RESULT_ERROR; + vdec_schedule_work(&hw->work); + + return IRQ_HANDLED; + } + + vf->index = index; + set_frame_info(hw, vf); + vf->signal_type = hw->reg_signal_type; + +#ifdef NV21 + vf->type = + VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | + VIDTYPE_VIU_NV21; +#else + vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; +#endif + if ((hw->seqinfo & SEQINFO_EXT_AVAILABLE) + && (hw->seqinfo & SEQINFO_PROG)) { + if (info & PICINFO_RPT_FIRST) { + if (info & PICINFO_TOP_FIRST) { + vf->duration = + vf->duration * 3; + /* repeat three times */ + } else { + vf->duration = + vf->duration * 2; + /* repeat two times */ + } + } + vf->duration_pulldown = 0; + /* no pull down */ + + } else { + vf->duration_pulldown = + (info & PICINFO_RPT_FIRST) ? + vf->duration >> 1 : 0; + } + + vf->duration += vf->duration_pulldown; + + vf->orientation = 0; + vf->pts = (pts_valid) ? pts : 0; + vf->pts_us64 = (pts_valid) ? pts_us64 : 0; + vf->type_original = vf->type; + hw->vfbuf_use[index]++; + + if ((error_skip(hw, info, vf)) || + ((hw->first_i_frame_ready == 0) + && ((PICINFO_TYPE_MASK & info) != + PICINFO_TYPE_I))) { + hw->drop_frame_count++; + hw->vfbuf_use[index]--; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + + } else { + debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "cpts=%d,pts64=%lld\n", + vf->pts, vf->pts_us64); + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + } + } +/*interlace temp*/ + else { + int first_field_type = (info & PICINFO_TOP_FIRST) ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM; + +#ifdef INTERLACE_SEQ_ALWAYS + /* once an interlaced sequence exist, + always force interlaced type */ + /* to make DI easy. */ + hw->dec_control |= DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE; +#endif + + hw->frame_rpt_state = FRAME_REPEAT_NONE; + + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "fatal error, no available buffer slot."); + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + + hw->vfbuf_use[index] += 2; + vf->signal_type = hw->reg_signal_type; + vf->index = index; + set_frame_info(hw, vf); + vf->type = + (first_field_type == VIDTYPE_INTERLACE_TOP) ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM; +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + if (info & PICINFO_RPT_FIRST) + vf->duration /= 3; + else + vf->duration >>= 1; + vf->duration_pulldown = (info & PICINFO_RPT_FIRST) ? + vf->duration >> 1 : 0; + vf->duration += vf->duration_pulldown; + vf->orientation = 0; + vf->pts = (pts_valid) ? pts : 0; + vf->pts_us64 = (pts_valid) ? pts_us64 : 0; + + if ((error_skip(hw, info, vf)) || + ((hw->first_i_frame_ready == 0) + && ((PICINFO_TYPE_MASK & info) != + PICINFO_TYPE_I))) { + hw->vfbuf_use[index]--; + hw->drop_frame_count++; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "cpts0=%d,pts64=%lld,dur=%d, index %d , use %d\n", + vf->pts, vf->pts_us64, vf->duration, + vf->index, hw->vfbuf_use[index]); + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } + + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "ammvdec_mpeg12: fatal error, no available buffer slot."); + + hw->vfbuf_use[index]--; + + vdec_schedule_work(&hw->work); + + return IRQ_HANDLED; + } + vf->signal_type = hw->reg_signal_type; + vf->index = index; + set_frame_info(hw, vf); + vf->type = (first_field_type == + VIDTYPE_INTERLACE_TOP) ? + VIDTYPE_INTERLACE_BOTTOM : + VIDTYPE_INTERLACE_TOP; +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + if (info & PICINFO_RPT_FIRST) + vf->duration /= 3; + else + vf->duration >>= 1; + vf->duration_pulldown = (info & PICINFO_RPT_FIRST) ? + vf->duration >> 1 : 0; + vf->duration += vf->duration_pulldown; + vf->orientation = 0; + vf->pts = 0; + vf->pts_us64 = 0; + vf->type_original = vf->type; + + if ((error_skip(hw, info, vf)) || + ((hw->first_i_frame_ready == 0) + && ((PICINFO_TYPE_MASK & info) != + PICINFO_TYPE_I))) { + hw->drop_frame_count++; + hw->vfbuf_use[index]--; + + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "cpts1=%d,pts64=%lld,dur=%d index %d, used %d\n", + vf->pts, vf->pts_us64, vf->duration, vf->index, + hw->vfbuf_use[index]); + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } + + if (info & PICINFO_RPT_FIRST) { + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + debug_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, + "error, no available buffer slot."); + return IRQ_HANDLED; + } + hw->vfbuf_use[index]++; + vf->index = index; + set_frame_info(hw, vf); + vf->type = (first_field_type == + VIDTYPE_INTERLACE_TOP) ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM; +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + vf->duration /= 3; + vf->duration_pulldown = + (info & PICINFO_RPT_FIRST) ? + vf->duration >> 1 : 0; + vf->duration += vf->duration_pulldown; + vf->orientation = 0; + + vf->pts = 0; + vf->pts_us64 = 0; + if ((error_skip(hw, info, vf)) || + ((hw->first_i_frame_ready == 0) + && ((PICINFO_TYPE_MASK & info) + != PICINFO_TYPE_I))) { + hw->vfbuf_use[index]--; + hw->drop_frame_count++; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + hw->frame_num++; + debug_print(DECODE_ID(hw), + PRINT_FLAG_TIMEINFO, + "cpts2=%d,pts64=%lld,dur=%d index %d, used %d\n", + vf->pts, vf->pts_us64, vf->duration, + vf->index, hw->vfbuf_use[index]); + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + vf_notify_receiver( + vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + } + } + } + vdec_schedule_work(&hw->work); + + debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "frame_num=%d\n", hw->frame_num); + if (hw->frame_num == 1) + debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "frame_num==1\n"); + if (hw->frame_num == 1000) + debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "frame_num==1000\n"); + } + + return IRQ_HANDLED; +} +static irqreturn_t vmpeg12_isr(struct vdec_s *vdec, int irq) +{ + u32 info, offset; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + if (hw->eos) + return IRQ_HANDLED; + info = READ_VREG(MREG_PIC_INFO); + offset = READ_VREG(MREG_FRAME_OFFSET); + + vdec_count_info(&gvs, info & PICINFO_ERROR, offset); + + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + return IRQ_WAKE_THREAD; +} + +static void vmpeg12_notify_work(struct work_struct *work) +{ + struct vdec_mpeg12_hw_s *hw = container_of(work, + struct vdec_mpeg12_hw_s, notify_work); + struct vdec_s *vdec = hw_to_vdec(hw); + + if (vdec->fr_hint_state == VDEC_NEED_HINT) { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long)hw->frame_dur)); + vdec->fr_hint_state = VDEC_HINTED; + } +} + +static void wait_vmmpeg12_search_done(struct vdec_mpeg12_hw_s *hw) +{ + u32 vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + int count = 0; + + do { + usleep_range(100, 500); + if (vld_rp == READ_VREG(VLD_MEM_VIFIFO_RP)) + break; + if (count > 1000) { + debug_print(DECODE_ID(hw), 0, + "%s, count %d vld_rp 0x%x VLD_MEM_VIFIFO_RP 0x%x\n", + __func__, count, vld_rp, READ_VREG(VLD_MEM_VIFIFO_RP)); + break; + } else + vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + count++; + } while (1); +} + +static void vmpeg12_work(struct work_struct *work) +{ + struct vdec_mpeg12_hw_s *hw = + container_of(work, struct vdec_mpeg12_hw_s, work); + if (hw->dec_result != DEC_RESULT_DONE) + debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "ammvdec_mpeg12: vmpeg_work,result=%d,status=%d\n", + hw->dec_result, hw_to_vdec(hw)->next_status); + + if (hw->dec_result == DEC_RESULT_DONE) { + if (!hw->ctx_valid) + hw->ctx_valid = 1; + + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + } else if (hw->dec_result == DEC_RESULT_AGAIN + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + /* + stream base: stream buf empty or timeout + frame base: vdec_prepare_input fail + */ + if (!vdec_has_more_input(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + } else if (hw->dec_result == DEC_RESULT_GET_DATA + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + if (!vdec_has_more_input(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "%s DEC_RESULT_GET_DATA %x %x %x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP)); + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); + return; + } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s: force exit\n", __func__); + if (hw->stat & STAT_ISR_REG) { + amvdec_stop(); + /*disable mbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + } else if (hw->dec_result == DEC_RESULT_EOS) { + pr_info("%s: end of stream\n", __func__); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + hw->eos = 1; + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); + } + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + wait_vmmpeg12_search_done(hw); + vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + + if (hw->vdec_cb) { + hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); + debug_print(DECODE_ID(hw), 0x80000, + "%s:\n", __func__); + } +} + +static struct vframe_s *vmpeg_vf_peek(void *op_arg) +{ + struct vframe_s *vf; + struct vdec_s *vdec = op_arg; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + hw->peek_num++; + if (kfifo_peek(&hw->display_q, &vf)) + return vf; + + return NULL; +} + +static struct vframe_s *vmpeg_vf_get(void *op_arg) +{ + struct vframe_s *vf; + struct vdec_s *vdec = op_arg; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + + hw->get_num++; + if (kfifo_get(&hw->display_q, &vf)) + return vf; + + return NULL; +} + +static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg) +{ + struct vdec_s *vdec = op_arg; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + + hw->vfbuf_use[vf->index]--; + hw->put_num++; + kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); +} + +static int vmpeg_event_cb(int type, void *data, void *private_data) +{ + return 0; +} + +static int vmpeg_vf_states(struct vframe_states *states, void *op_arg) +{ + unsigned long flags; + struct vdec_s *vdec = op_arg; + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + + spin_lock_irqsave(&hw->lock, flags); + + 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); + states->buf_recycle_num = 0; + + spin_unlock_irqrestore(&hw->lock, flags); + return 0; +} +static int vmmpeg12_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + if (!hw) + return 0; + vstatus->frame_width = hw->frame_width; + vstatus->frame_height = hw->frame_height; + if (hw->frame_dur != 0) + vstatus->frame_rate = 96000 / hw->frame_dur; + else + vstatus->frame_rate = -1; + vstatus->error_count = READ_VREG(AV_SCRATCH_C); + vstatus->status = hw->stat; + vstatus->bit_rate = gvs.bit_rate; + vstatus->frame_dur = hw->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 = hw->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 void vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw) +{ + int i, ret; + u32 canvas_width, canvas_height; + u32 decbuf_size, decbuf_y_size, decbuf_uv_size; + unsigned long decbuf_start; + /*u32 disp_addr = 0xffffffff;*/ + struct vdec_s *vdec = hw_to_vdec(hw); + + if (buf_size <= 0x00400000) { + /* SD only */ + canvas_width = 768; + canvas_height = 576; + decbuf_y_size = 0x80000; + decbuf_uv_size = 0x20000; + decbuf_size = 0x100000; + } else { + /* HD & SD */ + canvas_width = 1920; + canvas_height = 1088; + decbuf_y_size = 0x200000; + decbuf_uv_size = 0x80000; + decbuf_size = 0x300000; + } + + for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) { + + unsigned canvas; + if (i == (MAX_BMMU_BUFFER_NUM - 1)) /* SWAP&CCBUF&MATIRX&MV */ + decbuf_size = WORKSPACE_SIZE; + ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, + decbuf_size, DRIVER_NAME, &decbuf_start); + if (ret < 0) { + pr_err("mmu alloc failed! size 0x%d idx %d\n", + decbuf_size, i); + return; + } + + if (i == (MAX_BMMU_BUFFER_NUM - 1)) { + hw->buf_start = decbuf_start; + hw->ccbuf_phyAddress = hw->buf_start + CTX_CCBUF_OFFSET; + WRITE_VREG(MREG_CO_MV_START, hw->buf_start); + } else { + canvas = vdec->get_canvas(i, 2); + hw->canvas_spec[i] = canvas; + + hw->canvas_config[i][0].phy_addr = + decbuf_start; + hw->canvas_config[i][0].width = + canvas_width; + hw->canvas_config[i][0].height = + canvas_height; + hw->canvas_config[i][0].block_mode = + CANVAS_BLKMODE_32X32; + + canvas_config_config(canvas_y(canvas), + &hw->canvas_config[i][0]); + + hw->canvas_config[i][1].phy_addr = + decbuf_start + decbuf_y_size; + hw->canvas_config[i][1].width = + canvas_width; + hw->canvas_config[i][1].height = + canvas_height / 2; + hw->canvas_config[i][1].block_mode = + CANVAS_BLKMODE_32X32; + + canvas_config_config(canvas_u(canvas), + &hw->canvas_config[i][1]); + } + } + return; +} + +static void vmpeg2_dump_state(struct vdec_s *vdec) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + u32 i; + debug_print(DECODE_ID(hw), 0, + "====== %s\n", __func__); + debug_print(DECODE_ID(hw), 0, + "width/height (%d/%d),i_first %d\n", + hw->frame_width, + hw->frame_height, + hw->first_i_frame_ready + ); + debug_print(DECODE_ID(hw), 0, + "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d put_frm %d run %d not_run_ready %d,input_empty %d\n", + input_frame_based(vdec), + hw->eos, + hw->stat, + hw->dec_result, + hw->frame_num, + hw->put_num, + hw->run_count, + hw->not_run_ready, + hw->input_empty + ); + + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + debug_print(DECODE_ID(hw), 0, + "index %d, used %d\n", i, hw->vfbuf_use[i]); + } + + if (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); + debug_print(DECODE_ID(hw), 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + debug_print(DECODE_ID(hw), 0, + "%s, newq(%d/%d), dispq(%d/%d) vf peek/get/put (%d/%d/%d),drop=%d, buffer_not_ready %d\n", + __func__, + kfifo_len(&hw->newframe_q), + VF_POOL_SIZE, + kfifo_len(&hw->display_q), + VF_POOL_SIZE, + hw->peek_num, + hw->get_num, + hw->put_num, + hw->drop_frame_count, + hw->buffer_not_ready + ); + debug_print(DECODE_ID(hw), 0, + "VIFF_BIT_CNT=0x%x\n", + READ_VREG(VIFF_BIT_CNT)); + debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_LEVEL=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_WP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_RP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_RP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_RP)); + debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_WP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_WP)); + if (input_frame_based(vdec) && + debug_enable & PRINT_FRAMEBASE_DATA + ) { + int jj; + if (hw->chunk && hw->chunk->block && + hw->chunk->size > 0) { + u8 *data = + ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + debug_print(DECODE_ID(hw), 0, + "frame data size 0x%x\n", + hw->chunk->size); + for (jj = 0; jj < hw->chunk->size; jj++) { + if ((jj & 0xf) == 0) + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + } + } +} + +static void reset_process_time(struct vdec_mpeg12_hw_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[DECODE_ID(hw)]) + max_process_time[DECODE_ID(hw)] = process_time; + } +} +static void start_process_time(struct vdec_mpeg12_hw_s *hw) +{ + hw->decode_timeout_count = 2; + hw->start_process_time = jiffies; +} +static void timeout_process(struct vdec_mpeg12_hw_s *hw) +{ + struct vdec_s *vdec = hw_to_vdec(hw); + amvdec_stop(); + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s decoder timeout, status=%d, level=%d\n", + __func__, vdec->status, READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + hw->dec_result = DEC_RESULT_DONE; + reset_process_time(hw); + hw->first_i_frame_ready = 0; + vdec_schedule_work(&hw->work); +} + +static void check_timer_func(unsigned long arg) +{ + struct vdec_mpeg12_hw_s *hw = (struct vdec_mpeg12_hw_s *)arg; + struct vdec_s *vdec = hw_to_vdec(hw); + unsigned int timeout_val = decode_timeout_val; + + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + + if (debug_enable == 0 && + (input_frame_based(vdec) || + (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x100)) && + (timeout_val > 0) && + (hw->start_process_time > 0) && + ((1000 * (jiffies - hw->start_process_time) / HZ) + > timeout_val)) { + if (hw->last_vld_level == READ_VREG(VLD_MEM_VIFIFO_LEVEL)) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + timeout_process(hw); + } + hw->last_vld_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); + } + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED) { + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + pr_info("vdec requested to be disconnected\n"); + return; + } + + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); +} + +static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw) +{ + u32 index; + index = find_buffer(hw); + if (index >= DECODE_BUFFER_NUM_MAX) + return -1; + vmpeg12_canvas_init(hw); + + /* prepare REF0 & REF1 + points to the past two IP buffers + prepare REC_CANVAS_ADDR and ANC2_CANVAS_ADDR + points to the output buffer*/ + WRITE_VREG(MREG_REF0, + (hw->refs[1] == -1) ? 0xffffffff : hw->canvas_spec[hw->refs[0]]); + WRITE_VREG(MREG_REF1, + (hw->refs[0] == -1) ? 0xffffffff : hw->canvas_spec[hw->refs[1]]); + WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]); + WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]); + + debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE, + "%s,ref0=0x%x, ref1=0x%x,rec=0x%x, ctx_valid=%d,index=%d\n", + __func__, + READ_VREG(MREG_REF0), + READ_VREG(MREG_REF1), + READ_VREG(REC_CANVAS_ADDR), + hw->ctx_valid, index); + + /* set to mpeg1 default */ + WRITE_VREG(MPEG1_2_REG, + (hw->ctx_valid) ? hw->reg_mpeg1_2_reg : 0); + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + /* for Mpeg1 default value */ + WRITE_VREG(PIC_HEAD_INFO, + (hw->ctx_valid) ? hw->reg_pic_head_info : 0x380); + /* disable mpeg4 */ + WRITE_VREG(M4_CONTROL_REG, 0); + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + /* clear buffer IN/OUT registers */ + WRITE_VREG(MREG_BUFFEROUT, 0); + /* set reference width and height */ + if ((hw->frame_width != 0) && (hw->frame_height != 0)) + WRITE_VREG(MREG_CMD, + (hw->frame_width << 16) | hw->frame_height); + else + WRITE_VREG(MREG_CMD, 0); + + + debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE, + "0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + hw->frame_width, hw->frame_height, hw->seqinfo, + hw->reg_f_code_reg, hw->reg_slice_ver_pos_pic_type, + hw->reg_mb_info); + + WRITE_VREG(MREG_PIC_WIDTH, hw->reg_pic_width); + WRITE_VREG(MREG_PIC_HEIGHT, hw->reg_pic_height); + WRITE_VREG(MREG_SEQ_INFO, hw->seqinfo); + WRITE_VREG(F_CODE_REG, hw->reg_f_code_reg); + WRITE_VREG(SLICE_VER_POS_PIC_TYPE, + hw->reg_slice_ver_pos_pic_type); + WRITE_VREG(MB_INFO, hw->reg_mb_info); + WRITE_VREG(VCOP_CTRL_REG, hw->reg_vcop_ctrl_reg); + WRITE_VREG(AV_SCRATCH_H, hw->reg_signal_type); + + /* clear error count */ + WRITE_VREG(MREG_ERROR_COUNT, 0); + WRITE_VREG(MREG_FATAL_ERROR, 0); + /* clear wait buffer status */ + WRITE_VREG(MREG_WAIT_BUFFER, 0); +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1<<17); +#endif + + if (hw->chunk) { + /*frame based input*/ + WRITE_VREG(MREG_INPUT, + (hw->chunk->offset & 7) | (1<<7) | (hw->ctx_valid<<6)); + } else { + /*stream based input*/ + WRITE_VREG(MREG_INPUT, (hw->ctx_valid<<6)); + } + + return 0; +} + +static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw) +{ + int i; + INIT_KFIFO(hw->display_q); + INIT_KFIFO(hw->newframe_q); + + for (i = 0; i < VF_POOL_SIZE; i++) { + const struct vframe_s *vf; + vf = &hw->vfpool[i]; + hw->vfpool[i].index = DECODE_BUFFER_NUM_MAX; + kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); + } + + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) + hw->vfbuf_use[i] = 0; + + + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + + hw->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); + hw->eos = 0; + hw->frame_width = hw->frame_height = 0; + hw->frame_dur = hw->frame_prog = 0; + hw->frame_force_skip_flag = 0; + hw->wait_buffer_counter = 0; + hw->first_i_frame_ready = 0; + hw->dec_control &= DEC_CONTROL_INTERNAL_MASK; + hw->refs[0] = -1; + hw->refs[1] = -1; + hw->frame_num = 0; + hw->put_num = 0; + hw->run_count = 0; + hw->not_run_ready = 0; + hw->input_empty = 0; + hw->peek_num = 0; + hw->get_num = 0; + hw->drop_frame_count = 0; + hw->buffer_not_ready = 0; + hw->start_process_time = 0; + hw->error_frame_skip_level = error_frame_skip_level; + if (dec_control) + hw->dec_control = dec_control; +} + +static s32 vmpeg12_init(struct vdec_mpeg12_hw_s *hw) +{ + int size; + u32 fw_size = 16*0x1000; + struct firmware_s *fw; + + vmpeg12_local_init(hw); + + fw = vmalloc(sizeof(struct firmware_s) + fw_size); + if (IS_ERR_OR_NULL(fw)) + return -ENOMEM; + + pr_debug("get firmware ...\n"); + size = get_firmware_data(VIDEO_DEC_MPEG12_MULTI, fw->data); + if (size < 0) { + pr_err("get firmware fail.\n"); + vfree(fw); + return -1; + } + + fw->len = size; + hw->fw = fw; + + INIT_WORK(&hw->work, vmpeg12_work); + INIT_WORK(&hw->notify_work, vmpeg12_notify_work); + + amvdec_enable(); + + init_timer(&hw->check_timer); + hw->check_timer.data = (unsigned long)hw; + hw->check_timer.function = check_timer_func; + hw->check_timer.expires = jiffies + CHECK_INTERVAL; + + hw->stat |= STAT_TIMER_ARM; + hw->stat |= STAT_ISR_REG; + + hw->buf_start = 0; + hw->init_flag = 0; + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + + return 0; +} + +static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) +{ + int index; + + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + if (hw->eos) + return 0; + if (vdec_stream_based(vdec) && (hw->init_flag == 0) + && pre_decode_buf_level != 0) { + u32 rp, wp, level; + + rp = READ_PARSER_REG(PARSER_VIDEO_RP); + wp = READ_PARSER_REG(PARSER_VIDEO_WP); + if (wp < rp) + level = vdec->input.size + wp - rp; + else + level = wp - rp; + + if (level < pre_decode_buf_level) { + hw->not_run_ready++; + return 0; + } + } + + index = find_buffer(hw); + if (index >= DECODE_BUFFER_NUM_MAX) { + hw->buffer_not_ready++; + return 0; + } + hw->not_run_ready = 0; + hw->buffer_not_ready = 0; + + return (unsigned long)(CORE_MASK_VDEC_1 | CORE_MASK_HEVC); +} + +static unsigned char get_data_check_sum + (struct vdec_mpeg12_hw_s *hw, int size) +{ + int jj; + int sum = 0; + u8 *data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + for (jj = 0; jj < size; jj++) + sum += data[jj]; + return sum; +} + +static void run(struct vdec_s *vdec, unsigned long mask, +void (*callback)(struct vdec_s *, void *), + void *arg) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)vdec->private; + int save_reg = READ_VREG(POWER_CTL_VLD); + int size, ret; + /* reset everything except DOS_TOP[1] and APB_CBUS[0]*/ + WRITE_VREG(DOS_SW_RESET0, 0xfffffff0); + WRITE_VREG(DOS_SW_RESET0, 0); + WRITE_VREG(POWER_CTL_VLD, save_reg); + hw->run_count++; + vdec_reset_core(vdec); + hw->vdec_cb_arg = arg; + hw->vdec_cb = callback; + + size = vdec_prepare_input(vdec, &hw->chunk); + if (size < 0) { + hw->input_empty++; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + return; + } + if (input_frame_based(vdec)) { + u8 *data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + if (debug_enable & PRINT_FLAG_VDEC_STATUS + ) { + debug_print(DECODE_ID(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]); + } + if (debug_enable & PRINT_FRAMEBASE_DATA + ) { + int jj; + u8 *data = + ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + for (jj = 0; jj < size; jj++) { + if ((jj & 0xf) == 0) + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + } + + } else + debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: %x %x %x %x %x size 0x%x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_PARSER_REG(PARSER_VIDEO_RP), + READ_PARSER_REG(PARSER_VIDEO_WP), + size); + + + hw->input_empty = 0; + debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "%s,%d, size=%d\n", __func__, __LINE__, size); + vdec_enable_input(vdec); + hw->init_flag = 1; + + if (hw->chunk) + debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "input chunk offset %d, size %d\n", + hw->chunk->offset, hw->chunk->size); + + hw->dec_result = DEC_RESULT_NONE; + + ret = amvdec_vdec_loadmc_buf_ex(VFORMAT_MPEG12, "mmpeg12", vdec, + hw->fw->data, hw->fw->len); + if (ret < 0) { + pr_err("[%d] %s: the %s fw loading failed, err: %x\n", vdec->id, + hw->fw->name, tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + return; + } + + if (vmpeg12_hw_ctx_restore(hw) < 0) { + hw->dec_result = DEC_RESULT_ERROR; + debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "ammvdec_mpeg12: error HW context restore\n"); + vdec_schedule_work(&hw->work); + return; + } + /*wmb();*/ + hw->stat |= STAT_MC_LOAD; + hw->last_vld_level = 0; + start_process_time(hw); + amvdec_start(); + hw->stat |= STAT_VDEC_RUN; + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); +} + +static void reset(struct vdec_s *vdec) +{ + pr_info("ammvdec_mpeg12: reset.\n"); +} + +static int ammvdec_mpeg12_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct vdec_mpeg12_hw_s *hw = NULL; + + pr_info("ammvdec_mpeg12 probe start.\n"); + + if (pdata == NULL) { + pr_info("ammvdec_mpeg12 platform data undefined.\n"); + return -EFAULT; + } + + hw = (struct vdec_mpeg12_hw_s *)devm_kzalloc(&pdev->dev, + sizeof(struct vdec_mpeg12_hw_s), GFP_KERNEL); + if (hw == NULL) { + pr_info("\nammvdec_mpeg12 decoder driver alloc failed\n"); + return -ENOMEM; + } + + pdata->private = hw; + pdata->dec_status = vmmpeg12_dec_status; + pdata->run_ready = run_ready; + pdata->run = run; + pdata->reset = reset; + pdata->irq_handler = vmpeg12_isr; + pdata->threaded_irq_handler = vmpeg12_isr_thread_fn; + pdata->dump_state = vmpeg2_dump_state; + if (pdata->use_vfm_path) { + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + VFM_DEC_PROVIDER_NAME); + hw->frameinfo_enable = 1; + } + else + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + PROVIDER_NAME ".%02x", pdev->id & 0xff); + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vf_provider_ops, pdata); + + platform_set_drvdata(pdev, pdata); + + hw->platform_dev = pdev; + + if (pdata->sys_info) + hw->vmpeg12_amstream_dec_info = *pdata->sys_info; + + if (vmpeg12_init(hw) < 0) { + pr_info("ammvdec_mpeg12 init failed.\n"); + devm_kfree(&pdev->dev, (void *)hw); + return -ENODEV; + } + + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + + /*INIT_WORK(&userdata_push_work, userdata_push_do_work);*/ + return 0; +} + +static int ammvdec_mpeg12_remove(struct platform_device *pdev) + +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *) + (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); + + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + + cancel_work_sync(&hw->work); + cancel_work_sync(&hw->notify_work); + + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + + 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 (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + + pr_info("ammvdec_mpeg12 removed.\n"); + memset(&gvs, 0x0, sizeof(gvs)); + + return 0; +} + +/****************************************/ + +static struct platform_driver ammvdec_mpeg12_driver = { + .probe = ammvdec_mpeg12_probe, + .remove = ammvdec_mpeg12_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif + .driver = { + .name = DRIVER_NAME, + } +}; + +static struct codec_profile_t ammvdec_mpeg12_profile = { + .name = "mmpeg12", + .profile = "" +}; + +static struct mconfig mmpeg12_configs[] = { + MC_PU32("stat", &stat), + MC_PU32("radr", &radr), + MC_PU32("rval", &rval), + MC_PU32("dec_control", &dec_control), + MC_PU32("error_frame_skip_level", &error_frame_skip_level), + MC_PU32("decode_timeout_val", &decode_timeout_val), +}; +static struct mconfig_node mmpeg12_node; + +static int __init ammvdec_mpeg12_driver_init_module(void) +{ + pr_info("ammvdec_mpeg12 module init\n"); + + if (platform_driver_register(&ammvdec_mpeg12_driver)) { + pr_info("failed to register ammvdec_mpeg12 driver\n"); + return -ENODEV; + } + vcodec_profile_register(&ammvdec_mpeg12_profile); + INIT_REG_NODE_CONFIGS("media.decoder", &mmpeg12_node, + "mmpeg12", mmpeg12_configs, CONFIG_FOR_RW); + return 0; +} + +static void __exit ammvdec_mpeg12_driver_remove_module(void) +{ + pr_info("ammvdec_mpeg12 module exit.\n"); + platform_driver_unregister(&ammvdec_mpeg12_driver); +} + +/****************************************/ +module_param(dec_control, uint, 0664); +MODULE_PARM_DESC(dec_control, "\n ammvdec_mpeg12 decoder control\n"); +module_param(error_frame_skip_level, uint, 0664); +MODULE_PARM_DESC(error_frame_skip_level, + "\n ammvdec_mpeg12 error_frame_skip_level\n"); + +module_param(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_param(debug_enable, uint, 0664); +MODULE_PARM_DESC(debug_enable, + "\n ammvdec_mpeg12 debug enable\n"); +module_param(pre_decode_buf_level, int, 0664); +MODULE_PARM_DESC(pre_decode_buf_level, + "\n ammvdec_mpeg12 pre_decode_buf_level\n"); +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mpeg12 decode_timeout_val\n"); + +module_param_array(max_process_time, uint, &max_decode_instance_num, 0664); + +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n ammvdec_mpeg12 udebug_flag\n"); + +module_init(ammvdec_mpeg12_driver_init_module); +module_exit(ammvdec_mpeg12_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC MULTI MPEG1/2 Video Decoder Driver"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c index 4e97dde..063cae1 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c @@ -32,9 +32,8 @@ #include <linux/amlogic/media/vfm/vframe_receiver.h> #include <linux/amlogic/media/canvas/canvas.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> - +#include <linux/amlogic/tee.h> #include <linux/amlogic/media/utils/vdec_reg.h> -#include "vmpeg4.h" #include <linux/amlogic/media/registers/register.h> #include "../../../stream_input/amports/amports_priv.h" @@ -42,7 +41,10 @@ #include "../utils/vdec_input.h" #include "../utils/vdec.h" #include "../utils/firmware.h" -#include <linux/amlogic/tee.h> +#include "../utils/decoder_mmu_box.h" +#include "../utils/decoder_bmmu_box.h" +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../utils/firmware.h" #define DRIVER_NAME "ammvdec_mpeg4" #define MODULE_NAME "ammvdec_mpeg4" @@ -90,6 +92,9 @@ #define VF_POOL_SIZE 16 #define DECODE_BUFFER_NUM_MAX 4 #define PUT_INTERVAL (HZ/100) +#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1) +#define WORKSPACE_SIZE (12*SZ_64K) +static u32 buf_size = 32 * 1024 * 1024; #define CTX_LMEM_SWAP_OFFSET 0 #define CTX_QUANT_MATRIX_OFFSET 0x800 @@ -100,6 +105,7 @@ #define RATE_DETECT_COUNT 5 #define DURATION_UNIT 96000 #define PTS_UNIT 90000 +#define CHECK_INTERVAL (HZ/100) #define DUR2PTS(x) ((x) - ((x) >> 4)) @@ -107,17 +113,69 @@ #define DEC_RESULT_DONE 1 #define DEC_RESULT_AGAIN 2 #define DEC_RESULT_ERROR 3 +#define DEC_RESULT_FORCE_EXIT 4 +#define DEC_RESULT_EOS 5 +#define DEC_DECODE_TIMEOUT 0x21 +#define DECODE_ID(hw) (hw_to_vdec(hw)->id) +#define DECODE_STOP_POS AV_SCRATCH_K +static u32 udebug_flag; static struct vframe_s *vmpeg_vf_peek(void *); static struct vframe_s *vmpeg_vf_get(void *); static void vmpeg_vf_put(struct vframe_s *, void *); static int vmpeg_vf_states(struct vframe_states *states, void *); static int vmpeg_event_cb(int type, void *data, void *private_data); +static int pre_decode_buf_level = 0x800; +static int debug_enable; +static unsigned int radr; +static unsigned int rval; + +#define VMPEG4_DEV_NUM 9 +static unsigned int max_decode_instance_num = VMPEG4_DEV_NUM; +static unsigned int max_process_time[VMPEG4_DEV_NUM]; +static unsigned int decode_timeout_val = 100; + + +#undef pr_info +#define pr_info printk +unsigned int mpeg4_debug_mask = 0xff; + +#define PRINT_FLAG_ERROR 0x0 +#define PRINT_FLAG_RUN_FLOW 0X0001 +#define PRINT_FLAG_TIMEINFO 0x0002 +#define PRINT_FLAG_UCODE_DETAIL 0x0004 +#define PRINT_FLAG_VLD_DETAIL 0x0008 +#define PRINT_FLAG_DEC_DETAIL 0x0010 +#define PRINT_FLAG_BUFFER_DETAIL 0x0020 +#define PRINT_FLAG_RESTORE 0x0040 +#define PRINT_FRAME_NUM 0x0080 +#define PRINT_FLAG_FORCE_DONE 0x0100 +#define PRINT_FLAG_COUNTER 0X0200 +#define PRINT_FRAMEBASE_DATA 0x0400 +#define PRINT_FLAG_VDEC_STATUS 0x0800 +#define PRINT_FLAG_TIMEOUT_STATUS 0x1000 + +int mmpeg4_debug_print(int index, int debug_flag, const char *fmt, ...) +{ + if (((debug_enable & debug_flag) && + ((1 << index) & mpeg4_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) { + unsigned char buf[512]; + int len = 0; + va_list args; + va_start(args, fmt); + len = sprintf(buf, "%d: ", index); + vsnprintf(buf + len, 512-len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} struct vdec_mpeg4_hw_s { spinlock_t lock; struct platform_device *platform_dev; - struct device *cma_dev; + /* struct device *cma_dev; */ DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); @@ -141,13 +199,22 @@ struct vdec_mpeg4_hw_s { u32 reg_iqidct_control; u32 reg_resync_marker_length; u32 reg_rv_ai_mb_count; + struct timer_list check_timer; + u32 decode_timeout_count; + u32 start_process_time; + u32 last_vld_level; + u8 init_flag; + u32 eos; + void *mm_blk_handle; struct vframe_chunk_s *chunk; u32 stat; - u32 buf_start; + unsigned long buf_start; u32 buf_size; + /* unsigned long cma_alloc_addr; int cma_alloc_count; + */ u32 vmpeg4_ratio; u64 vmpeg4_ratio64; u32 rate_detect; @@ -164,7 +231,7 @@ struct vdec_mpeg4_hw_s { u32 pts_missed; u32 pts_i_hit; u32 pts_i_missed; - + u32 decoded_type[DECODE_BUFFER_NUM_MAX]; u32 buffer_info[DECODE_BUFFER_NUM_MAX]; u32 pts[DECODE_BUFFER_NUM_MAX]; u64 pts64[DECODE_BUFFER_NUM_MAX]; @@ -183,6 +250,19 @@ struct vdec_mpeg4_hw_s { void (*vdec_cb)(struct vdec_s *, void *); void *vdec_cb_arg; + u32 frame_num; + u32 put_num; + u32 sys_mp4_rate; + u32 run_count; + u32 not_run_ready; + u32 buffer_not_ready; + u32 input_empty; + u32 peek_num; + u32 get_num; + u32 first_i_frame_ready; + u32 drop_frame_count; + u32 timeout_flag; + struct firmware_s *fw; }; static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw); @@ -213,6 +293,7 @@ static unsigned char aspect_ratio_table[16] = { PARC_RESERVED, PARC_EXTENDED }; +static void reset_process_time(struct vdec_mpeg4_hw_s *hw); static int find_buffer(struct vdec_mpeg4_hw_s *hw) { int i; @@ -222,7 +303,7 @@ static int find_buffer(struct vdec_mpeg4_hw_s *hw) return i; } - return -1; + return DECODE_BUFFER_NUM_MAX; } static int spec_to_index(struct vdec_mpeg4_hw_s *hw, u32 spec) @@ -343,7 +424,7 @@ static inline void vmpeg4_save_hw_context(struct vdec_mpeg4_hw_s *hw) hw->reg_rv_ai_mb_count = READ_VREG(RV_AI_MB_COUNT); } -static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) +static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) { u32 reg; struct vframe_s *vf = NULL; @@ -355,23 +436,42 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) u32 time_increment_resolution, fixed_vop_rate, vop_time_inc; u32 repeat_cnt, duration = 3200; struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)(vdec->private); + if (hw->eos) + return IRQ_HANDLED; WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - + if (READ_VREG(AV_SCRATCH_M) != 0 && + (debug_enable & PRINT_FLAG_UCODE_DETAIL)) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_UCODE_DETAIL, + "dbg %x: %x, level %x, wp %x, rp %x, cnt %x\n", + READ_VREG(AV_SCRATCH_M), READ_VREG(AV_SCRATCH_N), + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VIFF_BIT_CNT)); + WRITE_VREG(AV_SCRATCH_M, 0); + return IRQ_HANDLED; + } reg = READ_VREG(MREG_BUFFEROUT); time_increment_resolution = READ_VREG(MP4_RATE); fixed_vop_rate = time_increment_resolution >> 16; time_increment_resolution &= 0xffff; - + if (time_increment_resolution > 0 && fixed_vop_rate == 0) + hw->sys_mp4_rate = time_increment_resolution; if (hw->vmpeg4_amstream_dec_info.rate == 0) { if ((fixed_vop_rate != 0) && (time_increment_resolution != 0)) { /* fixed VOP rate */ hw->vmpeg4_amstream_dec_info.rate = fixed_vop_rate * - DURATION_UNIT / - time_increment_resolution; - } + DURATION_UNIT / time_increment_resolution; + } else if (time_increment_resolution == 0 + && hw->sys_mp4_rate > 0) + time_increment_resolution = hw->sys_mp4_rate; } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "resolution=%d,fvop=%d,rate=%d\n", + time_increment_resolution, fixed_vop_rate, + hw->vmpeg4_amstream_dec_info.rate); if (reg == 2) { /* timeout when decoding next frame */ @@ -380,15 +480,24 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) * at the beginning when only VOL head is available save * HW context also, such as for the QTable from VCOP register */ - if (input_frame_based(vdec)) + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "ammvdec_mpeg4: timeout\n"); + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL, + "level=%x, vtl=%x,bcnt=%d\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_CONTROL), + READ_VREG(VIFF_BIT_CNT)); + if (input_frame_based(vdec)) { vmpeg4_save_hw_context(hw); - + hw->timeout_flag++; + } else { hw->dec_result = DEC_RESULT_AGAIN; schedule_work(&hw->work); - + } return IRQ_HANDLED; } else { + reset_process_time(hw); picture_type = (reg >> 3) & 7; repeat_cnt = READ_VREG(MP4_NOT_CODED_CNT); vop_time_inc = READ_VREG(MP4_VOP_TIME_INC); @@ -396,42 +505,30 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) index = spec_to_index(hw, READ_VREG(REC_CANVAS_ADDR)); if (index < 0) { - pr_err("invalid buffer index."); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "invalid buffer index."); hw->dec_result = DEC_RESULT_ERROR; schedule_work(&hw->work); return IRQ_HANDLED; } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, + "index=%d, used=%d cnt=%d, vopinc=%d\n", + index, hw->vfbuf_use[index], repeat_cnt, vop_time_inc); hw->dec_result = DEC_RESULT_DONE; - pr_debug("amvdec_mpeg4: offset = 0x%x\n", - READ_VREG(MP4_OFFSET_REG)); - if (hw->vmpeg4_amstream_dec_info.width == 0) { hw->vmpeg4_amstream_dec_info.width = READ_VREG(MP4_PIC_WH) >> 16; } -#if 0 - else { - pr_info("info width = %d, ucode width = %d\n", - hw->vmpeg4_amstream_dec_info.width, - READ_VREG(MP4_PIC_WH) >> 16); - } -#endif if (hw->vmpeg4_amstream_dec_info.height == 0) { hw->vmpeg4_amstream_dec_info.height = READ_VREG(MP4_PIC_WH) & 0xffff; } -#if 0 - else { - pr_info("info height = %d, ucode height = %d\n", - hw->vmpeg4_amstream_dec_info.height, - READ_VREG(MP4_PIC_WH) & 0xffff); - } -#endif + if (hw->vmpeg4_amstream_dec_info.rate == 0) { if (vop_time_inc < hw->last_vop_time_inc) { duration = vop_time_inc + @@ -444,7 +541,8 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) if (duration == hw->last_duration) { hw->rate_detect++; - if ((hw->rate_detect >= RATE_DETECT_COUNT) && (time_increment_resolution != 0)) { + if ((hw->rate_detect >= RATE_DETECT_COUNT) && + (time_increment_resolution != 0)) { hw->vmpeg4_amstream_dec_info.rate = duration * DURATION_UNIT / time_increment_resolution; @@ -464,8 +562,8 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) #endif } - if ((picture_type == I_PICTURE) || - (picture_type == P_PICTURE)) { + if ((I_PICTURE == picture_type) || + (P_PICTURE == picture_type)) { offset = READ_VREG(MP4_OFFSET_REG); if (hw->chunk) { hw->pts_valid[index] = hw->chunk->pts_valid; @@ -484,9 +582,10 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) hw->pts_missed++; } } - pr_debug("I/P offset 0x%x, pts_valid %d pts=0x%x\n", + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "I/P offset 0x%x, pts_valid %d pts=0x%x,index=%d,used=%d\n", offset, hw->pts_valid[index], - hw->pts[index]); + hw->pts[index], index, hw->vfbuf_use[index]); } else { hw->pts_valid[index] = false; hw->pts[index] = 0; @@ -495,11 +594,13 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) hw->buffer_info[index] = reg; hw->vfbuf_use[index] = 0; - - pr_debug("amvdec_mpeg4: decoded buffer %d, frame_type %s\n", + hw->decoded_type[index] = picture_type; + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "amvdec_mpeg4: decoded buffer %d, frame_type %s,pts=%x\n", index, (picture_type == I_PICTURE) ? "I" : - (picture_type == P_PICTURE) ? "P" : "B"); + (picture_type == P_PICTURE) ? "P" : "B", + hw->pts[index]); /* Buffer management * todo: add sequence-end flush @@ -542,15 +643,20 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) pts = hw->pts[index]; pts_us64 = hw->pts64[index]; - pr_debug("queued buffer %d, pts = 0x%x, pts_valid=%d\n", - index, pts, pts_valid); + if ((hw->first_i_frame_ready == 0) && + (I_PICTURE == hw->decoded_type[index])) + hw->first_i_frame_ready = 1; + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "queued %d, pts = 0x%x, pts_valid=%d,index=%d,used=%d,type=%d,decode_type=%d\n", + index, pts, pts_valid, index, hw->vfbuf_use[index], + picture_type, hw->decoded_type[index]); if (pts_valid) { hw->last_anch_pts = pts; hw->last_anch_pts_us64 = pts_us64; hw->frame_num_since_last_anch = 0; hw->vop_time_inc_since_last_anch = 0; - } else { + } else if (input_stream_based(vdec)) { pts = hw->last_anch_pts; pts_us64 = hw->last_anch_pts_us64; @@ -607,8 +713,8 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) if (reg & INTERLACE_FLAG) { /* interlace */ if (kfifo_get(&hw->newframe_q, &vf) == 0) { - pr_err - ("fatal error, no available buffer slot."); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "fatal error, no available buffer slot."); return IRQ_HANDLED; } @@ -631,15 +737,29 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) set_frame_info(hw, vf, index); hw->vfbuf_use[index]++; - - kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "pts0=%d,pts64=%lld,w%d,h%d,dur:%d\n", + vf->pts, vf->pts_us64, + vf->width, vf->height, + vf->duration); + if ((hw->first_i_frame_ready == 0) + && (picture_type != I_PICTURE)) { + hw->drop_frame_count++; + hw->vfbuf_use[index]--; + + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - + } if (kfifo_get(&hw->newframe_q, &vf) == 0) { - pr_err("fatal error, no available buffer slot."); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "fatal error, no available buffer slot."); hw->dec_result = DEC_RESULT_ERROR; schedule_work(&hw->work); return IRQ_HANDLED; @@ -665,16 +785,30 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) set_frame_info(hw, vf, index); hw->vfbuf_use[index]++; - - kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "pts1=%d,pts64=%lld,w%d,h%d,dur:%d\n", + vf->pts, vf->pts_us64, + vf->width, vf->height, + vf->duration); + if ((hw->first_i_frame_ready == 0) + && (picture_type != I_PICTURE)) { + hw->drop_frame_count++; + hw->vfbuf_use[index]--; + + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - + } } else { /* progressive */ if (kfifo_get(&hw->newframe_q, &vf) == 0) { - pr_err("fatal error, no available buffer slot."); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "fatal error, no available buffer slot."); return IRQ_HANDLED; } @@ -698,14 +832,33 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) #endif set_frame_info(hw, vf, index); - hw->vfbuf_use[index]++; - - kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, + "pts=%d,pts64=%lld,w%d,h%d,index=%d,used=%d,dur:%d, flag=%d, type=%d\n", + vf->pts, vf->pts_us64, + vf->width, vf->height, + index, hw->vfbuf_use[index], + vf->duration, + hw->timeout_flag, picture_type); + if ((hw->first_i_frame_ready == 0) + && (picture_type != I_PICTURE)) { + hw->drop_frame_count++; + hw->vfbuf_use[index]--; + hw->timeout_flag++; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } else { + if (hw->timeout_flag > 2) + hw->timeout_flag = 2; + if (hw->timeout_flag && input_frame_based(vdec)) + vf->duration = duration * (hw->timeout_flag + 1); + kfifo_put(&hw->display_q, + (const struct vframe_s *)vf); + hw->frame_num++; + hw->timeout_flag = 0; + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } hw->total_frame += repeat_cnt + 1; @@ -713,10 +866,40 @@ static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) schedule_work(&hw->work); } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "%s:frame num:%d\n", __func__, hw->frame_num); return IRQ_HANDLED; } +static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq) +{ + u32 time_increment_resolution, fixed_vop_rate; + struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)(vdec->private); + + if (hw->eos) + return IRQ_HANDLED; + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + time_increment_resolution = READ_VREG(MP4_RATE); + fixed_vop_rate = time_increment_resolution >> 16; + time_increment_resolution &= 0xffff; + if (time_increment_resolution > 0 && fixed_vop_rate == 0) + hw->sys_mp4_rate = time_increment_resolution; + if (hw->vmpeg4_amstream_dec_info.rate == 0) { + if ((fixed_vop_rate != 0) && (time_increment_resolution != 0)) { + hw->vmpeg4_amstream_dec_info.rate = fixed_vop_rate * + DURATION_UNIT / + time_increment_resolution; + } else if (time_increment_resolution == 0 + && hw->sys_mp4_rate > 0) + time_increment_resolution = hw->sys_mp4_rate; + } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "resolution=%d,fvop=%d,rate=%d\n", + time_increment_resolution, fixed_vop_rate, + hw->vmpeg4_amstream_dec_info.rate); + return IRQ_WAKE_THREAD; +} static void vmpeg4_work(struct work_struct *work) { struct vdec_mpeg4_hw_s *hw = @@ -725,7 +908,10 @@ static void vmpeg4_work(struct work_struct *work) /* finished decoding one frame or error, * notify vdec core to switch context */ - amvdec_stop(); + if (hw->dec_result != DEC_RESULT_DONE) + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "mmpeg4: vmpeg_work,result=%d,status=%d\n", + hw->dec_result, hw_to_vdec(hw)->next_status); if ((hw->dec_result == DEC_RESULT_DONE) || ((hw->chunk) && @@ -734,7 +920,47 @@ static void vmpeg4_work(struct work_struct *work) hw->ctx_valid = 1; vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + } else if (hw->dec_result == DEC_RESULT_AGAIN + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + /* + stream base: stream buf empty or timeout + frame base: vdec_prepare_input fail + */ + if (!vdec_has_more_input(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + /*pr_info("%s: return\n", + __func__);*/ + return; + } + } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s: force exit\n", __func__); + if (hw->stat & STAT_ISR_REG) { + amvdec_stop(); + /*disable mbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + } else if (hw->dec_result == DEC_RESULT_EOS) { + /*pr_info("%s: end of stream\n", + __func__);*/ + hw->eos = 1; + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); + } + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; } + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; /* mark itself has all HW resource released and input released */ vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); @@ -751,7 +977,7 @@ static struct vframe_s *vmpeg_vf_peek(void *op_arg) if (!hw) return NULL; - + hw->peek_num++; if (kfifo_peek(&hw->display_q, &vf)) return vf; @@ -763,7 +989,7 @@ static struct vframe_s *vmpeg_vf_get(void *op_arg) struct vframe_s *vf; struct vdec_s *vdec = op_arg; struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; - + hw->get_num++; if (kfifo_get(&hw->display_q, &vf)) return vf; @@ -776,7 +1002,13 @@ static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg) struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; hw->vfbuf_use[vf->index]--; - + hw->put_num++; + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM, + "%s:put num:%d\n", + __func__, hw->put_num); + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, + "index=%d, used=%d\n", + vf->index, hw->vfbuf_use[vf->index]); kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); } @@ -825,85 +1057,285 @@ static int dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) /****************************************/ static int vmpeg4_canvas_init(struct vdec_mpeg4_hw_s *hw) { - int i; + int i, ret; + u32 canvas_width, canvas_height; u32 decbuf_size, decbuf_y_size; struct vdec_s *vdec = hw_to_vdec(hw); - u32 decbuf_start; - - int w = hw->vmpeg4_amstream_dec_info.width; - int h = hw->vmpeg4_amstream_dec_info.height; - - if (w == 0) - w = 1920; - if (h == 0) - h = 1088; - - w = ALIGN(w, 64); - h = ALIGN(h, 64); - decbuf_y_size = ALIGN(w * h, SZ_64K); - decbuf_size = ALIGN(w * h * 3/2, SZ_64K); + unsigned long decbuf_start; + + if (buf_size <= 0x00400000) { + /* SD only */ + canvas_width = 768; + canvas_height = 576; + decbuf_y_size = 0x80000; + decbuf_size = 0x100000; + } else { + int w = hw->vmpeg4_amstream_dec_info.width; + int h = hw->vmpeg4_amstream_dec_info.height; + int align_w, align_h; + int max, min; + if (w == 0) + w = 1920; + if (h == 0) + h = 1088; + align_w = ALIGN(w, 64); + align_h = ALIGN(h, 64); + if (align_w > align_h) { + max = align_w; + min = align_h; + } else { + max = align_h; + min = align_w; + } + /* HD & SD */ + if ((max > 1920 || min > 1088) && + ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <= + buf_size) { + canvas_width = align_w; + canvas_height = align_h; + decbuf_y_size = + ALIGN(align_w * align_h, SZ_64K); + decbuf_size = + ALIGN(align_w * align_h * 3/2, SZ_64K); + } else { /*1080p*/ + if (h > w) { + canvas_width = 1088; + canvas_height = 1920; + } else { + canvas_width = 1920; + canvas_height = 1088; + } + decbuf_y_size = 0x200000; + decbuf_size = 0x300000; + } + } - decbuf_start = hw->buf_start + CTX_DECBUF_OFFSET; + for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) { + + unsigned canvas; + if (i == (MAX_BMMU_BUFFER_NUM - 1)) + decbuf_size = WORKSPACE_SIZE; + ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, + decbuf_size, DRIVER_NAME, &decbuf_start); + if (ret < 0) { + pr_err("mmu alloc failed! size 0x%d idx %d\n", + decbuf_size, i); + return ret; + } - for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { -#ifdef NV21 - unsigned int canvas = vdec->get_canvas(i, 2); -#else - unsigned int canvas = vdec->get_canvas(i, 3); -#endif + if (i == (MAX_BMMU_BUFFER_NUM - 1)) { + hw->buf_start = decbuf_start; + } else { + canvas = vdec->get_canvas(i, 2); hw->canvas_spec[i] = canvas; -#ifdef NV21 - hw->canvas_config[i][0].phy_addr = decbuf_start + - i * decbuf_size; - hw->canvas_config[i][0].width = w; - hw->canvas_config[i][0].height = h; - hw->canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32; + hw->canvas_config[i][0].phy_addr = + decbuf_start; + hw->canvas_config[i][0].width = + canvas_width; + hw->canvas_config[i][0].height = + canvas_height; + hw->canvas_config[i][0].block_mode = + CANVAS_BLKMODE_32X32; canvas_config_config(canvas_y(canvas), &hw->canvas_config[i][0]); - hw->canvas_config[i][1].phy_addr = decbuf_start + - i * decbuf_size + decbuf_y_size; - hw->canvas_config[i][1].width = w; - hw->canvas_config[i][1].height = h / 2; - hw->canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32; + hw->canvas_config[i][1].phy_addr = + decbuf_start + decbuf_y_size; + hw->canvas_config[i][1].width = + canvas_width; + hw->canvas_config[i][1].height = + canvas_height / 2; + hw->canvas_config[i][1].block_mode = + CANVAS_BLKMODE_32X32; canvas_config_config(canvas_u(canvas), &hw->canvas_config[i][1]); -#else - hw->canvas_config[i][0].phy_addr = decbuf_start + - i * decbuf_size; - hw->canvas_config[i][0].width = w; - hw->canvas_config[i][0].height = h; - hw->canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32; + } + } - canvas_config_config(canvas_y(canvas), - &hw->canvas_config[i][0]); + return 0; +} +static void vmpeg4_dump_state(struct vdec_s *vdec) +{ + struct vdec_mpeg4_hw_s *hw = + (struct vdec_mpeg4_hw_s *)(vdec->private); + u32 i; + mmpeg4_debug_print(DECODE_ID(hw), 0, + "====== %s\n", __func__); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "width/height (%d/%d), i_fram:%d, buffer_not_ready %d\n", + hw->vmpeg4_amstream_dec_info.width, + hw->vmpeg4_amstream_dec_info.height, + hw->first_i_frame_ready, + hw->buffer_not_ready + ); + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + mmpeg4_debug_print(DECODE_ID(hw), 0, + "index %d, used %d\n", i, hw->vfbuf_use[i]); + } - hw->canvas_config[i][1].phy_addr = decbuf_start + - i * decbuf_size + decbuf_y_size; - hw->canvas_config[i][1].width = w / 2; - hw->canvas_config[i][1].height = h / 2; - hw->canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32; + mmpeg4_debug_print(DECODE_ID(hw), 0, + "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d\n", + input_frame_based(vdec), + hw->eos, + hw->stat, + hw->dec_result, + hw->frame_num + ); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "is_framebase(%d), put_frm %d run %d not_run_ready %d input_empty %d,drop %d\n", + input_frame_based(vdec), + hw->put_num, + hw->run_count, + hw->not_run_ready, + hw->input_empty, + hw->drop_frame_count + ); + + if (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); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + mmpeg4_debug_print(DECODE_ID(hw), 0, + "%s, newq(%d/%d), dispq(%d/%d) vf peek/get/put (%d/%d/%d)\n", + __func__, + kfifo_len(&hw->newframe_q), + VF_POOL_SIZE, + kfifo_len(&hw->display_q), + VF_POOL_SIZE, + hw->peek_num, + hw->get_num, + hw->put_num + ); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "VIFF_BIT_CNT=0x%x\n", + READ_VREG(VIFF_BIT_CNT)); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_LEVEL=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_WP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_RP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_RP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_RP)); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_WP=0x%x\n", + READ_PARSER_REG(PARSER_VIDEO_WP)); + if (input_frame_based(vdec) && + debug_enable & PRINT_FRAMEBASE_DATA + ) { + int jj; + if (hw->chunk && hw->chunk->block && + hw->chunk->size > 0) { + u8 *data = + ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + mmpeg4_debug_print(DECODE_ID(hw), 0, + "frame data size 0x%x\n", + hw->chunk->size); + for (jj = 0; jj < hw->chunk->size; jj++) { + if ((jj & 0xf) == 0) + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + } + } +} - canvas_config_config(canvas_u(canvas), - &hw->canvas_config[i][1]); - hw->canvas_config[i][2].phy_addr = decbuf_start + - i * decbuf_size + decbuf_y_size + - decbuf_uv_size; - hw->canvas_config[i][2].width = w / 2; - hw->canvas_config[i][2].height = h / 2; - hw->canvas_config[i][2].block_mode = CANVAS_BLKMODE_32X32; +static void reset_process_time(struct vdec_mpeg4_hw_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[DECODE_ID(hw)]) + max_process_time[DECODE_ID(hw)] = process_time; + } +} +static void start_process_time(struct vdec_mpeg4_hw_s *hw) +{ + hw->decode_timeout_count = 2; + hw->start_process_time = jiffies; +} - canvas_config_config(canvas_v(canvas), - &hw->canvas_config[i][2]); -#endif +static void timeout_process(struct vdec_mpeg4_hw_s *hw) +{ + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEOUT_STATUS, + "%s decoder timeout\n", __func__); + reset_process_time(hw); + hw->first_i_frame_ready = 0; + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); +} - return 0; + +static void check_timer_func(unsigned long arg) +{ + struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)arg; + struct vdec_s *vdec = hw_to_vdec(hw); + unsigned int timeout_val = decode_timeout_val; + + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + + if (debug_enable == 0 && + (input_frame_based(vdec) || + (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x100)) && + (timeout_val > 0) && + (hw->start_process_time > 0) && + ((1000 * (jiffies - hw->start_process_time) / HZ) + > timeout_val)) { + if (hw->last_vld_level == READ_VREG(VLD_MEM_VIFIFO_LEVEL)) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + timeout_process(hw); + } + hw->last_vld_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); + } + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "vdec requested to be disconnected\n"); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + return; + } + + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); } static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw) @@ -941,11 +1373,12 @@ static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw) WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]); WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]); - pr_debug("vmpeg4_hw_ctx_restore ref0=0x%x, ref1=0x%x, rec=0x%x, ctx_valid=%d\n", + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE, + "restore ref0=0x%x, ref1=0x%x, rec=0x%x, ctx_valid=%d,index=%d\n", READ_VREG(MREG_REF0), READ_VREG(MREG_REF1), READ_VREG(REC_CANVAS_ADDR), - hw->ctx_valid); + hw->ctx_valid, index); /* notify ucode the buffer start address */ WRITE_VREG(MEM_OFFSET_REG, hw->buf_start); @@ -1013,7 +1446,7 @@ static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw) hw->vmpeg4_rotation = (((unsigned long) hw->vmpeg4_amstream_dec_info.param) >> 16) & 0xffff; - + hw->sys_mp4_rate = hw->vmpeg4_amstream_dec_info.rate; hw->frame_width = hw->frame_height = hw->frame_dur = hw->frame_prog = 0; hw->total_frame = 0; @@ -1027,8 +1460,21 @@ static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw) hw->vop_time_inc_since_last_anch = 0; hw->frame_num_since_last_anch = 0; + hw->frame_num = 0; + hw->put_num = 0; + hw->run_count = 0; + hw->not_run_ready = 0; + hw->input_empty = 0; + hw->peek_num = 0; + hw->get_num = 0; hw->pts_hit = hw->pts_missed = hw->pts_i_hit = hw->pts_i_missed = 0; + hw->refs[0] = -1; + hw->refs[1] = -1; + hw->first_i_frame_ready = 0; + hw->drop_frame_count = 0; + hw->buffer_not_ready = 0; + hw->timeout_flag = 0; for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) hw->vfbuf_use[i] = 0; @@ -1042,7 +1488,17 @@ static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw) hw->vfpool[i].index = DECODE_BUFFER_NUM_MAX; kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); } - + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + hw->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); INIT_WORK(&hw->work, vmpeg4_work); } @@ -1058,22 +1514,16 @@ static s32 vmmpeg4_init(struct vdec_mpeg4_hw_s *hw) if (hw->vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_MPEG4_5) { - size = get_firmware_data(VIDEO_DEC_MPEG4_5, fw->data); - strncpy(fw->name, "vmpeg4_mc_5", sizeof(fw->name)); - - pr_info("load VIDEO_DEC_FORMAT_MPEG4_5\n"); + size = get_firmware_data(VIDEO_DEC_MPEG4_5_MULTI, fw->data); + strncpy(fw->name, "mmpeg4_mc_5", sizeof(fw->name)); } else if (hw->vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_H263) { - size = get_firmware_data(VIDEO_DEC_H263, fw->data); - strncpy(fw->name, "h263_mc", sizeof(fw->name)); - - pr_info("load VIDEO_DEC_FORMAT_H263\n"); - } else - pr_info("not supported MPEG4 format %d\n", - hw->vmpeg4_amstream_dec_info.format); - + size = get_firmware_data(VIDEO_DEC_H263_MULTI, fw->data); + strncpy(fw->name, "mh263_mc", sizeof(fw->name)); + } + pr_info("mmpeg4 get fw %s, size %x\n", fw->name, size); if (size < 0) { - pr_err("get firmware fail."); + pr_err("get firmware failed."); vfree(fw); return -1; } @@ -1087,7 +1537,16 @@ static s32 vmmpeg4_init(struct vdec_mpeg4_hw_s *hw) amvdec_enable(); + init_timer(&hw->check_timer); + hw->check_timer.data = (unsigned long)hw; + hw->check_timer.function = check_timer_func; + hw->check_timer.expires = jiffies + CHECK_INTERVAL; + hw->stat |= STAT_TIMER_ARM; + hw->eos = 0; + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + vmpeg4_local_init(hw); + wmb(); return 0; } @@ -1096,10 +1555,45 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { int index; struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; + if (hw->eos) + return 0; + if (vdec_stream_based(vdec) && (hw->init_flag == 0) + && pre_decode_buf_level != 0) { + u32 rp, wp, level; + + rp = READ_PARSER_REG(PARSER_VIDEO_RP); + wp = READ_PARSER_REG(PARSER_VIDEO_WP); + if (wp < rp) + level = vdec->input.size + wp - rp; + else + level = wp - rp; + if (level < pre_decode_buf_level) { + hw->not_run_ready++; + return 0; + } + } index = find_buffer(hw); + if (index >= DECODE_BUFFER_NUM_MAX) { + hw->buffer_not_ready++; + return 0; + } + hw->not_run_ready = 0; + hw->buffer_not_ready = 0; - return (index >= 0) ? (CORE_MASK_VDEC_1 | CORE_MASK_HEVC) : 0; + return (unsigned long)(CORE_MASK_VDEC_1 | CORE_MASK_HEVC); +} + +static unsigned char get_data_check_sum + (struct vdec_mpeg4_hw_s *hw, int size) +{ + int jj; + int sum = 0; + u8 *data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + for (jj = 0; jj < size; jj++) + sum += data[jj]; + return sum; } static void run(struct vdec_s *vdec, unsigned long mask, @@ -1107,8 +1601,9 @@ static void run(struct vdec_s *vdec, unsigned long mask, { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; int save_reg = READ_VREG(POWER_CTL_VLD); - int ret = -1; + int size, ret = 0; + hw->run_count++; /* reset everything except DOS_TOP[1] and APB_CBUS[0] */ WRITE_VREG(DOS_SW_RESET0, 0xfffffff0); WRITE_VREG(DOS_SW_RESET0, 0); @@ -1116,47 +1611,120 @@ static void run(struct vdec_s *vdec, unsigned long mask, hw->vdec_cb_arg = arg; hw->vdec_cb = callback; - - ret = vdec_prepare_input(vdec, &hw->chunk); - if (ret < 0) { - pr_debug("amvdec_mmpeg4: Input not ready\n"); + vdec_reset_core(vdec); + size = vdec_prepare_input(vdec, &hw->chunk); + if (size < 0) { + hw->input_empty++; hw->dec_result = DEC_RESULT_AGAIN; schedule_work(&hw->work); return; } - vdec_enable_input(vdec); + if (input_frame_based(vdec)) { + u8 *data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + if (debug_enable & PRINT_FLAG_VDEC_STATUS + ) { + mmpeg4_debug_print(DECODE_ID(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]); + } + if (debug_enable & PRINT_FRAMEBASE_DATA + ) { + int jj; + u8 *data = + ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + for (jj = 0; jj < size; jj++) { + if ((jj & 0xf) == 0) + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + mmpeg4_debug_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + } - if (hw->chunk) - pr_debug("input chunk offset %d, size %d\n", - hw->chunk->offset, hw->chunk->size); + } else + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: %x %x %x %x %x size 0x%x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_PARSER_REG(PARSER_VIDEO_RP), + READ_PARSER_REG(PARSER_VIDEO_WP), + size); + + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "%s,%d, size=%d, %x %x %x %x %x\n", + __func__, __LINE__, size, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_PARSER_REG(PARSER_VIDEO_RP), + READ_PARSER_REG(PARSER_VIDEO_WP)); hw->dec_result = DEC_RESULT_NONE; ret = amvdec_vdec_loadmc_buf_ex(VFORMAT_MPEG4,hw->fw->name, vdec, hw->fw->data, hw->fw->len); if (ret < 0) { - hw->dec_result = DEC_RESULT_ERROR; - schedule_work(&hw->work); - pr_err("[%d] %s: the %s fw loading failed, err: %x\n", vdec->id, hw->fw->name, tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + schedule_work(&hw->work); return; } if (vmpeg4_hw_ctx_restore(hw) < 0) { hw->dec_result = DEC_RESULT_ERROR; - pr_err("amvdec_mmpeg4: error HW context restore\n"); + mmpeg4_debug_print(DECODE_ID(hw), 0, + "amvdec_mpeg4: error HW context restore\n"); schedule_work(&hw->work); return; } - + hw->input_empty = 0; + hw->last_vld_level = 0; + start_process_time(hw); + vdec_enable_input(vdec); /* wmb before ISR is handled */ wmb(); amvdec_start(); + hw->stat |= STAT_VDEC_RUN; + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); } +static int vmpeg4_stop(struct vdec_mpeg4_hw_s *hw) +{ + cancel_work_sync(&hw->work); + + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + + if (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + return 0; +} static void reset(struct vdec_s *vdec) { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; @@ -1182,7 +1750,7 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) hw = vmalloc(sizeof(struct vdec_mpeg4_hw_s)); if (hw == NULL) { - pr_info("\namvdec_mpeg4 decoder driver alloc failed\n"); + pr_err("\namvdec_mpeg4 decoder driver alloc failed\n"); return -ENOMEM; } memset(hw, 0, sizeof(struct vdec_mpeg4_hw_s)); @@ -1194,7 +1762,8 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) pdata->run = run; pdata->reset = reset; pdata->irq_handler = vmpeg4_isr; - + pdata->threaded_irq_handler = vmpeg4_isr_thread_fn; + pdata->dump_state = vmpeg4_dump_state; if (pdata->use_vfm_path) snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, @@ -1203,14 +1772,14 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, PROVIDER_NAME ".%02x", pdev->id & 0xff); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vf_provider_ops, pdata); + vf_provider_init(&pdata->vframe_provider, + pdata->vf_provider_name, &vf_provider_ops, pdata); platform_set_drvdata(pdev, pdata); - hw->platform_dev = pdev; - hw->cma_dev = pdata->cma_dev; +/* + hw->cma_dev = pdata->cma_dev; hw->cma_alloc_count = PAGE_ALIGN(DEFAULT_MEM_SIZE) / PAGE_SIZE; hw->cma_alloc_addr = codec_mm_alloc_for_dma(MEM_NAME, hw->cma_alloc_count, @@ -1228,16 +1797,26 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) } hw->buf_start = hw->cma_alloc_addr; hw->buf_size = DEFAULT_MEM_SIZE; - +*/ if (pdata->sys_info) hw->vmpeg4_amstream_dec_info = *pdata->sys_info; + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "W:%d,H:%d,rate=%d\n", + hw->vmpeg4_amstream_dec_info.width, + hw->vmpeg4_amstream_dec_info.height, + hw->vmpeg4_amstream_dec_info.rate); + hw->vmpeg4_amstream_dec_info.height = 0; + hw->vmpeg4_amstream_dec_info.width = 0; + if (vmmpeg4_init(hw) < 0) { pr_err("%s init failed.\n", __func__); +/* if (hw->cma_alloc_addr) { codec_mm_free_for_dma(MEM_NAME, hw->cma_alloc_addr); hw->cma_alloc_count = 0; } +*/ if (hw) { vfree((void *)hw); hw = NULL; @@ -1257,27 +1836,23 @@ static int ammvdec_mpeg4_remove(struct platform_device *pdev) (struct vdec_mpeg4_hw_s *) (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); - - vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); - - amvdec_disable(); - + vmpeg4_stop(hw); + /* if (hw->cma_alloc_addr) { pr_info("codec_mm release buffer 0x%lx\n", hw->cma_alloc_addr); codec_mm_free_for_dma(MEM_NAME, hw->cma_alloc_addr); hw->cma_alloc_count = 0; } + */ + vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED); - vfree(hw->fw); - hw->fw = NULL; - if (hw) { - vfree((void *)hw); - hw = NULL; - } pr_info("pts hit %d, pts missed %d, i hit %d, missed %d\n", hw->pts_hit, hw->pts_missed, hw->pts_i_hit, hw->pts_i_missed); pr_info("total frame %d, rate %d\n", hw->total_frame, hw->vmpeg4_amstream_dec_info.rate); + vfree((void *)hw); + hw = NULL; return 0; } @@ -1321,7 +1896,27 @@ static void __exit ammvdec_mpeg4_driver_remove_module(void) } /****************************************/ +module_param(debug_enable, uint, 0664); +MODULE_PARM_DESC(debug_enable, + "\n ammvdec_mpeg4 debug enable\n"); + +module_param(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mpeg4 decode_timeout_val\n"); + +module_param_array(max_process_time, uint, &max_decode_instance_num, 0664); + +module_param(pre_decode_buf_level, int, 0664); +MODULE_PARM_DESC(pre_decode_buf_level, + "\n ammvdec_ mpeg4 pre_decode_buf_level\n"); +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n ammvdec_mpeg4 udebug_flag\n"); module_init(ammvdec_mpeg4_driver_init_module); module_exit(ammvdec_mpeg4_driver_remove_module); diff --git a/drivers/frame_provider/decoder/utils/amvdec.c b/drivers/frame_provider/decoder/utils/amvdec.c index afc813f..e9c097e 100644 --- a/drivers/frame_provider/decoder/utils/amvdec.c +++ b/drivers/frame_provider/decoder/utils/amvdec.c @@ -397,7 +397,10 @@ s32 optee_load_fw(enum vformat_e type, const char *fw_name) break; case VFORMAT_MPEG12: - format = VIDEO_DEC_MPEG12; + if (!strcmp(name, "mpeg12")) + format = VIDEO_DEC_MPEG12; + else if (!strcmp(name, "mmpeg12")) + format = VIDEO_DEC_MPEG12_MULTI; break; case VFORMAT_MJPEG: @@ -434,14 +437,19 @@ s32 optee_load_fw(enum vformat_e type, const char *fw_name) break; case VFORMAT_MPEG4: - if (!strcmp(name, "vmpeg4_mc_311")) - format = VIDEO_DEC_MPEG4_3; - else if (!strcmp(name, "vmpeg4_mc_4")) - format = VIDEO_DEC_MPEG4_4; + if (!strcmp(name, "mmpeg4_mc_5")) + format = VIDEO_DEC_MPEG4_5_MULTI; + else if ((!strcmp(name, "mh263_mc"))) + format = VIDEO_DEC_H263_MULTI; else if (!strcmp(name, "vmpeg4_mc_5")) format = VIDEO_DEC_MPEG4_5; else if (!strcmp(name, "h263_mc")) format = VIDEO_DEC_H263; + /*not support now*/ + else if (!strcmp(name, "vmpeg4_mc_311")) + format = VIDEO_DEC_MPEG4_3; + else if (!strcmp(name, "vmpeg4_mc_4")) + format = VIDEO_DEC_MPEG4_4; break; case VFORMAT_H264_4K2K: @@ -803,6 +811,12 @@ void amvdec_stop(void) break; } + timeout = jiffies + HZ; + while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) { + if (time_after(jiffies, timeout)) + break; + } + /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) { READ_VREG(DOS_SW_RESET0); @@ -876,6 +890,12 @@ void amhevc_stop(void) break; } + timeout = jiffies + HZ; + while (READ_VREG(HEVC_LMEM_DMA_CTRL) & 0x8000) { + if (time_after(jiffies, timeout)) + break; + } + READ_VREG(DOS_SW_RESET3); READ_VREG(DOS_SW_RESET3); READ_VREG(DOS_SW_RESET3); diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 2ad8c3c..3369043 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -1213,7 +1213,7 @@ void vdec_clean_input(struct vdec_s *vdec) while (!list_empty(&input->vframe_chunk_list)) { struct vframe_chunk_s *chunk = vdec_input_next_chunk(input); - if (chunk->flag & VFRAME_CHUNK_FLAG_CONSUMED) + if (chunk && (chunk->flag & VFRAME_CHUNK_FLAG_CONSUMED)) vdec_input_release_chunk(input, chunk); else break; @@ -1372,14 +1372,24 @@ int vdec_disconnect(struct vdec_s *vdec) mutex_unlock(&vdec_mutex); up(&vdec_core->sem); - wait_for_completion(&vdec->inactive_done); + if(!wait_for_completion_timeout(&vdec->inactive_done, + msecs_to_jiffies(2000))) + goto discon_timeout; - if (vdec->slave) - wait_for_completion(&vdec->slave->inactive_done); - else if (vdec->master) - wait_for_completion(&vdec->master->inactive_done); + if (vdec->slave) { + if(!wait_for_completion_timeout(&vdec->slave->inactive_done, + msecs_to_jiffies(2000))) + goto discon_timeout; + } else if (vdec->master) { + if(!wait_for_completion_timeout(&vdec->master->inactive_done, + msecs_to_jiffies(2000))) + goto discon_timeout; + } return 0; +discon_timeout: + pr_err("%s timeout!!! status: 0x%x\n", __func__, vdec->status); + return 0; } EXPORT_SYMBOL(vdec_disconnect); @@ -2021,6 +2031,20 @@ static void vdec_route_interrupt(struct vdec_s *vdec, unsigned long mask, } } +static void vdec_remove_reset(struct vdec_s *vdec) +{ + struct vdec_input_s *input = &vdec->input; + + if (input->target == VDEC_INPUT_TARGET_VLD) { + amvdec_stop(); + vdec_reset_core(vdec); + } else if (input->target == VDEC_INPUT_TARGET_HEVC) { + amhevc_stop(); + hevc_reset_core(vdec); + } + pr_info(" %s vdec %p\n", __func__, vdec); +} + /* * Set up secure protection for each decoder instance running. * Note: The operation from REE side only resets memory access @@ -2102,8 +2126,8 @@ static int vdec_core_thread(void *data) &input->vframe_chunk_list)) { struct vframe_chunk_s *chunk = vdec_input_next_chunk(input); - if (chunk->flag & - VFRAME_CHUNK_FLAG_CONSUMED) + if (chunk && (chunk->flag & + VFRAME_CHUNK_FLAG_CONSUMED)) vdec_input_release_chunk(input, chunk); else @@ -2137,8 +2161,10 @@ static int vdec_core_thread(void *data) &core->connected_vdec_list, list) { if ((vdec->status == VDEC_STATUS_CONNECTED) && (vdec->next_status == VDEC_STATUS_DISCONNECTED)) { - if (core->active_vdec == vdec) + if (core->active_vdec == vdec) { + vdec_remove_reset(vdec); core->active_vdec = NULL; + } list_move(&vdec->list, &disconnecting_list); } } @@ -2773,6 +2799,45 @@ int vdec_source_changed(int format, int width, int height, int fps) } EXPORT_SYMBOL(vdec_source_changed); +void vdec_reset_core(struct vdec_s *vdec) +{ + unsigned long flags; + spin_lock_irqsave(&vdec_spin_lock, flags); + codec_dmcbus_write(DMC_REQ_CTRL, + codec_dmcbus_read(DMC_REQ_CTRL) & (~(1 << 13))); + spin_unlock_irqrestore(&vdec_spin_lock, flags); + + while (!(codec_dmcbus_read(DMC_CHAN_STS) + & (1 << 13))) + ; + /* + * 2: assist + * 3: vld_reset + * 4: vld_part_reset + * 5: vfifo reset + * 6: iqidct + * 7: mc + * 8: dblk + * 9: pic_dc + * 10: psc + * 11: mcpu + * 12: ccpu + * 13: ddr + * 14: afifo + */ + + WRITE_VREG(DOS_SW_RESET0, + (1<<3)|(1<<4)|(1<<5)); + + WRITE_VREG(DOS_SW_RESET0, 0); + + spin_lock_irqsave(&vdec_spin_lock, flags); + codec_dmcbus_write(DMC_REQ_CTRL, + codec_dmcbus_read(DMC_REQ_CTRL) | (1 << 13)); + spin_unlock_irqrestore(&vdec_spin_lock, flags); +} +EXPORT_SYMBOL(vdec_reset_core); + void hevc_reset_core(struct vdec_s *vdec) { unsigned long flags; diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 7bd1832..d3a64aa 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -385,6 +385,8 @@ extern void vdec_count_info(struct vdec_info *vs, unsigned int err, extern bool vdec_need_more_data(struct vdec_s *vdec); +extern void vdec_reset_core(struct vdec_s *vdec); + extern void hevc_reset_core(struct vdec_s *vdec); extern void vdec_set_suspend_clk(int mode, int hevc); diff --git a/drivers/frame_provider/decoder/utils/vdec_input.c b/drivers/frame_provider/decoder/utils/vdec_input.c index 74dcb87..3eb49b3 100644 --- a/drivers/frame_provider/decoder/utils/vdec_input.c +++ b/drivers/frame_provider/decoder/utils/vdec_input.c @@ -802,11 +802,10 @@ int vdec_input_add_frame(struct vdec_input_s *input, const char *buf, /*nopts*/ input->last_in_nopts_cnt++; } - vdec_input_unlock(input, flags); if (chunk->size > input->frame_max_size) input->frame_max_size = chunk->size; input->total_wr_count += count; - + vdec_input_unlock(input, flags); #if 0 if (add_count == 2) input->total_wr_count += 38; diff --git a/drivers/frame_provider/decoder/vp9/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c index a7cabcd..7e469f4 100644 --- a/drivers/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/frame_provider/decoder/vp9/vvp9.c @@ -6998,8 +6998,7 @@ int continue_decoding(struct VP9Decoder_s *pbi) } pbi->process_state = PROC_STATE_DECODESLICE; if (pbi->mmu_enable) { - if (pbi->last_put_idx >= 0 && - pbi->last_put_idx < pbi->used_buf_num) { + if (pbi->last_put_idx < pbi->used_buf_num) { struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs; int i = pbi->last_put_idx; @@ -8663,6 +8662,8 @@ static void run_front(struct vdec_s *vdec) vp9_print(pbi, PRINT_FLAG_ERROR, "VP9: the %s fw loading failed, err: %x\n", tee_enabled() ? "TEE" : "local", ret); + pbi->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&pbi->work); return; } |