From bba22b6d96ecb731f7d00367212449be83551d55 Mon Sep 17 00:00:00 2001 From: miaohong chen Date: Mon, 30 Nov 2020 18:53:48 +0800 Subject: [PATCH] decoder: FCC adds decoder frame drop mode [1/1] PD#SWPL-35624 Problem: Make the cutting stage fast and synchronize audio and video. Solution: Decoder adds drop frame mode. Verify: AH212 Change-Id: I82737adaa5203d50d02615fbab875ea8442f8688 Signed-off-by: miaohong chen --- .../decoder/h264_multi/h264_dpb.h | 1 + .../decoder/h264_multi/vmh264.c | 99 +++++++- drivers/frame_provider/decoder/h265/vh265.c | 92 +++++++- .../decoder/mpeg12/vmpeg12_multi.c | 92 ++++++++ drivers/frame_provider/decoder/utils/vdec.c | 211 ++++++++++++++++- drivers/frame_provider/decoder/utils/vdec.h | 35 +++ drivers/stream_input/amports/amports_priv.h | 2 + drivers/stream_input/amports/amstream.c | 217 +++++++++++++++++- .../stream_input/amports/stream_buffer_base.c | 43 +++- drivers/stream_input/amports/streambuf.h | 3 +- 10 files changed, 772 insertions(+), 23 deletions(-) diff --git a/drivers/frame_provider/decoder/h264_multi/h264_dpb.h b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h index 85ee158..16d9317 100644 --- a/drivers/frame_provider/decoder/h264_multi/h264_dpb.h +++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h @@ -38,6 +38,7 @@ #define RRINT_FLAG_RPM 0x0400 #define DEBUG_DISABLE_RUNREADY_RMBUF 0x0800 #define PRINT_FLAG_DUMP_BUFSPEC 0x1000 +#define PRINT_FLAG_FCC_STATUS 0x2000 #define PRINT_FLAG_V4L_DETAIL 0x8000 #define DISABLE_ERROR_HANDLE 0x10000 #define DEBUG_DUMP_STAT 0x80000 diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c index 7e2fded..43188aa 100644 --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c @@ -554,6 +554,7 @@ static const struct vframe_operations_s vf_provider_ops = { #define DEC_RESULT_EOS 7 #define DEC_RESULT_FORCE_EXIT 8 #define DEC_RESULT_TIMEOUT 9 +#define DEC_RESULT_DISCARD_DATA 10 /* @@ -2901,6 +2902,7 @@ static int post_video_frame(struct vdec_s *vdec, struct FrameStore *frame) if (!hw->enable_fence) hw->buffer_spec[buffer_index].vf_ref = 0; fill_frame_info(hw, frame); + for (i = 0; i < vf_count; i++) { if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { @@ -3119,6 +3121,7 @@ static int post_video_frame(struct vdec_s *vdec, struct FrameStore *frame) hw->buffer_spec[buffer_index].aux_data_buf, hw->buffer_spec[buffer_index].aux_data_size, false, vdec->vf_provider_name, NULL); + if (without_display_mode == 0) { vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); @@ -6172,6 +6175,60 @@ static int vh264_pic_done_proc(struct vdec_s *vdec) return 0; } +#ifdef VDEC_FCC_SUPPORT +static void fcc_discard_mode_process(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + if (vdec->fcc_status == AGAIN_STATUS) { + vdec->stream_offset = (p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_LO] | + p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_HI] << 16); + dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Notify stream_offset: %d\n", + vdec->id, vdec->stream_offset); + vdec_wakeup_fcc_poll(vdec); + amvdec_stop(); + vdec->mc_loaded = 0; + hw->init_flag = 0; + vdec->fcc_status = WAIT_MSG_STATUS; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } else if (vdec->fcc_status == DISCARD_STATUS) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Discard current gop and to find next gop!\n", + vdec->id); + amvdec_stop(); + vdec->mc_loaded = 0; + hw->init_flag = 0; + vdec->fcc_status = AGAIN_STATUS; + hw->dec_result = DEC_RESULT_DISCARD_DATA; + vdec_schedule_work(&hw->work); + } +} + +static int vh264_fcc_process(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + + if (input_stream_based(vdec)) { + switch (vdec->fcc_mode) { + case FCC_DISCARD_MODE: + fcc_discard_mode_process(vdec); + return 1; + case FCC_DEC_MODE: + dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Current is Dec mode.\n", vdec->id); + break; + case FCC_BUTT: + default: + break; + } + } + + return 0; +} +#endif static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) { @@ -6232,7 +6289,7 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) p_H264_Dpb->frame_crop_top_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_top_offset; p_H264_Dpb->frame_crop_bottom_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_bottom_offset; - dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, "%s chroma_format_idc %d crop offset: left %d right %d top %d bottom %d\n", __func__, p_H264_Dpb->chroma_format_idc, p_H264_Dpb->frame_crop_left_offset, @@ -6241,6 +6298,11 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) p_H264_Dpb->frame_crop_bottom_offset); #endif +#ifdef VDEC_FCC_SUPPORT + if (vh264_fcc_process(vdec) > 0) + return IRQ_HANDLED; +#endif + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE); reset_process_time(hw); hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); @@ -6644,10 +6706,11 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) } } - if (slice_header_process_status == 1) + if (slice_header_process_status == 1) { WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_NEWPIC); - else + } else { WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_SLICE); + } hw->last_mby_mbx = 0; hw->last_vld_level = 0; start_process_time(hw); @@ -7537,8 +7600,9 @@ static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw) if (hw->init_flag == 0) WRITE_VREG(DPB_STATUS_REG, 0); - else + else { WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_START); + } WRITE_VREG(FRAME_COUNTER_REG, hw->decode_pic_count); WRITE_VREG(AV_SCRATCH_8, hw->buf_offset); @@ -8976,6 +9040,7 @@ static void vh264_work_implement(struct vdec_h264_hw_s *hw, return; } else if (hw->dec_result == DEC_RESULT_DONE || hw->dec_result == DEC_RESULT_TIMEOUT) { + /* if (!hw->ctx_valid) hw->ctx_valid = 1; */ if ((hw->dec_result == DEC_RESULT_TIMEOUT) && @@ -9096,6 +9161,11 @@ result_done: vdec_free_irq(VDEC_IRQ_1, (void *)hw); hw->stat &= ~STAT_ISR_REG; } + } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) { + mutex_lock(&hw->chunks_mutex); + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + hw->chunk = NULL; + mutex_unlock(&hw->chunks_mutex); } WRITE_VREG(ASSIST_MBOX1_MASK, 0); del_timer_sync(&hw->check_timer); @@ -9177,6 +9247,13 @@ static void vh264_timeout_work(struct work_struct *work) } +#ifdef VDEC_FCC_SUPPORT +static void vmh264_wakeup_fcc_poll(struct vdec_s *vdec) +{ + amstream_wakeup_fcc_poll(vdec); +} +#endif + static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { bool ret = 0; @@ -9184,6 +9261,9 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) (struct vdec_h264_hw_s *)vdec->private; int tvp = vdec_secure(hw_to_vdec(hw)) ? CODEC_MM_FLAGS_TVP : 0; +#ifdef VDEC_FCC_SUPPORT + int get_msg = 1; +#endif if (hw->timeout_processing && (work_pending(&hw->work) || work_busy(&hw->work) || @@ -9303,10 +9383,16 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) } +#ifdef VDEC_FCC_SUPPORT + get_msg = vdec_has_get_fcc_new_msg(vdec); + ret &= get_msg; +#endif + if (ret) not_run_ready[DECODE_ID(hw)] = 0; else not_run_ready[DECODE_ID(hw)]++; + if (vdec->parallel_dec == 1) { if (hw->mmu_enable == 0) return ret ? (CORE_MASK_VDEC_1) : 0; @@ -10062,6 +10148,11 @@ static int ammvdec_h264_probe(struct platform_device *pdev) pdata->user_data_read = NULL; pdata->reset_userdata_fifo = NULL; #endif + +#ifdef VDEC_FCC_SUPPORT + pdata->wakeup_fcc_poll = vmh264_wakeup_fcc_poll; +#endif + if (pdata->use_vfm_path) { snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, VFM_DEC_PROVIDER_NAME); diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c index 0b489ad..e6345a6 100644 --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c @@ -1504,6 +1504,7 @@ struct tile_s { #define DEC_RESULT_EOS 9 #define DEC_RESULT_FORCE_EXIT 10 #define DEC_RESULT_FREE_CANVAS 11 +#define DEC_RESULT_DISCARD_DATA 12 static void vh265_work(struct work_struct *work); static void vh265_timeout_work(struct work_struct *work); @@ -9729,14 +9730,17 @@ static int post_video_frame(struct vdec_s *vdec, struct PIC_s *pic) pic->vf_ref = 1; put_vf_to_display_q(hevc, vf); #endif + /*count info*/ vdec_count_info(hevc->gvs, 0, stream_offset); - if (hevc->cur_pic->slice_type == I_SLICE) { - hevc->gvs->i_decoded_frames++; - } else if (hevc->cur_pic->slice_type == P_SLICE) { - hevc->gvs->p_decoded_frames++; - } else if (hevc->cur_pic->slice_type == B_SLICE) { - hevc->gvs->b_decoded_frames++; + if (hevc->cur_pic != NULL) { + if (hevc->cur_pic->slice_type == I_SLICE) { + hevc->gvs->i_decoded_frames++; + } else if (hevc->cur_pic->slice_type == P_SLICE) { + hevc->gvs->p_decoded_frames++; + } else if (hevc->cur_pic->slice_type == B_SLICE) { + hevc->gvs->b_decoded_frames++; + } } hevc_update_gvs(hevc); memcpy(&tmp4x, hevc->gvs, sizeof(struct vdec_info)); @@ -10304,6 +10308,55 @@ static int hevc_skip_nal(struct hevc_state_s *hevc) return 0; } +#ifdef VDEC_FCC_SUPPORT +static void fcc_discard_mode_process(struct vdec_s *vdec, struct hevc_state_s *hevc) +{ + if (vdec->fcc_status == AGAIN_STATUS && + hevc->param.p.slice_type == I_SLICE) { + vdec->stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT); + hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, + "[%d][FCC]: Notify stream_offset: %u\n", + vdec->id, vdec->stream_offset); + + vdec_wakeup_fcc_poll(vdec); + amhevc_stop(); + vdec->fcc_status = WAIT_MSG_STATUS; + hevc->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hevc->work); + } else if (vdec->fcc_status == DISCARD_STATUS || + hevc->param.p.slice_type != I_SLICE) { + hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, + "[%d][FCC]: Discard current gop and to find next gop!\n", + vdec->id); + + amhevc_stop(); + vdec->fcc_status = AGAIN_STATUS; + hevc->dec_result = DEC_RESULT_DISCARD_DATA; + vdec_schedule_work(&hevc->work); + } +} + +static int vh265_fcc_process(struct vdec_s *vdec, struct hevc_state_s *hevc) +{ + if (input_stream_based(vdec)) { + switch (vdec->fcc_mode) { + case FCC_DISCARD_MODE: + fcc_discard_mode_process(vdec, hevc); + return 1; + case FCC_DEC_MODE: + hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, + "[%d][FCC]: Current is Dec mode.\n", vdec->id); + break; + case FCC_BUTT: + default: + break; + } + } + + return 0; +} +#endif + static irqreturn_t vh265_isr_thread_fn(int irq, void *data) { struct hevc_state_s *hevc = (struct hevc_state_s *) data; @@ -11004,6 +11057,10 @@ force_output: check_head_error(hevc); #endif } +#ifdef VDEC_FCC_SUPPORT + if (vh265_fcc_process(vdec, hevc) > 0) + return IRQ_HANDLED; +#endif if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) { hevc_print(hevc, 0, "rpm_param: (%d)\n", hevc->slice_idx); @@ -12952,6 +13009,7 @@ static void vh265_work_implement(struct hevc_state_s *hevc, } } #endif + if (hevc->mmu_enable && ((hevc->double_write_mode & 0x10) == 0)) { hevc->used_4k_num = READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; @@ -13208,6 +13266,11 @@ static void vh265_work_implement(struct hevc_state_s *hevc, } hevc_print(hevc, 0, "%s: force exit end\n", __func__); + } else if (hevc->dec_result == DEC_RESULT_DISCARD_DATA) { + mutex_lock(&hevc->chunks_mutex); + vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk); + hevc->chunk = NULL; + mutex_unlock(&hevc->chunks_mutex); } if (hevc->stat & STAT_VDEC_RUN) { @@ -13283,6 +13346,12 @@ static void vh265_timeout_work(struct work_struct *work) vh265_work_implement(hevc, vdec, 1); } +#ifdef VDEC_FCC_SUPPORT +static void vh265_wakeup_fcc_poll(struct vdec_s *vdec) +{ + amstream_wakeup_fcc_poll(vdec); +} +#endif static int vh265_hw_ctx_restore(struct hevc_state_s *hevc) { @@ -13297,6 +13366,9 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) int tvp = vdec_secure(hw_to_vdec(hevc)) ? CODEC_MM_FLAGS_TVP : 0; bool ret = 0; +#ifdef VDEC_FCC_SUPPORT + int get_msg = 1; +#endif if (step == 0x12) return 0; else if (step == 0x11) @@ -13421,6 +13493,10 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) } } +#ifdef VDEC_FCC_SUPPORT + get_msg = vdec_has_get_fcc_new_msg(vdec); + ret &= get_msg; +#endif if (ret) not_run_ready[hevc->index] = 0; else @@ -14084,7 +14160,9 @@ static int ammvdec_h265_probe(struct platform_device *pdev) pdata->irq_handler = vh265_irq_cb; pdata->threaded_irq_handler = vh265_threaded_irq_cb; pdata->dump_state = vh265_dump_state; - +#ifdef VDEC_FCC_SUPPORT + pdata->wakeup_fcc_poll = vh265_wakeup_fcc_poll; +#endif hevc->index = pdev->id; hevc->m_ins_flag = 1; diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c index 5bf0a8a..da8deb1 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c @@ -180,6 +180,7 @@ enum { #define DEC_RESULT_EOS 5 #define DEC_RESULT_GET_DATA 6 #define DEC_RESULT_GET_DATA_RETRY 7 +#define DEC_RESULT_DISCARD_DATA 8 #define DEC_DECODE_TIMEOUT 0x21 #define DECODE_ID(hw) (hw_to_vdec(hw)->id) @@ -378,6 +379,7 @@ static int error_proc_policy = 0x1; #define PRINT_FLAG_USERDATA_DETAIL 0x2000 #define PRINT_FLAG_TIMEOUT_STATUS 0x4000 #define PRINT_FLAG_V4L_DETAIL 0x8000 +#define PRINT_FLAG_FCC_STATUS 0x10000 #define IGNORE_PARAM_FROM_CONFIG 0x8000000 @@ -1841,6 +1843,65 @@ static int v4l_res_change(struct vdec_mpeg12_hw_s *hw, int width, int height) return ret; } +#ifdef VDEC_FCC_SUPPORT +static void fcc_discard_mode_process(struct vdec_s *vdec) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + int wrap_count; + u32 rp; + u32 first_ptr; + + if (vdec->fcc_status == AGAIN_STATUS) { + wrap_count = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT); + rp = READ_VREG(VLD_MEM_VIFIFO_RP); + first_ptr = vdec->vbuf.ext_buf_addr; + + vdec->stream_offset = rp + vdec->input.size * wrap_count - first_ptr; + debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Notify stream_offset: %d\n", + vdec->id, vdec->stream_offset); + + debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: rp : 0x%x size: 0x%x wrap_count:%d first_ptr: 0x%x\n", + vdec->id, rp, vdec->input.size, wrap_count, first_ptr); + vdec_wakeup_fcc_poll(vdec); + vdec->fcc_status = WAIT_MSG_STATUS; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } else if (vdec->fcc_status == DISCARD_STATUS) { + debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Discard current gop and to find next gop!\n", + vdec->id); + vdec->fcc_status = AGAIN_STATUS; + hw->dec_result = DEC_RESULT_DISCARD_DATA; + vdec_schedule_work(&hw->work); + } +} + +static int vmpeg2_fcc_process(struct vdec_s *vdec) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + + if (input_stream_based(vdec)) { + switch (vdec->fcc_mode) { + case FCC_DISCARD_MODE: + fcc_discard_mode_process(vdec); + return 1; + case FCC_DEC_MODE: + debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, + "[%d][FCC]: Current is Dec mode.\n", vdec->id); + break; + case FCC_BUTT: + default: + break; + } + } + + return 0; +} +#endif static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) { @@ -1872,6 +1933,13 @@ static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) "[vdec_kpi][%s] First I frame coming.\n", __func__); } + +#ifdef VDEC_FCC_SUPPORT + if (vmpeg2_fcc_process(vdec) > 0) { + WRITE_VREG(AV_SCRATCH_G, 0); + return IRQ_HANDLED; + } +#endif if (hw->is_used_v4l) { int frame_width = READ_VREG(MREG_PIC_WIDTH); int frame_height = READ_VREG(MREG_PIC_HEIGHT); @@ -2319,6 +2387,10 @@ static void vmpeg12_work_implement(struct vdec_mpeg12_hw_s *hw, debug_print(DECODE_ID(hw), 0, "%s: end of stream, num %d(%d)\n", __func__, hw->disp_num, hw->dec_num); + } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) { + hw->dec_again_cnt = 0; + vdec_vframe_dirty(vdec, hw->chunk); + hw->chunk = NULL; } if (hw->stat & STAT_VDEC_RUN) { amvdec_stop(); @@ -3084,6 +3156,13 @@ static s32 vmpeg12_init(struct vdec_mpeg12_hw_s *hw) return 0; } +#ifdef VDEC_FCC_SUPPORT +static void vmmpeg2_wakeup_fcc_poll(struct vdec_s *vdec) +{ + amstream_wakeup_fcc_poll(vdec); +} +#endif + static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { struct vdec_mpeg12_hw_s *hw = @@ -3157,6 +3236,14 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) hw->buffer_not_ready++; return 0; } + +#ifdef VDEC_FCC_SUPPORT + if (!vdec_has_get_fcc_new_msg(vdec)) { + hw->buffer_not_ready++; + return 0; + } +#endif + hw->not_run_ready = 0; hw->buffer_not_ready = 0; if (vdec->parallel_dec == 1) @@ -3383,6 +3470,7 @@ void (*callback)(struct vdec_s *, void *), amvdec_start(); hw->stat |= STAT_VDEC_RUN; hw->init_flag = 1; + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); } @@ -3444,6 +3532,10 @@ static int ammvdec_mpeg12_probe(struct platform_device *pdev) pdata->reset_userdata_fifo = vmmpeg2_reset_userdata_fifo; pdata->wakeup_userdata_poll = vmmpeg2_wakeup_userdata_poll; +#ifdef VDEC_FCC_SUPPORT + pdata->wakeup_fcc_poll = vmmpeg2_wakeup_fcc_poll; +#endif + if (pdata->use_vfm_path) { snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, VFM_DEC_PROVIDER_NAME); diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 1d6edc5..a60494e 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -96,7 +96,10 @@ static int keep_vdec_mem; static unsigned int debug_trace_num = 16 * 20; static int step_mode; static unsigned int clk_config; - +#ifdef VDEC_FCC_SUPPORT +static int fcc_debug; +static void vdec_fcc_jump_back(struct vdec_s *vdec); +#endif /* * 0x1 : sched_priority to MAX_RT_PRIO -1. * 0x2 : always reload firmware. @@ -1414,8 +1417,6 @@ void vdec_stream_skip_data(struct vdec_s *vdec, int skip_size) } EXPORT_SYMBOL(vdec_stream_skip_data); - - /* *get next frame from input chain */ @@ -1573,6 +1574,9 @@ int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p) while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) ; WRITE_VREG(VLD_MEM_SWAP_CTL, 0); +#ifdef VDEC_FCC_SUPPORT + vdec_fcc_jump_back(vdec); +#endif /* restore wrap count */ WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, @@ -1606,7 +1610,9 @@ int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p) & (1<<7)) ; WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0); - +#ifdef VDEC_FCC_SUPPORT + vdec_fcc_jump_back(vdec); +#endif /* restore stream offset */ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, input->stream_cookie); @@ -2318,8 +2324,8 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) if (dev_name == NULL) return -ENODEV; - pr_info("vdec_init, dev_name:%s, vdec_type=%s\n", - dev_name, vdec_type_str(vdec)); + pr_info("vdec_init, dev_name:%s, vdec_type=%s id = %d\n", + dev_name, vdec_type_str(vdec), vdec->id); /* *todo: VFM patch control should be configurable, @@ -2703,6 +2709,13 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) vdec->sys_info->height); /* vdec is now ready to be active */ vdec_set_status(vdec, VDEC_STATUS_DISCONNECTED); + +#ifdef VDEC_FCC_SUPPORT + init_waitqueue_head(&vdec->jump_back_wq); + mutex_init(&vdec->jump_back_mutex); + vdec->fcc_mode = FCC_BUTT; + vdec->fcc_status = STATUS_BUTT; +#endif return 0; error: @@ -2814,8 +2827,8 @@ void vdec_release(struct vdec_s *vdec) if (vdec->vbuf.ops && !vdec->master) vdec->vbuf.ops->release(&vdec->vbuf); - pr_debug("vdec_release instance %p, total %d\n", vdec, - atomic_read(&vdec_core->vdec_nr)); + pr_debug("vdec_release instance %p, total %d id = %d\n", vdec, + atomic_read(&vdec_core->vdec_nr), vdec->id); mutex_lock(&vdec_mutex); vdec_core->vdec_resouce_status &= ~BIT(vdec->frame_base_video_path); @@ -4629,6 +4642,157 @@ void vdec_set_profile_level(struct vdec_s *vdec, u32 profile_idc, u32 level_idc) } EXPORT_SYMBOL(vdec_set_profile_level); +#ifdef VDEC_FCC_SUPPORT +int vdec_wakeup_fcc_poll(struct vdec_s *vdec) +{ + if (vdec) { + if (vdec->wakeup_fcc_poll) + vdec->wakeup_fcc_poll(vdec); + } + + return 0; +} +EXPORT_SYMBOL(vdec_wakeup_fcc_poll); + +int vdec_has_get_fcc_new_msg(struct vdec_s *vdec) +{ + int ret = 1; + + if (vdec == NULL) { + pr_info("Error, invalid vdec instance!\n"); + return 0; + } + + if (input_stream_based(vdec)) { + if (vdec->fcc_mode == FCC_DISCARD_MODE && + vdec->fcc_status == STATUS_BUTT) { + ret = 1; + vdec->fcc_status = AGAIN_STATUS; + } else if (vdec->fcc_mode == FCC_DEC_MODE && + vdec->fcc_status != SWITCH_DONE_STATUS) { + ret = 1; + + if (wait_event_interruptible_timeout(vdec->jump_back_wq, vdec->jump_back_done | vdec->jump_back_error, + HZ / 2) <= 0) { + pr_info("[%d][FCC]: Error! Wait jump back wp timeout 500ms!\n", + vdec->id); + vdec->fcc_status = SWITCH_DONE_STATUS; + } else { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: jump_back_done = %d\n", + vdec->id, vdec->jump_back_done); + if (vdec->jump_back_done) { + vdec->fcc_status = JUMP_BACK_STATUS; + vdec->jump_back_done = 0; + } else { + vdec->fcc_status = SWITCH_DONE_STATUS; + vdec->jump_back_error = 0; + } + } + + if (fcc_debug_enable()) + pr_info("[%d][FCC]: It is DEC mode now! fcc_status: %d\n", + vdec->id, vdec->fcc_status); + } else if (vdec->fcc_mode == FCC_DISCARD_MODE && + !vdec->fcc_new_msg) { + if (vdec->fcc_status == WAIT_MSG_STATUS) { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Wait msg!\n", vdec->id); + ret = 0; + } else { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Continue to find header!\n", vdec->id); + ret = 1; + } + } else if (vdec->fcc_new_msg) { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Got discard msg!\n", vdec->id); + ret = 1; + vdec->fcc_new_msg = 0; + if (vdec->fcc_mode == FCC_DISCARD_MODE) { + vdec->fcc_status = DISCARD_STATUS; + } + } + } + + return ret; +} +EXPORT_SYMBOL(vdec_has_get_fcc_new_msg); + +int fcc_debug_enable(void) +{ + return fcc_debug; +} +EXPORT_SYMBOL(fcc_debug_enable); + +static void vdec_fcc_jump_back(struct vdec_s *vdec) +{ + u32 cur_rp, set_rp; + struct vdec_input_s *input = &vdec->input; + + if (fcc_debug_enable()) + pr_info("[%d][FCC]: fcc_mode = %d fcc_status = %d\n", + vdec->id, vdec->fcc_mode, vdec->fcc_status); + + if (input->target == VDEC_INPUT_TARGET_VLD) { + if (vdec->fcc_mode == FCC_DEC_MODE && + vdec->fcc_status == JUMP_BACK_STATUS) { + set_rp = vdec->jump_back_rp; + cur_rp =READ_VREG(VLD_MEM_VIFIFO_RP); + input->stream_cookie = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT); + if (cur_rp < set_rp) { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Packet is wrapped! VLD_MEM_VIFIFO_WRAP_COUNT = %d\n", + vdec->id, input->stream_cookie); + input->stream_cookie = (input->stream_cookie - 1) < 0 ? + 0 : input->stream_cookie - 1; + } + + WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR, set_rp); + WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1); + WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); + + WRITE_VREG(VLD_MEM_SWAP_ADDR, + input->swap_page_phys); + WRITE_VREG(VLD_MEM_SWAP_CTL, 3); + while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) + ; + WRITE_VREG(VLD_MEM_SWAP_CTL, 0); + vdec->fcc_status = SWITCH_DONE_STATUS; + if (fcc_debug_enable()) { + pr_info("[%d][FCC]:Current VLD_MEM_VIFIFO_WRAP_COUNT = %d cur_rp = %x set_rp = %x\n", + vdec->id, input->stream_cookie, cur_rp, set_rp); + } + } + } else if (input->target == VDEC_INPUT_TARGET_HEVC) { + if (vdec->fcc_mode == FCC_DEC_MODE && + vdec->fcc_status == JUMP_BACK_STATUS) { + set_rp = vdec->jump_back_rp; + cur_rp = READ_VREG(HEVC_STREAM_RD_PTR); + if (cur_rp < set_rp) { + input->stream_cookie = input->stream_cookie + set_rp - cur_rp - vdec->input.size; + } else { + input->stream_cookie = input->stream_cookie - cur_rp + set_rp; + } + + WRITE_VREG(HEVC_STREAM_RD_PTR, set_rp); + vdec->fcc_status = SWITCH_DONE_STATUS; + + WRITE_VREG(HEVC_STREAM_SWAP_ADDR, + input->swap_page_phys); + WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 3); + + while (READ_VREG(HEVC_STREAM_SWAP_CTRL) + & (1<<7)) + ; + WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0); + } + } + + return; +} +#endif + static int dump_mode; static ssize_t dump_risc_mem_store(struct class *class, struct class_attribute *attr, @@ -5185,6 +5349,28 @@ static ssize_t level_idc_show(struct class *class, struct class_attribute *attr, return pbuf - buf; } +#ifdef VDEC_FCC_SUPPORT +static ssize_t store_fcc_debug(struct class *class, + struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int val; + ssize_t ret; + + ret = kstrtoint(buf, 0, &val); + if (ret != 0) + return -EINVAL; + fcc_debug = val; + return size; +} + +static ssize_t show_fcc_debug(struct class *class, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", fcc_debug); +} +#endif + static struct class_attribute vdec_class_attrs[] = { __ATTR_RO(amrisc_regs), __ATTR_RO(dump_trace), @@ -5217,6 +5403,10 @@ static struct class_attribute vdec_class_attrs[] = { __ATTR_RO(level_idc), __ATTR(vfm_path, S_IRUGO | S_IWUSR | S_IWGRP, show_vdec_vfm_path, store_vdec_vfm_path), +#ifdef VDEC_FCC_SUPPORT + __ATTR(fcc_debug, S_IRUGO | S_IWUSR | S_IWGRP, + show_fcc_debug, store_fcc_debug), +#endif __ATTR_NULL }; @@ -5729,6 +5919,11 @@ MODULE_PARM_DESC(max_di_instance, module_param(debug_vdetect, int, 0664); MODULE_PARM_DESC(debug_vdetect, "\n debug_vdetect\n"); +#ifdef VDEC_FCC_SUPPORT +module_param(fcc_debug, int, 0664); +MODULE_PARM_DESC(fcc_debug, "\n fcc_debug\n"); +#endif + module_param(enable_stream_mode_multi_dec, int, 0664); EXPORT_SYMBOL(enable_stream_mode_multi_dec); MODULE_PARM_DESC(enable_stream_mode_multi_dec, diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index c02faf8..fc91079 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -56,6 +56,8 @@ void vdec_module_exit(void); #define VDEC_FIFO_ALIGN 8 +#define VDEC_FCC_SUPPORT + enum vdec_type_e { VDEC_1 = 0, VDEC_HCODEC, @@ -111,6 +113,19 @@ enum vdec_fr_hint_state { VDEC_NEED_HINT, VDEC_HINTED, }; + +#ifdef VDEC_FCC_SUPPORT +typedef enum { + DISCARD_STATUS = 1, + AGAIN_STATUS, + WAIT_MSG_STATUS, + SWITCHING_STATUS, + JUMP_BACK_STATUS, + SWITCH_DONE_STATUS, + STATUS_BUTT +} FCC_STATUS; +#endif + extern s32 vdec_request_threaded_irq(enum vdec_irq_num num, irq_handler_t handler, irq_handler_t thread_fn, @@ -259,6 +274,9 @@ struct vdec_s { struct userdata_param_t *puserdata_para); void (*reset_userdata_fifo)(struct vdec_s *vdec, int bInit); void (*wakeup_userdata_poll)(struct vdec_s *vdec); +#ifdef VDEC_FCC_SUPPORT + void (*wakeup_fcc_poll)(struct vdec_s *vdec); +#endif /* private */ void *private; /* decoder per instance specific data */ #ifdef VDEC_DEBUG_SUPPORT @@ -285,6 +303,17 @@ struct vdec_s { bool hdr10p_data_valid; u32 profile_idc; u32 level_idc; +#ifdef VDEC_FCC_SUPPORT + enum fcc_mode_e fcc_mode; + u32 stream_offset; + int fcc_new_msg; + FCC_STATUS fcc_status; + wait_queue_head_t jump_back_wq; + struct mutex jump_back_mutex; + u32 jump_back_done; + u32 jump_back_error; + u32 jump_back_rp; +#endif }; /* common decoder vframe provider name to use default vfm path */ @@ -457,6 +486,12 @@ void vdec_reset_userdata_fifo(struct vdec_s *vdec, int bInit); struct vdec_s *vdec_get_vdec_by_id(int vdec_id); +#ifdef VDEC_FCC_SUPPORT +int vdec_wakeup_fcc_poll(struct vdec_s *vdec); +int vdec_has_get_fcc_new_msg(struct vdec_s *vdec); +int fcc_debug_enable(void); +#endif + #ifdef VDEC_DEBUG_SUPPORT extern void vdec_set_step_mode(void); #endif diff --git a/drivers/stream_input/amports/amports_priv.h b/drivers/stream_input/amports/amports_priv.h index ffead01..296b94a 100644 --- a/drivers/stream_input/amports/amports_priv.h +++ b/drivers/stream_input/amports/amports_priv.h @@ -51,4 +51,6 @@ void amstream_wakeup_userdata_poll(struct vdec_s *vdec); struct device *amports_get_dma_device(void); struct device *get_codec_cma_device(void); +void amstream_wakeup_fcc_poll(struct vdec_s *vdec); + #endif diff --git a/drivers/stream_input/amports/amstream.c b/drivers/stream_input/amports/amstream.c index 854c3a8..8940a49 100644 --- a/drivers/stream_input/amports/amstream.c +++ b/drivers/stream_input/amports/amstream.c @@ -192,11 +192,18 @@ static int (*amstream_adec_status) static ssize_t amstream_mprm_write (struct file *file, const char *buf, size_t count, loff_t *ppos); #endif +#ifdef VDEC_FCC_SUPPORT +static unsigned int amstream_offset_poll +(struct file *file, poll_table *wait_table); +#endif static const struct file_operations vbuf_fops = { .owner = THIS_MODULE, .open = amstream_open, .release = amstream_release, +#ifdef VDEC_FCC_SUPPORT + .poll = amstream_offset_poll, +#endif .write = amstream_vbuf_write, .unlocked_ioctl = amstream_ioctl, #ifdef CONFIG_COMPAT @@ -332,6 +339,25 @@ static u32 force_dv_mode; static DEFINE_MUTEX(userdata_mutex); +#ifdef VDEC_FCC_SUPPORT +static void amstream_fcc_get_one_slot(struct vdec_s *vdec); +static void amstream_fcc_release_one_slot(struct vdec_s *vdec); + +#define MAX_FCC_CHANNEL_NUM 5 + +typedef struct { + struct mutex mutex; + wait_queue_head_t offset_wait; + u32 offset[MAX_FCC_CHANNEL_NUM]; + u32 offset_ready_flag[MAX_FCC_CHANNEL_NUM]; + int used[MAX_FCC_CHANNEL_NUM]; + int id[MAX_FCC_CHANNEL_NUM]; +} st_fcc; + +st_fcc fcc; +static u32 fcc_enable; +#endif + static struct stream_port_s ports[] = { { .name = "amstream_vbuf", @@ -600,6 +626,10 @@ static void video_port_release(struct port_priv_s *priv, /*fallthrough*/ case 0: /*release all */ case 3: +#ifdef VDEC_FCC_SUPPORT + if (fcc_enable & 0x1) + amstream_fcc_release_one_slot(vdec); +#endif if (vdec->slave) slave = vdec->slave; vdec_release(vdec); @@ -696,6 +726,10 @@ static int video_port_init(struct port_priv_s *priv, goto err; } } +#ifdef VDEC_FCC_SUPPORT + if (fcc_enable & 0x1) + amstream_fcc_get_one_slot(vdec); +#endif return 0; err: @@ -1615,6 +1649,123 @@ static ssize_t amstream_userdata_read(struct file *file, char __user *buf, return retVal; } +#ifdef VDEC_FCC_SUPPORT +static unsigned int amstream_offset_poll(struct file *file, + poll_table *wait_table) +{ + struct port_priv_s *priv = (struct port_priv_s *)file->private_data; + struct vdec_s *vdec = priv->vdec; + int fd_match = 0; + int i; + + poll_wait(file, &fcc.offset_wait, wait_table); + mutex_lock(&fcc.mutex); + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + if (fcc.id[i] == vdec->id && fcc.offset_ready_flag[i] == 1) { + fd_match = 1; + if (fcc_debug_enable()) + pr_info("i = %d vdec->id = %d offset_ready_flag = %d\n", + i, vdec->id, fcc.offset_ready_flag[i]); + break; + } + } + + if (fd_match) { + mutex_unlock(&fcc.mutex); + return POLLIN | POLLRDNORM; + } + + mutex_unlock(&fcc.mutex); + return 0; +} + +void amstream_wakeup_fcc_poll(struct vdec_s *vdec) +{ + int i; + + if (vdec == NULL) { + pr_info("Error, invalid vdec instance!\n"); + return; + } + + mutex_lock(&fcc.mutex); + + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + if (fcc.id[i] == vdec->id) { + fcc.offset[i] = vdec->stream_offset; + fcc.offset_ready_flag[i] = 1; + if (fcc_debug_enable()) + pr_info("i = %d vdec->id = %d stream_offset = %d\n", + i, vdec->id, vdec->stream_offset); + break; + } + } + + mutex_unlock(&fcc.mutex); + + wake_up_interruptible(&fcc.offset_wait); +} +EXPORT_SYMBOL(amstream_wakeup_fcc_poll); + +static void amstream_fcc_init(void) +{ + int i; + + init_waitqueue_head(&fcc.offset_wait); + mutex_init(&fcc.mutex); + + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + fcc.offset_ready_flag[i] = 0; + fcc.id[i] = -1; + fcc.used[i] = 0; + } + + return; +} + +static void amstream_fcc_get_one_slot(struct vdec_s *vdec) +{ + int i; + + mutex_lock(&fcc.mutex); + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + if (!fcc.used[i]) { + fcc.offset_ready_flag[i] = 0; + fcc.id[i] = vdec->id; + fcc.used[i] = 1; + break; + } + } + mutex_unlock(&fcc.mutex); + + if (i >= MAX_FCC_CHANNEL_NUM) + pr_info("Error, no free fcc slot\n"); + + return; +} + +static void amstream_fcc_release_one_slot(struct vdec_s *vdec) +{ + int i; + + mutex_lock(&fcc.mutex); + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + if (fcc.used[i] && vdec->id == fcc.id[i]) { + fcc.offset_ready_flag[i] = 0; + fcc.id[i] = -1; + fcc.used[i] = 0; + break; + } + } + mutex_unlock(&fcc.mutex); + + if (i >= MAX_FCC_CHANNEL_NUM) + pr_info("Error, no fcc slot matched to release\n"); + + return; +} +#endif + static int amstream_open(struct inode *inode, struct file *file) { s32 i; @@ -1891,7 +2042,9 @@ static long amstream_ioctl_get(struct port_priv_s *priv, ulong arg) { struct stream_port_s *this = priv->port; long r = 0; - +#ifdef VDEC_FCC_SUPPORT + int i; +#endif struct am_ioctl_parm parm; if (copy_from_user @@ -2035,6 +2188,22 @@ static long amstream_ioctl_get(struct port_priv_s *priv, ulong arg) case AMSTREAM_GET_FREED_HANDLE: parm.data_32 = vdec_input_get_freed_handle(priv->vdec); break; + case AMSTREAM_GET_OFFSET: +#ifdef VDEC_FCC_SUPPORT + mutex_lock(&fcc.mutex); + for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) { + if (priv->vdec->id == fcc.id[i] && + fcc.offset_ready_flag[i]) { + parm.data_32 = fcc.offset[i]; + fcc.offset_ready_flag[i] = 0; + break; + } + } + mutex_unlock(&fcc.mutex); + if (i >= MAX_FCC_CHANNEL_NUM) + pr_info("Error, Get offset fail!\n"); +#endif + break; default: r = -ENOIOCTLCMD; break; @@ -2281,6 +2450,41 @@ static long amstream_ioctl_set(struct port_priv_s *priv, ulong arg) pr_debug("no drmmode\n"); } break; + case AMSTREAM_SET_WORKMODE: + case AMSTREAM_SET_FCC_MODE: +#ifdef VDEC_FCC_SUPPORT + if (parm.cmd == AMSTREAM_SET_FCC_MODE) { + priv->vdec->fcc_new_msg = 1; + if (priv->vdec->fcc_mode == FCC_DEC_MODE) { + priv->vdec->fcc_new_msg = 0; + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Current is dec mode, ignore discard message!\n", + priv->vdec->id); + break; + } + } + + if (parm.data_32 == FCC_DISCARD_MODE) { + if (fcc_debug_enable()) + pr_info("[%d][FCC]: Set discard pic mode!\n", + priv->vdec->id); + if ((this->type & PORT_TYPE_VIDEO) && + (priv->vdec)) { + priv->vdec->fcc_mode = FCC_DISCARD_MODE; + } + } else if (parm.data_32 == FCC_DEC_MODE) { + if ((this->type & PORT_TYPE_VIDEO) && + (priv->vdec)) { + priv->vdec->fcc_mode = FCC_DEC_MODE; + } + if (fcc_debug_enable()) { + pr_info("[%d][FCC]: Set dec pic mode!\n", priv->vdec->id); + } + } else { + pr_info("Para error! Unknow FCC Mode! vdec id: %d\n", priv->vdec->id); + } +#endif + break; case AMSTREAM_SET_APTS: { unsigned int pts; @@ -4498,7 +4702,10 @@ static int amstream_probe(struct platform_device *pdev) /*prealloc fetch buf to avoid no continue buffer later...*/ stbuf_fetch_init(); REG_PATH_CONFIGS("media.amports", amports_configs); - +#ifdef VDEC_FCC_SUPPORT + if (fcc_enable & 0x1) + amstream_fcc_init(); +#endif /* poweroff the decode core because dos can not be reset when reboot */ if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_G12A) vdec_power_reset(); @@ -4622,6 +4829,12 @@ module_param(force_dv_mode, uint, 0664); MODULE_PARM_DESC(force_dv_mode, "\n force_dv_mode \n"); +#ifdef VDEC_FCC_SUPPORT +module_param(fcc_enable, uint, 0664); +MODULE_PARM_DESC(fcc_enable, + "\n fcc_enable \n"); +#endif + module_param(def_4k_vstreambuf_sizeM, uint, 0664); MODULE_PARM_DESC(def_4k_vstreambuf_sizeM, "\nDefault video Stream buf size for 4K MByptes\n"); diff --git a/drivers/stream_input/amports/stream_buffer_base.c b/drivers/stream_input/amports/stream_buffer_base.c index a7e5259..b5e06db 100644 --- a/drivers/stream_input/amports/stream_buffer_base.c +++ b/drivers/stream_input/amports/stream_buffer_base.c @@ -126,13 +126,50 @@ void stream_buffer_set_ext_buf(struct stream_buf_s *stbuf, } EXPORT_SYMBOL(stream_buffer_set_ext_buf); +#ifdef VDEC_FCC_SUPPORT +void fcc_wakeup_jump_back(struct vdec_s *vdec, + struct stream_buffer_metainfo *meta) +{ + u32 first_ptr; + u32 round_down_size = 0; + if (fcc_debug_enable()) + pr_info("[%d][FCC]: jump_back_done = %d jump_back_flag = %d stbuf_pktaddr = 0x%x size = 0x%x\n", + vdec->id, vdec->jump_back_done, meta->jump_back_flag, + meta->stbuf_pktaddr, meta->stbuf_size); + if (vdec->fcc_mode == FCC_DEC_MODE && vdec->fcc_status != SWITCH_DONE_STATUS) { + mutex_lock(&vdec->jump_back_mutex); + if (meta->jump_back_flag && !vdec->jump_back_done) { + if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) + round_down_size = 0x80; + else if (vdec->input.target == VDEC_INPUT_TARGET_VLD) + round_down_size = 0x100; + + if (vdec->vbuf.ext_buf_addr > (meta->stbuf_pktaddr - round_down_size)) + first_ptr = vdec->vbuf.ext_buf_addr; + else { + first_ptr = round_down(meta->stbuf_pktaddr, round_down_size); + } + vdec->jump_back_done = 1; + vdec->jump_back_rp = first_ptr; + wake_up_interruptible(&vdec->jump_back_wq); + } else if (!vdec->jump_back_done && !vdec->jump_back_error) { + vdec->jump_back_error = 1; + wake_up_interruptible(&vdec->jump_back_wq); + } + mutex_unlock(&vdec->jump_back_mutex); + } + + return; +} +#endif + void stream_buffer_meta_write(struct stream_buf_s *stbuf, struct stream_buffer_metainfo *meta) { u32 wp = stbuf->ops->get_wp(stbuf); if ((stbuf->stream_offset == 0) && - (wp == stbuf->ext_buf_addr) && + /*(wp == stbuf->ext_buf_addr) &&*/ /*For fcc, when switching to dec mode it doesn't meet*/ (meta->stbuf_pktaddr > stbuf->ext_buf_addr)) { struct vdec_s *vdec = container_of(stbuf, struct vdec_s, vbuf); u32 first_ptr; @@ -171,6 +208,10 @@ void stream_buffer_meta_write(struct stream_buf_s *stbuf, stbuf->ops->set_wp(stbuf, wp); stbuf->stream_offset += meta->stbuf_pktsize; + +#ifdef VDEC_FCC_SUPPORT + fcc_wakeup_jump_back(container_of(stbuf, struct vdec_s, vbuf), meta); +#endif /* pr_debug("%s, update wp 0x%x + sz 0x%x --> 0x%x, stream_offset 0x%x\n", __func__, meta->stbuf_pktaddr, meta->stbuf_pktsize, wp, stbuf->stream_offset); diff --git a/drivers/stream_input/amports/streambuf.h b/drivers/stream_input/amports/streambuf.h index 6b13519..afb2ebe 100644 --- a/drivers/stream_input/amports/streambuf.h +++ b/drivers/stream_input/amports/streambuf.h @@ -156,7 +156,8 @@ struct stream_buffer_metainfo { }; u32 stbuf_flag; u32 stbuf_private; - u32 reserved[16]; + u32 jump_back_flag; + u32 reserved[15]; }; struct stream_buffer_status { -- 2.20.1