v4l: optimize the format mjpeg for v4l codec. [1/2]
authorPeng Yixin <yixin.peng@amlogic.com>
Sat, 4 Apr 2020 10:35:04 +0000 (18:35 +0800)
committerNanxin Qin <nanxin.qin@amlogic.com>
Wed, 1 Jul 2020 14:50:04 +0000 (22:50 +0800)
PD#SWPL-23747

Problem:
optimize the format mjpeg for v4l codec.

Solution:
1. supports parser the picture params from HW.
2. supports picture format YU12(I420)
3. ucode commit id:
   879f23b8b65c09241ff40b29ff0d2aa270a0fa12

Android P, Q share CLs.

Verify:
u212

Change-Id: I6c506e007f0c3a4bcda66f53fac943cee404cf18
Signed-off-by: Peng Yixin <yixin.peng@amlogic.com>
drivers/amvdec_ports/aml_vcodec_dec.c
drivers/amvdec_ports/decoder/vdec_mjpeg_if.c
drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
firmware/video_ucode.bin

index 14d83b0ea9cdceba2b3037c0dd522b625af801c3..681eb059aaa57ef89debde585d38e6efd32fbcce 100644 (file)
@@ -116,6 +116,11 @@ static struct aml_video_fmt aml_video_formats[] = {
                .type = AML_FMT_FRAME,
                .num_planes = 2,
        },
+       {
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .type = AML_FMT_FRAME,
+               .num_planes = 1,
+       },
 };
 
 static const struct aml_codec_framesizes aml_vdec_framesizes[] = {
@@ -642,10 +647,9 @@ static void aml_check_dpb_ready(struct aml_vcodec_ctx *ctx)
 {
        if (!ctx->v4l_codec_dpb_ready) {
                /*
-                * make sure enough dst bufs for decoding, and
-                * the backend maybe hold 4 frms so need to minus 4.
+                * make sure enough dst bufs for decoding.
                 */
-               if ((ctx->dpb_size) && (ctx->cap_pool.in >= ctx->dpb_size - 4))
+               if ((ctx->dpb_size) && (ctx->cap_pool.in >= ctx->dpb_size))
                        ctx->v4l_codec_dpb_ready = true;
 
                v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
index 4ede6b5ebcc320f6233b5cbc455913dc04848b4b..949f0256c589ab8a4be1c0aadba8b51ba36a1497 100644 (file)
@@ -30,6 +30,7 @@
 #include "../vdec_drv_base.h"
 #include "../aml_vcodec_vfm.h"
 #include "aml_mjpeg_parser.h"
+#include <media/v4l2-mem2mem.h>
 
 #define NAL_TYPE(value)                                ((value) & 0x1F)
 #define HEADER_BUFFER_SIZE                     (32 * 1024)
@@ -112,6 +113,7 @@ struct vdec_mjpeg_inst {
        struct aml_vdec_adapt vdec;
        struct vdec_mjpeg_vsi *vsi;
        struct vcodec_vfm_s vfm;
+       struct aml_dec_params parms;
        struct completion comp;
 };
 
@@ -144,11 +146,48 @@ static void get_crop_info(struct vdec_mjpeg_inst *inst, struct v4l2_rect *cr)
 
 static void get_dpb_size(struct vdec_mjpeg_inst *inst, unsigned int *dpb_sz)
 {
-       *dpb_sz = 20;//inst->vsi->dec.dpb_sz;
+       *dpb_sz = inst->vsi->dec.dpb_sz;
        v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO,
                "sz=%d\n", *dpb_sz);
 }
 
+static u32 vdec_config_default_parms(u8 *parm)
+{
+       u8 *pbuf = parm;
+
+       pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;");
+       pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;");
+       pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:0;");
+
+       return pbuf - parm;
+}
+
+static void vdec_parser_parms(struct vdec_mjpeg_inst *inst)
+{
+       struct aml_vcodec_ctx *ctx = inst->ctx;
+
+       if (ctx->config.parm.dec.parms_status &
+               V4L2_CONFIG_PARM_DECODE_CFGINFO) {
+               u8 *pbuf = ctx->config.buf;
+
+               pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;");
+               pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;",
+                       ctx->config.parm.dec.cfg.canvas_mem_mode);
+               pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;",
+                       ctx->config.parm.dec.cfg.ref_buf_margin);
+               pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;",
+                       ctx->config.parm.dec.cfg.canvas_mem_endian);
+               ctx->config.length = pbuf - ctx->config.buf;
+       } else {
+               ctx->config.length = vdec_config_default_parms(ctx->config.buf);
+       }
+
+       inst->vdec.config       = ctx->config;
+       inst->parms.cfg         = ctx->config.parm.dec.cfg;
+       inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO;
+}
+
+
 static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
 {
        struct vdec_mjpeg_inst *inst = NULL;
@@ -165,6 +204,7 @@ static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
        inst->vdec.ctx          = ctx;
        inst->ctx               = ctx;
 
+       vdec_parser_parms(inst);
        /* set play mode.*/
        if (ctx->is_drm_mode)
                inst->vdec.port.flag |= PORT_FLAG_DRM;
@@ -203,18 +243,10 @@ static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
                goto err;
        }
 
-       inst->vsi->pic.visible_width    = 1920;
-       inst->vsi->pic.visible_height   = 1080;
-       inst->vsi->pic.coded_width      = 1920;
-       inst->vsi->pic.coded_height     = 1088;
-       inst->vsi->pic.y_bs_sz          = 0;
-       inst->vsi->pic.y_len_sz         = (1920 * 1088);
-       inst->vsi->pic.c_bs_sz          = 0;
-       inst->vsi->pic.c_len_sz         = (1920 * 1088 / 2);
-
        v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
                "mjpeg Instance >> %lx\n", (ulong) inst);
 
+       init_completion(&inst->comp);
        ctx->ada_ctx    = &inst->vdec;
        *h_vdec         = (unsigned long)inst;
 
@@ -266,10 +298,10 @@ static void fill_vdec_params(struct vdec_mjpeg_inst *inst,
        pic->coded_height       = ALIGN(ps->height, 64);
 
        pic->y_len_sz           = pic->coded_width * pic->coded_height;
-       pic->c_len_sz           = pic->y_len_sz >> 1;
+       pic->c_len_sz           = pic->y_len_sz;
 
-       /* calc DPB size */
-       dec->dpb_sz = 9;//refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h);
+       /*8(DECODE_BUFFER_NUM_DEF) */
+       dec->dpb_sz = 8;
 
        v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR,
                "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n",
@@ -542,7 +574,46 @@ static int vdec_mjpeg_get_param(unsigned long h_vdec,
 static void set_param_ps_info(struct vdec_mjpeg_inst *inst,
        struct aml_vdec_ps_infos *ps)
 {
-       v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "\n");
+       struct vdec_pic_info *pic = &inst->vsi->pic;
+       struct vdec_mjpeg_dec_info *dec = &inst->vsi->dec;
+       struct v4l2_rect *rect = &inst->vsi->crop;
+
+       v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "%s in\n", __func__);
+       /* fill visible area size that be used for EGL. */
+       pic->visible_width      = ps->visible_width;
+       pic->visible_height     = ps->visible_height;
+
+       /* calc visible ares. */
+       rect->left              = 0;
+       rect->top               = 0;
+       rect->width             = pic->visible_width;
+       rect->height            = pic->visible_height;
+
+       /* config canvas size that be used for decoder. */
+       pic->coded_width        = ps->coded_width;
+       pic->coded_height       = ps->coded_height;
+       pic->y_len_sz           = pic->coded_width * pic->coded_height;
+       pic->c_len_sz           = pic->y_len_sz;
+
+       dec->dpb_sz             = ps->dpb_size;
+
+       inst->parms.ps  = *ps;
+       inst->parms.parms_status |=
+               V4L2_CONFIG_PARM_DECODE_PSINFO;
+
+       /*wake up*/
+       complete(&inst->comp);
+
+       v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+               "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n",
+               ps->visible_width, ps->visible_height,
+               ps->coded_width, ps->coded_height,
+               dec->dpb_sz);
+}
+
+static void set_param_write_sync(struct vdec_mjpeg_inst *inst)
+{
+       complete(&inst->comp);
 }
 
 static int vdec_mjpeg_set_param(unsigned long h_vdec,
@@ -558,6 +629,9 @@ static int vdec_mjpeg_set_param(unsigned long h_vdec,
        }
 
        switch (type) {
+       case SET_PARAM_WRITE_FRAME_SYNC:
+               set_param_write_sync(inst);
+               break;
        case SET_PARAM_PS_INFO:
                set_param_ps_info(inst, in);
                break;
index 436c8cd8557ecbcedf08b02884da93d755e12211..8f413df5abc10e45efeced764ed561e2561cb18b 100644 (file)
@@ -46,6 +46,7 @@
 #include "../utils/firmware.h"
 #include "../utils/vdec_v4l2_buffer_ops.h"
 #include "../utils/config_parser.h"
+#include <media/v4l2-mem2mem.h>
 
 #define MEM_NAME "codec_mmjpeg"
 
@@ -100,6 +101,7 @@ static int pre_decode_buf_level = 0x800;
 static int start_decode_buf_level = 0x2000;
 static u32 without_display_mode;
 static u32 dynamic_buf_num_margin;
+static u32 run_ready_min_buf_num = 2;
 #undef pr_info
 #define pr_info printk
 unsigned int mmjpeg_debug_mask = 0xff;
@@ -225,9 +227,14 @@ struct vdec_mjpeg_hw_s {
        int dynamic_buf_num_margin;
        int sidebind_type;
        int sidebind_channel_id;
+       unsigned int res_ch_flag;
+       u32 canvas_mode;
+       u32 canvas_endian;
 };
 
 static void reset_process_time(struct vdec_mjpeg_hw_s *hw);
+static int notify_v4l_eos(struct vdec_s *vdec);
+
 static void set_frame_info(struct vdec_mjpeg_hw_s *hw, struct vframe_s *vf)
 {
        u32 temp;
@@ -277,6 +284,51 @@ static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq)
        return IRQ_WAKE_THREAD;
 }
 
+static int vmjpeg_get_ps_info(struct vdec_mjpeg_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps)
+{
+       ps->visible_width       = width;
+       ps->visible_height      = height;
+       ps->coded_width         = ALIGN(width, 64);
+       ps->coded_height        = ALIGN(height, 64);
+       ps->dpb_size            = hw->buf_num;
+
+       return 0;
+}
+
+static int v4l_res_change(struct vdec_mjpeg_hw_s *hw, int width, int height)
+{
+       struct aml_vcodec_ctx *ctx =
+                       (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+       int ret = 0;
+
+       if (ctx->param_sets_from_ucode &&
+               hw->res_ch_flag == 0) {
+               struct aml_vdec_ps_infos ps;
+
+               if ((hw->frame_width != 0 &&
+                       hw->frame_height != 0) &&
+                       (hw->frame_width != width ||
+                       hw->frame_height != height)) {
+                       mmjpeg_debug_print(DECODE_ID(hw), 0,
+                               "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n",
+                               hw->frame_width, hw->frame_height,
+                               width,
+                               height);
+                       vmjpeg_get_ps_info(hw, width, height, &ps);
+                       vdec_v4l_set_ps_infos(ctx, &ps);
+                       vdec_v4l_res_ch_event(ctx);
+                       hw->v4l_params_parsed = false;
+                       hw->res_ch_flag = 1;
+                       hw->eos = 1;
+                       notify_v4l_eos(hw_to_vdec(hw));
+
+                       ret = 1;
+               }
+       }
+
+       return ret;
+}
+
 static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq)
 {
        struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)(vdec->private);
@@ -295,8 +347,38 @@ static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq)
                return IRQ_HANDLED;
        }
 
+       if (READ_VREG(DEC_STATUS_REG) == 1) {
+               if (hw->is_used_v4l) {
+                       int frame_width = READ_VREG(MREG_PIC_WIDTH);
+                       int frame_height = READ_VREG(MREG_PIC_HEIGHT);
+
+                       if (!v4l_res_change(hw, frame_width, frame_height)) {
+                               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_ps_infos ps;
+
+                                       vmjpeg_get_ps_info(hw, frame_width, frame_height, &ps);
+                                       hw->v4l_params_parsed = true;
+                                       vdec_v4l_set_ps_infos(ctx, &ps);
+                                       reset_process_time(hw);
+                                       hw->dec_result = DEC_RESULT_AGAIN;
+                                       vdec_schedule_work(&hw->work);
+                               } else {
+                                       WRITE_VREG(DEC_STATUS_REG, 0);
+                               }
+                       } else {
+                               reset_process_time(hw);
+                               hw->dec_result = DEC_RESULT_AGAIN;
+                               vdec_schedule_work(&hw->work);
+                       }
+               } else
+                       WRITE_VREG(DEC_STATUS_REG, 0);
+               return IRQ_HANDLED;
+       }
+
        reg = READ_VREG(MREG_FROM_AMRISC);
-       index = READ_VREG(AV_SCRATCH_5);
+       index = READ_VREG(AV_SCRATCH_5) & 0xffffff;
 
        if (index >= hw->buf_num) {
                pr_err("fatal error, invalid buffer index.");
@@ -309,23 +391,6 @@ static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq)
                return IRQ_HANDLED;
        }
 
-       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_ps_infos ps;
-
-                       ps.visible_width        = hw->frame_width;
-                       ps.visible_height       = hw->frame_height;
-                       ps.coded_width          = ALIGN(hw->frame_width, 64);
-                       ps.coded_height         = ALIGN(hw->frame_height, 64);
-                       ps.dpb_size             = hw->buf_num;
-                       hw->v4l_params_parsed   = true;
-                       vdec_v4l_set_ps_infos(ctx, &ps);
-               }
-       }
-
        if (hw->is_used_v4l) {
                vf->v4l_mem_handle
                        = hw->buffer_spec[index].v4l_ref_buf_addr;
@@ -345,6 +410,7 @@ static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq)
        if (hw->chunk) {
                vf->pts = hw->chunk->pts;
                vf->pts_us64 = hw->chunk->pts64;
+               vf->timestamp = hw->chunk->timestamp;
        } else {
                offset = READ_VREG(MREG_FRAME_OFFSET);
                if (pts_lookup_offset_us64
@@ -856,11 +922,13 @@ static int vmjpeg_v4l_alloc_buff_config_canvas(struct vdec_mjpeg_hw_s *hw, int i
 {
        int ret;
        u32 canvas;
-       ulong decbuf_start = 0, addr;
-       int decbuf_y_size = 0, decbuf_uv_size = 0;
+       ulong decbuf_start = 0, decbuf_u_start = 0, decbuf_v_start = 0;
+       int decbuf_y_size = 0, decbuf_u_size = 0, decbuf_v_size = 0;
        u32 canvas_width = 0, canvas_height = 0;
        struct vdec_s *vdec = hw_to_vdec(hw);
        struct vdec_v4l2_buffer *fb = NULL;
+       struct aml_vcodec_ctx *ctx =
+               (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
 
        if (hw->buffer_spec[i].v4l_ref_buf_addr)
                return 0;
@@ -874,34 +942,54 @@ static int vmjpeg_v4l_alloc_buff_config_canvas(struct vdec_mjpeg_hw_s *hw, int i
                return ret;
        }
 
+       if (!hw->frame_width || !hw->frame_height) {
+                       struct vdec_pic_info pic;
+                       vdec_v4l_get_pic_info(ctx, &pic);
+                       hw->frame_width = pic.visible_width;
+                       hw->frame_height = pic.visible_height;
+                       mmjpeg_debug_print(DECODE_ID(hw), 0,
+                               "[%d] set %d x %d from IF layer\n", ctx->id,
+                               hw->frame_width, hw->frame_height);
+       }
+
        hw->buffer_spec[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;
-               decbuf_uv_size  = fb->m.mem[0].size - fb->m.mem[0].offset;
-               canvas_width    = ALIGN(hw->frame_width, 16);
-               canvas_height   = ALIGN(hw->frame_height, 16);
+               decbuf_u_start  = decbuf_start + decbuf_y_size;
+               decbuf_u_size   = decbuf_y_size / 4;
+               decbuf_v_start  = decbuf_u_start + decbuf_u_size;
+               decbuf_v_size   = decbuf_u_size;
+               canvas_width    = ALIGN(hw->frame_width, 64);
+               canvas_height   = ALIGN(hw->frame_height, 64);
                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;
-               decbuf_uv_size  = fb->m.mem[1].size << 1;
-               canvas_width    = ALIGN(hw->frame_width, 16);
-               canvas_height   = ALIGN(hw->frame_height, 16);
-               fb->m.mem[0].bytes_used = decbuf_y_size;
-               fb->m.mem[1].bytes_used = decbuf_uv_size >> 1;
+               decbuf_u_start  = fb->m.mem[1].addr;
+               decbuf_u_size   = fb->m.mem[1].size;
+               decbuf_v_start  = decbuf_u_start + decbuf_u_size;
+               decbuf_v_size   = decbuf_u_size;
+               canvas_width    = ALIGN(hw->frame_width, 64);
+               canvas_height   = ALIGN(hw->frame_height, 64);
+               fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+               fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+       } else if (fb->num_planes == 3) {
+               decbuf_start    = fb->m.mem[0].addr;
+               decbuf_y_size   = fb->m.mem[0].size;
+               decbuf_u_start  = fb->m.mem[1].addr;
+               decbuf_u_size   = fb->m.mem[1].size;
+               decbuf_v_start  = fb->m.mem[2].addr;
+               decbuf_v_size   = fb->m.mem[2].size;
+               canvas_width    = ALIGN(hw->frame_width, 64);
+               canvas_height   = ALIGN(hw->frame_height, 64);
+               fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+               fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+               fb->m.mem[2].bytes_used = fb->m.mem[2].size;
        }
 
-       hw->buffer_spec[i].buf_adr = decbuf_start;
-       addr = hw->buffer_spec[i].buf_adr;
-       hw->buffer_spec[i].y_addr = addr;
-       addr += decbuf_y_size;
-       hw->buffer_spec[i].u_addr = addr;
-       addr += decbuf_uv_size;
-       hw->buffer_spec[i].v_addr = addr;
-
-       mmjpeg_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);
+       mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+               "[%d] v4l ref buf addr: 0x%x\n", ctx->id, fb);
 
        if (vdec->parallel_dec == 1) {
                if (hw->buffer_spec[i].y_canvas_index == -1)
@@ -920,50 +1008,52 @@ static int vmjpeg_v4l_alloc_buff_config_canvas(struct vdec_mjpeg_hw_s *hw, int i
                hw->buffer_spec[i].v_canvas_index = canvas_v(canvas);
        }
 
-       canvas_config(hw->buffer_spec[i].y_canvas_index,
-               hw->buffer_spec[i].y_addr,
-               canvas_width,
-               canvas_height,
-               CANVAS_ADDR_NOWRAP,
-               CANVAS_BLKMODE_LINEAR);
        hw->buffer_spec[i].canvas_config[0].phy_addr =
-               hw->buffer_spec[i].y_addr;
+               decbuf_start;
        hw->buffer_spec[i].canvas_config[0].width =
                canvas_width;
        hw->buffer_spec[i].canvas_config[0].height =
                canvas_height;
        hw->buffer_spec[i].canvas_config[0].block_mode =
-               CANVAS_BLKMODE_LINEAR;
-
-       canvas_config(hw->buffer_spec[i].u_canvas_index,
-               hw->buffer_spec[i].u_addr,
-               canvas_width / 2,
-               canvas_height / 2,
-               CANVAS_ADDR_NOWRAP,
-               CANVAS_BLKMODE_LINEAR);
+               hw->canvas_mode;
+       hw->buffer_spec[i].canvas_config[0].endian =
+               hw->canvas_endian;
+
+       canvas_config_config(hw->buffer_spec[i].y_canvas_index,
+                       &hw->buffer_spec[i].canvas_config[0]);
+
        hw->buffer_spec[i].canvas_config[1].phy_addr =
-               hw->buffer_spec[i].u_addr;
+               decbuf_u_start;
        hw->buffer_spec[i].canvas_config[1].width =
                canvas_width / 2;
        hw->buffer_spec[i].canvas_config[1].height =
                canvas_height / 2;
        hw->buffer_spec[i].canvas_config[1].block_mode =
-               CANVAS_BLKMODE_LINEAR;
-
-       canvas_config(hw->buffer_spec[i].v_canvas_index,
-               hw->buffer_spec[i].v_addr,
-               canvas_width / 2,
-               canvas_height / 2,
-               CANVAS_ADDR_NOWRAP,
-               CANVAS_BLKMODE_LINEAR);
+               hw->canvas_mode;
+       hw->buffer_spec[i].canvas_config[1].endian =
+               hw->canvas_endian;
+
+       canvas_config_config(hw->buffer_spec[i].u_canvas_index,
+                       &hw->buffer_spec[i].canvas_config[1]);
+
        hw->buffer_spec[i].canvas_config[2].phy_addr =
-               hw->buffer_spec[i].v_addr;
+               decbuf_v_start;
        hw->buffer_spec[i].canvas_config[2].width =
                canvas_width / 2;
        hw->buffer_spec[i].canvas_config[2].height =
                canvas_height / 2;
        hw->buffer_spec[i].canvas_config[2].block_mode =
-               CANVAS_BLKMODE_LINEAR;
+               hw->canvas_mode;
+       hw->buffer_spec[i].canvas_config[2].endian =
+               hw->canvas_endian;
+
+       canvas_config_config(hw->buffer_spec[i].v_canvas_index,
+                       &hw->buffer_spec[i].canvas_config[2]);
+
+       /* mjpeg decoder canvas need to be revert to match display. */
+       hw->buffer_spec[i].canvas_config[0].endian = hw->canvas_endian ? 0 : 7;
+       hw->buffer_spec[i].canvas_config[1].endian = hw->canvas_endian ? 0 : 7;
+       hw->buffer_spec[i].canvas_config[2].endian = hw->canvas_endian ? 0 : 7;
 
        return 0;
 }
@@ -1004,9 +1094,17 @@ static int find_free_buffer(struct vdec_mjpeg_hw_s *hw)
        if (i == hw->buf_num)
                return -1;
 
-       if (hw->is_used_v4l)
-               if (vmjpeg_v4l_alloc_buff_config_canvas(hw, i))
-                       return -1;
+       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) {
+                       /*run to parser csd data*/
+                       i = 0;
+               } else {
+                       if (vmjpeg_v4l_alloc_buff_config_canvas(hw, i))
+                               return -1;
+               }
+       }
 
        return i;
 }
@@ -1041,8 +1139,7 @@ static int vmjpeg_hw_ctx_restore(struct vdec_mjpeg_hw_s *hw)
 
        /* find next decode buffer index */
        WRITE_VREG(AV_SCRATCH_4, spec2canvas(&hw->buffer_spec[index]));
-       WRITE_VREG(AV_SCRATCH_5, index);
-
+       WRITE_VREG(AV_SCRATCH_5, index | 1 << 24);
        init_scaler();
 
        /* clear buffer IN/OUT registers */
@@ -1086,8 +1183,13 @@ static s32 vmjpeg_init(struct vdec_s *vdec)
        fw->len = size;
        hw->fw = fw;
 
-       hw->frame_width = hw->vmjpeg_amstream_dec_info.width;
-       hw->frame_height = hw->vmjpeg_amstream_dec_info.height;
+       if (hw->is_used_v4l) {
+               hw->frame_width = 0;
+               hw->frame_height = 0;
+       } else {
+               hw->frame_width = hw->vmjpeg_amstream_dec_info.width;
+               hw->frame_height = hw->vmjpeg_amstream_dec_info.height;
+       }
        hw->frame_dur = ((hw->vmjpeg_amstream_dec_info.rate) ?
        hw->vmjpeg_amstream_dec_info.rate : 3840);
        hw->saved_resolution = 0;
@@ -1164,6 +1266,29 @@ static unsigned long run_ready(struct vdec_s *vdec,
                        return 0;
        }
 
+       if (hw->is_used_v4l) {
+               struct aml_vcodec_ctx *ctx =
+                       (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+
+               if (ctx->param_sets_from_ucode) {
+                       if (hw->v4l_params_parsed) {
+                               if (!ctx->v4l_codec_dpb_ready &&
+                                       v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+                                       run_ready_min_buf_num)
+                                       return 0;
+                       } else {
+                               if ((hw->res_ch_flag == 1) &&
+                               ((ctx->state <= AML_STATE_INIT) ||
+                               (ctx->state >= AML_STATE_FLUSHING)))
+                                       return 0;
+                       }
+               } else if (!ctx->v4l_codec_dpb_ready) {
+                       if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+                               run_ready_min_buf_num)
+                               return 0;
+               }
+       }
+
        if (!is_enough_free_buffer(hw)) {
                hw->buffer_not_ready++;
                return 0;
@@ -1299,6 +1424,7 @@ static int notify_v4l_eos(struct vdec_s *vdec)
        struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
        struct vframe_s *vf = NULL;
        struct vdec_v4l2_buffer *fb = NULL;
+       int index;
 
        if (hw->is_used_v4l && hw->eos) {
                if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) {
@@ -1308,13 +1434,17 @@ static int notify_v4l_eos(struct vdec_s *vdec)
                        return -1;
                }
 
-               if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) {
+               index = find_free_buffer(hw);
+
+               if ((index == -1) && vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) {
                        pr_err("[%d] get fb fail.\n", ctx->id);
                        return -1;
                }
 
+               vf->type |= VIDTYPE_V4L_EOS;
                vf->timestamp = ULONG_MAX;
-               vf->v4l_mem_handle = (unsigned long)fb;
+               vf->v4l_mem_handle = (index == -1) ? (ulong)fb :
+                       hw->buffer_spec[index].v4l_ref_buf_addr;
                vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
 
                kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
@@ -1381,6 +1511,16 @@ static void vmjpeg_work(struct work_struct *work)
        /*disable mbox interrupt */
        WRITE_VREG(ASSIST_MBOX1_MASK, 0);
        wait_vmjpeg_search_done(hw);
+
+       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)
+                       vdec_v4l_write_frame_sync(ctx);
+       }
+
        /* mark itself has all HW resource released and input released */
        if (vdec->parallel_dec == 1)
                vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1);
@@ -1486,6 +1626,16 @@ static int ammvdec_mjpeg_probe(struct platform_device *pdev)
                else
                        hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
 
+               if (get_config_int(pdata->config,
+                       "parm_v4l_canvas_mem_mode",
+                       &config_val) == 0)
+                       hw->canvas_mode = config_val;
+
+               if (get_config_int(pdata->config,
+                       "parm_v4l_canvas_mem_endian",
+                       &config_val) == 0)
+                       hw->canvas_endian = config_val;
+
                if (get_config_int(pdata->config, "sidebind_type",
                                &config_val) == 0)
                        hw->sidebind_type = config_val;
@@ -1493,6 +1643,11 @@ static int ammvdec_mjpeg_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_v4l_codec_enable",
+                       &config_val) == 0)
+                       hw->is_used_v4l = config_val;
        } else {
                hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
        }
@@ -1502,11 +1657,9 @@ static int ammvdec_mjpeg_probe(struct platform_device *pdev)
        vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
                &vf_provider_ops, pdata);
 
-       if (pdata->sys_info) {
-               hw->vmjpeg_amstream_dec_info = *pdata->sys_info;
-               hw->is_used_v4l = (((unsigned long)
-                       hw->vmjpeg_amstream_dec_info.param & 0x80) >> 7);
-       }
+       platform_set_drvdata(pdev, pdata);
+
+       hw->platform_dev = pdev;
 
        vdec_source_changed(VFORMAT_MJPEG,
                        1920, 1080, 60);
index a628df2edbb7a6a28c77d78e66846720e8daf327..51d2caf7934b1f4c9ea58b3564037bc5ced0e3cd 100644 (file)
Binary files a/firmware/video_ucode.bin and b/firmware/video_ucode.bin differ