diff options
Diffstat (limited to 'drivers/media/platform/amphion')
-rw-r--r-- | drivers/media/platform/amphion/vdec.c | 294 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu.h | 7 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_color.c | 73 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_dbg.c | 15 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_defs.h | 12 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_helpers.c | 123 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_helpers.h | 12 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_malone.c | 5 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_mbox.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_mbox.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/amphion/vpu_v4l2.c | 11 |
11 files changed, 425 insertions, 132 deletions
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 85d518823159..32eef2fd1f2a 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -26,6 +26,7 @@ #include "vpu_cmds.h" #include "vpu_rpc.h" +#define VDEC_SLOT_CNT_DFT 32 #define VDEC_MIN_BUFFER_CAP 8 #define VDEC_MIN_BUFFER_OUT 8 @@ -41,6 +42,14 @@ struct vdec_fs_info { u32 tag; }; +struct vdec_frame_store_t { + struct vpu_vb2_buffer *curr; + struct vpu_vb2_buffer *pend; + dma_addr_t addr; + unsigned int state; + u32 tag; +}; + struct vdec_t { u32 seq_hdr_found; struct vpu_buffer udata; @@ -48,7 +57,8 @@ struct vdec_t { struct vpu_dec_codec_info codec_info; enum vpu_codec_state state; - struct vpu_vb2_buffer *slots[VB2_MAX_FRAME]; + struct vdec_frame_store_t *slots; + u32 slot_count; u32 req_frame_count; struct vdec_fs_info mbi; struct vdec_fs_info dcp; @@ -232,6 +242,35 @@ static int vdec_ctrl_init(struct vpu_inst *inst) V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, 0, 1, 1, 0); + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), + V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + 0, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + ~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + 0, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4); + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2); if (ctrl) @@ -258,6 +297,63 @@ static int vdec_ctrl_init(struct vpu_inst *inst) return 0; } +static void vdec_attach_frame_store(struct vpu_inst *inst, struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); + struct vdec_t *vdec = inst->priv; + struct vdec_frame_store_t *new_slots = NULL; + dma_addr_t addr; + int i; + + addr = vpu_get_vb_phy_addr(vb, 0); + for (i = 0; i < vdec->slot_count; i++) { + if (addr == vdec->slots[i].addr) { + if (vdec->slots[i].curr && vdec->slots[i].curr != vpu_buf) { + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED); + vdec->slots[i].pend = vpu_buf; + } else { + vpu_set_buffer_state(vbuf, vdec->slots[i].state); + } + vpu_buf->fs_id = i; + return; + } + } + + for (i = 0; i < vdec->slot_count; i++) { + if (!vdec->slots[i].addr) { + vdec->slots[i].addr = addr; + vpu_buf->fs_id = i; + return; + } + } + + new_slots = krealloc_array(vdec->slots, vdec->slot_count * 2, + sizeof(*vdec->slots), + GFP_KERNEL | __GFP_ZERO); + if (!new_slots) { + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR); + return; + } + + vdec->slots = new_slots; + vdec->slot_count *= 2; + + vdec->slots[i].addr = addr; + vpu_buf->fs_id = i; +} + +static void vdec_reset_frame_store(struct vpu_inst *inst) +{ + struct vdec_t *vdec = inst->priv; + + if (!vdec->slots || !vdec->slot_count) + return; + + vpu_trace(inst->dev, "inst[%d] reset slots\n", inst->id); + memset(vdec->slots, 0, sizeof(*vdec->slots) * vdec->slot_count); +} + static void vdec_handle_resolution_change(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; @@ -714,11 +810,11 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) struct vb2_v4l2_buffer *src_buf; int ret = 0; - if (!info || info->id >= ARRAY_SIZE(vdec->slots)) + if (!info || info->id >= vdec->slot_count) return -EINVAL; vpu_inst_lock(inst); - vpu_buf = vdec->slots[info->id]; + vpu_buf = vdec->slots[info->id].curr; if (!vpu_buf) { dev_err(inst->dev, "[%d] decoded invalid frame[%d]\n", inst->id, info->id); ret = -EINVAL; @@ -739,11 +835,13 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); + vdec->slots[info->id].state = VPU_BUF_STATE_DECODED; vdec->decoded_frame_count++; if (vdec->params.display_delay_enable) { struct vpu_format *cur_fmt; cur_fmt = vpu_get_format(inst, inst->cap_format.type); + vdec->slots[info->id].state = VPU_BUF_STATE_READY; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); for (int i = 0; i < vbuf->vb2_buf.num_planes; i++) vb2_set_plane_payload(&vbuf->vb2_buf, @@ -766,11 +864,11 @@ static struct vpu_vb2_buffer *vdec_find_buffer(struct vpu_inst *inst, u32 luma) struct vdec_t *vdec = inst->priv; int i; - for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { - if (!vdec->slots[i]) + for (i = 0; i < vdec->slot_count; i++) { + if (!vdec->slots[i].curr) continue; - if (luma == vdec->slots[i]->luma) - return vdec->slots[i]; + if (luma == vdec->slots[i].addr) + return vdec->slots[i].curr; } return NULL; @@ -804,11 +902,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) cur_fmt = vpu_get_format(inst, inst->cap_format.type); vbuf = &vpu_buf->m2m_buf.vb; - if (vbuf->vb2_buf.index != frame->id) - dev_err(inst->dev, "[%d] buffer id(%d, %d) mismatch\n", - inst->id, vbuf->vb2_buf.index, frame->id); + if (vpu_buf->fs_id != frame->id) + dev_err(inst->dev, "[%d] buffer id(%d(%d), %d) mismatch\n", + inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index, frame->id); - if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_READY && vdec->params.display_delay_enable) + if (vdec->params.display_delay_enable) return; if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED) @@ -821,10 +919,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) vbuf->sequence = vdec->sequence; dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); vpu_inst_lock(inst); + vdec->slots[vpu_buf->fs_id].state = VPU_BUF_STATE_READY; vdec->display_frame_count++; vpu_inst_unlock(inst); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); dev_dbg(inst->dev, "[%d] decoded : %d, display : %d, sequence : %d\n", inst->id, vdec->decoded_frame_count, vdec->display_frame_count, vdec->sequence); } @@ -1052,18 +1151,30 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb if (!vbuf) return -EINVAL; - if (vdec->slots[vbuf->vb2_buf.index]) { - dev_err(inst->dev, "[%d] repeat alloc fs %d\n", - inst->id, vbuf->vb2_buf.index); + vpu_buf = to_vpu_vb2_buffer(vbuf); + if (vpu_buf->fs_id < 0 || vpu_buf->fs_id >= vdec->slot_count) { + dev_err(inst->dev, "invalid fs %d for v4l2 buffer %d\n", + vpu_buf->fs_id, vbuf->vb2_buf.index); return -EINVAL; } + if (vdec->slots[vpu_buf->fs_id].curr) { + if (vdec->slots[vpu_buf->fs_id].curr != vpu_buf) { + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED); + vdec->slots[vpu_buf->fs_id].pend = vpu_buf; + } else { + vpu_set_buffer_state(vbuf, vdec->slots[vpu_buf->fs_id].state); + } + dev_err(inst->dev, "[%d] repeat alloc fs %d (v4l2 index %d)\n", + inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index); + return -EAGAIN; + } + dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n", inst->id, vpu_codec_state_name(inst->state), vbuf->vb2_buf.index, vdec->seq_tag); - vpu_buf = to_vpu_vb2_buffer(vbuf); memset(&info, 0, sizeof(info)); - info.id = vbuf->vb2_buf.index; + info.id = vpu_buf->fs_id; info.type = MEM_RES_FRAME; info.tag = vdec->seq_tag; info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0); @@ -1078,12 +1189,13 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb if (ret) return ret; - vpu_buf->tag = info.tag; vpu_buf->luma = info.luma_addr; vpu_buf->chroma_u = info.chroma_addr; vpu_buf->chroma_v = 0; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); - vdec->slots[info.id] = vpu_buf; + vdec->slots[info.id].tag = info.tag; + vdec->slots[info.id].curr = vpu_buf; + vdec->slots[info.id].state = VPU_BUF_STATE_INUSE; vdec->req_frame_count--; return 0; @@ -1144,25 +1256,76 @@ static void vdec_recycle_buffer(struct vpu_inst *inst, struct vb2_v4l2_buffer *v v4l2_m2m_buf_queue(inst->fh.m2m_ctx, vbuf); } -static void vdec_clear_slots(struct vpu_inst *inst) +static void vdec_release_curr_frame_store(struct vpu_inst *inst, u32 id) { struct vdec_t *vdec = inst->priv; struct vpu_vb2_buffer *vpu_buf; struct vb2_v4l2_buffer *vbuf; + + if (id >= vdec->slot_count) + return; + if (!vdec->slots[id].curr) + return; + + vpu_buf = vdec->slots[id].curr; + vbuf = &vpu_buf->m2m_buf.vb; + + vdec_response_fs_release(inst, id, vdec->slots[id].tag); + if (vpu_buf->fs_id == id) { + if (vpu_buf->state != VPU_BUF_STATE_READY) + vdec_recycle_buffer(inst, vbuf); + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); + } + + vdec->slots[id].curr = NULL; + vdec->slots[id].state = VPU_BUF_STATE_IDLE; + + if (vdec->slots[id].pend) { + vpu_set_buffer_state(&vdec->slots[id].pend->m2m_buf.vb, VPU_BUF_STATE_IDLE); + vdec->slots[id].pend = NULL; + } +} + +static void vdec_clear_slots(struct vpu_inst *inst) +{ + struct vdec_t *vdec = inst->priv; int i; - for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { - if (!vdec->slots[i]) + for (i = 0; i < vdec->slot_count; i++) { + if (!vdec->slots[i].curr) continue; - vpu_buf = vdec->slots[i]; - vbuf = &vpu_buf->m2m_buf.vb; - vpu_trace(inst->dev, "clear slot %d\n", i); - vdec_response_fs_release(inst, i, vpu_buf->tag); - vdec_recycle_buffer(inst, vbuf); - vdec->slots[i]->state = VPU_BUF_STATE_IDLE; - vdec->slots[i] = NULL; + vdec_release_curr_frame_store(inst, i); + } +} + +static void vdec_update_v4l2_ctrl(struct vpu_inst *inst, u32 id, u32 val) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id); + + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, val); +} + +static void vdec_update_v4l2_profile_level(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr) +{ + switch (inst->out_format.pixfmt) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_H264_MVC: + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_PROFILE, + vpu_get_h264_v4l2_profile(hdr)); + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LEVEL, + vpu_get_h264_v4l2_level(hdr)); + break; + case V4L2_PIX_FMT_HEVC: + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + vpu_get_hevc_v4l2_profile(hdr)); + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + vpu_get_hevc_v4l2_level(hdr)); + break; + default: + return; } } @@ -1189,6 +1352,7 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info vdec_init_crop(inst); vdec_init_mbi(inst); vdec_init_dcp(inst); + vdec_update_v4l2_profile_level(inst, hdr); if (!vdec->seq_hdr_found) { vdec->seq_tag = vdec->codec_info.tag; if (vdec->is_source_changed) { @@ -1263,39 +1427,29 @@ static void vdec_event_req_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) static void vdec_evnet_rel_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) { struct vdec_t *vdec = inst->priv; - struct vpu_vb2_buffer *vpu_buf; - struct vb2_v4l2_buffer *vbuf; - if (!fs || fs->id >= ARRAY_SIZE(vdec->slots)) + if (!fs || fs->id >= vdec->slot_count) return; if (fs->type != MEM_RES_FRAME) return; - if (fs->id >= vpu_get_num_buffers(inst, inst->cap_format.type)) { + if (fs->id >= vdec->slot_count) { dev_err(inst->dev, "[%d] invalid fs(%d) to release\n", inst->id, fs->id); return; } vpu_inst_lock(inst); - vpu_buf = vdec->slots[fs->id]; - vdec->slots[fs->id] = NULL; - - if (!vpu_buf) { + if (!vdec->slots[fs->id].curr) { dev_dbg(inst->dev, "[%d] fs[%d] has bee released\n", inst->id, fs->id); goto exit; } - vbuf = &vpu_buf->m2m_buf.vb; - if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) { + if (vdec->slots[fs->id].state == VPU_BUF_STATE_DECODED) { dev_dbg(inst->dev, "[%d] frame skip\n", inst->id); vdec->sequence++; } - vdec_response_fs_release(inst, fs->id, vpu_buf->tag); - if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_READY) - vdec_recycle_buffer(inst, vbuf); - - vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); + vdec_release_curr_frame_store(inst, fs->id); vpu_process_capture_buffer(inst); exit: @@ -1485,6 +1639,11 @@ static void vdec_cleanup(struct vpu_inst *inst) return; vdec = inst->priv; + if (vdec) { + kfree(vdec->slots); + vdec->slots = NULL; + vdec->slot_count = 0; + } vfree(vdec); inst->priv = NULL; vfree(inst); @@ -1606,11 +1765,43 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) return 0; } -static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) +static int vdec_get_slot_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) { struct vdec_t *vdec = inst->priv; + struct vpu_vb2_buffer *vpu_buf; int num = -1; + vpu_inst_lock(inst); + if (i >= vdec->slot_count || !vdec->slots[i].addr) + goto exit; + + vpu_buf = vdec->slots[i].curr; + + num = scnprintf(str, size, "slot[%2d] :", i); + if (vpu_buf) { + num += scnprintf(str + num, size - num, " %2d", + vpu_buf->m2m_buf.vb.vb2_buf.index); + num += scnprintf(str + num, size - num, "; state = %d", vdec->slots[i].state); + } else { + num += scnprintf(str + num, size - num, " -1"); + } + + if (vdec->slots[i].pend) + num += scnprintf(str + num, size - num, "; %d", + vdec->slots[i].pend->m2m_buf.vb.vb2_buf.index); + + num += scnprintf(str + num, size - num, "\n"); +exit: + vpu_inst_unlock(inst); + + return num; +} + +static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) +{ + struct vdec_t *vdec = inst->priv; + int num; + switch (i) { case 0: num = scnprintf(str, size, @@ -1664,6 +1855,7 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i vdec->codec_info.vui_present); break; default: + num = vdec_get_slot_debug_info(inst, str, size, i - 10); break; } @@ -1687,6 +1879,8 @@ static struct vpu_inst_ops vdec_inst_ops = { .get_debug_info = vdec_get_debug_info, .wait_prepare = vpu_inst_unlock, .wait_finish = vpu_inst_lock, + .attach_frame_store = vdec_attach_frame_store, + .reset_frame_store = vdec_reset_frame_store, }; static void vdec_init(struct file *file) @@ -1727,6 +1921,16 @@ static int vdec_open(struct file *file) return -ENOMEM; } + vdec->slots = kmalloc_array(VDEC_SLOT_CNT_DFT, + sizeof(*vdec->slots), + GFP_KERNEL | __GFP_ZERO); + if (!vdec->slots) { + vfree(vdec); + vfree(inst); + return -ENOMEM; + } + vdec->slot_count = VDEC_SLOT_CNT_DFT; + inst->ops = &vdec_inst_ops; inst->formats = vdec_formats; inst->type = VPU_CORE_TYPE_DEC; diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index 1451549c9dd2..cac0f1a64fea 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -222,6 +222,8 @@ struct vpu_inst_ops { int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i); void (*wait_prepare)(struct vpu_inst *inst); void (*wait_finish)(struct vpu_inst *inst); + void (*attach_frame_store)(struct vpu_inst *inst, struct vb2_buffer *vb); + void (*reset_frame_store)(struct vpu_inst *inst); }; struct vpu_inst { @@ -295,7 +297,8 @@ enum { VPU_BUF_STATE_DECODED, VPU_BUF_STATE_READY, VPU_BUF_STATE_SKIP, - VPU_BUF_STATE_ERROR + VPU_BUF_STATE_ERROR, + VPU_BUF_STATE_CHANGED }; struct vpu_vb2_buffer { @@ -304,8 +307,8 @@ struct vpu_vb2_buffer { dma_addr_t chroma_u; dma_addr_t chroma_v; unsigned int state; - u32 tag; u32 average_qp; + s32 fs_id; }; void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val); diff --git a/drivers/media/platform/amphion/vpu_color.c b/drivers/media/platform/amphion/vpu_color.c index 4ae435cbc5cd..7c0ab8289a7b 100644 --- a/drivers/media/platform/amphion/vpu_color.c +++ b/drivers/media/platform/amphion/vpu_color.c @@ -108,76 +108,3 @@ u32 vpu_color_cvrt_full_range_i2v(u32 full_range) return V4L2_QUANTIZATION_LIM_RANGE; } - -int vpu_color_check_primaries(u32 primaries) -{ - return vpu_color_cvrt_primaries_v2i(primaries) ? 0 : -EINVAL; -} - -int vpu_color_check_transfers(u32 transfers) -{ - return vpu_color_cvrt_transfers_v2i(transfers) ? 0 : -EINVAL; -} - -int vpu_color_check_matrix(u32 matrix) -{ - return vpu_color_cvrt_matrix_v2i(matrix) ? 0 : -EINVAL; -} - -int vpu_color_check_full_range(u32 full_range) -{ - int ret = -EINVAL; - - switch (full_range) { - case V4L2_QUANTIZATION_FULL_RANGE: - case V4L2_QUANTIZATION_LIM_RANGE: - ret = 0; - break; - default: - break; - } - - return ret; -} - -int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range) -{ - u32 transfers; - u32 matrix; - u32 full_range; - - switch (primaries) { - case V4L2_COLORSPACE_REC709: - transfers = V4L2_XFER_FUNC_709; - matrix = V4L2_YCBCR_ENC_709; - break; - case V4L2_COLORSPACE_470_SYSTEM_M: - case V4L2_COLORSPACE_470_SYSTEM_BG: - case V4L2_COLORSPACE_SMPTE170M: - transfers = V4L2_XFER_FUNC_709; - matrix = V4L2_YCBCR_ENC_601; - break; - case V4L2_COLORSPACE_SMPTE240M: - transfers = V4L2_XFER_FUNC_SMPTE240M; - matrix = V4L2_YCBCR_ENC_SMPTE240M; - break; - case V4L2_COLORSPACE_BT2020: - transfers = V4L2_XFER_FUNC_709; - matrix = V4L2_YCBCR_ENC_BT2020; - break; - default: - transfers = V4L2_XFER_FUNC_DEFAULT; - matrix = V4L2_YCBCR_ENC_DEFAULT; - break; - } - full_range = V4L2_QUANTIZATION_LIM_RANGE; - - if (ptransfers) - *ptransfers = transfers; - if (pmatrix) - *pmatrix = matrix; - if (pfull_range) - *pfull_range = full_range; - - return 0; -} diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index 940e5bda5fa3..497ae4e8a229 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -48,6 +48,7 @@ static char *vpu_stat_name[] = { [VPU_BUF_STATE_READY] = "ready", [VPU_BUF_STATE_SKIP] = "skip", [VPU_BUF_STATE_ERROR] = "error", + [VPU_BUF_STATE_CHANGED] = "changed", }; static inline const char *to_vpu_stat_name(int state) @@ -164,6 +165,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) for (i = 0; i < vb2_get_num_buffers(vq); i++) { struct vb2_buffer *vb; struct vb2_v4l2_buffer *vbuf; + struct vpu_vb2_buffer *vpu_buf; vb = vb2_get_buffer(vq, i); if (!vb) @@ -173,13 +175,24 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) continue; vbuf = to_vb2_v4l2_buffer(vb); + vpu_buf = to_vpu_vb2_buffer(vbuf); num = scnprintf(str, sizeof(str), - "capture[%2d] state = %10s, %8s\n", + "capture[%2d] state = %10s, %8s", i, vb2_stat_name[vb->state], to_vpu_stat_name(vpu_get_buffer_state(vbuf))); if (seq_write(s, str, num)) return 0; + + if (vpu_buf->fs_id >= 0) { + num = scnprintf(str, sizeof(str), "; fs %d", vpu_buf->fs_id); + if (seq_write(s, str, num)) + return 0; + } + + num = scnprintf(str, sizeof(str), "\n"); + if (seq_write(s, str, num)) + return 0; } num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence); diff --git a/drivers/media/platform/amphion/vpu_defs.h b/drivers/media/platform/amphion/vpu_defs.h index 428d988cf2f7..f56245ae2205 100644 --- a/drivers/media/platform/amphion/vpu_defs.h +++ b/drivers/media/platform/amphion/vpu_defs.h @@ -134,6 +134,7 @@ struct vpu_dec_codec_info { u32 decoded_height; struct v4l2_fract frame_rate; u32 dsp_asp_ratio; + u32 profile_idc; u32 level_idc; u32 bit_depth_luma; u32 bit_depth_chroma; @@ -147,6 +148,17 @@ struct vpu_dec_codec_info { u32 mbi_size; u32 dcp_size; u32 stride; + union { + struct { + u32 constraint_set5_flag : 1; + u32 constraint_set4_flag : 1; + u32 constraint_set3_flag : 1; + u32 constraint_set2_flag : 1; + u32 constraint_set1_flag : 1; + u32 constraint_set0_flag : 1; + }; + u32 constraint_set_flags; + }; }; struct vpu_dec_pic_info { diff --git a/drivers/media/platform/amphion/vpu_helpers.c b/drivers/media/platform/amphion/vpu_helpers.c index d12310af9ebc..886d5632388e 100644 --- a/drivers/media/platform/amphion/vpu_helpers.c +++ b/drivers/media/platform/amphion/vpu_helpers.c @@ -509,3 +509,126 @@ const char *vpu_codec_state_name(enum vpu_codec_state state) } return "<unknown>"; } + +struct codec_id_mapping { + u32 id; + u32 v4l2_id; +}; + +static struct codec_id_mapping h264_profiles[] = { + {66, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE}, + {77, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN}, + {88, V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED}, + {100, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH} +}; + +static struct codec_id_mapping h264_levels[] = { + {10, V4L2_MPEG_VIDEO_H264_LEVEL_1_0}, + {9, V4L2_MPEG_VIDEO_H264_LEVEL_1B}, + {11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1}, + {12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2}, + {13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3}, + {20, V4L2_MPEG_VIDEO_H264_LEVEL_2_0}, + {21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1}, + {22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2}, + {30, V4L2_MPEG_VIDEO_H264_LEVEL_3_0}, + {31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1}, + {32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2}, + {40, V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, + {41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2}, + {50, V4L2_MPEG_VIDEO_H264_LEVEL_5_0}, + {51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1}, + {52, V4L2_MPEG_VIDEO_H264_LEVEL_5_2}, + {60, V4L2_MPEG_VIDEO_H264_LEVEL_6_0}, + {61, V4L2_MPEG_VIDEO_H264_LEVEL_6_1}, + {62, V4L2_MPEG_VIDEO_H264_LEVEL_6_2} +}; + +static struct codec_id_mapping hevc_profiles[] = { + {1, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN}, + {2, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10} +}; + +static struct codec_id_mapping hevc_levels[] = { + {30, V4L2_MPEG_VIDEO_HEVC_LEVEL_1}, + {60, V4L2_MPEG_VIDEO_HEVC_LEVEL_2}, + {63, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1}, + {90, V4L2_MPEG_VIDEO_HEVC_LEVEL_3}, + {93, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1}, + {120, V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, + {123, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, + {150, V4L2_MPEG_VIDEO_HEVC_LEVEL_5}, + {153, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1}, + {156, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2}, + {180, V4L2_MPEG_VIDEO_HEVC_LEVEL_6}, + {183, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1}, + {186, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2} +}; + +static u32 vpu_find_v4l2_id(u32 id, struct codec_id_mapping *array, u32 array_sz) +{ + u32 i; + + if (!array || !array_sz) + return 0; + + for (i = 0; i < array_sz; i++) { + if (id == array[i].id) + return array[i].v4l2_id; + } + + return 0; +} + +u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr) +{ + if (!hdr) + return 0; + + /* + * In H.264 Document section A.2.1.1 Constrained Baseline profile + * Conformance of a bitstream to the Constrained Baseline profile is indicated by + * profile_idc being equal to 66 with constraint_set1_flag being equal to 1. + */ + if (hdr->profile_idc == 66 && hdr->constraint_set1_flag) + return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; + + return vpu_find_v4l2_id(hdr->profile_idc, h264_profiles, ARRAY_SIZE(h264_profiles)); +} + +u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr) +{ + if (!hdr) + return 0; + + /* + * In H.264 Document section 7.4.2.1.1 Sequence parameter set data semantics + * If profile_idc is equal to 66, 77, or 88 and level_idc is equal to 11, + * constraint_set3_flag equal to 1 indicates that the coded video sequence + * obeys all constraints specified in Annex A for level 1b + * and constraint_set3_flag equal to 0 indicates that the coded video sequence + * obeys all constraints specified in Annex A for level 1.1. + */ + if (hdr->level_idc == 11 && hdr->constraint_set3_flag && + (hdr->profile_idc == 66 || hdr->profile_idc == 77 || hdr->profile_idc == 88)) + return V4L2_MPEG_VIDEO_H264_LEVEL_1B; + + return vpu_find_v4l2_id(hdr->level_idc, h264_levels, ARRAY_SIZE(h264_levels)); +} + +u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr) +{ + if (!hdr) + return 0; + + return vpu_find_v4l2_id(hdr->profile_idc, hevc_profiles, ARRAY_SIZE(hevc_profiles)); +} + +u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr) +{ + if (!hdr) + return 0; + + return vpu_find_v4l2_id(hdr->level_idc, hevc_levels, ARRAY_SIZE(hevc_levels)); +} diff --git a/drivers/media/platform/amphion/vpu_helpers.h b/drivers/media/platform/amphion/vpu_helpers.h index 0eaddb07190d..76fba0d6090c 100644 --- a/drivers/media/platform/amphion/vpu_helpers.h +++ b/drivers/media/platform/amphion/vpu_helpers.h @@ -6,6 +6,8 @@ #ifndef _AMPHION_VPU_HELPERS_H #define _AMPHION_VPU_HELPERS_H +#include "vpu_defs.h" + struct vpu_pair { u32 src; u32 dst; @@ -54,10 +56,6 @@ static inline u8 vpu_helper_read_byte(struct vpu_buffer *stream_buffer, u32 pos) return pdata[pos % stream_buffer->length]; } -int vpu_color_check_primaries(u32 primaries); -int vpu_color_check_transfers(u32 transfers); -int vpu_color_check_matrix(u32 matrix); -int vpu_color_check_full_range(u32 full_range); u32 vpu_color_cvrt_primaries_v2i(u32 primaries); u32 vpu_color_cvrt_primaries_i2v(u32 primaries); u32 vpu_color_cvrt_transfers_v2i(u32 transfers); @@ -66,8 +64,12 @@ u32 vpu_color_cvrt_matrix_v2i(u32 matrix); u32 vpu_color_cvrt_matrix_i2v(u32 matrix); u32 vpu_color_cvrt_full_range_v2i(u32 full_range); u32 vpu_color_cvrt_full_range_i2v(u32 full_range); -int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range); int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src); int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst); + +u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr); +u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr); +u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr); +u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr); #endif diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index feca7d4220ed..ba688566dffd 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -908,7 +908,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt, info->frame_rate.numerator = 1000; info->frame_rate.denominator = pkt->data[8]; info->dsp_asp_ratio = pkt->data[9]; - info->level_idc = pkt->data[10]; + info->profile_idc = (pkt->data[10] >> 8) & 0xff; + info->level_idc = pkt->data[10] & 0xff; info->bit_depth_luma = pkt->data[13]; info->bit_depth_chroma = pkt->data[14]; info->chroma_fmt = pkt->data[15]; @@ -925,6 +926,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt, info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128; else info->pixfmt = V4L2_PIX_FMT_NV12M_8L128; + if (pkt->hdr.num > 28) + info->constraint_set_flags = pkt->data[28]; if (info->frame_rate.numerator && info->frame_rate.denominator) { unsigned long n, d; diff --git a/drivers/media/platform/amphion/vpu_mbox.c b/drivers/media/platform/amphion/vpu_mbox.c index c2963b8deb48..b2ac8de6a2d9 100644 --- a/drivers/media/platform/amphion/vpu_mbox.c +++ b/drivers/media/platform/amphion/vpu_mbox.c @@ -109,7 +109,3 @@ void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data) mbox_send_message(core->tx_data.ch, &data); mbox_send_message(core->tx_type.ch, &type); } - -void vpu_mbox_enable_rx(struct vpu_dev *dev) -{ -} diff --git a/drivers/media/platform/amphion/vpu_mbox.h b/drivers/media/platform/amphion/vpu_mbox.h index 79cfd874e92b..8b7aea4f606c 100644 --- a/drivers/media/platform/amphion/vpu_mbox.h +++ b/drivers/media/platform/amphion/vpu_mbox.h @@ -11,6 +11,5 @@ int vpu_mbox_request(struct vpu_core *core); void vpu_mbox_free(struct vpu_core *core); void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data); void vpu_mbox_send_type(struct vpu_core *core, u32 type); -void vpu_mbox_enable_rx(struct vpu_dev *dev); #endif diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 45707931bc4f..74668fa362e2 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -501,14 +501,25 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, call_void_vop(inst, release); } + if (V4L2_TYPE_IS_CAPTURE(vq->type)) + call_void_vop(inst, reset_frame_store); + return 0; } static int vpu_vb2_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); + struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + vpu_buf->fs_id = -1; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); + + if (!inst->ops->attach_frame_store || V4L2_TYPE_IS_OUTPUT(vb->type)) + return 0; + + call_void_vop(inst, attach_frame_store, vb); return 0; } |