vmh264: add the feature of fence for h264 decoder. [2/2]
authorNanxin Qin <nanxin.qin@amlogic.com>
Tue, 15 Sep 2020 13:16:01 +0000 (21:16 +0800)
committerNanxin Qin <nanxin.qin@amlogic.com>
Wed, 23 Sep 2020 10:49:57 +0000 (03:49 -0700)
PD#SWPL-32845

Problem:
need decode fence  on cloud game docking

Solution:
1. add the feature of fence for h264 decoder.
2. just used ip only stream source.

Verify:
u212

Change-Id: I80ed4f19d5f05c491e9599574cdb153c2a87b06d
Signed-off-by: Nanxin Qin <nanxin.qin@amlogic.com>
drivers/fake_video_out/fake_video.c
drivers/frame_provider/decoder/h264_multi/h264_dpb.c
drivers/frame_provider/decoder/h264_multi/h264_dpb.h
drivers/frame_provider/decoder/h264_multi/vmh264.c
drivers/frame_provider/decoder/utils/vdec.c
drivers/frame_provider/decoder/utils/vdec_sync.c
drivers/frame_provider/decoder/utils/vdec_sync.h
drivers/frame_provider/decoder/vp9/vvp9.c

index c175c9299fa60e5afce14b6ad8dd991de7cbf7b3..e0e9b1645f7c1b4f5454ed043b322cda9d9ca906 100644 (file)
 #include <linux/amlogic/major.h>
 #include "../frame_provider/decoder/utils/vdec.h"
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 #define RECEIVER_NAME "fake-amvideo"
 #define DEVICE_NAME "fake-amvideo"
 
+#define TUNNEL_MODE    (0)
+#define NON_TUNNEL_MODE        (1)
+
+static u32 display_mode = TUNNEL_MODE;
+module_param(display_mode, uint, 0664);
+MODULE_PARM_DESC(display_mode, "\n display_mode\n");
+
 static struct device *amvideo_dev = NULL;
-struct work_struct worker;
+struct timer_list timer;
+struct task_struct *task;
+bool thread_stop = false;
+atomic_t frame_count;
 
 static struct vframe_receiver_s fake_video_vf_recv;
 static int video_receiver_event_fun(int type, void *data, void *);
@@ -83,16 +94,20 @@ static int video_receiver_event_fun(int type, void *data, void *private_data)
 {
        switch (type) {
        case VFRAME_EVENT_PROVIDER_UNREG: {
+               atomic_set(&frame_count, 0);
+               pr_info("VFRAME_EVENT_PROVIDER_UNREG\n");
                break;
        }
        case VFRAME_EVENT_PROVIDER_START: {
+               pr_info("VFRAME_EVENT_PROVIDER_START\n");
                break;
        }
        case VFRAME_EVENT_PROVIDER_QUREY_STATE: {
                break;
        }
        case VFRAME_EVENT_PROVIDER_VFRAME_READY: {
-               vdec_schedule_work(&worker);
+               pr_info("VFRAME_EVENT_PROVIDER_VFRAME_READY\n");
+               atomic_inc(&frame_count);
                break;
        }
        default:
@@ -102,34 +117,72 @@ static int video_receiver_event_fun(int type, void *data, void *private_data)
        return 0;
 }
 
-void displayer_worker(struct work_struct *work)
+static void display_timer_func(unsigned long arg)
 {
        struct vframe_s *vf = NULL;
 
-       if (video_vf_peek()) {
-               vf = video_vf_get();
-               if (!vf) {
-                       pr_err("receiver vf err.\n");
-                       return;
+       if (display_mode != TUNNEL_MODE)
+               goto out;
+
+       vf = video_vf_peek();
+       if (!vf) {
+               goto out;
+       }
+
+       if (vf->fence) {
+               if (vdec_fence_status_get(vf->fence) == 1) {
+                       pr_info("[VDEC-FENCE]: Display, idx: %d\n",
+                               vf->index & 0xff);
+                       vf = video_vf_get();
+                       video_vf_put(vf);
+               } else {
+                       pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n");
                }
+       }
+
+out:
+       mod_timer(&timer, jiffies + msecs_to_jiffies(16));
+}
+
+static int display_thread(void *data)
+{
+       struct vframe_s *vf = NULL;
 
-               /* add delay to simulation pipeline time*/
-               udelay(2000);
+       for (;;) {
+               if (thread_stop)
+                       break;
 
-               if (vf->fence) {
-                       /* fence waiting until frame ready. */
-                       vdec_fence_wait(vf->fence, 2000);
+               if ((atomic_read(&frame_count) == 0) ||
+                       display_mode != NON_TUNNEL_MODE)
+                       continue;
 
-                       if (vdec_fence_status_get(vf->fence) == 1) {
-                               pr_info("[VDEC-FENCE]: Display, idx: %d, dec cost: %lld\n",
-                                       vf->index & 0xff, local_clock() - get_sync_pt(vf->fence)->timestamp);
-                       } else {
-                               pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n");
+               if (video_vf_peek()) {
+                       vf = video_vf_get();
+                       if (!vf) {
+                               pr_err("receiver vf err.\n");
+                               break;
                        }
-               }
 
-               video_vf_put(vf);
+                       atomic_dec(&frame_count);
+
+                       if (vf->fence) {
+                               u64 timestamp = local_clock();
+                               /* fence waiting until frame ready. */
+                               vdec_fence_wait(vf->fence, msecs_to_jiffies(2000));
+
+                               if (vdec_fence_status_get(vf->fence) == 1) {
+                                       pr_info("[VDEC-FENCE]: Display, idx: %d, dec cost: %lld\n",
+                                               vf->index & 0xff, local_clock() - timestamp);
+                               } else {
+                                       pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n");
+                               }
+                       }
+
+                       video_vf_put(vf);
+               }
+               msleep(16);
        }
+       return 0;
 }
 
 static int amvideo_open(struct inode *inode, struct file *file)
@@ -173,7 +226,7 @@ static struct class amvideo_class = {
        .name = "fake_video",
 };
 
-#define FAKEVIDEO_MAJOR                (21 + (AML_BASE))
+#define FAKEVIDEO_MAJOR                (23 + (AML_BASE))
 
 static int __init fake_video_init(void)
 {
@@ -204,8 +257,21 @@ static int __init fake_video_init(void)
                &fake_video_vf_receiver, NULL);
        vf_reg_receiver(&fake_video_vf_recv);
 
+       atomic_set(&frame_count, 0);
 
-       INIT_WORK(&worker, displayer_worker);
+       init_timer(&timer);
+       //timer.data = 0;
+       timer.function = display_timer_func;
+       timer.expires = jiffies + HZ;
+       add_timer(&timer);
+
+       thread_stop = false;
+       task = kthread_run(display_thread, NULL, "aml-%s", "fake-video-thread");
+       if (IS_ERR(task)) {
+               ret = PTR_ERR(task);
+               pr_err("Failed to creat display thread, ret: %d.\n", ret);
+               goto err;
+       }
 
        return 0;
 
@@ -219,7 +285,10 @@ err1:
 
 static void __exit fake_video_exit(void)
 {
-       cancel_work_sync(&worker);
+       thread_stop = true;
+       kthread_stop(task);
+
+       del_timer_sync(&timer);
 
        vf_unreg_receiver(&fake_video_vf_recv);
 
index 8ab6103b53bedba4992c7ba479d12e53d8ac2e18..43d4719e25b79b93589c2a76bc96d14122e5f30c 100644 (file)
@@ -1797,6 +1797,7 @@ void reset_frame_store(struct h264_dpb_stru *p_H264_Dpb,
 
                f->is_output = 0;
                f->pre_output = 0;
+               f->show_frame   = false;
 
                f->frame        = NULL;
                f->top_field    = NULL;
@@ -2160,6 +2161,7 @@ void bufmgr_h264_remove_unused_frame(struct h264_dpb_stru *p_H264_Dpb,
        struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB;
        int ret = 0;
        unsigned char removed_flag = 0;
+
        do {
                ret = remove_unused_frame_from_dpb(p_H264_Dpb);
                if (ret != 0)
@@ -2325,9 +2327,9 @@ int output_frames(struct h264_dpb_stru *p_H264_Dpb, unsigned char flush_flag)
                dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL,
                        "%s first_insert_frame %d \n", __func__, p_H264_Dpb->first_insert_frame);
        }
-       if (prepare_display_buf(p_H264_Dpb->vdec, p_Dpb->fs[pos]) >= 0)
+       if (prepare_display_buf(p_H264_Dpb->vdec, p_Dpb->fs[pos]) >= 0) {
                p_Dpb->fs[pos]->pre_output = 1;
-       else {
+       else {
                if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) {
                        dpb_print(p_H264_Dpb->decoder_index, 0,
                        "%s[%d] poc:%d last_output_poc:%d poc_even_odd_flag:%d\n",
@@ -5467,6 +5469,7 @@ void set_frame_output_flag(struct h264_dpb_stru *p_H264_Dpb, int index)
 
        p_H264_Dpb->mFrameStore[index].is_output = 1;
        p_H264_Dpb->mFrameStore[index].pre_output = 0;
+       p_H264_Dpb->mFrameStore[index].show_frame = false;
        dump_dpb(p_Dpb, 0);
 }
 
@@ -5867,6 +5870,10 @@ int h264_slice_header_process(struct h264_dpb_stru *p_H264_Dpb, int *frame_num_g
                }
        }
 
+       if (post_picture_early(p_H264_Dpb->vdec,
+               p_H264_Dpb->mVideo.dec_picture->buf_spec_num))
+               return -1;
+
        if (p_H264_Dpb->mSlice.slice_type == P_SLICE)
                init_lists_p_slice(&p_H264_Dpb->mSlice);
        else if (p_H264_Dpb->mSlice.slice_type == B_SLICE)
index ac549b0b02297c45a899004d1b7976a8d139209e..0f7cb2d6b3ddd5d1b36c02b894eabffb5c55cf7c 100644 (file)
@@ -819,9 +819,10 @@ struct FrameStore {
        int dpb_frame_count;
        u32 hw_decode_time;
        u32 frame_size2; // For recording the chunk->size in frame mode
+       bool show_frame;
+       struct fence *fence;
 };
 
-
 /* #define DPB_SIZE_MAX     16 */
 #define DPB_SIZE_MAX     32
 struct DecodedPictureBuffer {
@@ -989,5 +990,6 @@ void unmark_for_reference(struct DecodedPictureBuffer *p_Dpb,
 
 void update_ref_list(struct DecodedPictureBuffer *p_Dpb);
 
+int post_picture_early(struct vdec_s *vdec, int index);
 
 #endif
index 2abf92efad98e41a4c106b197b3bd668d0935492..d455516276fb6281887f387c046cc074784788fb 100644 (file)
@@ -345,7 +345,14 @@ static u32 without_display_mode;
 static u32 loop_playback_poc_threshold = 400;
 static u32 poc_threshold = 50;
 
-
+/*
+ *[3:0] 0: default use config from omx.
+ *      1: force enable fence.
+ *      2: disable fence.
+ *[7:4] 0: fence use for driver.
+ *      1: fence fd use for app.
+ */
+static u32 force_config_fence;
 
 #define IS_VDEC_DW(hw)  (hw->double_write_mode >> 16 & 0xf)
 
@@ -486,6 +493,7 @@ struct buffer_spec_s {
        /*unsigned int comp_body_size;*/
        unsigned int dw_y_adr;
        unsigned int dw_u_v_adr;
+       int fs_idx;
 };
 
 #define AUX_DATA_SIZE(pic) (hw->buffer_spec[pic->buf_spec_num].aux_data_size)
@@ -909,6 +917,8 @@ struct vdec_h264_hw_s {
        int buffer_wrap[BUFSPEC_POOL_SIZE];
        int loop_flag;
        int loop_last_poc;
+       bool enable_fence;
+       int fence_usage;
 };
 
 static u32 again_threshold;
@@ -2691,18 +2701,10 @@ static int is_iframe(struct FrameStore *frame) {
        return 0;
 }
 
-
-
-int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
+static int post_prepare_process(struct vdec_s *vdec, struct FrameStore *frame)
 {
        struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
-       struct vframe_s *vf = NULL;
        int buffer_index = frame->buf_spec_num;
-       struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
-       ulong nv_order = VIDTYPE_VIU_NV21;
-       int vf_count = 1;
-       int i;
-       int bForceInterlace = 0;
 
        if (buffer_index < 0 || buffer_index >= BUFSPEC_POOL_SIZE) {
                dpb_print(DECODE_ID(hw), 0,
@@ -2711,13 +2713,6 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                return -1;
        }
 
-       /* swap uv */
-       if (hw->is_used_v4l) {
-               if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
-                       (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
-                       nv_order = VIDTYPE_VIU_NV12;
-       }
-
        if (force_disp_bufspec_num & 0x100) {
                /*recycle directly*/
                if (hw->buffer_spec[frame->buf_spec_num].used != 3 &&
@@ -2736,11 +2731,14 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                        && (!(frame->data_flag & I_FLAG)))
                        frame->data_flag |= ERROR_FLAG;
        }
+
        dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG,
-                       "%s, buffer_index 0x%x  frame_error %x  poc %d hw error %x error_proc_policy %x\n",
-                       __func__, buffer_index,  frame->data_flag & ERROR_FLAG,
-                       frame->poc, hw->data_flag & ERROR_FLAG,
-                       error_proc_policy);
+               "%s, buffer_index 0x%x  frame_error %x  poc %d hw error %x error_proc_policy %x\n",
+               __func__, buffer_index,
+               frame->data_flag & ERROR_FLAG,
+               frame->poc, hw->data_flag & ERROR_FLAG,
+               error_proc_policy);
+
        if (frame->frame == NULL &&
                        ((frame->is_used == 1 && frame->top_field)
                        || (frame->is_used == 2 && frame->bottom_field))) {
@@ -2822,19 +2820,14 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
        if ((frame->data_flag & NODISP_FLAG) ||
                (frame->data_flag & NULL_FLAG) ||
                ((!hw->send_error_frame_flag) &&
-                       (frame->data_flag & ERROR_FLAG)) ||
+               (frame->data_flag & ERROR_FLAG)) ||
                ((hw->i_only & 0x1) &&
-               (!(frame->data_flag & I_FLAG)))
-                       ) {
+               (!(frame->data_flag & I_FLAG)))) {
                set_frame_output_flag(&hw->dpb, frame->index);
-               return 0; /*do not return -1,
-                       otherwise flush_dpb() will not flush all dbp frames*/
+               frame->show_frame = false;
        }
 
-       display_frame_count[DECODE_ID(hw)]++;
-
-       if (dpb_is_debug(DECODE_ID(hw),
-        PRINT_FLAG_DPB_DETAIL)) {
+       if (dpb_is_debug(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL)) {
                dpb_print(DECODE_ID(hw), 0,
                        "%s, fs[%d] poc %d, buf_spec_num %d\n",
                        __func__, frame->index, frame->poc,
@@ -2847,16 +2840,41 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                        frame->bottom_field, -1);
        }
 
+       frame->show_frame = true;
+
+       return 0;
+}
+
+static int post_video_frame(struct vdec_s *vdec, struct FrameStore *frame)
+{
+       struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+       struct vframe_s *vf = NULL;
+       int buffer_index = frame->buf_spec_num;
+       struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+       ulong nv_order = VIDTYPE_VIU_NV21;
+       int bForceInterlace = 0;
+       int vf_count = 1;
+       int i;
+
+       /* swap uv */
+       if (hw->is_used_v4l) {
+               if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
+                       (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
+                       nv_order = VIDTYPE_VIU_NV12;
+       }
+
        if (!is_interlace(frame))
                vf_count = 1;
        else
                vf_count = 2;
+
        bForceInterlace = check_force_interlace(hw, frame);
        if (bForceInterlace)
                vf_count = 2;
        if (hw->is_used_v4l)
                vf_count = 1;
-       hw->buffer_spec[buffer_index].vf_ref = 0;
+       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 ||
@@ -2884,6 +2902,12 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                                = hw->buffer_spec[buffer_index].cma_alloc_addr;
                }
 
+               if (hw->enable_fence) {
+                       /* fill fence information. */
+                       if (hw->fence_usage == FENCE_USE_FOR_DRIVER)
+                               vf->fence       = frame->fence;
+               }
+
                if (hw->mmu_enable) {
                        if (hw->double_write_mode & 0x10) {
                                /* double write only */
@@ -2962,8 +2986,11 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                if (frame->data_flag & ERROR_FLAG)
                        vf->flag |= VFRAME_FLAG_ERROR_RECOVERY;
                update_vf_memhandle(hw, vf, buffer_index);
-               hw->buffer_spec[buffer_index].used = 2;
-               hw->buffer_spec[buffer_index].vf_ref++;
+
+               if (!hw->enable_fence) {
+                       hw->buffer_spec[buffer_index].used = 2;
+                       hw->buffer_spec[buffer_index].vf_ref++;
+               }
 
                dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL,
                        "%s %d frame = %p top_field = %p bottom_field = %p\n", __func__, __LINE__, frame->frame,
@@ -3014,9 +3041,9 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
                        }
 
                        dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL,
-                       "%s %d type = 0x%x pic_struct = %d pts = 0x%x pts_us64 = 0x%llx bForceInterlace = %d\n",
-                       __func__, __LINE__, vf->type, frame->frame->pic_struct,
-                       vf->pts, vf->pts_us64, bForceInterlace);
+                               "%s %d type = 0x%x pic_struct = %d pts = 0x%x pts_us64 = 0x%llx bForceInterlace = %d\n",
+                               __func__, __LINE__, vf->type, frame->frame->pic_struct,
+                               vf->pts, vf->pts_us64, bForceInterlace);
                }
                if (i == 0) {
                        struct vdec_s *pvdec;
@@ -3057,6 +3084,76 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
        return 0;
 }
 
+int post_picture_early(struct vdec_s *vdec, int index)
+{
+       struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+       struct h264_dpb_stru *dpb_stru = &hw->dpb;
+       struct FrameStore fs;
+       u32 offset_lo, offset_hi;
+
+       if (!hw->enable_fence)
+               return 0;
+
+       /* create fence for each buffers. */
+       if (vdec_timeline_create_fence(&vdec->sync))
+               return -1;
+
+       memset(&fs, 0, sizeof(fs));
+
+       fs.buf_spec_num         = index;
+       fs.fence                = vdec->sync.fence;
+       fs.slice_type           = dpb_stru->mSlice.slice_type;
+       fs.dpb_frame_count      = dpb_stru->dpb_frame_count;
+
+       offset_lo = dpb_stru->dpb_param.l.data[OFFSET_DELIMITER_LO];
+       offset_hi = dpb_stru->dpb_param.l.data[OFFSET_DELIMITER_HI];
+       fs.offset_delimiter     = (offset_lo | offset_hi << 16);
+
+       if (hw->chunk) {
+               fs.pts          = hw->chunk->pts;
+               fs.pts64        = hw->chunk->pts64;
+               fs.timestamp    = hw->chunk->timestamp;
+       }
+
+       post_video_frame(vdec, &fs);
+
+       display_frame_count[DECODE_ID(hw)]++;
+       return 0;
+}
+
+int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
+{
+       struct vdec_h264_hw_s *hw =
+               (struct vdec_h264_hw_s *)vdec->private;
+
+       if (hw->enable_fence) {
+               post_prepare_process(vdec, frame);
+
+               if (!frame->show_frame)
+                       pr_info("do not display.\n");
+
+               hw->buffer_spec[frame->buf_spec_num].used = 2;
+               hw->buffer_spec[frame->buf_spec_num].vf_ref = 1;
+               hw->buffer_spec[frame->buf_spec_num].fs_idx = frame->index;
+
+               /* notify signal to wake up wq of fence. */
+               vdec_timeline_increase(&vdec->sync, 1);
+               return 0;
+       }
+
+       if (post_prepare_process(vdec, frame))
+               return -1;
+
+       if (!frame->show_frame)
+               return 0;
+
+       if (post_video_frame(vdec, frame))
+               return -1;
+
+       display_frame_count[DECODE_ID(hw)]++;
+       return 0;
+}
+
 int notify_v4l_eos(struct vdec_s *vdec)
 {
        struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
@@ -4163,8 +4260,13 @@ static void vh264_vf_put(struct vframe_s *vf, void *op_arg)
                        __func__, vf);
                return;
        }
-       frame_index = FRAME_INDEX(vf->index);
+
        buf_spec_num = BUFSPEC_INDEX(vf->index);
+       if (hw->enable_fence)
+               frame_index = hw->buffer_spec[buf_spec_num].fs_idx;
+       else
+               frame_index = FRAME_INDEX(vf->index);
+
        if (frame_index < 0 ||
                frame_index >= DPB_SIZE_MAX ||
                buf_spec_num < 0 ||
@@ -4176,6 +4278,12 @@ static void vh264_vf_put(struct vframe_s *vf, void *op_arg)
        }
                /*get_buf_spec_idx_by_canvas_config(hw,
                        &vf->canvas0_config[0]);*/
+
+       if (hw->enable_fence && vf->fence) {
+               vdec_fence_put(vf->fence);
+               vf->fence = NULL;
+       }
+
        spin_lock_irqsave(&hw->bufspec_lock, flags);
        if (hw->buffer_spec[buf_spec_num].used == 2) {
                struct h264_dpb_stru *p_H264_Dpb = &hw->dpb;
@@ -9780,9 +9888,32 @@ static int ammvdec_h264_probe(struct platform_device *pdev)
                if (get_config_int(pdata->config, "sidebind_channel_id",
                                &config_val) == 0)
                        hw->sidebind_channel_id = config_val;
+
+               if (get_config_int(pdata->config,
+                       "parm_enable_fence",
+                       &config_val) == 0)
+                       hw->enable_fence = config_val;
+
+               if (get_config_int(pdata->config,
+                       "parm_fence_usage",
+                       &config_val) == 0)
+                       hw->fence_usage = config_val;
        } else
                hw->double_write_mode = double_write_mode;
 
+       if (force_config_fence) {
+               hw->enable_fence = true;
+               hw->fence_usage = (force_config_fence >> 4) & 0xf;
+               if (force_config_fence & 0x2)
+                       hw->enable_fence = false;
+               dpb_print(DECODE_ID(hw), 0,
+                       "enable fence: %d, fence usage: %d\n",
+                       hw->enable_fence, hw->fence_usage);
+       }
+
+       if (hw->enable_fence)
+               pdata->sync.usage = hw->fence_usage;
+
        if (!hw->is_used_v4l) {
                hw->reorder_dpb_size_margin = reorder_dpb_size_margin;
                hw->canvas_mode = mem_map_mode;
@@ -9984,9 +10115,47 @@ static int ammvdec_h264_probe(struct platform_device *pdev)
        display_frame_count[DECODE_ID(hw)] = 0;
        decode_frame_count[DECODE_ID(hw)] = 0;
 
+       if (hw->enable_fence) {
+               /* creat timeline. */
+               vdec_timeline_create(&pdata->sync, DRIVER_NAME);
+       }
+
        return 0;
 }
 
+static void vdec_fence_release(struct vdec_h264_hw_s *hw,
+                              struct vdec_sync *sync)
+{
+       ulong expires;
+       int i;
+
+       /* clear display pool. */
+       clear_refer_bufs(hw);
+
+       /* notify signal to wake up all fences. */
+       vdec_timeline_increase(sync, VF_POOL_SIZE);
+
+       expires = jiffies + msecs_to_jiffies(2000);
+       while (!check_objs_all_signaled(sync)) {
+               if (time_after(jiffies, expires)) {
+                       pr_err("wait fence signaled timeout.\n");
+                       break;
+               }
+       }
+
+       for (i = 0; i < VF_POOL_SIZE; i++) {
+               struct vframe_s *vf = &hw->vfpool[hw->cur_pool][i];
+
+               if (vf->fence) {
+                       vdec_fence_put(vf->fence);
+                       vf->fence = NULL;
+               }
+       }
+
+       /* decreases refcnt of timeline. */
+       vdec_timeline_put(sync);
+}
+
 static int ammvdec_h264_remove(struct platform_device *pdev)
 {
        struct vdec_h264_hw_s *hw =
@@ -10050,6 +10219,9 @@ static int ammvdec_h264_remove(struct platform_device *pdev)
                }
        }
 
+       if (hw->enable_fence)
+               vdec_fence_release(hw, &vdec->sync);
+
        ammvdec_h264_mmu_release(hw);
        h264_free_hw_stru(&pdev->dev, (void *)hw);
        clk_adj_frame_count = 0;
@@ -10131,9 +10303,9 @@ static int __init ammvdec_h264_driver_init_module(void)
        if (vdec_is_support_4k()) {
                if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX) {
                        ammvdec_h264_profile.profile =
-                                       "4k, dwrite, compressed, frame_dv";
+                                       "4k, dwrite, compressed, frame_dv, fence";
                } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) {
-                       ammvdec_h264_profile.profile = "4k, frame_dv";
+                       ammvdec_h264_profile.profile = "4k, frame_dv, fence";
                }
        }
 
@@ -10350,6 +10522,8 @@ MODULE_PARM_DESC(loop_playback_poc_threshold, "\n loop_playback_poc_threshold\n"
 module_param(poc_threshold, uint, 0664);
 MODULE_PARM_DESC(poc_threshold, "\n poc_threshold\n");
 
+module_param(force_config_fence, uint, 0664);
+MODULE_PARM_DESC(force_config_fence, "\n force enable fence\n");
 
 module_init(ammvdec_h264_driver_init_module);
 module_exit(ammvdec_h264_driver_remove_module);
index f938f62916b685fcb28ba2ceaa48c746261d0312..82180eb9cb87b3bf99ae07c734e5238e67de7b7d 100644 (file)
@@ -2514,6 +2514,13 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
                                "amvideo");
                        snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
                                "vdec-map-%d", vdec->id);
+               } else if (p->frame_base_video_path ==
+                       FRAME_BASE_PATH_AMLVIDEO_FENCE) {
+                       snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+                               "%s %s", vdec->vf_provider_name,
+                               "amlvideo amvideo");
+                       snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+                               "vdec-map-%d", vdec->id);
                }
 
                if (vfm_map_add(vdec->vfm_map_id,
@@ -3432,7 +3439,6 @@ void vdec_power_reset(void)
 }
 EXPORT_SYMBOL(vdec_power_reset);
 
-
 void vdec_poweron(enum vdec_type_e core)
 {
        if (core >= VDEC_MAX)
index 855b82214676958c2973d55e005f261c641dce0b..01d77356fff525293c0b5403dd0354fed79f1a80 100644 (file)
@@ -53,6 +53,7 @@ static struct sync_timeline *sync_timeline_create(const char *name)
 
        kref_init(&obj->kref);
        obj->context = fence_context_alloc(1);
+       obj->timestamp = local_clock();
        strlcpy(obj->name, name, sizeof(obj->name));
        INIT_LIST_HEAD(&obj->active_list_head);
        INIT_LIST_HEAD(&obj->pt_list);
@@ -67,7 +68,6 @@ static void sync_timeline_free(struct kref *kref)
                container_of(kref, struct sync_timeline, kref);
 
        pr_info("[VDEC-FENCE] free timeline: %lx\n", (ulong) obj);
-
        kfree(obj);
 }
 
@@ -188,7 +188,7 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
        obj->value += inc;
        list_for_each_entry_safe(pt, next, &obj->active_list_head,
                                 active_list) {
-               if (fence_is_signaled_locked(&pt->fence))
+               if (fence_is_signaled(&pt->fence))
                        list_del_init(&pt->active_list);
        }
        spin_unlock_irqrestore(&obj->lock, flags);
@@ -297,8 +297,8 @@ EXPORT_SYMBOL(vdec_fence_get);
 void vdec_fence_put(struct fence *fence)
 {
        if (debug & VDEC_DBG_ENABLE_FENCE)
-               pr_info("[VDEC-FENCE]: the fence cost time: %lld ns\n",
-                       local_clock() - get_sync_pt(fence)->timestamp);
+               pr_info("[VDEC-FENCE]: the fence (%px) cost time: %lld ns\n",
+                       fence, local_clock() - get_sync_pt(fence)->timestamp);
        fence_put(fence);
 }
 EXPORT_SYMBOL(vdec_fence_put);
@@ -328,13 +328,26 @@ EXPORT_SYMBOL(vdec_timeline_create);
 int vdec_timeline_create_fence(struct vdec_sync *sync)
 {
        struct sync_timeline *obj = sync->timeline;
+       struct sync_pt *pt = NULL;
+       ulong flags;
        u32 value = 0;
 
        if (obj == NULL)
                return -EPERM;
 
+       spin_lock_irqsave(&obj->lock, flags);
+
+       pt = list_last_entry(&obj->pt_list, struct sync_pt, link);
        value = obj->value + 1;
 
+       if (!list_empty(&obj->pt_list)) {
+               pt = list_last_entry(&obj->pt_list, struct sync_pt, link);
+               if (value == pt->fence.seqno) {
+                       value++;
+               }
+       }
+       spin_unlock_irqrestore(&obj->lock, flags);
+
        return timeline_create_fence(sync,
                                     sync->usage,
                                     &sync->fence,
@@ -394,3 +407,21 @@ bool check_objs_all_signaled(struct vdec_sync *sync)
 }
 EXPORT_SYMBOL(check_objs_all_signaled);
 
+int vdec_clean_all_fence(struct vdec_sync *sync)
+{
+       struct sync_timeline *obj = sync->timeline;
+       struct sync_pt *pt, *next;
+
+       spin_lock_irq(&obj->lock);
+
+       list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
+               fence_set_error(&pt->fence, -ENOENT);
+               fence_signal_locked(&pt->fence);
+       }
+
+       spin_unlock_irq(&obj->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(vdec_clean_all_fence);
+
index fa07721c2ee410224d3abb08414f04aee5e08212..062234115cdef8ad1370f8163b5809ada453264a 100644 (file)
@@ -87,3 +87,5 @@ void vdec_fence_status_set(struct fence *fence, int status);
 
 bool check_objs_all_signaled(struct vdec_sync *sync);
 
+int vdec_clean_all_fence(struct vdec_sync *sync);
+
index 5717d608f073f4c35b94ade0d5604af67725d4a2..d6ac49a9bcdd84facc0fb228c30687ed6da191a5 100644 (file)
@@ -11175,24 +11175,24 @@ static int __init amvdec_vp9_driver_init_module(void)
 
        if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
                amvdec_vp9_profile.profile =
-                               "8k, 10bit, dwrite, compressed";
+                               "8k, 10bit, dwrite, compressed, fence";
        } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL
                /*&& get_cpu_major_id() != MESON_CPU_MAJOR_ID_GXLX*/
                && get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TXL) {
                        if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX) {
                                if (vdec_is_support_4k())
                                        amvdec_vp9_profile.profile =
-                                               "4k, 10bit, dwrite, compressed";
+                                               "4k, 10bit, dwrite, compressed, fence";
                                else
                                        amvdec_vp9_profile.profile =
-                                               "10bit, dwrite, compressed";
+                                               "10bit, dwrite, compressed, fence";
                        } else {
                                if (vdec_is_support_4k())
                                        amvdec_vp9_profile.profile =
-                                               "4k, 10bit, dwrite, compressed";
+                                               "4k, 10bit, dwrite, compressed, fence";
                                else
                                        amvdec_vp9_profile.profile =
-                                               "10bit, dwrite, compressed";
+                                               "10bit, dwrite, compressed, fence";
                        }
 
        } else {