decoder: FCC adds decoder frame drop mode [1/1]
authormiaohong chen <miaohong.chen@amlogic.com>
Mon, 30 Nov 2020 10:53:48 +0000 (18:53 +0800)
committerHui Zhang <hui.zhang@amlogic.com>
Tue, 5 Jan 2021 12:41:20 +0000 (04:41 -0800)
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 <miaohong.chen@amlogic.com>
drivers/frame_provider/decoder/h264_multi/h264_dpb.h
drivers/frame_provider/decoder/h264_multi/vmh264.c
drivers/frame_provider/decoder/h265/vh265.c
drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
drivers/frame_provider/decoder/utils/vdec.c
drivers/frame_provider/decoder/utils/vdec.h
drivers/stream_input/amports/amports_priv.h
drivers/stream_input/amports/amstream.c
drivers/stream_input/amports/stream_buffer_base.c
drivers/stream_input/amports/streambuf.h

index 85ee1583c70059703c832c23b1ed5f818ffe4953..16d9317329a07b5165925a2a58da312b6a3cc172 100644 (file)
@@ -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
index 7e2fdedd91f46b8875dfc881b7e4431264b05f76..43188aa56cf514d6857a3e84426e2541ef1fab3d 100644 (file)
@@ -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);
index 0b489ade42b1c9833d89468346e22e6bc2b92cbf..e6345a69b426cc047c9598d8f1d547adb9cef48e 100644 (file)
@@ -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;
 
index 5bf0a8a5fe1c95e7b311c740fbc8dc055b3f32ff..da8deb18cd645b677ceff301e5dfbd2d46ab2b7c 100644 (file)
@@ -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);
index 1d6edc53ebce8ff557dfba97dbb92f29cac716f2..a60494eb841039cbad1e95c1cb0f29e1611792bf 100644 (file)
@@ -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,
index c02faf849d413875d62a00b230073d41551a4f00..fc910794d5c3f6955b116c6038e82e9e7bf2f84a 100644 (file)
@@ -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
index ffead011e3e95f24dcf7d63d87c80e34e8f732fa..296b94a2d6ef35b6978ed002acd0a88c07333d61 100644 (file)
@@ -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
index 854c3a87291cc88d79be2b5324a24b4f64831779..8940a49169e1e0a678332fbf44a5cdfb7fddbb24 100644 (file)
@@ -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");
index a7e525908084349f6885bc26f83b6a0e220434d9..b5e06db04dd7005f18a985f7037f0ca81288f7e1 100644 (file)
@@ -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);
index 6b13519ec83891327930c47a370b522dfe2b977c..afb2ebedf21fbbc6bf3ebaa8ed6b60a1e24ef8f1 100644 (file)
@@ -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 {