55 files changed, 11471 insertions, 2282 deletions
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c index d3bdb51..30e4072 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c @@ -45,8 +45,7 @@ #include "../utils/decoder_bmmu_box.h" #include <linux/amlogic/media/codec_mm/configs.h> #include "../utils/firmware.h" - - +#include "../utils/vdec_v4l2_buffer_ops.h" #define DRIVER_NAME "ammvdec_mpeg4" #define MODULE_NAME "ammvdec_mpeg4" @@ -167,6 +166,7 @@ unsigned int mpeg4_debug_mask = 0xff; #define PRINT_FRAMEBASE_DATA 0x0400 #define PRINT_FLAG_VDEC_STATUS 0x0800 #define PRINT_FLAG_TIMEOUT_STATUS 0x1000 +#define PRINT_FLAG_V4L_DETAIL 0x8000 int mmpeg4_debug_print(int index, int debug_flag, const char *fmt, ...) { @@ -194,6 +194,7 @@ struct pic_info_t { bool pts_valid; u32 duration; u32 repeat_cnt; + ulong v4l_ref_buf_addr; }; struct vdec_mpeg4_hw_s { @@ -294,6 +295,9 @@ struct vdec_mpeg4_hw_s { struct firmware_s *fw; u32 blkmode; wait_queue_head_t wait_q; + bool is_used_v4l; + void *v4l2_ctx; + bool v4l_params_parsed; }; static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw); static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw); @@ -326,16 +330,122 @@ static unsigned char aspect_ratio_table[16] = { }; static void reset_process_time(struct vdec_mpeg4_hw_s *hw); -static int find_buffer(struct vdec_mpeg4_hw_s *hw) + +static int vmpeg4_v4l_alloc_buff_config_canvas(struct vdec_mpeg4_hw_s *hw, int i) +{ + int ret; + u32 canvas; + ulong decbuf_start = 0; + int decbuf_y_size = 0; + u32 canvas_width = 0, canvas_height = 0; + struct vdec_s *vdec = hw_to_vdec(hw); + struct vdec_v4l2_buffer *fb = NULL; + + if (hw->pic[i].v4l_ref_buf_addr) + return 0; + + ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + if (ret) { + mmpeg4_debug_print(DECODE_ID(hw), 0, + "[%d] get fb fail.\n", + ((struct aml_vcodec_ctx *) + (hw->v4l2_ctx))->id); + return ret; + } + + hw->pic[i].v4l_ref_buf_addr = (ulong)fb; + if (fb->num_planes == 1) { + decbuf_start = fb->m.mem[0].addr; + decbuf_y_size = fb->m.mem[0].offset; + canvas_width = ALIGN(hw->frame_width, 64); + canvas_height = ALIGN(hw->frame_height, 32); + fb->m.mem[0].bytes_used = fb->m.mem[0].size; + } else if (fb->num_planes == 2) { + decbuf_start = fb->m.mem[0].addr; + decbuf_y_size = fb->m.mem[0].size; + canvas_width = ALIGN(hw->frame_width, 64); + canvas_height = ALIGN(hw->frame_height, 32); + fb->m.mem[0].bytes_used = decbuf_y_size; + fb->m.mem[1].bytes_used = decbuf_y_size << 1; + } + + mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%x\n", + ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, __func__, fb); + + if (vdec->parallel_dec == 1) { + u32 tmp; + if (canvas_y(hw->canvas_spec[i]) == 0xff) { + tmp = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->canvas_spec[i] &= ~0xff; + hw->canvas_spec[i] |= tmp; + } + if (canvas_u(hw->canvas_spec[i]) == 0xff) { + tmp = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->canvas_spec[i] &= ~(0xffff << 8); + hw->canvas_spec[i] |= tmp << 8; + hw->canvas_spec[i] |= tmp << 16; + } + canvas = hw->canvas_spec[i]; + } else { + canvas = vdec->get_canvas(i, 2); + hw->canvas_spec[i] = canvas; + } + + hw->canvas_config[i][0].phy_addr = decbuf_start; + hw->canvas_config[i][0].width = canvas_width; + hw->canvas_config[i][0].height = canvas_height; + hw->canvas_config[i][0].block_mode = hw->blkmode; + if (hw->blkmode == CANVAS_BLKMODE_LINEAR) + hw->canvas_config[i][0].endian = 7; + else + hw->canvas_config[i][0].endian = 0; + canvas_config_config(canvas_y(canvas), + &hw->canvas_config[i][0]); + + hw->canvas_config[i][1].phy_addr = + decbuf_start + decbuf_y_size; + hw->canvas_config[i][1].width = canvas_width; + hw->canvas_config[i][1].height = (canvas_height >> 1); + hw->canvas_config[i][1].block_mode = hw->blkmode; + if (hw->blkmode == CANVAS_BLKMODE_LINEAR) + hw->canvas_config[i][1].endian = 7; + else + hw->canvas_config[i][1].endian = 0; + canvas_config_config(canvas_u(canvas), + &hw->canvas_config[i][1]); + + return 0; +} + +static bool is_enough_free_buffer(struct vdec_mpeg4_hw_s *hw) { int i; for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { if (hw->vfbuf_use[i] == 0) - return i; + break; + } + + return i == DECODE_BUFFER_NUM_MAX ? false : true; +} + +static int find_free_buffer(struct vdec_mpeg4_hw_s *hw) +{ + int i; + + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + if (hw->vfbuf_use[i] == 0) + break; } - return DECODE_BUFFER_NUM_MAX; + if (i == DECODE_BUFFER_NUM_MAX) + return -1; + + if (hw->is_used_v4l) + if (vmpeg4_v4l_alloc_buff_config_canvas(hw, i)) + return -1; + + return i; } static int spec_to_index(struct vdec_mpeg4_hw_s *hw, u32 spec) @@ -477,7 +587,6 @@ static int update_ref(struct vdec_mpeg4_hw_s *hw, int index) return index; } - static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, struct pic_info_t *pic) { @@ -492,6 +601,15 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, return -1; } + if (hw->is_used_v4l) { + vf->v4l_mem_handle + = hw->pic[index].v4l_ref_buf_addr; + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), v4l mem handle: 0x%lx\n", + ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, + __func__, vf->v4l_mem_handle); + } + vf->index = pic->index; vf->width = hw->frame_width; vf->height = hw->frame_height; @@ -596,6 +714,20 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, return -1; } + if (hw->is_used_v4l) { + vf->v4l_mem_handle + = hw->pic[index].v4l_ref_buf_addr; + if (vdec_v4l_binding_fd_and_vf(vf->v4l_mem_handle, vf) < 0) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "v4l: binding vf fail.\n"); + return -1; + } + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), v4l mem handle: 0x%lx\n", + ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, + __func__, vf->v4l_mem_handle); + } + vf->index = index; vf->width = hw->frame_width; vf->height = hw->frame_height; @@ -817,6 +949,26 @@ static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) if (dec_h != 0) hw->frame_height = dec_h; + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { + struct aml_vdec_pic_infos info; + + info.visible_width = hw->frame_width; + info.visible_height = hw->frame_height; + info.coded_width = ALIGN(hw->frame_width, 64); + info.coded_height = ALIGN(hw->frame_height, 64); + info.dpb_size = MAX_BMMU_BUFFER_NUM - 1; + hw->v4l_params_parsed = true; + vdec_v4l_set_pic_infos(ctx, &info); + } + + if (!ctx->v4l_codec_ready) + return IRQ_HANDLED; + } + if (hw->vmpeg4_amstream_dec_info.rate == 0) { if (vop_time_inc < hw->last_vop_time_inc) { duration = vop_time_inc + @@ -918,7 +1070,6 @@ static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) return IRQ_HANDLED; } disp_pic = &hw->pic[index]; - if ((hw->first_i_frame_ready == 0) && (I_PICTURE == disp_pic->pic_type)) hw->first_i_frame_ready = 1; @@ -1106,6 +1257,40 @@ static void flush_output(struct vdec_mpeg4_hw_s * hw) } } +static int notify_v4l_eos(struct vdec_s *vdec) +{ + struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct vframe_s *vf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + + if (hw->is_used_v4l && hw->eos) { + if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s fatal error, no available buffer slot.\n", + __func__); + return -1; + } + + if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { + pr_err("[%d] get fb fail.\n", ctx->id); + return -1; + } + + vf->timestamp = ULONG_MAX; + vf->v4l_mem_handle = (unsigned long)fb; + vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + pr_info("[%d] mpeg4 EOS notify.\n", ctx->id); + } + + return 0; +} + static void vmpeg4_work(struct work_struct *work) { struct vdec_mpeg4_hw_s *hw = @@ -1160,6 +1345,10 @@ static void vmpeg4_work(struct work_struct *work) hw->chunk = NULL; vdec_clean_input(vdec); flush_output(hw); + + if (hw->is_used_v4l) + notify_v4l_eos(vdec); + mmpeg4_debug_print(DECODE_ID(hw), 0, "%s: eos flushed, frame_num %d\n", __func__, hw->frame_num); @@ -1289,55 +1478,61 @@ static int vmpeg4_canvas_init(struct vdec_mpeg4_hw_s *hw) canvas_height = 576; decbuf_y_size = 0x80000; decbuf_size = 0x100000; + } else { + int w = 1920; + int h = 1088; + int align_w, align_h; + int max, min; + + align_w = ALIGN(w, 64); + align_h = ALIGN(h, 64); + if (align_w > align_h) { + max = align_w; + min = align_h; } else { - int w = 1920; - int h = 1088; - int align_w, align_h; - int max, min; - - align_w = ALIGN(w, 64); - align_h = ALIGN(h, 64); - if (align_w > align_h) { - max = align_w; - min = align_h; + max = align_h; + min = align_w; + } + /* HD & SD */ + if ((max > 1920 || min > 1088) && + ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <= + buf_size) { + canvas_width = align_w; + canvas_height = align_h; + decbuf_y_size = + ALIGN(align_w * align_h, SZ_64K); + decbuf_size = + ALIGN(align_w * align_h * 3/2, SZ_64K); + } else { /*1080p*/ + if (h > w) { + canvas_width = 1088; + canvas_height = 1920; } else { - max = align_h; - min = align_w; - } - /* HD & SD */ - if ((max > 1920 || min > 1088) && - ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <= - buf_size) { - canvas_width = align_w; - canvas_height = align_h; - decbuf_y_size = - ALIGN(align_w * align_h, SZ_64K); - decbuf_size = - ALIGN(align_w * align_h * 3/2, SZ_64K); - } else { /*1080p*/ - if (h > w) { - canvas_width = 1088; - canvas_height = 1920; - } else { - canvas_width = 1920; - canvas_height = 1088; - } - decbuf_y_size = 0x200000; - decbuf_size = 0x300000; + canvas_width = 1920; + canvas_height = 1088; } + decbuf_y_size = 0x200000; + decbuf_size = 0x300000; } + } for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) { unsigned canvas; + if (i == (MAX_BMMU_BUFFER_NUM - 1)) decbuf_size = WORKSPACE_SIZE; - ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, - decbuf_size, DRIVER_NAME, &decbuf_start); - if (ret < 0) { - pr_err("mmu alloc failed! size 0x%d idx %d\n", - decbuf_size, i); - return ret; + + if (hw->is_used_v4l && !(i == (MAX_BMMU_BUFFER_NUM - 1))) { + continue; + } else { + ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, + decbuf_size, DRIVER_NAME, &decbuf_start); + if (ret < 0) { + pr_err("mmu alloc failed! size %d idx %d\n", + decbuf_size, i); + return ret; + } } if (i == (MAX_BMMU_BUFFER_NUM - 1)) { @@ -1391,6 +1586,7 @@ static int vmpeg4_canvas_init(struct vdec_mpeg4_hw_s *hw) return 0; } + static void vmpeg4_dump_state(struct vdec_s *vdec) { struct vdec_mpeg4_hw_s *hw = @@ -1590,19 +1786,21 @@ static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw) int index, i; void *workspace_buf = NULL; - index = find_buffer(hw); - if (index >= DECODE_BUFFER_NUM_MAX) + index = find_free_buffer(hw); + if (index < 0) return -1; if (!hw->init_flag) { if (vmpeg4_canvas_init(hw) < 0) return -1; } else { - for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { - canvas_config_config(canvas_y(hw->canvas_spec[i]), - &hw->canvas_config[i][0]); - canvas_config_config(canvas_u(hw->canvas_spec[i]), - &hw->canvas_config[i][1]); + if (!hw->is_used_v4l) { + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + canvas_config_config(canvas_y(hw->canvas_spec[i]), + &hw->canvas_config[i][0]); + canvas_config_config(canvas_u(hw->canvas_spec[i]), + &hw->canvas_config[i][1]); + } } } /* prepare REF0 & REF1 @@ -1827,7 +2025,6 @@ static s32 vmmpeg4_init(struct vdec_mpeg4_hw_s *hw) static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { - int index; struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; if (hw->eos) @@ -1848,11 +2045,11 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) } } - index = find_buffer(hw); - if (index >= DECODE_BUFFER_NUM_MAX) { + if (!is_enough_free_buffer(hw)) { hw->buffer_not_ready++; return 0; } + hw->not_run_ready = 0; hw->buffer_not_ready = 0; if (vdec->parallel_dec == 1) @@ -2055,6 +2252,9 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) } memset(hw, 0, sizeof(struct vdec_mpeg4_hw_s)); + /* the ctx from v4l2 driver. */ + hw->v4l2_ctx = pdata->private; + pdata->private = hw; pdata->dec_status = dec_status; /* pdata->set_trickmode = set_trickmode; */ @@ -2085,7 +2285,6 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) hw->platform_dev = pdev; hw->blkmode = pdata->canvas_mode; - if (pdata->sys_info) { hw->vmpeg4_amstream_dec_info = *pdata->sys_info; if ((hw->vmpeg4_amstream_dec_info.height != 0) && @@ -2104,6 +2303,8 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) hw->vmpeg4_amstream_dec_info.width, hw->vmpeg4_amstream_dec_info.height, hw->vmpeg4_amstream_dec_info.rate); + hw->is_used_v4l = (((unsigned long) + hw->vmpeg4_amstream_dec_info.param & 0x80) >> 7); } if (vmmpeg4_init(hw) < 0) { @@ -2116,6 +2317,7 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) pdata->dec_status = NULL; return -ENODEV; } + if (pdata->parallel_dec == 1) vdec_core_request(pdata, CORE_MASK_VDEC_1); else { @@ -2125,7 +2327,6 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) mmpeg4_debug_print(DECODE_ID(hw), 0, "%s end.\n", __func__); - return 0; } |