struct aml_vdec_adapt vdec;
struct vdec_mpeg4_vsi *vsi;
struct vcodec_vfm_s vfm;
+ struct aml_dec_params parms;
struct completion comp;
};
static void get_dpb_size(struct vdec_mpeg4_inst *inst, unsigned int *dpb_sz)
{
- *dpb_sz = 9;//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_mpeg4_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);
+ 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_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
{
struct vdec_mpeg4_inst *inst = NULL;
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;
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,
"mpeg4 Instance >> %lx\n", (ulong) inst);
+ init_completion(&inst->comp);
ctx->ada_ctx = &inst->vdec;
*h_vdec = (unsigned long)inst;
pic->y_len_sz = pic->coded_width * pic->coded_height;
pic->c_len_sz = pic->y_len_sz >> 1;
- /* 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",
static void set_param_ps_info(struct vdec_mpeg4_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_mpeg4_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 >> 1;
+
+ 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_mpeg4_inst *inst)
+{
+ complete(&inst->comp);
}
static int vdec_mpeg4_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;
#include "../utils/firmware.h"
#include "../utils/vdec_v4l2_buffer_ops.h"
#include "../utils/config_parser.h"
+#include <media/v4l2-mem2mem.h>
#define DRIVER_NAME "ammvdec_mpeg4"
#define MODULE_NAME "ammvdec_mpeg4"
#define MP4_OFFSET_REG AV_SCRATCH_C
#define MP4_SYS_RATE AV_SCRATCH_E
#define MEM_OFFSET_REG AV_SCRATCH_F
+#define MP4_PIC_INFO AV_SCRATCH_H
#define PARC_FORBIDDEN 0
#define PARC_SQUARE 1
static void vmpeg_vf_put(struct vframe_s *, void *);
static int vmpeg_vf_states(struct vframe_states *states, void *);
static int vmpeg_event_cb(int type, void *data, void *private_data);
+static int notify_v4l_eos(struct vdec_s *vdec);
+
static int pre_decode_buf_level = 0x800;
static int start_decode_buf_level = 0x4000;
static int debug_enable;
#undef pr_info
#define pr_info printk
unsigned int mpeg4_debug_mask = 0xff;
+static u32 run_ready_min_buf_num = 2;
+
#define PRINT_FLAG_ERROR 0x0
#define PRINT_FLAG_RUN_FLOW 0X0001
u32 i_only;
int sidebind_type;
int sidebind_channel_id;
+ unsigned int res_ch_flag;
};
static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw);
static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw);
static unsigned char
get_data_check_sum(struct vdec_mpeg4_hw_s *hw, int size);
+static void flush_output(struct vdec_mpeg4_hw_s * hw);
#define PROVIDER_NAME "vdec.mpeg4"
{
int ret;
u32 canvas;
- ulong decbuf_start = 0;
- int decbuf_y_size = 0;
+ ulong decbuf_start = 0, decbuf_uv_start = 0;
+ int decbuf_y_size = 0, decbuf_uv_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->pic[i].v4l_ref_buf_addr)
return 0;
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;
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "[%d] set %d x %d from IF layer\n", ctx->id,
+ hw->frame_width, hw->frame_height);
+ }
+
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;
+ decbuf_uv_start = decbuf_start + decbuf_y_size;
+ decbuf_uv_size = decbuf_y_size / 2;
canvas_width = ALIGN(hw->frame_width, 64);
- canvas_height = ALIGN(hw->frame_height, 32);
+ 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_start = fb->m.mem[1].addr;
+ decbuf_uv_size = fb->m.mem[1].size;
canvas_width = ALIGN(hw->frame_width, 64);
- canvas_height = ALIGN(hw->frame_height, 32);
+ canvas_height = ALIGN(hw->frame_height, 64);
fb->m.mem[0].bytes_used = decbuf_y_size;
- fb->m.mem[1].bytes_used = decbuf_y_size << 1;
+ fb->m.mem[1].bytes_used = decbuf_uv_size;
}
mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%x\n",
&hw->canvas_config[i][0]);
hw->canvas_config[i][1].phy_addr =
- decbuf_start + decbuf_y_size;
+ decbuf_uv_start;
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 (i == hw->buf_num)
return -1;
- if (hw->is_used_v4l)
- if (vmpeg4_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 (vmpeg4_v4l_alloc_buff_config_canvas(hw, i))
+ return -1;
+ }
+ }
+
return i;
}
}
}
+static int vmpeg4_get_ps_info(struct vdec_mpeg4_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_mpeg4_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)) {
+ mmpeg4_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);
+ vmpeg4_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;
+ flush_output(hw);
+ notify_v4l_eos(hw_to_vdec(hw));
+
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+
static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq)
{
u32 reg;
if (hw->eos)
return IRQ_HANDLED;
+ if (READ_VREG(MP4_PIC_INFO) == 1) {
+ if (hw->is_used_v4l) {
+ int frame_width = READ_VREG(MP4_PIC_WH)>> 16;
+ int frame_height = READ_VREG(MP4_PIC_WH) & 0xffff;
+ 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;
+
+ vmpeg4_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(MP4_PIC_INFO, 0);
+ }
+ } else {
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ }
+ } else
+ WRITE_VREG(MP4_PIC_INFO, 0);
+ return IRQ_HANDLED;
+ }
+
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
if (READ_VREG(AV_SCRATCH_M) != 0 &&
(debug_enable & PRINT_FLAG_UCODE_DETAIL)) {
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_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->vmpeg4_amstream_dec_info.rate == 0) {
if (vop_time_inc < hw->last_vop_time_inc) {
duration = vop_time_inc +
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) {
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->pic[index].v4l_ref_buf_addr;;
vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
del_timer_sync(&hw->check_timer);
hw->stat &= ~STAT_TIMER_ARM;
+ 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(vdec, CORE_MASK_VDEC_1);
/* disable PSCALE for hardware sharing */
WRITE_VREG(PSCALE_CTRL, 0);
- WRITE_VREG(MREG_BUFFEROUT, 0);
+ WRITE_VREG(MREG_BUFFEROUT, 0x10000);
/* clear mailbox interrupt */
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
hw->vmpeg4_rotation =
(((unsigned long)hw->vmpeg4_amstream_dec_info.param) >> 16) & 0xffff;
hw->sys_mp4_rate = hw->vmpeg4_amstream_dec_info.rate;
- hw->frame_width = hw->vmpeg4_amstream_dec_info.width;
- hw->frame_height = hw->vmpeg4_amstream_dec_info.height;
+ if (hw->is_used_v4l) {
+ hw->frame_width = 0;
+ hw->frame_height = 0;
+ } else {
+ hw->frame_width = hw->vmpeg4_amstream_dec_info.width;
+ hw->frame_height = hw->vmpeg4_amstream_dec_info.height;
+ }
+
hw->frame_dur = 0;
hw->frame_prog = 0;
hw->unstable_pts =
}
}
+ 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;
platform_set_drvdata(pdev, pdata);
hw->platform_dev = pdev;
- if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) {
- mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
- "pdata->config: %s\n", pdata->config);
- if (get_config_int(pdata->config, "parm_v4l_buffer_margin",
- &config_val) == 0)
- hw->dynamic_buf_num_margin = config_val;
- else
- hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
-
- if (get_config_int(pdata->config, "sidebind_type",
- &config_val) == 0)
- hw->sidebind_type = config_val;
-
- if (get_config_int(pdata->config, "sidebind_channel_id",
- &config_val) == 0)
- hw->sidebind_channel_id = config_val;
- } else {
- hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
- }
- hw->buf_num = vmpeg4_get_buf_num(hw);
-
if (pdata->parallel_dec == 1) {
int i;
for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
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 (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "pdata->config: %s\n", pdata->config);
+ if (get_config_int(pdata->config, "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ hw->dynamic_buf_num_margin = config_val;
+ else
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ if (get_config_int(pdata->config, "sidebind_type",
+ &config_val) == 0)
+ hw->sidebind_type = config_val;
+
+ 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;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_canvas_mem_mode",
+ &config_val) == 0)
+ hw->blkmode = config_val;
+ } else
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ hw->buf_num = vmpeg4_get_buf_num(hw);
+
if (vmmpeg4_init(hw) < 0) {
pr_err("%s init failed.\n", __func__);