diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-25 04:09:16 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-25 04:09:16 +0300 |
commit | 827060261cf3c7b79ee7185d5aa61c851beb9403 (patch) | |
tree | ea33be6609b189d31d1e56c09c92c967078eb3f8 /drivers/media/platform | |
parent | 268db333b561c77dee3feb6831806412293b4a7e (diff) | |
parent | 340ce50f75a6bdfe6d1850ca49ef37a8e2765dd1 (diff) | |
download | linux-827060261cf3c7b79ee7185d5aa61c851beb9403.tar.xz |
Merge tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- dvb-usb drivers entries got reworked to avoid usage of magic numbers
to refer to data position inside tables
- vcodec driver has gained support for MT8186 and for vp8 and vp9
stateless codecs
- hantro has gained support for Hantro G1 on RK366x
- Added more h264 levels on coda960
- ccs gained support for MIPI CSI-2 28 bits per pixel raw data type
- venus driver gained support for Qualcomm custom compressed pixel
formats
- lots of driver fixes and updates
* tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
media: hantro: Enable HOLD_CAPTURE_BUF for H.264
media: hantro: Add H.264 field decoding support
media: hantro: h264: Make dpb entry management more robust
media: hantro: Stop using H.264 parameter pic_num
media: rkvdec: Enable capture buffer holding for H264
media: rkvdec-h264: Add field decoding support
media: rkvdec: Ensure decoded resolution fit coded resolution
media: rkvdec: h264: Fix reference frame_num wrap for second field
media: rkvdec: h264: Validate and use pic width and height in mbs
media: rkvdec: Move H264 SPS validation in rkvdec-h264
media: rkvdec: h264: Fix bit depth wrap in pps packet
media: rkvdec: h264: Fix dpb_valid implementation
media: rkvdec: Stop overclocking the decoder
media: v4l2: Reorder field reflist
media: h264: Sort p/b reflist using frame_num
media: v4l2: Trace calculated p/b0/b1 initial reflist
media: h264: Store all fields into the unordered list
media: h264: Store current picture fields
media: h264: Increase reference lists size to 32
media: h264: Use v4l2_h264_reference for reflist
...
Diffstat (limited to 'drivers/media/platform')
107 files changed, 5640 insertions, 1526 deletions
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 4a3d06c70e34..2423714afcb9 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -3249,13 +3249,8 @@ static int allegro_release(struct file *file) static int allegro_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); - struct allegro_dev *dev = video_get_drvdata(vdev); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 8f8dfd6ce2c6..3c02aa2a54aa 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -26,8 +26,8 @@ #include "vpu_cmds.h" #include "vpu_rpc.h" -#define VDEC_FRAME_DEPTH 256 #define VDEC_MIN_BUFFER_CAP 8 +#define VDEC_MIN_BUFFER_OUT 8 struct vdec_fs_info { char name[8]; @@ -63,8 +63,6 @@ struct vdec_t { bool is_source_changed; u32 source_change; u32 drain; - u32 ts_pre_count; - u32 frame_depth; }; static const struct vpu_format vdec_formats[] = { @@ -164,6 +162,12 @@ static int vdec_ctrl_init(struct vpu_inst *inst) if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (inst->ctrl_handler.error) { + ret = inst->ctrl_handler.error; + v4l2_ctrl_handler_free(&inst->ctrl_handler); + return ret; + } + ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler); if (ret) { dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret); @@ -470,7 +474,7 @@ static int vdec_drain(struct vpu_inst *inst) if (!vdec->drain) return 0; - if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx)) + if (!vpu_is_source_empty(inst)) return 0; if (!vdec->params.frame_count) { @@ -589,11 +593,8 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type) { struct vdec_t *vdec = inst->priv; - if (V4L2_TYPE_IS_OUTPUT(type)) { - if (vdec->ts_pre_count >= vdec->frame_depth) - return false; + if (V4L2_TYPE_IS_OUTPUT(type)) return true; - } if (vdec->req_frame_count) return true; @@ -601,12 +602,21 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type) return false; } +static struct vb2_v4l2_buffer *vdec_get_src_buffer(struct vpu_inst *inst, u32 count) +{ + if (count > 1) + vpu_skip_frame(inst, count - 1); + + return vpu_next_src_buf(inst); +} + static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) { struct vdec_t *vdec = inst->priv; struct vpu_dec_pic_info *info = arg; struct vpu_vb2_buffer *vpu_buf; struct vb2_v4l2_buffer *vbuf; + struct vb2_v4l2_buffer *src_buf; int ret = 0; if (!info || info->id >= ARRAY_SIZE(vdec->slots)) @@ -620,14 +630,21 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) goto exit; } vbuf = &vpu_buf->m2m_buf.vb; + src_buf = vdec_get_src_buffer(inst, info->consumed_count); + if (src_buf) { + v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + if (info->consumed_count) { + v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_DECODED); + } + } 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->decoded_frame_count++; - if (vdec->ts_pre_count >= info->consumed_count) - vdec->ts_pre_count -= info->consumed_count; - else - vdec->ts_pre_count = 0; exit: vpu_inst_unlock(inst); @@ -683,10 +700,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]); vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]); - vbuf->vb2_buf.timestamp = frame->timestamp; vbuf->field = inst->cap_format.field; vbuf->sequence = sequence; - dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->timestamp); + 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); @@ -708,7 +724,6 @@ static void vdec_stop_done(struct vpu_inst *inst) vdec->fixed_fmt = false; vdec->params.end_flag = 0; vdec->drain = 0; - vdec->ts_pre_count = 0; vdec->params.frame_count = 0; vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; @@ -782,7 +797,7 @@ static void vdec_init_fmt(struct vpu_inst *inst) if (vdec->codec_info.progressive) inst->cap_format.field = V4L2_FIELD_NONE; else - inst->cap_format.field = V4L2_FIELD_SEQ_BT; + inst->cap_format.field = V4L2_FIELD_SEQ_TB; if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT) vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709; if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT) @@ -1244,18 +1259,14 @@ static int vdec_process_output(struct vpu_inst *inst, struct vb2_buffer *vb) if (free_space < vb2_get_plane_payload(vb, 0) + 0x40000) return -ENOMEM; + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); ret = vpu_iface_input_frame(inst, vb); if (ret < 0) return -ENOMEM; dev_dbg(inst->dev, "[%d][INPUT TS]%32lld\n", inst->id, vb->timestamp); - vdec->ts_pre_count++; vdec->params.frame_count++; - v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); - if (vdec->drain) vdec_drain(inst); @@ -1318,7 +1329,6 @@ static void vdec_abort(struct vpu_inst *inst) vdec->sequence); vdec->params.end_flag = 0; vdec->drain = 0; - vdec->ts_pre_count = 0; vdec->params.frame_count = 0; vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; @@ -1525,10 +1535,6 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i vdec->drain, vdec->eos_received, vdec->source_change); break; case 8: - num = scnprintf(str, size, "ts_pre_count = %d, frame_depth = %d\n", - vdec->ts_pre_count, vdec->frame_depth); - break; - case 9: num = scnprintf(str, size, "fps = %d/%d\n", vdec->codec_info.frame_rate.numerator, vdec->codec_info.frame_rate.denominator); @@ -1562,12 +1568,8 @@ static struct vpu_inst_ops vdec_inst_ops = { static void vdec_init(struct file *file) { struct vpu_inst *inst = to_inst(file); - struct vdec_t *vdec; struct v4l2_format f; - vdec = inst->priv; - vdec->frame_depth = VDEC_FRAME_DEPTH; - memset(&f, 0, sizeof(f)); f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; @@ -1612,36 +1614,18 @@ static int vdec_open(struct file *file) vdec->fixed_fmt = false; inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP; + inst->min_buffer_out = VDEC_MIN_BUFFER_OUT; vdec_init(file); return 0; } -static __poll_t vdec_poll(struct file *file, poll_table *wait) -{ - struct vpu_inst *inst = to_inst(file); - struct vb2_queue *src_q, *dst_q; - __poll_t ret; - - ret = v4l2_m2m_fop_poll(file, wait); - src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); - dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - if (vb2_is_streaming(src_q) && !vb2_is_streaming(dst_q)) - ret &= (~EPOLLERR); - if (!src_q->error && !dst_q->error && - (vb2_is_streaming(src_q) && list_empty(&src_q->queued_list)) && - (vb2_is_streaming(dst_q) && list_empty(&dst_q->queued_list))) - ret &= (~EPOLLERR); - - return ret; -} - static const struct v4l2_file_operations vdec_fops = { .owner = THIS_MODULE, .open = vdec_open, .release = vpu_v4l2_close, .unlocked_ioctl = video_ioctl2, - .poll = vdec_poll, + .poll = v4l2_m2m_fop_poll, .mmap = v4l2_m2m_fop_mmap, }; diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index d33c2748e4b7..43d61d82f58c 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -33,6 +33,8 @@ #define VENC_CAPTURE_ENABLE BIT(1) #define VENC_ENABLE_MASK (VENC_OUTPUT_ENABLE | VENC_CAPTURE_ENABLE) #define VENC_MAX_BUF_CNT 8 +#define VENC_MIN_BUFFER_OUT 6 +#define VENC_MIN_BUFFER_CAP 6 struct venc_t { struct vpu_encode_params params; @@ -281,6 +283,9 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm if (!parm) return -EINVAL; + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + if (!vpu_helper_check_type(inst, parm->type)) return -EINVAL; @@ -302,6 +307,9 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm if (!parm) return -EINVAL; + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + if (!vpu_helper_check_type(inst, parm->type)) return -EINVAL; @@ -423,7 +431,7 @@ static int venc_drain(struct vpu_inst *inst) if (inst->state != VPU_CODEC_STATE_DRAIN) return 0; - if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx)) + if (!vpu_is_source_empty(inst)) return 0; if (!venc->input_ready) @@ -680,6 +688,12 @@ static int venc_ctrl_init(struct vpu_inst *inst) ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); + if (inst->ctrl_handler.error) { + ret = inst->ctrl_handler.error; + v4l2_ctrl_handler_free(&inst->ctrl_handler); + return ret; + } + ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler); if (ret) { dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret); @@ -775,10 +789,20 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vbuf) { struct venc_t *venc = inst->priv; + struct vb2_v4l2_buffer *src_buf; if (!vbuf) return -EAGAIN; + src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id); + if (src_buf) { + v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + vbuf->vb2_buf.timestamp = frame->info.timestamp; + } if (!venc_get_enable(inst->priv, vbuf->vb2_buf.type)) { v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); return 0; @@ -800,11 +824,10 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, } vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->bytesused); vbuf->sequence = frame->info.frame_id; - vbuf->vb2_buf.timestamp = frame->info.timestamp; vbuf->field = inst->cap_format.field; vbuf->flags |= frame->info.pic_type; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->info.timestamp); + dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); venc->ready_count++; @@ -860,33 +883,6 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg) return ret; } -static void venc_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) -{ - struct vb2_v4l2_buffer *vbuf; - - if (!inst->fh.m2m_ctx) - return; - - vpu_inst_lock(inst); - if (!venc_get_enable(inst->priv, frame->type)) - goto exit; - vbuf = vpu_find_buf_by_sequence(inst, frame->type, frame->sequence); - if (!vbuf) { - dev_err(inst->dev, "[%d] can't find buf: type %d, sequence %d\n", - inst->id, frame->type, frame->sequence); - goto exit; - } - - vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - if (V4L2_TYPE_IS_OUTPUT(frame->type)) - v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - else - v4l2_m2m_dst_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); -exit: - vpu_inst_unlock(inst); -} - static void venc_set_last_buffer_dequeued(struct vpu_inst *inst) { struct venc_t *venc = inst->priv; @@ -1252,7 +1248,6 @@ static struct vpu_inst_ops venc_inst_ops = { .check_ready = venc_check_ready, .input_done = venc_input_done, .get_one_frame = venc_frame_encoded, - .buf_done = venc_buf_done, .stop_done = venc_stop_done, .event_notify = venc_event_notify, .release = venc_release, @@ -1333,6 +1328,8 @@ static int venc_open(struct file *file) if (ret) return ret; + inst->min_buffer_out = VENC_MIN_BUFFER_OUT; + inst->min_buffer_cap = VENC_MIN_BUFFER_CAP; venc_init(file); return 0; diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index 376196bea178..da62bd718fb8 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -413,10 +413,6 @@ int vpu_inst_create_dbgfs_file(struct vpu_inst *inst) vpu->debugfs, inst, &vpu_dbg_inst_fops); - if (!inst->debugfs) { - dev_err(inst->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } return 0; } @@ -451,10 +447,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core) vpu->debugfs, core, &vpu_dbg_core_fops); - if (!core->debugfs) { - dev_err(core->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } } if (!core->debugfs_fwlog) { scnprintf(name, sizeof(name), "fwlog.%d", core->id); @@ -463,10 +455,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core) vpu->debugfs, core, &vpu_dbg_fwlog_fops); - if (!core->debugfs_fwlog) { - dev_err(core->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } } return 0; diff --git a/drivers/media/platform/amphion/vpu_defs.h b/drivers/media/platform/amphion/vpu_defs.h index 282664202dcf..667637eedb5d 100644 --- a/drivers/media/platform/amphion/vpu_defs.h +++ b/drivers/media/platform/amphion/vpu_defs.h @@ -69,8 +69,8 @@ enum { VPU_MSG_ID_BS_ERROR, VPU_MSG_ID_UNSUPPORTED, VPU_MSG_ID_TIMESTAMP_INFO, - VPU_MSG_ID_FIRMWARE_XCPT, + VPU_MSG_ID_PIC_SKIPPED, }; enum VPU_ENC_MEMORY_RESOURSE { diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index 446a9de0cc11..f29c223eefce 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -170,6 +170,7 @@ enum { VID_API_EVENT_DEC_CHECK_RES = 0x24, VID_API_EVENT_DEC_CFG_INFO = 0x25, VID_API_EVENT_UNSUPPORTED_STREAM = 0x26, + VID_API_EVENT_PIC_SKIPPED = 0x27, VID_API_EVENT_STR_SUSPENDED = 0x30, VID_API_EVENT_SNAPSHOT_DONE = 0x40, VID_API_EVENT_FW_STATUS = 0xF0, @@ -703,6 +704,7 @@ static struct vpu_pair malone_msgs[] = { {VPU_MSG_ID_BS_ERROR, VID_API_EVENT_BS_ERROR}, {VPU_MSG_ID_UNSUPPORTED, VID_API_EVENT_UNSUPPORTED_STREAM}, {VPU_MSG_ID_FIRMWARE_XCPT, VID_API_EVENT_FIRMWARE_XCPT}, + {VPU_MSG_ID_PIC_SKIPPED, VID_API_EVENT_PIC_SKIPPED}, }; static void vpu_malone_pack_fs_alloc(struct vpu_rpc_event *pkt, @@ -1556,7 +1558,7 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, * merge the data to next frame */ vbuf = to_vb2_v4l2_buffer(vb); - if (vpu_vb_is_codecconfig(vbuf) && (s64)vb->timestamp < 0) { + if (vpu_vb_is_codecconfig(vbuf)) { inst->extra_size += size; return 0; } diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c index 58502c51ddb3..d5850df8f1d5 100644 --- a/drivers/media/platform/amphion/vpu_msgs.c +++ b/drivers/media/platform/amphion/vpu_msgs.c @@ -166,6 +166,13 @@ static void vpu_session_handle_firmware_xcpt(struct vpu_inst *inst, struct vpu_r vpu_v4l2_set_error(inst); } +static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc_event *pkt) +{ + vpu_inst_lock(inst); + vpu_skip_frame(inst, 1); + vpu_inst_unlock(inst); +} + static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_START_DONE, vpu_session_handle_start_done}, {VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done}, @@ -181,6 +188,7 @@ static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos}, {VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error}, {VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt}, + {VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped}, }; static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 9c0704cd5766..446f07d09d0b 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -73,10 +73,10 @@ void vpu_v4l2_set_error(struct vpu_inst *inst) if (inst->fh.m2m_ctx) { src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - if (src_q) - src_q->error = 1; - if (dst_q) - dst_q->error = 1; + src_q->error = 1; + dst_q->error = 1; + wake_up(&src_q->done_wq); + wake_up(&dst_q->done_wq); } vpu_inst_unlock(inst); } @@ -127,6 +127,19 @@ int vpu_set_last_buffer_dequeued(struct vpu_inst *inst) return 0; } +bool vpu_is_source_empty(struct vpu_inst *inst) +{ + struct v4l2_m2m_buffer *buf = NULL; + + if (!inst->fh.m2m_ctx) + return true; + v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) { + if (vpu_get_buffer_state(&buf->vb) == VPU_BUF_STATE_IDLE) + return false; + } + return true; +} + const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; @@ -234,6 +247,49 @@ int vpu_process_capture_buffer(struct vpu_inst *inst) return call_vop(inst, process_capture, &vbuf->vb2_buf); } +struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst) +{ + struct vb2_v4l2_buffer *src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); + + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + + while (vpu_vb_is_codecconfig(src_buf)) { + v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + } + + return src_buf; +} + +void vpu_skip_frame(struct vpu_inst *inst, int count) +{ + struct vb2_v4l2_buffer *src_buf; + enum vb2_buffer_state state; + int i = 0; + + if (count <= 0) + return; + + while (i < count) { + src_buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return; + if (vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_DECODED) + state = VB2_BUF_STATE_DONE; + else + state = VB2_BUF_STATE_ERROR; + i++; + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, state); + } +} + struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence) { struct v4l2_m2m_buffer *buf = NULL; @@ -342,6 +398,10 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, return 0; } + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out); + else + *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap); *plane_count = cur_fmt->num_planes; for (i = 0; i < cur_fmt->num_planes; i++) psize[i] = cur_fmt->sizeimage[i]; diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h index 90fa7ea67495..795ca33a6a50 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.h +++ b/drivers/media/platform/amphion/vpu_v4l2.h @@ -19,6 +19,8 @@ int vpu_v4l2_close(struct file *file); const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f); int vpu_process_output_buffer(struct vpu_inst *inst); int vpu_process_capture_buffer(struct vpu_inst *inst); +struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst); +void vpu_skip_frame(struct vpu_inst *inst, int count); struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); void vpu_v4l2_set_error(struct vpu_inst *inst); @@ -27,6 +29,7 @@ int vpu_notify_source_change(struct vpu_inst *inst); int vpu_set_last_buffer_dequeued(struct vpu_inst *inst); void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); +bool vpu_is_source_empty(struct vpu_inst *inst); dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index b937dbcbe9e0..20f795ccc11b 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1993,6 +1993,7 @@ static int aspeed_video_probe(struct platform_device *pdev) rc = aspeed_video_setup_video(video); if (rc) { + aspeed_video_free_buf(video, &video->jpeg); clk_unprepare(video->vclk); clk_unprepare(video->eclk); return rc; @@ -2024,8 +2025,7 @@ static int aspeed_video_remove(struct platform_device *pdev) v4l2_device_unregister(v4l2_dev); - dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt, - video->jpeg.dma); + aspeed_video_free_buf(video, &video->jpeg); of_reserved_mem_device_release(dev); diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index db15770d5b88..2f07a50035c8 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -401,6 +401,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) struct isc_buffer *buf; int ret; + mutex_lock(&isc->awb_mutex); v4l2_ctrl_activate(isc->do_wb_ctrl, false); isc->stop = true; @@ -410,6 +411,8 @@ static void isc_stop_streaming(struct vb2_queue *vq) v4l2_err(&isc->v4l2_dev, "Timeout waiting for end of the capture\n"); + mutex_unlock(&isc->awb_mutex); + /* Disable DMA interrupt */ regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); @@ -442,7 +445,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&isc->dma_queue_lock, flags); if (!isc->cur_frm && list_empty(&isc->dma_queue) && - vb2_is_streaming(vb->vb2_queue)) { + vb2_start_streaming_called(vb->vb2_queue)) { isc->cur_frm = buf; isc_start_dma(isc); } else @@ -1029,7 +1032,7 @@ static int isc_s_fmt_vid_cap(struct file *file, void *priv, { struct isc_device *isc = video_drvdata(file); - if (vb2_is_streaming(&isc->vb2_vidq)) + if (vb2_is_busy(&isc->vb2_vidq)) return -EBUSY; return isc_set_fmt(isc, f); @@ -1397,10 +1400,6 @@ static void isc_awb_work(struct work_struct *w) u32 min, max; int ret; - /* streaming is not active anymore */ - if (isc->stop) - return; - if (ctrls->hist_stat != HIST_ENABLED) return; @@ -1455,7 +1454,24 @@ static void isc_awb_work(struct work_struct *w) } regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his, hist_id | baysel | ISC_HIS_CFG_RAR); + + /* + * We have to make sure the streaming has not stopped meanwhile. + * ISC requires a frame to clock the internal profile update. + * To avoid issues, lock the sequence with a mutex + */ + mutex_lock(&isc->awb_mutex); + + /* streaming is not active anymore */ + if (isc->stop) { + mutex_unlock(&isc->awb_mutex); + return; + }; + isc_update_profile(isc); + + mutex_unlock(&isc->awb_mutex); + /* if awb has been disabled, we don't need to start another histogram */ if (ctrls->awb) regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); @@ -1534,6 +1550,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) isc_update_awb_ctrls(isc); + mutex_lock(&isc->awb_mutex); if (vb2_is_streaming(&isc->vb2_vidq)) { /* * If we are streaming, we can update profile to @@ -1548,6 +1565,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) */ v4l2_ctrl_activate(isc->do_wb_ctrl, false); } + mutex_unlock(&isc->awb_mutex); /* if we have autowhitebalance on, start histogram procedure */ if (ctrls->awb == ISC_WB_AUTO && @@ -1729,6 +1747,7 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); + mutex_destroy(&isc->awb_mutex); cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); v4l2_ctrl_handler_free(&isc->ctrls.handler); @@ -1838,6 +1857,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); mutex_init(&isc->lock); + mutex_init(&isc->awb_mutex); + init_completion(&isc->comp); /* Initialize videobuf2 queue */ @@ -1906,6 +1927,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) return 0; isc_async_complete_err: + mutex_destroy(&isc->awb_mutex); mutex_destroy(&isc->lock); return ret; } diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h index 07fa6dbf8460..ff60ba020cb9 100644 --- a/drivers/media/platform/atmel/atmel-isc.h +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -218,6 +218,7 @@ struct isc_reg_offsets { * * @lock: lock for serializing userspace file operations * with ISC operations + * @awb_mutex: serialize access to streaming status from awb work queue * @awb_lock: lock for serializing awb work queue operations * with DMA/buffer operations * @@ -272,7 +273,7 @@ struct isc_device { struct video_device video_dev; struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; /* serialize access to dma queue */ + spinlock_t dma_queue_lock; struct list_head dma_queue; struct isc_buffer *cur_frm; unsigned int sequence; @@ -289,8 +290,9 @@ struct isc_device { struct isc_ctrls ctrls; struct work_struct awb_work; - struct mutex lock; /* serialize access to file operations */ - spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */ + struct mutex lock; + struct mutex awb_mutex; + spinlock_t awb_lock; struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index c5b9563e36cb..9881d89a645b 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -60,56 +60,39 @@ static const struct isc_format sama5d2_controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { + }, { .fourcc = V4L2_PIX_FMT_RGB565, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV420, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUYV, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { + }, { .fourcc = V4L2_PIX_FMT_GREY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB10, }, }; @@ -291,7 +274,7 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc) * Thus, if the YCYC mode is selected, replace it with the * sama5d2-compliant mode which is YYCC . */ - if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) { + if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) { rlp_mode &= ~ISC_RLP_CFG_MODE_MASK; rlp_mode |= ISC_RLP_CFG_MODE_YYCC; } @@ -562,7 +545,7 @@ static int atmel_isc_probe(struct platform_device *pdev) ret = clk_prepare_enable(isc->ispck); if (ret) { dev_err(dev, "failed to enable ispck: %d\n", ret); - goto cleanup_subdev; + goto disable_pm; } /* ispck should be greater or equal to hclock */ @@ -580,6 +563,9 @@ static int atmel_isc_probe(struct platform_device *pdev) unprepare_clk: clk_disable_unprepare(isc->ispck); +disable_pm: + pm_runtime_disable(dev); + cleanup_subdev: isc_subdev_cleanup(isc); diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index 07a80b08bc54..83b175070c06 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -63,65 +63,45 @@ static const struct isc_format sama7g5_controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { + }, { .fourcc = V4L2_PIX_FMT_RGB565, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV420, - }, - { + }, { .fourcc = V4L2_PIX_FMT_UYVY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_VYUY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUYV, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { + }, { .fourcc = V4L2_PIX_FMT_GREY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y16, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB10, }, }; @@ -225,7 +205,6 @@ static struct isc_format sama7g5_formats_list[] = { .mbus_code = MEDIA_BUS_FMT_Y10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, }, - }; static void isc_sama7g5_config_csc(struct isc_device *isc) diff --git a/drivers/media/platform/atmel/microchip-csi2dc.c b/drivers/media/platform/atmel/microchip-csi2dc.c index 2487978db1f1..d5b359f607ae 100644 --- a/drivers/media/platform/atmel/microchip-csi2dc.c +++ b/drivers/media/platform/atmel/microchip-csi2dc.c @@ -454,6 +454,10 @@ static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd, return 0; } +static const struct media_entity_operations csi2dc_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = { .enum_mbus_code = csi2dc_enum_mbus_code, .set_fmt = csi2dc_set_fmt, @@ -683,6 +687,7 @@ static int csi2dc_probe(struct platform_device *pdev) csi2dc->csi2dc_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; csi2dc->csi2dc_sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + csi2dc->csi2dc_sd.entity.ops = &csi2dc_entity_ops; platform_set_drvdata(pdev, csi2dc); diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 8f8c36056354..58e405b69f67 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> +#include <media/mipi-csi2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -121,12 +122,12 @@ static const struct csi2tx_fmt csi2tx_formats[] = { { .mbus = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 2, - .dt = 0x1e, + .dt = MIPI_CSI2_DT_YUV422_8B, }, { .mbus = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 3, - .dt = 0x24, + .dt = MIPI_CSI2_DT_RGB888, }, }; diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda-bit.c index c484c008ab02..2736a902e3df 100644 --- a/drivers/media/platform/chips-media/coda-bit.c +++ b/drivers/media/platform/chips-media/coda-bit.c @@ -326,6 +326,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) struct coda_buffer_meta *meta; u32 start; + lockdep_assert_held(&ctx->bitstream_mutex); + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) return; @@ -2174,7 +2176,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", coda_get_bitstream_payload(ctx)); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return -EAGAIN; } @@ -2184,7 +2185,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return -EAGAIN; } else { ctx->initialized = 1; diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda-common.c index a57822b05070..af71eea04dbd 100644 --- a/drivers/media/platform/chips-media/coda-common.c +++ b/drivers/media/platform/chips-media/coda-common.c @@ -657,6 +657,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, const struct coda_q_data *q_data_src; const struct coda_codec *codec; struct vb2_queue *src_vq; + int hscale = 0; + int vscale = 0; int ret; bool use_vdoa; @@ -673,8 +675,13 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, */ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (vb2_is_streaming(src_vq)) { - f->fmt.pix.width = q_data_src->width; - f->fmt.pix.height = q_data_src->height; + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + f->fmt.pix.width = q_data_src->width >> hscale; + f->fmt.pix.height = q_data_src->height >> vscale; if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { if (ctx->params.jpeg_chroma_subsampling == @@ -704,8 +711,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, /* The decoders always write complete macroblocks or MCUs */ if (ctx->inst_type == CODA_INST_DECODER) { - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.height = round_up(f->fmt.pix.height, 16); + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale); + f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale); if (codec->src_fourcc == V4L2_PIX_FMT_JPEG && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * @@ -850,17 +857,26 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, struct coda_q_data *q_data_src; const struct coda_codec *codec; struct v4l2_rect r; + int hscale = 0; + int vscale = 0; int ret; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + ret = coda_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); r.left = 0; r.top = 0; - r.width = q_data_src->width; - r.height = q_data_src->height; + r.width = q_data_src->width >> hscale; + r.height = q_data_src->height >> vscale; ret = coda_s_fmt(ctx, f, &r); if (ret) @@ -1091,17 +1107,6 @@ static int coda_s_selection(struct file *file, void *fh, } } -static int coda_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - - if (ctx->inst_type != CODA_INST_ENCODER) - return -ENOTTY; - - return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); -} - static void coda_wake_up_capture_queue(struct coda_ctx *ctx) { struct vb2_queue *dst_vq; @@ -1120,7 +1125,7 @@ static int coda_encoder_cmd(struct file *file, void *fh, struct vb2_v4l2_buffer *buf; int ret; - ret = coda_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; @@ -1149,17 +1154,6 @@ static int coda_encoder_cmd(struct file *file, void *fh, return 0; } -static int coda_try_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - - if (ctx->inst_type != CODA_INST_DECODER) - return -ENOTTY; - - return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); -} - static bool coda_mark_last_meta(struct coda_ctx *ctx) { struct coda_buffer_meta *meta; @@ -1216,7 +1210,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, bool wakeup; int ret; - ret = coda_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; @@ -1291,9 +1285,6 @@ static int coda_enum_framesizes(struct file *file, void *fh, struct coda_q_data *q_data_dst; const struct coda_codec *codec; - if (ctx->inst_type != CODA_INST_ENCODER) - return -ENOTTY; - if (fsize->index) return -EINVAL; @@ -1324,7 +1315,8 @@ static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { struct coda_ctx *ctx = fh_to_ctx(fh); - int i; + struct coda_q_data *q_data; + const struct coda_codec *codec; if (f->index) return -EINVAL; @@ -1333,12 +1325,19 @@ static int coda_enum_frameintervals(struct file *file, void *fh, if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) return -EINVAL; - for (i = 0; i < CODA_MAX_FORMATS; i++) { - if (f->pixel_format == ctx->cvd->src_formats[i] || - f->pixel_format == ctx->cvd->dst_formats[i]) - break; + if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) { + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, f->pixel_format, + q_data->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + f->pixel_format); } - if (i == CODA_MAX_FORMATS) + if (!codec) + return -EINVAL; + + if (f->width < MIN_W || f->width > codec->max_w || + f->height < MIN_H || f->height > codec->max_h) return -EINVAL; f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; @@ -1498,9 +1497,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_g_selection = coda_g_selection, .vidioc_s_selection = coda_s_selection, - .vidioc_try_encoder_cmd = coda_try_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, .vidioc_encoder_cmd = coda_encoder_cmd, - .vidioc_try_decoder_cmd = coda_try_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, .vidioc_g_parm = coda_g_parm, @@ -1535,12 +1534,8 @@ static void coda_pic_run_work(struct work_struct *work) mutex_lock(&dev->coda_mutex); ret = ctx->ops->prepare_run(ctx); - if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) { - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - /* job_finish scheduled by prepare_decode */ - return; - } + if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) + goto out; if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { @@ -1562,6 +1557,7 @@ static void coda_pic_run_work(struct work_struct *work) ctx->ops->seq_end_work) queue_work(dev->workqueue, &ctx->seq_end_work); +out: mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); @@ -1665,13 +1661,18 @@ static void set_default_params(struct coda_ctx *ctx) csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); ctx->params.codec_mode = ctx->codec->mode; - if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG) - ctx->colorspace = V4L2_COLORSPACE_JPEG; - else + if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG || + ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + ctx->colorspace = V4L2_COLORSPACE_SRGB; + ctx->xfer_func = V4L2_XFER_FUNC_SRGB; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; + ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } else { ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; - ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + } ctx->params.framerate = 30; /* Default formats for output and input queues */ @@ -2011,13 +2012,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) */ if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - ret = coda_jpeg_decode_header(ctx, &buf->vb2_buf); - if (ret < 0) { - v4l2_err(v4l2_dev, - "failed to decode JPEG header: %d\n", - ret); - goto err; - } + coda_jpeg_decode_header(ctx, &buf->vb2_buf); + /* + * We have to start streaming even if the first buffer + * does not contain a valid JPEG image. The error will + * be caught during device run and will be signalled + * via the capture buffer error flag. + */ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); q_data_dst->width = round_up(q_data_src->width, 16); @@ -2344,8 +2345,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, - V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, - V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); if (ctx->dev->devtype->product == CODA_HX4 || ctx->dev->devtype->product == CODA_7541) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, @@ -2359,12 +2360,15 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) if (ctx->dev->devtype->product == CODA_960) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, - V4L2_MPEG_VIDEO_H264_LEVEL_4_0, - ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + V4L2_MPEG_VIDEO_H264_LEVEL_4_2, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)), + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), V4L2_MPEG_VIDEO_H264_LEVEL_4_0); } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, @@ -2426,7 +2430,7 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_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_HIGH)), V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); @@ -2901,6 +2905,23 @@ static int coda_register_device(struct coda_dev *dev, int i) v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); + if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) { + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + } else { + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); if (!ret) v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c index a72f4655e5ad..a0b22b07f69a 100644 --- a/drivers/media/platform/chips-media/coda-jpeg.c +++ b/drivers/media/platform/chips-media/coda-jpeg.c @@ -283,7 +283,8 @@ int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb) ret = v4l2_jpeg_parse_header(buf, len, &header); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to parse header\n"); + v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n", + ERR_PTR(ret)); return ret; } @@ -1328,6 +1329,7 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) struct coda_q_data *q_data_src, *q_data_dst; struct vb2_v4l2_buffer *src_buf, *dst_buf; int chroma_interleave; + int scl_hor_mode, scl_ver_mode; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1335,27 +1337,24 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_fourcc = q_data_dst->fourcc; + scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width); + scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height); + if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) vb2_set_plane_payload(&src_buf->vb2_buf, 0, vb2_plane_size(&src_buf->vb2_buf, 0)); chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc); - if (chroma_format < 0) { - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + if (chroma_format < 0) return chroma_format; - } ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to decode JPEG header: %d\n", - ret); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return ret; } @@ -1386,7 +1385,11 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); - coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO); + if (scl_hor_mode || scl_ver_mode) + val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode; + else + val = 0; + coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO); coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); coda_write(dev, ctx->params.jpeg_restart_interval, CODA9_REG_JPEG_RST_INTVAL); @@ -1396,7 +1399,6 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to set up Huffman tables: %d\n", ret); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return ret; } } diff --git a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda.h index dcf35641c603..ddfd0a32c653 100644 --- a/drivers/media/platform/chips-media/coda.h +++ b/drivers/media/platform/chips-media/coda.h @@ -380,6 +380,13 @@ u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, u8 level_idc); +static inline int coda_jpeg_scale(int src, int dst) +{ + return (dst <= src / 8) ? 3 : + (dst <= src / 4) ? 2 : + (dst <= src / 2) ? 1 : 0; +} + bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_write_tables(struct coda_ctx *ctx); diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c index 03dcf8bf705e..ae97ce4ead98 100644 --- a/drivers/media/platform/marvell/cafe-driver.c +++ b/drivers/media/platform/marvell/cafe-driver.c @@ -497,7 +497,6 @@ static int cafe_pci_probe(struct pci_dev *pdev, mcam->plat_power_up = cafe_ctlr_power_up; mcam->plat_power_down = cafe_ctlr_power_down; mcam->dev = &pdev->dev; - snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev)); /* * Vmalloc mode for buffers is traditional with this driver. * We *might* be able to run DMA_contig, especially on a system diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index ab5485dfc20c..bc5b0a0168ec 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -137,8 +137,6 @@ static int mtk_jpeg_querycap(struct file *file, void *priv, strscpy(cap->driver, jpeg->variant->dev_name, sizeof(cap->driver)); strscpy(cap->card, jpeg->variant->dev_name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(jpeg->dev)); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/Kconfig b/drivers/media/platform/mediatek/vcodec/Kconfig index c5c76753c626..74b00eb1bc97 100644 --- a/drivers/media/platform/mediatek/vcodec/Kconfig +++ b/drivers/media/platform/mediatek/vcodec/Kconfig @@ -22,6 +22,7 @@ config VIDEO_MEDIATEK_VCODEC select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP select V4L2_H264 + select V4L2_VP9 select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API help diff --git a/drivers/media/platform/mediatek/vcodec/Makefile b/drivers/media/platform/mediatek/vcodec/Makefile index 359619653a0e..93e7a343b5b0 100644 --- a/drivers/media/platform/mediatek/vcodec/Makefile +++ b/drivers/media/platform/mediatek/vcodec/Makefile @@ -7,8 +7,12 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ + vdec/vdec_vp8_req_if.o \ vdec/vdec_vp9_if.o \ + vdec/vdec_vp9_req_lat_if.o \ vdec/vdec_h264_req_if.o \ + vdec/vdec_h264_req_common.o \ + vdec/vdec_h264_req_multi_if.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 130ecef2e766..52e5d36aa912 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -26,7 +26,7 @@ mtk_vdec_find_format(struct v4l2_format *f, const struct mtk_video_fmt *fmt; unsigned int k; - for (k = 0; k < dec_pdata->num_formats; k++) { + for (k = 0; k < *dec_pdata->num_formats; k++) { fmt = &dec_pdata->vdec_formats[k]; if (fmt->fourcc == f->fmt.pix_mp.pixelformat) return fmt; @@ -47,14 +47,7 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); - - /* Use M2M stateless helper if relevant */ - if (ctx->dev->vdec_pdata->uses_stateless_api) - return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, - cmd); - else - return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); + return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); } @@ -69,10 +62,6 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, if (ret) return ret; - /* Use M2M stateless helper if relevant */ - if (ctx->dev->vdec_pdata->uses_stateless_api) - return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd); - mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -152,13 +141,15 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; + ctx->max_width = MTK_VDEC_MAX_W; + ctx->max_height = MTK_VDEC_MAX_H; v4l_bound_align_image(&q_data->coded_width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 4, + ctx->max_width, 4, &q_data->coded_height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 5, 6); + ctx->max_height, 5, 6); q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; @@ -217,7 +208,7 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, } } -static int vidioc_try_fmt(struct v4l2_format *f, +static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; @@ -225,9 +216,9 @@ static int vidioc_try_fmt(struct v4l2_format *f, pix_fmt_mp->field = V4L2_FIELD_NONE; pix_fmt_mp->width = - clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W); + clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width); pix_fmt_mp->height = - clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H); + clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; @@ -245,16 +236,16 @@ static int vidioc_try_fmt(struct v4l2_format *f, tmp_h = pix_fmt_mp->height; v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 6, + ctx->max_width, 6, &pix_fmt_mp->height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 6, 9); + ctx->max_height, 6, 9); if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W) + (pix_fmt_mp->width + 64) <= ctx->max_width) pix_fmt_mp->width += 64; if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H) + (pix_fmt_mp->height + 64) <= ctx->max_height) pix_fmt_mp->height += 64; mtk_v4l2_debug(0, @@ -294,7 +285,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, fmt = mtk_vdec_find_format(f, dec_pdata); } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, @@ -317,7 +308,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, return -EINVAL; } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_vdec_g_selection(struct file *file, void *priv, @@ -444,8 +435,15 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, if (fmt == NULL) return -EINVAL; + if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && + fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) { + mtk_v4l2_debug(3, "4K is enabled"); + ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH; + ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT; + } + q_data->fmt = fmt; - vidioc_try_fmt(f, q_data->fmt); + vidioc_try_fmt(ctx, f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; q_data->coded_width = pix_mp->width; @@ -466,6 +464,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, } ctx->state = MTK_STATE_INIT; } + } else { + ctx->capture_fourcc = fmt->fourcc; } /* @@ -476,11 +476,14 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ctx->picinfo.pic_w = pix_mp->width; ctx->picinfo.pic_h = pix_mp->height; + /* + * If get pic info fail, need to use the default pic info params, or + * v4l2-compliance will fail + */ ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo); if (ret) { mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail", ctx->id); - return -EINVAL; } ctx->last_decoded_picinfo = ctx->picinfo; @@ -523,20 +526,15 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, if (fsize->index != 0) return -EINVAL; - for (i = 0; i < dec_pdata->num_framesizes; ++i) { + for (i = 0; i < *dec_pdata->num_framesizes; ++i) { if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) continue; fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; - if (!(ctx->dev->dec_capability & - VCODEC_CAPABILITY_4K_DISABLED)) { - mtk_v4l2_debug(3, "4K is enabled"); - fsize->stepwise.max_width = - VCODEC_DEC_4K_CODED_WIDTH; - fsize->stepwise.max_height = - VCODEC_DEC_4K_CODED_HEIGHT; - } + + fsize->stepwise.max_width = ctx->max_width; + fsize->stepwise.max_height = ctx->max_height; mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d", ctx->dev->dec_capability, fsize->stepwise.min_width, @@ -545,6 +543,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, fsize->stepwise.min_height, fsize->stepwise.max_height, fsize->stepwise.step_height); + return 0; } @@ -559,7 +558,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, const struct mtk_video_fmt *fmt; int i, j = 0; - for (i = 0; i < dec_pdata->num_formats; i++) { + for (i = 0; i < *dec_pdata->num_formats; i++) { if (output_queue && dec_pdata->vdec_formats[i].type != MTK_FMT_DEC) continue; @@ -572,7 +571,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, ++j; } - if (i == dec_pdata->num_formats) + if (i == *dec_pdata->num_formats) return -EINVAL; fmt = &dec_pdata->vdec_formats[i]; @@ -737,6 +736,8 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) i, vb2_plane_size(vb, i), q_data->sizeimage[i]); } + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) + vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); } return 0; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h index 66cd6d2242c3..4572f92826f2 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h @@ -69,6 +69,7 @@ extern const struct media_device_ops mtk_vcodec_media_ops; extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata; /* diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index df7b25e9cbc8..995e6e2fb1ab 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -193,9 +193,6 @@ static int fops_vcodec_open(struct file *file) mtk_vcodec_dec_set_default_params(ctx); if (v4l2_fh_is_singular(&ctx->fh)) { - ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0); - if (ret < 0) - goto err_load_fw; /* * Does nothing if firmware was already loaded. */ @@ -252,8 +249,6 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_dec_release(ctx); - if (v4l2_fh_is_singular(&ctx->fh)) - mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); @@ -400,6 +395,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } if (dev->vdec_pdata->uses_stateless_api) { + v4l2_disable_ioctl(vfd_dec, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd_dec, VIDIOC_TRY_DECODER_CMD); + dev->mdev_dec.dev = &pdev->dev; strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME, sizeof(dev->mdev_dec.model)); @@ -463,6 +461,10 @@ static const struct of_device_id mtk_vcodec_match[] = { .compatible = "mediatek,mt8192-vcodec-dec", .data = &mtk_lat_sig_core_pdata, }, + { + .compatible = "mediatek,mt8186-vcodec-dec", + .data = &mtk_vdec_single_core_pdata, + }, {}, }; @@ -487,7 +489,8 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) video_unregister_device(dev->vfd_dec); v4l2_device_unregister(&dev->v4l2_dev); - pm_runtime_disable(dev->pm.dev); + if (!dev->vdec_pdata->is_subdev_supported) + pm_runtime_disable(dev->pm.dev); mtk_vcodec_fw_release(dev->fw_handler); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 7e0c2644bf7b..0fb7e5ba635b 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -57,74 +57,31 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm * } EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return -EINVAL; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_resume_and_get(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); return ret; } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_put_sync(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int ret, i; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - enable_irq(subdev_dev->dec_irq); - } else { - pm = &vdec_dev->pm; - enable_irq(vdec_dev->dec_irq); - } - dec_clk = &pm->vdec_clk; for (i = 0; i < dec_clk->clk_num; i++) { ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); @@ -140,30 +97,119 @@ error: for (i -= 1; i >= 0; i--) clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int i; + dec_clk = &pm->vdec_clk; + for (i = dec_clk->clk_num - 1; i >= 0; i--) + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +} + +static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + if (vdec_dev->vdec_pdata->is_subdev_supported) { subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { + if (subdev_dev) + enable_irq(subdev_dev->dec_irq); + else + mtk_v4l2_err("Failed to get hw dev\n"); + } else { + enable_irq(vdec_dev->dec_irq); + } +} + +static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + disable_irq(subdev_dev->dec_irq); + else mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - disable_irq(subdev_dev->dec_irq); } else { - pm = &vdec_dev->pm; disable_irq(vdec_dev->dec_irq); } +} - dec_clk = &pm->vdec_clk; - for (i = dec_clk->clk_num - 1; i >= 0; i--) - clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return NULL; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + return &subdev_dev->pm; + + mtk_v4l2_err("Failed to get hw dev\n"); + return NULL; + } + + return &vdec_dev->pm; +} + +static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_pw_on(pm); + mtk_vcodec_dec_clock_on(pm); + } +} + +static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_clock_off(pm); + mtk_vcodec_dec_pw_off(pm); + } +} + +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mutex_lock(&ctx->dev->dec_mutex[hw_idx]); + + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0); + mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); + + mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); + +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); + + mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0); + + mutex_unlock(&ctx->dev->dec_mutex[hw_idx]); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off); +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h index 3cc721bbfaf6..dbcf3cabe6f3 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h @@ -11,9 +11,7 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); #endif /* _MTK_VCODEC_DEC_PM_H_ */ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c index 04ca43c77e5f..9c7e6145cebb 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c @@ -37,7 +37,9 @@ static const struct mtk_video_fmt mtk_video_formats[] = { }, }; -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +static const unsigned int num_supported_formats = + ARRAY_SIZE(mtk_video_formats); + #define DEFAULT_OUT_FMT_IDX 0 #define DEFAULT_CAP_FMT_IDX 3 @@ -59,7 +61,8 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { }, }; -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) +static const unsigned int num_supported_framesize = + ARRAY_SIZE(mtk_vdec_framesizes); /* * This function tries to clean all display buffers, the buffers will return @@ -90,11 +93,6 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) vb = &dstbuf->m2m_buf.vb; mutex_lock(&ctx->lock); if (dstbuf->used) { - vb2_set_plane_payload(&vb->vb2_buf, 0, ctx->picinfo.fb_sz[0]); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&vb->vb2_buf, 1, - ctx->picinfo.fb_sz[1]); - mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", ctx->id, disp_frame_buffer->status, vb->vb2_buf.index, dstbuf->queued_in_vb2); @@ -235,7 +233,7 @@ static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, unsigned int k; dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (k = 0; k < NUM_FORMATS; k++) { + for (k = 0; k < num_supported_formats; k++) { fmt = &mtk_video_formats[k]; if (fmt->fourcc == pixelformat) { mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", @@ -613,16 +611,15 @@ static struct vb2_ops mtk_vdec_frame_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { - .chip = MTK_MT8173, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, + .num_formats = &num_supported_formats, .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_supported_framesize, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, .is_subdev_supported = false, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c index 23d997ac114d..16d55785d84b 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c @@ -76,69 +76,102 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, .codec_type = V4L2_PIX_FMT_H264_SLICE, - } -}; - -#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) - -static const struct mtk_video_fmt mtk_video_formats[] = { + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_VP8_FRAME, + }, + .codec_type = V4L2_PIX_FMT_VP8_FRAME, + }, { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .type = MTK_FMT_DEC, - .num_planes = 1, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + .min = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP8_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP8_FRAME, }, { - .fourcc = V4L2_PIX_FMT_MM21, - .type = MTK_FMT_FRAME, - .num_planes = 2, + .cfg = { + .id = V4L2_CID_STATELESS_VP9_FRAME, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, -}; - -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) -#define DEFAULT_OUT_FMT_IDX 0 -#define DEFAULT_CAP_FMT_IDX 1 - -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, }; -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) +#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) -static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx, - struct vdec_fb *fb) +static struct mtk_video_fmt mtk_video_formats[5]; +static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; + +static struct mtk_video_fmt default_out_format; +static struct mtk_video_fmt default_cap_format; +static unsigned int num_formats; +static unsigned int num_framesizes; + +static struct v4l2_frmsize_stepwise stepwise_fhd = { + .min_width = MTK_VDEC_MIN_W, + .max_width = MTK_VDEC_MAX_W, + .step_width = 16, + .min_height = MTK_VDEC_MIN_H, + .max_height = MTK_VDEC_MAX_H, + .step_height = 16 +}; + +static void mtk_vdec_stateless_cap_to_disp(struct mtk_vcodec_ctx *ctx, int error, + struct media_request *src_buf_req) { - struct mtk_video_dec_buf *vdec_frame_buf = - container_of(fb, struct mtk_video_dec_buf, frame_buffer); - struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb; - unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + struct vb2_v4l2_buffer *vb2_dst; + enum vb2_buffer_state state; - vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - unsigned int cap_c_size = - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + if (error) + state = VB2_BUF_STATE_ERROR; + else + state = VB2_BUF_STATE_DONE; - vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size); - } + vb2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(vb2_dst, state); + + mtk_v4l2_debug(2, "free frame buffer id:%d to done list", + vb2_dst->vb2_buf.index); + + if (src_buf_req) + v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); } -static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx, - struct vb2_v4l2_buffer *vb2_v4l2) +static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx) { - struct mtk_video_dec_buf *framebuf = - container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); - struct vdec_fb *pfb = &framebuf->frame_buffer; - struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf; + struct mtk_video_dec_buf *framebuf; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vb2_buffer *dst_buf; + struct vdec_fb *pfb; + + vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!vb2_v4l2) { + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return NULL; + } + + dst_buf = &vb2_v4l2->vb2_buf; + framebuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); - pfb->base_y.va = NULL; + pfb = &framebuf->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0); pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - pfb->base_c.va = NULL; + pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1); pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; @@ -162,12 +195,12 @@ static void mtk_vdec_worker(struct work_struct *work) struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, decode_work); struct mtk_vcodec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst; + struct vb2_v4l2_buffer *vb2_v4l2_src; struct vb2_buffer *vb2_src; struct mtk_vcodec_mem *bs_src; struct mtk_video_dec_buf *dec_buf_src; struct media_request *src_buf_req; - struct vdec_fb *dst_buf; + enum vb2_buffer_state state; bool res_chg = false; int ret; @@ -178,13 +211,6 @@ static void mtk_vdec_worker(struct work_struct *work) return; } - vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (!vb2_v4l2_dst) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id); - return; - } - vb2_src = &vb2_v4l2_src->vb2_buf; dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf, m2m_buf.vb); @@ -193,9 +219,15 @@ static void mtk_vdec_worker(struct work_struct *work) mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb2_src->vb2_queue->type, vb2_src->index, vb2_src); - bs_src->va = NULL; + bs_src->va = vb2_plane_vaddr(vb2_src, 0); bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0); bs_src->size = (size_t)vb2_src->planes[0].bytesused; + if (!bs_src->va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d source buffer is NULL", ctx->id, + vb2_src->index); + return; + } mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src); @@ -206,9 +238,7 @@ static void mtk_vdec_worker(struct work_struct *work) else mtk_v4l2_err("vb2 buffer media request is NULL"); - dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst); - v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true); - ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg); + ret = vdec_if_decode(ctx, bs_src, NULL, &res_chg); if (ret) { mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>", ctx->id, vb2_src->index, bs_src->size, @@ -220,12 +250,17 @@ static void mtk_vdec_worker(struct work_struct *work) } } - mtk_vdec_stateless_set_dst_payload(ctx, dst_buf); - - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, - ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); + state = ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE; + if (!IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch) || + ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME || ret) { + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, state); + if (src_buf_req) + v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); + } else { + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(vb2_v4l2_src, state); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + } } static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb) @@ -307,6 +342,77 @@ const struct media_device_ops mtk_vcodec_media_ops = { .req_queue = v4l2_m2m_request_queue, }; +static void mtk_vcodec_add_formats(unsigned int fourcc, + struct mtk_vcodec_ctx *ctx) +{ + struct mtk_vcodec_dev *dev = ctx->dev; + const struct mtk_vcodec_dec_pdata *pdata = dev->vdec_pdata; + int count_formats = *pdata->num_formats; + int count_framesizes = *pdata->num_framesizes; + + switch (fourcc) { + case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_VP9_FRAME: + mtk_video_formats[count_formats].fourcc = fourcc; + mtk_video_formats[count_formats].type = MTK_FMT_DEC; + mtk_video_formats[count_formats].num_planes = 1; + + mtk_vdec_framesizes[count_framesizes].fourcc = fourcc; + mtk_vdec_framesizes[count_framesizes].stepwise = stepwise_fhd; + num_framesizes++; + break; + case V4L2_PIX_FMT_MM21: + case V4L2_PIX_FMT_MT21C: + mtk_video_formats[count_formats].fourcc = fourcc; + mtk_video_formats[count_formats].type = MTK_FMT_FRAME; + mtk_video_formats[count_formats].num_planes = 2; + break; + default: + mtk_v4l2_err("Can not add unsupported format type"); + return; + } + + num_formats++; + mtk_v4l2_debug(3, "num_formats: %d num_frames:%d dec_capability: 0x%x", + count_formats, count_framesizes, ctx->dev->dec_capability); +} + +static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) +{ + int cap_format_count = 0, out_format_count = 0; + + if (num_formats && num_framesizes) + return; + + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_MM21, ctx); + cap_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MT21C) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_MT21C, ctx); + cap_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_H264_SLICE) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_H264_SLICE, ctx); + out_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP8_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP8_FRAME, ctx); + out_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP9_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP9_FRAME, ctx); + out_format_count++; + } + + if (cap_format_count) + default_cap_format = mtk_video_formats[cap_format_count - 1]; + if (out_format_count) + default_out_format = + mtk_video_formats[cap_format_count + out_format_count - 1]; +} + static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) { struct vb2_queue *src_vq; @@ -314,6 +420,11 @@ static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!ctx->dev->vdec_pdata->is_subdev_supported) + ctx->dev->dec_capability |= + MTK_VDEC_FORMAT_H264_SLICE | MTK_VDEC_FORMAT_MM21; + mtk_vcodec_get_supported_formats(ctx); + /* Support request api for output plane */ src_vq->supports_requests = true; src_vq->requires_requests = true; @@ -343,38 +454,59 @@ static struct vb2_ops mtk_vdec_request_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { - .chip = MTK_MT8183, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, - .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], - .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = false, .hw_arch = MTK_VDEC_PURE_SINGLE_CORE, }; /* This platform data is used for one lat and one core architecture. */ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = { - .chip = MTK_MT8192, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, - .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], - .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = true, .hw_arch = MTK_VDEC_LAT_SINGLE_CORE, }; + +const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = { + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = &num_framesizes, + .uses_stateless_api = true, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, + .is_subdev_supported = true, + .hw_arch = MTK_VDEC_PURE_SINGLE_CORE, +}; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index 813901c4be5e..a29041a0b7e0 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -274,6 +274,7 @@ struct vdec_pic_info { * to be used with encoder and stateful decoder. * @is_flushing: set to true if flushing is in progress. * @current_codec: current set input codec, in V4L2 pixel format + * @capture_fourcc: capture queue type in V4L2 pixel format * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -284,6 +285,8 @@ struct vdec_pic_info { * mtk_video_dec_buf. * @hw_id: hardware index used to identify different hardware. * + * @max_width: hardware supported max width + * @max_height: hardware supported max height * @msg_queue: msg queue used to store lat buffer information. */ struct mtk_vcodec_ctx { @@ -319,6 +322,7 @@ struct mtk_vcodec_ctx { bool is_flushing; u32 current_codec; + u32 capture_fourcc; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; @@ -329,16 +333,11 @@ struct mtk_vcodec_ctx { struct mutex lock; int hw_id; + unsigned int max_width; + unsigned int max_height; struct vdec_msg_queue msg_queue; }; -enum mtk_chip { - MTK_MT8173, - MTK_MT8183, - MTK_MT8192, - MTK_MT8195, -}; - /* * enum mtk_vdec_hw_arch - Used to separate different hardware architecture */ @@ -347,13 +346,26 @@ enum mtk_vdec_hw_arch { MTK_VDEC_LAT_SINGLE_CORE, }; +/* + * struct mtk_vdec_format_types - Structure used to get supported + * format types according to decoder capability + */ +enum mtk_vdec_format_types { + MTK_VDEC_FORMAT_MM21 = 0x20, + MTK_VDEC_FORMAT_MT21C = 0x40, + MTK_VDEC_FORMAT_H264_SLICE = 0x100, + MTK_VDEC_FORMAT_VP8_FRAME = 0x200, + MTK_VDEC_FORMAT_VP9_FRAME = 0x400, +}; + /** * struct mtk_vcodec_dec_pdata - compatible data for each IC * @init_vdec_params: init vdec params * @ctrls_setup: init vcodec dec ctrls * @worker: worker to start a decode job * @flush_decoder: function that flushes the decoder - * + * @get_cap_buffer: get capture buffer from capture queue + * @cap_to_disp: put capture buffer to disp list for lat and core arch * @vdec_vb2_ops: struct vb2_ops * * @vdec_formats: supported video decoder formats @@ -364,7 +376,6 @@ enum mtk_vdec_hw_arch { * @vdec_framesizes: supported video decoder frame sizes * @num_framesizes: count of video decoder frame sizes * - * @chip: chip this decoder is compatible with * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core * * @is_subdev_supported: whether support parent-node architecture(subdev) @@ -376,18 +387,20 @@ struct mtk_vcodec_dec_pdata { int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx); void (*worker)(struct work_struct *work); int (*flush_decoder)(struct mtk_vcodec_ctx *ctx); + struct vdec_fb *(*get_cap_buffer)(struct mtk_vcodec_ctx *ctx); + void (*cap_to_disp)(struct mtk_vcodec_ctx *ctx, int error, + struct media_request *src_buf_req); struct vb2_ops *vdec_vb2_ops; const struct mtk_video_fmt *vdec_formats; - const int num_formats; + const int *num_formats; const struct mtk_video_fmt *default_out_fmt; const struct mtk_video_fmt *default_cap_fmt; const struct mtk_codec_framesizes *vdec_framesizes; - const int num_framesizes; + const int *num_framesizes; - enum mtk_chip chip; enum mtk_vdec_hw_arch hw_arch; bool is_subdev_supported; @@ -397,8 +410,6 @@ struct mtk_vcodec_dec_pdata { /** * struct mtk_vcodec_enc_pdata - compatible data for each IC * - * @chip: chip this encoder is compatible with - * * @uses_ext: whether the encoder uses the extended firmware messaging format * @min_bitrate: minimum supported encoding bitrate * @max_bitrate: maximum supported encoding bitrate @@ -409,8 +420,6 @@ struct mtk_vcodec_dec_pdata { * @core_id: stand for h264 or vp8 encode index */ struct mtk_vcodec_enc_pdata { - enum mtk_chip chip; - bool uses_ext; unsigned long min_bitrate; unsigned long max_bitrate; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c index 5172cfe0db4a..95e8c29ccc65 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c @@ -376,7 +376,6 @@ err_enc_pm: } static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { - .chip = MTK_MT8173, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), .output_formats = mtk_video_formats_output, @@ -387,7 +386,6 @@ static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { - .chip = MTK_MT8173, .capture_formats = mtk_video_formats_capture_vp8, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8), .output_formats = mtk_video_formats_output, @@ -398,7 +396,6 @@ static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8183_pdata = { - .chip = MTK_MT8183, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), @@ -410,7 +407,6 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8192_pdata = { - .chip = MTK_MT8192, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), @@ -422,7 +418,6 @@ static const struct mtk_vcodec_enc_pdata mt8192_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8195_pdata = { - .chip = MTK_MT8195, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c index 94b39ae5c2e1..556e54aadac9 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c @@ -65,3 +65,9 @@ int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, return fw->ops->ipi_send(fw, id, buf, len, wait); } EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send); + +int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw) +{ + return fw->type; +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_type); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h index 15ab6b8e3ae2..16824114657f 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h @@ -39,5 +39,6 @@ int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id, const char *name, void *priv); int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, unsigned int len, unsigned int wait); +int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw); #endif /* _MTK_VCODEC_FW_H_ */ diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c new file mode 100644 index 000000000000..ca628321d272 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include "vdec_h264_req_common.h" + +/* get used parameters for sps/pps */ +#define GET_MTK_VDEC_FLAG(cond, flag) \ + { dst_param->cond = ((src_param->flags & flag) ? (1) : (0)); } +#define GET_MTK_VDEC_PARAM(param) \ + { dst_param->param = src_param->param; } + +void mtk_vdec_h264_get_ref_list(u8 *ref_list, + const struct v4l2_h264_reference *v4l2_ref_list, + int num_valid) +{ + u32 i; + + /* + * TODO The firmware does not support field decoding. Future + * implementation must use v4l2_ref_list[i].fields to obtain + * the reference field parity. + */ + + for (i = 0; i < num_valid; i++) + ref_list[i] = v4l2_ref_list[i].index; + + /* + * The firmware expects unused reflist entries to have the value 0x20. + */ + memset(&ref_list[num_valid], 0x20, 32 - num_valid); +} + +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + if (!ctrl) + return ERR_PTR(-EINVAL); + + return ctrl->p_cur.p; +} + +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info) +{ + const struct slice_h264_dpb_entry *dpb; + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb2_v4l2; + int index, vb2_index; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + for (index = 0; index < V4L2_H264_NUM_DPB_ENTRIES; index++) { + dpb = &decode_params->dpb[index]; + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { + h264_dpb_info[index].reference_flag = 0; + continue; + } + + vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); + if (vb2_index < 0) { + dev_err(&ctx->dev->plat_dev->dev, + "Reference invalid: dpb_index(%d) reference_ts(%lld)", + index, dpb->reference_ts); + continue; + } + + /* 1 for short term reference, 2 for long term reference */ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + h264_dpb_info[index].reference_flag = 1; + else + h264_dpb_info[index].reference_flag = 2; + + vb = vq->bufs[vb2_index]; + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + h264_dpb_info[index].field = vb2_v4l2->field; + + h264_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + h264_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + else + h264_dpb_info[index].c_dma_addr = + h264_dpb_info[index].y_dma_addr + + ctx->picinfo.fb_sz[0]; + } +} + +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param) +{ + GET_MTK_VDEC_PARAM(chroma_format_idc); + GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); + GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); + GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); + GET_MTK_VDEC_PARAM(pic_order_cnt_type); + GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); + GET_MTK_VDEC_PARAM(max_num_ref_frames); + GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); + GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); + + GET_MTK_VDEC_FLAG(separate_colour_plane_flag, + V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); + GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, + V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); + GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, + V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); + GET_MTK_VDEC_FLAG(frame_mbs_only_flag, + V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); + GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, + V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, + V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); +} + +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param) +{ + GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); + GET_MTK_VDEC_PARAM(weighted_bipred_idc); + GET_MTK_VDEC_PARAM(pic_init_qp_minus26); + GET_MTK_VDEC_PARAM(chroma_qp_index_offset); + GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); + + GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, + V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); + GET_MTK_VDEC_FLAG(pic_order_present_flag, + V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); + GET_MTK_VDEC_FLAG(weighted_pred_flag, + V4L2_H264_PPS_FLAG_WEIGHTED_PRED); + GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, + V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); + GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, + V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); + GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, + V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); + GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, + V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); + GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, + V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); +} + +void mtk_vdec_h264_copy_slice_hd_params(struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param) +{ + int temp; + + GET_MTK_VDEC_PARAM(first_mb_in_slice); + GET_MTK_VDEC_PARAM(slice_type); + GET_MTK_VDEC_PARAM(cabac_init_idc); + GET_MTK_VDEC_PARAM(slice_qp_delta); + GET_MTK_VDEC_PARAM(disable_deblocking_filter_idc); + GET_MTK_VDEC_PARAM(slice_alpha_c0_offset_div2); + GET_MTK_VDEC_PARAM(slice_beta_offset_div2); + GET_MTK_VDEC_PARAM(num_ref_idx_l0_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_active_minus1); + + dst_param->frame_num = dec_param->frame_num; + dst_param->pic_order_cnt_lsb = dec_param->pic_order_cnt_lsb; + + dst_param->delta_pic_order_cnt_bottom = + dec_param->delta_pic_order_cnt_bottom; + dst_param->delta_pic_order_cnt0 = + dec_param->delta_pic_order_cnt0; + dst_param->delta_pic_order_cnt1 = + dec_param->delta_pic_order_cnt1; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; + dst_param->field_pic_flag = temp ? 1 : 0; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD; + dst_param->bottom_field_flag = temp ? 1 : 0; + + GET_MTK_VDEC_FLAG(direct_spatial_mv_pred_flag, + V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED); +} + +void mtk_vdec_h264_copy_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +{ + memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, + sizeof(dst_matrix->scaling_list_4x4)); + + memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, + sizeof(dst_matrix->scaling_list_8x8)); +} + +void +mtk_vdec_h264_copy_decode_params(struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) +{ + struct slice_h264_dpb_entry *dst_entry; + const struct v4l2_h264_dpb_entry *src_entry; + int i; + + for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { + dst_entry = &dst_params->dpb[i]; + src_entry = &dpb[i]; + + dst_entry->reference_ts = src_entry->reference_ts; + dst_entry->frame_num = src_entry->frame_num; + dst_entry->pic_num = src_entry->pic_num; + dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; + dst_entry->bottom_field_order_cnt = + src_entry->bottom_field_order_cnt; + dst_entry->flags = src_entry->flags; + } + + /* num_slices is a leftover from the old H.264 support and is ignored + * by the firmware. + */ + dst_params->num_slices = 0; + dst_params->nal_ref_idc = src_params->nal_ref_idc; + dst_params->top_field_order_cnt = src_params->top_field_order_cnt; + dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; + dst_params->flags = src_params->flags; +} + +static bool mtk_vdec_h264_dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +/* + * Move DPB entries of dec_param that refer to a frame already existing in dpb + * into the already existing slot in dpb, and move other entries into new slots. + * + * This function is an adaptation of the similarly-named function in + * hantro_h264.c. + */ +void mtk_vdec_h264_update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb) +{ + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + /* Disable all entries by default, and mark the ones in use. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + set_bit(i, in_use); + dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + } + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries were already used. + */ + for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &dpb[j]; + if (!mtk_vdec_h264_dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + /* Don't reiterate on this one. */ + clear_bit(j, in_use); + break; + } + + if (j == ARRAY_SIZE(dec_param->dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); + if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) + return; + + cdpb = &dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +unsigned int mtk_vdec_h264_get_mv_buf_size(unsigned int width, unsigned int height) +{ + int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; + + return HW_MB_STORE_SZ * unit_size; +} + +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz) +{ + if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) + return 3; + + if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && + data[3] == 1) + return 4; + + return -1; +} diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h new file mode 100644 index 000000000000..53d0a7c962a9 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h @@ -0,0 +1,277 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#ifndef _VDEC_H264_REQ_COMMON_H_ +#define _VDEC_H264_REQ_COMMON_H_ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/v4l2-h264.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include "../mtk_vcodec_drv.h" + +#define NAL_NON_IDR_SLICE 0x01 +#define NAL_IDR_SLICE 0x05 +#define NAL_TYPE(value) ((value) & 0x1F) + +#define BUF_PREDICTION_SZ (64 * 4096) +#define MB_UNIT_LEN 16 + +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_MV_NUM 32 + +/** + * struct mtk_h264_dpb_info - h264 dpb information + * + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag (short/long term reference picture) + * @field: field picture flag + */ +struct mtk_h264_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int field; +}; + +/* + * struct mtk_h264_sps_param - parameters for sps + */ +struct mtk_h264_sps_param { + unsigned char chroma_format_idc; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char log2_max_frame_num_minus4; + unsigned char pic_order_cnt_type; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char max_num_ref_frames; + unsigned char separate_colour_plane_flag; + unsigned short pic_width_in_mbs_minus1; + unsigned short pic_height_in_map_units_minus1; + unsigned int max_frame_nums; + unsigned char qpprime_y_zero_transform_bypass_flag; + unsigned char delta_pic_order_always_zero_flag; + unsigned char frame_mbs_only_flag; + unsigned char mb_adaptive_frame_field_flag; + unsigned char direct_8x8_inference_flag; + unsigned char reserved[3]; +}; + +/* + * struct mtk_h264_pps_param - parameters for pps + */ +struct mtk_h264_pps_param { + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char weighted_bipred_idc; + char pic_init_qp_minus26; + char chroma_qp_index_offset; + char second_chroma_qp_index_offset; + unsigned char entropy_coding_mode_flag; + unsigned char pic_order_present_flag; + unsigned char deblocking_filter_control_present_flag; + unsigned char constrained_intra_pred_flag; + unsigned char weighted_pred_flag; + unsigned char redundant_pic_cnt_present_flag; + unsigned char transform_8x8_mode_flag; + unsigned char scaling_matrix_present_flag; + unsigned char reserved[2]; +}; + +/* + * struct mtk_h264_slice_hd_param - parameters for slice header + */ +struct mtk_h264_slice_hd_param { + unsigned int first_mb_in_slice; + unsigned int field_pic_flag; + unsigned int slice_type; + unsigned int frame_num; + int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + unsigned int bottom_field_flag; + unsigned int direct_spatial_mv_pred_flag; + int delta_pic_order_cnt0; + int delta_pic_order_cnt1; + unsigned int cabac_init_idc; + int slice_qp_delta; + unsigned int disable_deblocking_filter_idc; + int slice_alpha_c0_offset_div2; + int slice_beta_offset_div2; + unsigned int num_ref_idx_l0_active_minus1; + unsigned int num_ref_idx_l1_active_minus1; + unsigned int reserved; +}; + +/* + * struct slice_api_h264_scaling_matrix - parameters for scaling list + */ +struct slice_api_h264_scaling_matrix { + unsigned char scaling_list_4x4[6][16]; + unsigned char scaling_list_8x8[6][64]; +}; + +/* + * struct slice_h264_dpb_entry - each dpb information + */ +struct slice_h264_dpb_entry { + unsigned long long reference_ts; + unsigned short frame_num; + unsigned short pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; +}; + +/* + * struct slice_api_h264_decode_param - parameters for decode. + */ +struct slice_api_h264_decode_param { + struct slice_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + unsigned short num_slices; + unsigned short nal_ref_idc; + unsigned char ref_pic_list_p0[32]; + unsigned char ref_pic_list_b0[32]; + unsigned char ref_pic_list_b1[32]; + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; +}; + +/** + * struct h264_fb - h264 decode frame buffer information + * + * @vdec_fb_va: virtual address of struct vdec_fb + * @y_fb_dma: dma address of Y frame buffer (luma) + * @c_fb_dma: dma address of C frame buffer (chroma) + * @poc: picture order count of frame buffer + * @reserved: for 8 bytes alignment + */ +struct h264_fb { + u64 vdec_fb_va; + u64 y_fb_dma; + u64 c_fb_dma; + s32 poc; + u32 reserved; +}; + +/** + * mtk_vdec_h264_get_ref_list - translate V4L2 reference list + * + * @ref_list: Mediatek reference picture list + * @v4l2_ref_list: V4L2 reference picture list + * @num_valid: used reference number + */ +void mtk_vdec_h264_get_ref_list(u8 *ref_list, + const struct v4l2_h264_reference *v4l2_ref_list, + int num_valid); + +/** + * mtk_vdec_h264_get_ctrl_ptr - get each CID contrl address. + * + * @ctx: v4l2 ctx + * @id: CID control ID + * + * Return: returns CID ctrl address. + */ +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id); + +/** + * mtk_vdec_h264_fill_dpb_info - get each CID contrl address. + * + * @ctx: v4l2 ctx + * @decode_params: slice decode params + * @h264_dpb_info: dpb buffer information + */ +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info); + +/** + * mtk_vdec_h264_copy_sps_params - get sps params. + * + * @dst_param: sps params for hw decoder + * @src_param: sps params from user driver + */ +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param); + +/** + * mtk_vdec_h264_copy_pps_params - get pps params. + * + * @dst_param: pps params for hw decoder + * @src_param: pps params from user driver + */ +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param); + +/** + * mtk_vdec_h264_copy_slice_hd_params - get slice header params. + * + * @dst_param: slice params for hw decoder + * @src_param: slice params from user driver + * @dec_param: decode params from user driver + */ +void mtk_vdec_h264_copy_slice_hd_params(struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param); + +/** + * mtk_vdec_h264_copy_scaling_matrix - get each CID contrl address. + * + * @dst_matrix: scaling list params for hw decoder + * @src_matrix: scaling list params from user driver + */ +void mtk_vdec_h264_copy_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix); + +/** + * mtk_vdec_h264_copy_decode_params - get decode params. + * + * @dst_params: dst params for hw decoder + * @src_params: decode params from user driver + * @dpb: dpb information + */ +void +mtk_vdec_h264_copy_decode_params(struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + +/** + * mtk_vdec_h264_update_dpb - updata dpb list. + * + * @dec_param: v4l2 control decode params + * @dpb: dpb entry informaton + */ +void mtk_vdec_h264_update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb); + +/** + * mtk_vdec_h264_find_start_code - find h264 start code using sofeware. + * + * @data: input buffer address + * @data_sz: input buffer size + * + * Return: returns start code position. + */ +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz); + +/** + * mtk_vdec_h264_get_mv_buf_size - get mv buffer size. + * + * @width: picture width + * @height: picture height + * + * Return: returns mv buffer size. + */ +unsigned int mtk_vdec_h264_get_mv_buf_size(unsigned int width, unsigned int height); + +#endif diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c index 43542de11e9c..4bc05ab5afea 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c @@ -12,109 +12,7 @@ #include "../vdec_drv_base.h" #include "../vdec_drv_if.h" #include "../vdec_vpu_if.h" - -#define BUF_PREDICTION_SZ (64 * 4096) -#define MB_UNIT_LEN 16 - -/* get used parameters for sps/pps */ -#define GET_MTK_VDEC_FLAG(cond, flag) \ - { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); } -#define GET_MTK_VDEC_PARAM(param) \ - { dst_param->param = src_param->param; } -/* motion vector size (bytes) for every macro block */ -#define HW_MB_STORE_SZ 64 - -#define H264_MAX_FB_NUM 17 -#define H264_MAX_MV_NUM 32 -#define HDR_PARSING_BUF_SZ 1024 - -/** - * struct mtk_h264_dpb_info - h264 dpb information - * @y_dma_addr: Y bitstream physical address - * @c_dma_addr: CbCr bitstream physical address - * @reference_flag: reference picture flag (short/long term reference picture) - * @field: field picture flag - */ -struct mtk_h264_dpb_info { - dma_addr_t y_dma_addr; - dma_addr_t c_dma_addr; - int reference_flag; - int field; -}; - -/* - * struct mtk_h264_sps_param - parameters for sps - */ -struct mtk_h264_sps_param { - unsigned char chroma_format_idc; - unsigned char bit_depth_luma_minus8; - unsigned char bit_depth_chroma_minus8; - unsigned char log2_max_frame_num_minus4; - unsigned char pic_order_cnt_type; - unsigned char log2_max_pic_order_cnt_lsb_minus4; - unsigned char max_num_ref_frames; - unsigned char separate_colour_plane_flag; - unsigned short pic_width_in_mbs_minus1; - unsigned short pic_height_in_map_units_minus1; - unsigned int max_frame_nums; - unsigned char qpprime_y_zero_transform_bypass_flag; - unsigned char delta_pic_order_always_zero_flag; - unsigned char frame_mbs_only_flag; - unsigned char mb_adaptive_frame_field_flag; - unsigned char direct_8x8_inference_flag; - unsigned char reserved[3]; -}; - -/* - * struct mtk_h264_pps_param - parameters for pps - */ -struct mtk_h264_pps_param { - unsigned char num_ref_idx_l0_default_active_minus1; - unsigned char num_ref_idx_l1_default_active_minus1; - unsigned char weighted_bipred_idc; - char pic_init_qp_minus26; - char chroma_qp_index_offset; - char second_chroma_qp_index_offset; - unsigned char entropy_coding_mode_flag; - unsigned char pic_order_present_flag; - unsigned char deblocking_filter_control_present_flag; - unsigned char constrained_intra_pred_flag; - unsigned char weighted_pred_flag; - unsigned char redundant_pic_cnt_present_flag; - unsigned char transform_8x8_mode_flag; - unsigned char scaling_matrix_present_flag; - unsigned char reserved[2]; -}; - -struct slice_api_h264_scaling_matrix { - unsigned char scaling_list_4x4[6][16]; - unsigned char scaling_list_8x8[6][64]; -}; - -struct slice_h264_dpb_entry { - unsigned long long reference_ts; - unsigned short frame_num; - unsigned short pic_num; - /* Note that field is indicated by v4l2_buffer.field */ - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ -}; - -/* - * struct slice_api_h264_decode_param - parameters for decode. - */ -struct slice_api_h264_decode_param { - struct slice_h264_dpb_entry dpb[16]; - unsigned short num_slices; - unsigned short nal_ref_idc; - unsigned char ref_pic_list_p0[32]; - unsigned char ref_pic_list_b0[32]; - unsigned char ref_pic_list_b1[32]; - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ -}; +#include "vdec_h264_req_common.h" /* * struct mtk_h264_dec_slice_param - parameters for decode current frame @@ -128,22 +26,6 @@ struct mtk_h264_dec_slice_param { }; /** - * struct h264_fb - h264 decode frame buffer information - * @vdec_fb_va : virtual address of struct vdec_fb - * @y_fb_dma : dma address of Y frame buffer (luma) - * @c_fb_dma : dma address of C frame buffer (chroma) - * @poc : picture order count of frame buffer - * @reserved : for 8 bytes alignment - */ -struct h264_fb { - u64 vdec_fb_va; - u64 y_fb_dma; - u64 c_fb_dma; - s32 poc; - u32 reserved; -}; - -/** * struct vdec_h264_dec_info - decode information * @dpb_sz : decoding picture buffer size * @resolution_changed : resoltion change happen @@ -212,285 +94,65 @@ struct vdec_h264_slice_inst { struct v4l2_h264_dpb_entry dpb[16]; }; -static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); - - return ctrl->p_cur.p; -} - -static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst, - struct mtk_h264_dec_slice_param *slice_param) -{ - struct vb2_queue *vq; - struct vb2_buffer *vb; - struct vb2_v4l2_buffer *vb2_v4l2; - u64 index; - - vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - - for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) { - const struct slice_h264_dpb_entry *dpb; - int vb2_index; - - dpb = &slice_param->decode_params.dpb[index]; - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { - slice_param->h264_dpb_info[index].reference_flag = 0; - continue; - } - - vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); - if (vb2_index < 0) { - mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)", - index, dpb->reference_ts); - continue; - } - /* 1 for short term reference, 2 for long term reference */ - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) - slice_param->h264_dpb_info[index].reference_flag = 1; - else - slice_param->h264_dpb_info[index].reference_flag = 2; - - vb = vq->bufs[vb2_index]; - vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); - slice_param->h264_dpb_info[index].field = vb2_v4l2->field; - - slice_param->h264_dpb_info[index].y_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 0); - if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - slice_param->h264_dpb_info[index].c_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 1); - } - } -} - -static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param, - const struct v4l2_ctrl_h264_sps *src_param) -{ - GET_MTK_VDEC_PARAM(chroma_format_idc); - GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); - GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); - GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); - GET_MTK_VDEC_PARAM(pic_order_cnt_type); - GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); - GET_MTK_VDEC_PARAM(max_num_ref_frames); - GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); - GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); - - GET_MTK_VDEC_FLAG(separate_colour_plane_flag, - V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); - GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, - V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); - GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, - V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); - GET_MTK_VDEC_FLAG(frame_mbs_only_flag, - V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); - GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, - V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); - GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, - V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); -} - -static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param, - const struct v4l2_ctrl_h264_pps *src_param) -{ - GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); - GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); - GET_MTK_VDEC_PARAM(weighted_bipred_idc); - GET_MTK_VDEC_PARAM(pic_init_qp_minus26); - GET_MTK_VDEC_PARAM(chroma_qp_index_offset); - GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); - - GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, - V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); - GET_MTK_VDEC_FLAG(pic_order_present_flag, - V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); - GET_MTK_VDEC_FLAG(weighted_pred_flag, - V4L2_H264_PPS_FLAG_WEIGHTED_PRED); - GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, - V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); - GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, - V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); - GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, - V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); - GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, - V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); - GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, - V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); -} - -static void -get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, - const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +static int get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) { - memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, - sizeof(dst_matrix->scaling_list_4x4)); - - memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, - sizeof(dst_matrix->scaling_list_8x8)); -} - -static void -get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params, - const struct v4l2_ctrl_h264_decode_params *src_params, - const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { - struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i]; - const struct v4l2_h264_dpb_entry *src_entry = &dpb[i]; - - dst_entry->reference_ts = src_entry->reference_ts; - dst_entry->frame_num = src_entry->frame_num; - dst_entry->pic_num = src_entry->pic_num; - dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; - dst_entry->bottom_field_order_cnt = - src_entry->bottom_field_order_cnt; - dst_entry->flags = src_entry->flags; - } - - /* - * num_slices is a leftover from the old H.264 support and is ignored - * by the firmware. - */ - dst_params->num_slices = 0; - dst_params->nal_ref_idc = src_params->nal_ref_idc; - dst_params->top_field_order_cnt = src_params->top_field_order_cnt; - dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; - dst_params->flags = src_params->flags; -} - -static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, - const struct v4l2_h264_dpb_entry *b) -{ - return a->top_field_order_cnt == b->top_field_order_cnt && - a->bottom_field_order_cnt == b->bottom_field_order_cnt; -} - -/* - * Move DPB entries of dec_param that refer to a frame already existing in dpb - * into the already existing slot in dpb, and move other entries into new slots. - * - * This function is an adaptation of the similarly-named function in - * hantro_h264.c. - */ -static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, - struct v4l2_h264_dpb_entry *dpb) -{ - DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - unsigned int i, j; - - /* Disable all entries by default, and mark the ones in use. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - set_bit(i, in_use); - dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; - } - - /* Try to match new DPB entries with existing ones by their POCs. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - - if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) - continue; - - /* - * To cut off some comparisons, iterate only on target DPB - * entries were already used. - */ - for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { - struct v4l2_h264_dpb_entry *cdpb; - - cdpb = &dpb[j]; - if (!dpb_entry_match(cdpb, ndpb)) - continue; - - *cdpb = *ndpb; - set_bit(j, used); - /* Don't reiterate on this one. */ - clear_bit(j, in_use); - break; - } - - if (j == ARRAY_SIZE(dec_param->dpb)) - set_bit(i, new); - } - - /* For entries that could not be matched, use remaining free slots. */ - for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - struct v4l2_h264_dpb_entry *cdpb; - - /* - * Both arrays are of the same sizes, so there is no way - * we can end up with no space in target array, unless - * something is buggy. - */ - j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); - if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) - return; - - cdpb = &dpb[j]; - *cdpb = *ndpb; - set_bit(j, used); - } -} - -/* - * The firmware expects unused reflist entries to have the value 0x20. - */ -static void fixup_ref_list(u8 *ref_list, size_t num_valid) -{ - memset(&ref_list[num_valid], 0x20, 32 - num_valid); -} - -static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) -{ - const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); - const struct v4l2_ctrl_h264_sps *sps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); - const struct v4l2_ctrl_h264_pps *pps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); - const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param; struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; - update_dpb(dec_params, inst->dpb); + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); - get_h264_sps_parameters(&slice_param->sps, sps); - get_h264_pps_parameters(&slice_param->pps, pps); - get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); - get_h264_decode_parameters(&slice_param->decode_params, dec_params, - inst->dpb); - get_h264_dpb_list(inst, slice_param); + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + scaling_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(scaling_matrix)) + return PTR_ERR(scaling_matrix); + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, + dec_params, inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); /* Build the reference lists */ v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, inst->dpb); - v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist); - v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, + v4l2_b1_reflist); + /* Adapt the built lists to the firmware's expectations */ - fixup_ref_list(p0_reflist, reflist_builder.num_valid); - fixup_ref_list(b0_reflist, reflist_builder.num_valid); - fixup_ref_list(b1_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, sizeof(inst->vsi_ctx.h264_slice_params)); -} - -static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) -{ - int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; - return HW_MB_STORE_SZ * unit_size; + return 0; } static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) @@ -525,7 +187,7 @@ static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, int i; int err; struct mtk_vcodec_mem *mem = NULL; - unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + unsigned int buf_sz = mtk_vdec_h264_get_mv_buf_size(pic->buf_w, pic->buf_h); mtk_v4l2_debug(3, "size = 0x%x", buf_sz); for (i = 0; i < H264_MAX_MV_NUM; i++) { @@ -670,33 +332,46 @@ static void vdec_h264_slice_deinit(void *h_vdec) } static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, - struct vdec_fb *fb, bool *res_chg) + struct vdec_fb *unused, bool *res_chg) { struct vdec_h264_slice_inst *inst = h_vdec; const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + struct mtk_video_dec_buf *dst_buf_info; + struct vdec_fb *fb; u32 data[2]; u64 y_fb_dma; u64 c_fb_dma; int err; + inst->num_nalu++; /* bs NULL means flush decoder */ if (!bs) return vpu_dec_reset(vpu); + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", - ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + inst->num_nalu, y_fb_dma, c_fb_dma, fb); inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr; inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; - get_vdec_decode_parameters(inst); + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + err = get_vdec_decode_parameters(inst); + if (err) + goto err_free_fb_out; + data[0] = bs->size; /* * Reconstruct the first byte of the NAL unit, as the firmware requests diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c new file mode 100644 index 000000000000..784d01f8bd50 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c @@ -0,0 +1,808 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/v4l2-h264.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" +#include "vdec_h264_req_common.h" + +/** + * enum vdec_h264_core_dec_err_type - core decode error type + * + * @TRANS_BUFFER_FULL: trans buffer is full + * @SLICE_HEADER_FULL: slice header buffer is full + */ +enum vdec_h264_core_dec_err_type { + TRANS_BUFFER_FULL = 1, + SLICE_HEADER_FULL, +}; + +/** + * struct vdec_h264_slice_lat_dec_param - parameters for decode current frame + * + * @sps: h264 sps syntax parameters + * @pps: h264 pps syntax parameters + * @slice_header: h264 slice header syntax parameters + * @scaling_matrix: h264 scaling list parameters + * @decode_params: decoder parameters of each frame used for hardware decode + * @h264_dpb_info: dpb reference list + */ +struct vdec_h264_slice_lat_dec_param { + struct mtk_h264_sps_param sps; + struct mtk_h264_pps_param pps; + struct mtk_h264_slice_hd_param slice_header; + struct slice_api_h264_scaling_matrix scaling_matrix; + struct slice_api_h264_decode_param decode_params; + struct mtk_h264_dpb_info h264_dpb_info[V4L2_H264_NUM_DPB_ENTRIES]; +}; + +/** + * struct vdec_h264_slice_info - decode information + * + * @nal_info: nal info of current picture + * @timeout: Decode timeout: 1 timeout, 0 no timeount + * @bs_buf_size: bitstream size + * @bs_buf_addr: bitstream buffer dma address + * @y_fb_dma: Y frame buffer dma address + * @c_fb_dma: C frame buffer dma address + * @vdec_fb_va: VDEC frame buffer struct virtual address + * @crc: Used to check whether hardware's status is right + */ +struct vdec_h264_slice_info { + u16 nal_info; + u16 timeout; + u32 bs_buf_size; + u64 bs_buf_addr; + u64 y_fb_dma; + u64 c_fb_dma; + u64 vdec_fb_va; + u32 crc[8]; +}; + +/** + * struct vdec_h264_slice_vsi - shared memory for decode information exchange + * between SCP and Host. + * + * @wdma_err_addr: wdma error dma address + * @wdma_start_addr: wdma start dma address + * @wdma_end_addr: wdma end dma address + * @slice_bc_start_addr: slice bc start dma address + * @slice_bc_end_addr: slice bc end dma address + * @row_info_start_addr: row info start dma address + * @row_info_end_addr: row info end dma address + * @trans_start: trans start dma address + * @trans_end: trans end dma address + * @wdma_end_addr_offset: wdma end address offset + * + * @mv_buf_dma: HW working motion vector buffer + * dma address (AP-W, VPU-R) + * @dec: decode information (AP-R, VPU-W) + * @h264_slice_params: decode parameters for hw used + */ +struct vdec_h264_slice_vsi { + /* LAT dec addr */ + u64 wdma_err_addr; + u64 wdma_start_addr; + u64 wdma_end_addr; + u64 slice_bc_start_addr; + u64 slice_bc_end_addr; + u64 row_info_start_addr; + u64 row_info_end_addr; + u64 trans_start; + u64 trans_end; + u64 wdma_end_addr_offset; + + u64 mv_buf_dma[H264_MAX_MV_NUM]; + struct vdec_h264_slice_info dec; + struct vdec_h264_slice_lat_dec_param h264_slice_params; +}; + +/** + * struct vdec_h264_slice_share_info - shared information used to exchange + * message between lat and core + * + * @sps: sequence header information from user space + * @dec_params: decoder params from user space + * @h264_slice_params: decoder params used for hardware + * @trans_start: trans start dma address + * @trans_end: trans end dma address + * @nal_info: nal info of current picture + */ +struct vdec_h264_slice_share_info { + struct v4l2_ctrl_h264_sps sps; + struct v4l2_ctrl_h264_decode_params dec_params; + struct vdec_h264_slice_lat_dec_param h264_slice_params; + u64 trans_start; + u64 trans_end; + u16 nal_info; +}; + +/** + * struct vdec_h264_slice_inst - h264 decoder instance + * + * @slice_dec_num: how many picture be decoded + * @ctx: point to mtk_vcodec_ctx + * @pred_buf: HW working predication buffer + * @mv_buf: HW working motion vector buffer + * @vpu: VPU instance + * @vsi: vsi used for lat + * @vsi_core: vsi used for core + * + * @vsi_ctx: Local VSI data for this decoding context + * @h264_slice_param: the parameters that hardware use to decode + * + * @resolution_changed:resolution changed + * @realloc_mv_buf: reallocate mv buffer + * @cap_num_planes: number of capture queue plane + * + * @dpb: decoded picture buffer used to store reference + * buffer information + *@is_field_bitstream: is field bitstream + */ +struct vdec_h264_slice_inst { + unsigned int slice_dec_num; + struct mtk_vcodec_ctx *ctx; + struct mtk_vcodec_mem pred_buf; + struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM]; + struct vdec_vpu_inst vpu; + struct vdec_h264_slice_vsi *vsi; + struct vdec_h264_slice_vsi *vsi_core; + + struct vdec_h264_slice_vsi vsi_ctx; + struct vdec_h264_slice_lat_dec_param h264_slice_param; + + unsigned int resolution_changed; + unsigned int realloc_mv_buf; + unsigned int cap_num_planes; + + struct v4l2_h264_dpb_entry dpb[16]; + bool is_field_bitstream; +}; + +static int vdec_h264_slice_fill_decode_parameters(struct vdec_h264_slice_inst *inst, + struct vdec_h264_slice_share_info *share_info) +{ + struct vdec_h264_slice_lat_dec_param *slice_param = &inst->vsi->h264_slice_params; + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + src_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(src_matrix)) + return PTR_ERR(src_matrix); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); + + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) { + mtk_vcodec_err(inst, "No support for H.264 field decoding."); + inst->is_field_bitstream = true; + return -EINVAL; + } + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, src_matrix); + + memcpy(&share_info->sps, sps, sizeof(*sps)); + memcpy(&share_info->dec_params, dec_params, sizeof(*dec_params)); + + return 0; +} + +static int get_vdec_sig_decode_parameters(struct vdec_h264_slice_inst *inst) +{ + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + struct vdec_h264_slice_lat_dec_param *slice_param = &inst->h264_slice_param; + struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; + u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; + u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; + u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; + + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); + + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + scaling_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(scaling_matrix)) + return PTR_ERR(scaling_matrix); + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); + + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, dec_params, inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); + + /* Build the reference lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, v4l2_b1_reflist); + + /* Adapt the built lists to the firmware's expectations */ + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); + + memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, + sizeof(inst->vsi_ctx.h264_slice_params)); + + return 0; +} + +static void vdec_h264_slice_fill_decode_reflist(struct vdec_h264_slice_inst *inst, + struct vdec_h264_slice_lat_dec_param *slice_param, + struct vdec_h264_slice_share_info *share_info) +{ + struct v4l2_ctrl_h264_decode_params *dec_params = &share_info->dec_params; + struct v4l2_ctrl_h264_sps *sps = &share_info->sps; + struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; + u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; + u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; + u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, dec_params, + inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); + + mtk_v4l2_debug(3, "cur poc = %d\n", dec_params->bottom_field_order_cnt); + /* Build the reference lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, + inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, v4l2_b1_reflist); + + /* Adapt the built lists to the firmware's expectations */ + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); +} + +static int vdec_h264_slice_alloc_mv_buf(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + unsigned int buf_sz = mtk_vdec_h264_get_mv_buf_size(pic->buf_w, pic->buf_h); + struct mtk_vcodec_mem *mem; + int i, err; + + mtk_v4l2_debug(3, "size = 0x%x", buf_sz); + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + mem->size = buf_sz; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "failed to allocate mv buf"); + return err; + } + } + + return 0; +} + +static void vdec_h264_slice_free_mv_buf(struct vdec_h264_slice_inst *inst) +{ + int i; + struct mtk_vcodec_mem *mem; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + } +} + +static void vdec_h264_slice_get_pic_info(struct vdec_h264_slice_inst *inst) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + u32 data[3]; + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&inst->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, VCODEC_DEC_ALIGNED_64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, VCODEC_DEC_ALIGNED_64); + ctx->picinfo.fb_sz[0] = inst->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = inst->vpu.fb_sz[1]; + inst->cap_num_planes = + ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0], + ctx->picinfo.fb_sz[1]); + + if (ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w || + ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h) { + inst->resolution_changed = true; + if (ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w || + ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h) + inst->realloc_mv_buf = true; + + mtk_v4l2_debug(1, "resChg: (%d %d) : old(%d, %d) -> new(%d, %d)", + inst->resolution_changed, + inst->realloc_mv_buf, + ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + } +} + +static void vdec_h264_slice_get_crop_info(struct vdec_h264_slice_inst *inst, + struct v4l2_rect *cr) +{ + cr->left = 0; + cr->top = 0; + cr->width = inst->ctx->picinfo.pic_w; + cr->height = inst->ctx->picinfo.pic_h; + + mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_h264_slice_inst *inst; + int err, vsi_size; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_LAT; + inst->vpu.core_id = SCP_IPI_VDEC_CORE; + inst->vpu.ctx = ctx; + inst->vpu.codec_type = ctx->current_codec; + inst->vpu.capture_type = ctx->capture_fourcc; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_h264 init err=%d", err); + goto error_free_inst; + } + + vsi_size = round_up(sizeof(struct vdec_h264_slice_vsi), VCODEC_DEC_ALIGNED_64); + inst->vsi = inst->vpu.vsi; + inst->vsi_core = + (struct vdec_h264_slice_vsi *)(((char *)inst->vpu.vsi) + vsi_size); + inst->resolution_changed = true; + inst->realloc_mv_buf = true; + + mtk_vcodec_debug(inst, "lat struct size = %d,%d,%d,%d vsi: %d\n", + (int)sizeof(struct mtk_h264_sps_param), + (int)sizeof(struct mtk_h264_pps_param), + (int)sizeof(struct vdec_h264_slice_lat_dec_param), + (int)sizeof(struct mtk_h264_dpb_info), + vsi_size); + mtk_vcodec_debug(inst, "lat H264 instance >> %p, codec_type = 0x%x", + inst, inst->vpu.codec_type); + + ctx->drv_handle = inst; + return 0; + +error_free_inst: + kfree(inst); + return err; +} + +static void vdec_h264_slice_deinit(void *h_vdec) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + vdec_h264_slice_free_mv_buf(inst); + vdec_msg_queue_deinit(&inst->ctx->msg_queue, inst->ctx); + + kfree(inst); +} + +static int vdec_h264_slice_core_decode(struct vdec_lat_buf *lat_buf) +{ + struct vdec_fb *fb; + u64 vdec_fb_va; + u64 y_fb_dma, c_fb_dma; + int err, timeout, i; + struct mtk_vcodec_ctx *ctx = lat_buf->ctx; + struct vdec_h264_slice_inst *inst = ctx->drv_handle; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vdec_h264_slice_share_info *share_info = lat_buf->private_data; + struct mtk_vcodec_mem *mem; + struct vdec_vpu_inst *vpu = &inst->vpu; + + mtk_vcodec_debug(inst, "[h264-core] vdec_h264 core decode"); + memcpy(&inst->vsi_core->h264_slice_params, &share_info->h264_slice_params, + sizeof(share_info->h264_slice_params)); + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + vdec_fb_va = (unsigned long)fb; + + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) + c_fb_dma = + y_fb_dma + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h; + else + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + mtk_vcodec_debug(inst, "[h264-core] y/c addr = 0x%llx 0x%llx", y_fb_dma, + c_fb_dma); + + inst->vsi_core->dec.y_fb_dma = y_fb_dma; + inst->vsi_core->dec.c_fb_dma = c_fb_dma; + inst->vsi_core->dec.vdec_fb_va = vdec_fb_va; + inst->vsi_core->dec.nal_info = share_info->nal_info; + inst->vsi_core->wdma_start_addr = + lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + inst->vsi_core->wdma_end_addr = + lat_buf->ctx->msg_queue.wdma_addr.dma_addr + + lat_buf->ctx->msg_queue.wdma_addr.size; + inst->vsi_core->wdma_err_addr = lat_buf->wdma_err_addr.dma_addr; + inst->vsi_core->slice_bc_start_addr = lat_buf->slice_bc_addr.dma_addr; + inst->vsi_core->slice_bc_end_addr = lat_buf->slice_bc_addr.dma_addr + + lat_buf->slice_bc_addr.size; + inst->vsi_core->trans_start = share_info->trans_start; + inst->vsi_core->trans_end = share_info->trans_end; + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi_core->mv_buf_dma[i] = mem->dma_addr; + } + + vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2, true); + + vdec_h264_slice_fill_decode_reflist(inst, &inst->vsi_core->h264_slice_params, + share_info); + + err = vpu_dec_core(vpu); + if (err) { + mtk_vcodec_err(inst, "core decode err=%d", err); + goto vdec_dec_end; + } + + /* wait decoder done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + if (timeout) + mtk_vcodec_err(inst, "core decode timeout: pic_%d", + ctx->decoded_frame_cnt); + inst->vsi_core->dec.timeout = !!timeout; + + vpu_dec_core_end(vpu); + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ctx->decoded_frame_cnt, + inst->vsi_core->dec.crc[0], inst->vsi_core->dec.crc[1], + inst->vsi_core->dec.crc[2], inst->vsi_core->dec.crc[3], + inst->vsi_core->dec.crc[4], inst->vsi_core->dec.crc[5], + inst->vsi_core->dec.crc[6], inst->vsi_core->dec.crc[7]); + +vdec_dec_end: + vdec_msg_queue_update_ube_rptr(&lat_buf->ctx->msg_queue, share_info->trans_end); + ctx->dev->vdec_pdata->cap_to_disp(ctx, !!err, lat_buf->src_buf_req); + mtk_vcodec_debug(inst, "core decode done err=%d", err); + ctx->decoded_frame_cnt++; + return 0; +} + +static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + int nal_start_idx, err, timeout = 0, i; + unsigned int data[2]; + struct vdec_lat_buf *lat_buf; + struct vdec_h264_slice_share_info *share_info; + unsigned char *buf; + struct mtk_vcodec_mem *mem; + + if (vdec_msg_queue_init(&inst->ctx->msg_queue, inst->ctx, + vdec_h264_slice_core_decode, + sizeof(*share_info))) + return -ENOMEM; + + /* bs NULL means flush decoder */ + if (!bs) { + vdec_msg_queue_wait_lat_buf_full(&inst->ctx->msg_queue); + return vpu_dec_reset(vpu); + } + + if (inst->is_field_bitstream) + return -EINVAL; + + lat_buf = vdec_msg_queue_dqbuf(&inst->ctx->msg_queue.lat_ctx); + if (!lat_buf) { + mtk_vcodec_err(inst, "failed to get lat buffer"); + return -EINVAL; + } + share_info = lat_buf->private_data; + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + + buf = (unsigned char *)bs->va; + nal_start_idx = mtk_vdec_h264_find_start_code(buf, bs->size); + if (nal_start_idx < 0) { + err = -EINVAL; + goto err_free_fb_out; + } + + inst->vsi->dec.nal_info = buf[nal_start_idx]; + inst->vsi->dec.bs_buf_addr = (u64)bs->dma_addr; + inst->vsi->dec.bs_buf_size = bs->size; + + lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req; + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true); + + err = vdec_h264_slice_fill_decode_parameters(inst, share_info); + if (err) + goto err_free_fb_out; + + *res_chg = inst->resolution_changed; + if (inst->resolution_changed) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->realloc_mv_buf) { + err = vdec_h264_slice_alloc_mv_buf(inst, &inst->ctx->picinfo); + inst->realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + inst->resolution_changed = false; + } + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi->mv_buf_dma[i] = mem->dma_addr; + } + inst->vsi->wdma_start_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + inst->vsi->wdma_end_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr + + lat_buf->ctx->msg_queue.wdma_addr.size; + inst->vsi->wdma_err_addr = lat_buf->wdma_err_addr.dma_addr; + inst->vsi->slice_bc_start_addr = lat_buf->slice_bc_addr.dma_addr; + inst->vsi->slice_bc_end_addr = lat_buf->slice_bc_addr.dma_addr + + lat_buf->slice_bc_addr.size; + + inst->vsi->trans_end = inst->ctx->msg_queue.wdma_rptr_addr; + inst->vsi->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + mtk_vcodec_debug(inst, "lat:trans(0x%llx 0x%llx) err:0x%llx", + inst->vsi->wdma_start_addr, + inst->vsi->wdma_end_addr, + inst->vsi->wdma_err_addr); + + mtk_vcodec_debug(inst, "slice(0x%llx 0x%llx) rprt((0x%llx 0x%llx))", + inst->vsi->slice_bc_start_addr, + inst->vsi->slice_bc_end_addr, + inst->vsi->trans_start, + inst->vsi->trans_end); + err = vpu_dec_start(vpu, data, 2); + if (err) { + mtk_vcodec_debug(inst, "lat decode err: %d", err); + goto err_scp_decode; + } + + /* wait decoder done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); + inst->vsi->dec.timeout = !!timeout; + + err = vpu_dec_end(vpu); + if (err == SLICE_HEADER_FULL || timeout || err == TRANS_BUFFER_FULL) { + err = -EINVAL; + goto err_scp_decode; + } + + share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + + inst->vsi->wdma_end_addr_offset; + share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + share_info->nal_info = inst->vsi->dec.nal_info; + vdec_msg_queue_update_ube_wptr(&lat_buf->ctx->msg_queue, share_info->trans_end); + + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + + inst->slice_dec_num++; + return 0; + +err_scp_decode: +err_free_fb_out: + vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); + mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err); + return err; +} + +static int vdec_h264_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *unused, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info, *dst_buf_info; + struct vdec_fb *fb; + unsigned char *buf; + unsigned int data[2], i; + u64 y_fb_dma, c_fb_dma; + struct mtk_vcodec_mem *mem; + int err, nal_start_idx; + + /* bs NULL means flush decoder */ + if (!bs) + return vpu_dec_reset(vpu); + + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + mtk_vcodec_debug(inst, "[h264-dec] [%d] y_dma=%llx c_dma=%llx", + inst->ctx->decoded_frame_cnt, y_fb_dma, c_fb_dma); + + inst->vsi_ctx.dec.bs_buf_addr = (u64)bs->dma_addr; + inst->vsi_ctx.dec.bs_buf_size = bs->size; + inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; + inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; + inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; + + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + err = get_vdec_sig_decode_parameters(inst); + if (err) + goto err_free_fb_out; + + buf = (unsigned char *)bs->va; + nal_start_idx = mtk_vdec_h264_find_start_code(buf, bs->size); + if (nal_start_idx < 0) { + err = -EINVAL; + goto err_free_fb_out; + } + inst->vsi_ctx.dec.nal_info = buf[nal_start_idx]; + + *res_chg = inst->resolution_changed; + if (inst->resolution_changed) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->realloc_mv_buf) { + err = vdec_h264_slice_alloc_mv_buf(inst, &inst->ctx->picinfo); + inst->realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + inst->resolution_changed = false; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr; + } + } + + memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx)); + err = vpu_dec_start(vpu, data, 2); + if (err) + goto err_free_fb_out; + + /* wait decoder done interrupt */ + err = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + if (err) + mtk_vcodec_err(inst, "decode timeout: pic_%d", + inst->ctx->decoded_frame_cnt); + + inst->vsi->dec.timeout = !!err; + err = vpu_dec_end(vpu); + if (err) + goto err_free_fb_out; + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + inst->ctx->decoded_frame_cnt, + inst->vsi_ctx.dec.crc[0], inst->vsi_ctx.dec.crc[1], + inst->vsi_ctx.dec.crc[2], inst->vsi_ctx.dec.crc[3], + inst->vsi_ctx.dec.crc[4], inst->vsi_ctx.dec.crc[5], + inst->vsi_ctx.dec.crc[6], inst->vsi_ctx.dec.crc[7]); + + inst->ctx->decoded_frame_cnt++; + return 0; + +err_free_fb_out: + mtk_vcodec_err(inst, "dec frame number: %d err: %d", + inst->ctx->decoded_frame_cnt, err); + return err; +} + +static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *unused, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + int ret; + + if (!h_vdec) + return -EINVAL; + + if (inst->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE) + ret = vdec_h264_slice_single_decode(h_vdec, bs, unused, res_chg); + else + ret = vdec_h264_slice_lat_decode(h_vdec, bs, unused, res_chg); + + return ret; +} + +static int vdec_h264_slice_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_h264_slice_get_pic_info(inst); + break; + case GET_PARAM_DPB_SIZE: + *(unsigned int *)out = 6; + break; + case GET_PARAM_CROP_INFO: + vdec_h264_slice_get_crop_info(inst, out); + break; + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + return 0; +} + +const struct vdec_common_if vdec_h264_slice_multi_if = { + .init = vdec_h264_slice_init, + .decode = vdec_h264_slice_decode, + .get_param = vdec_h264_slice_get_param, + .deinit = vdec_h264_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c new file mode 100644 index 000000000000..eef102f3f4f3 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include <linux/slab.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> +#include <uapi/linux/v4l2-controls.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +/* Decoding picture buffer size (3 reference frames plus current frame) */ +#define VP8_DPB_SIZE 4 + +/* HW working buffer size (bytes) */ +#define VP8_SEG_ID_SZ SZ_256K +#define VP8_PP_WRAPY_SZ SZ_64K +#define VP8_PP_WRAPC_SZ SZ_64K +#define VP8_VLD_PRED_SZ SZ_64K + +/** + * struct vdec_vp8_slice_info - decode misc information + * + * @vld_wrapper_dma: vld wrapper dma address + * @seg_id_buf_dma: seg id dma address + * @wrap_y_dma: wrap y dma address + * @wrap_c_dma: wrap y dma address + * @cur_y_fb_dma: current plane Y frame buffer dma address + * @cur_c_fb_dma: current plane C frame buffer dma address + * @bs_dma: bitstream dma address + * @bs_sz: bitstream size + * @resolution_changed:resolution change flag 1 - changed, 0 - not change + * @frame_header_type: current frame header type + * @wait_key_frame: wait key frame coming + * @crc: used to check whether hardware's status is right + * @reserved: reserved, currently unused + */ +struct vdec_vp8_slice_info { + u64 vld_wrapper_dma; + u64 seg_id_buf_dma; + u64 wrap_y_dma; + u64 wrap_c_dma; + u64 cur_y_fb_dma; + u64 cur_c_fb_dma; + u64 bs_dma; + u32 bs_sz; + u32 resolution_changed; + u32 frame_header_type; + u32 crc[8]; + u32 reserved; +}; + +/** + * struct vdec_vp8_slice_dpb_info - vp8 reference information + * + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag + * @reserved: 64bit align + */ +struct vdec_vp8_slice_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int reserved; +}; + +/** + * struct vdec_vp8_slice_vsi - VPU shared information + * + * @dec: decoding information + * @pic: picture information + * @vp8_dpb_info: reference buffer information + */ +struct vdec_vp8_slice_vsi { + struct vdec_vp8_slice_info dec; + struct vdec_pic_info pic; + struct vdec_vp8_slice_dpb_info vp8_dpb_info[3]; +}; + +/** + * struct vdec_vp8_slice_inst - VP8 decoder instance + * + * @seg_id_buf: seg buffer + * @wrap_y_buf: wrapper y buffer + * @wrap_c_buf: wrapper c buffer + * @vld_wrapper_buf: vld wrapper buffer + * @ctx: V4L2 context + * @vpu: VPU instance for decoder + * @vsi: VPU share information + */ +struct vdec_vp8_slice_inst { + struct mtk_vcodec_mem seg_id_buf; + struct mtk_vcodec_mem wrap_y_buf; + struct mtk_vcodec_mem wrap_c_buf; + struct mtk_vcodec_mem vld_wrapper_buf; + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + struct vdec_vp8_slice_vsi *vsi; +}; + +static void *vdec_vp8_slice_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + if (!ctrl) + return ERR_PTR(-EINVAL); + + return ctrl->p_cur.p; +} + +static void vdec_vp8_slice_get_pic_info(struct vdec_vp8_slice_inst *inst) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + unsigned int data[3]; + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&inst->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); + ctx->picinfo.fb_sz[0] = inst->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = inst->vpu.fb_sz[1]; + + inst->vsi->pic.pic_w = ctx->picinfo.pic_w; + inst->vsi->pic.pic_h = ctx->picinfo.pic_h; + inst->vsi->pic.buf_w = ctx->picinfo.buf_w; + inst->vsi->pic.buf_h = ctx->picinfo.buf_h; + inst->vsi->pic.fb_sz[0] = ctx->picinfo.fb_sz[0]; + inst->vsi->pic.fb_sz[1] = ctx->picinfo.fb_sz[1]; + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + ctx->picinfo.fb_sz[0], ctx->picinfo.fb_sz[1]); +} + +static int vdec_vp8_slice_alloc_working_buf(struct vdec_vp8_slice_inst *inst) +{ + int err; + struct mtk_vcodec_mem *mem; + + mem = &inst->seg_id_buf; + mem->size = VP8_SEG_ID_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "Cannot allocate working buffer"); + return err; + } + inst->vsi->dec.seg_id_buf_dma = (u64)mem->dma_addr; + + mem = &inst->wrap_y_buf; + mem->size = VP8_PP_WRAPY_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate WRAP Y buffer"); + return err; + } + inst->vsi->dec.wrap_y_dma = (u64)mem->dma_addr; + + mem = &inst->wrap_c_buf; + mem->size = VP8_PP_WRAPC_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate WRAP C buffer"); + return err; + } + inst->vsi->dec.wrap_c_dma = (u64)mem->dma_addr; + + mem = &inst->vld_wrapper_buf; + mem->size = VP8_VLD_PRED_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate vld wrapper buffer"); + return err; + } + inst->vsi->dec.vld_wrapper_dma = (u64)mem->dma_addr; + + return 0; +} + +static void vdec_vp8_slice_free_working_buf(struct vdec_vp8_slice_inst *inst) +{ + struct mtk_vcodec_mem *mem; + + mem = &inst->seg_id_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.seg_id_buf_dma = 0; + + mem = &inst->wrap_y_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.wrap_y_dma = 0; + + mem = &inst->wrap_c_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.wrap_c_dma = 0; + + mem = &inst->vld_wrapper_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.vld_wrapper_dma = 0; +} + +static u64 vdec_vp8_slice_get_ref_by_ts(const struct v4l2_ctrl_vp8_frame *frame_header, + int index) +{ + switch (index) { + case 0: + return frame_header->last_frame_ts; + case 1: + return frame_header->golden_frame_ts; + case 2: + return frame_header->alt_frame_ts; + default: + break; + } + + return -1; +} + +static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst) +{ + const struct v4l2_ctrl_vp8_frame *frame_header; + struct mtk_vcodec_ctx *ctx = inst->ctx; + struct vb2_queue *vq; + struct vb2_buffer *vb; + u64 referenct_ts; + int index, vb2_index; + + frame_header = vdec_vp8_slice_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_VP8_FRAME); + if (IS_ERR(frame_header)) + return PTR_ERR(frame_header); + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + for (index = 0; index < 3; index++) { + referenct_ts = vdec_vp8_slice_get_ref_by_ts(frame_header, index); + vb2_index = vb2_find_timestamp(vq, referenct_ts, 0); + if (vb2_index < 0) { + if (!V4L2_VP8_FRAME_IS_KEY_FRAME(frame_header)) + mtk_vcodec_err(inst, "reference invalid: index(%d) ts(%lld)", + index, referenct_ts); + inst->vsi->vp8_dpb_info[index].reference_flag = 0; + continue; + } + inst->vsi->vp8_dpb_info[index].reference_flag = 1; + + vb = vq->bufs[vb2_index]; + inst->vsi->vp8_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + inst->vsi->vp8_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + else + inst->vsi->vp8_dpb_info[index].c_dma_addr = + inst->vsi->vp8_dpb_info[index].y_dma_addr + + ctx->picinfo.fb_sz[0]; + } + + inst->vsi->dec.frame_header_type = frame_header->flags >> 1; + + return 0; +} + +static int vdec_vp8_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_vp8_slice_inst *inst; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_LAT; + inst->vpu.core_id = SCP_IPI_VDEC_CORE; + inst->vpu.ctx = ctx; + inst->vpu.codec_type = ctx->current_codec; + inst->vpu.capture_type = ctx->capture_fourcc; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err); + goto error_free_inst; + } + + inst->vsi = inst->vpu.vsi; + err = vdec_vp8_slice_alloc_working_buf(inst); + if (err) + goto error_deinit; + + mtk_vcodec_debug(inst, "vp8 struct size = %d vsi: %d\n", + (int)sizeof(struct v4l2_ctrl_vp8_frame), + (int)sizeof(struct vdec_vp8_slice_vsi)); + mtk_vcodec_debug(inst, "vp8:%p, codec_type = 0x%x vsi: 0x%p", + inst, inst->vpu.codec_type, inst->vpu.vsi); + + ctx->drv_handle = inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); +error_free_inst: + kfree(inst); + return err; +} + +static int vdec_vp8_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info, *dst_buf_info; + unsigned int data; + u64 y_fb_dma, c_fb_dma; + int err, timeout; + + /* Resolution changes are never initiated by us */ + *res_chg = false; + + /* bs NULL means flush decoder */ + if (!bs) + return vpu_dec_reset(vpu); + + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) + c_fb_dma = y_fb_dma + + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h; + else + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + inst->vsi->dec.bs_dma = (u64)bs->dma_addr; + inst->vsi->dec.bs_sz = bs->size; + inst->vsi->dec.cur_y_fb_dma = y_fb_dma; + inst->vsi->dec.cur_c_fb_dma = c_fb_dma; + + mtk_vcodec_debug(inst, "frame[%d] bs(%zu 0x%llx) y/c(0x%llx 0x%llx)", + inst->ctx->decoded_frame_cnt, + bs->size, (u64)bs->dma_addr, + y_fb_dma, c_fb_dma); + + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + + err = vdec_vp8_slice_get_decode_parameters(inst); + if (err) + goto error; + + err = vpu_dec_start(vpu, &data, 1); + if (err) { + mtk_vcodec_debug(inst, "vp8 dec start err!"); + goto error; + } + + if (inst->vsi->dec.resolution_changed) { + mtk_vcodec_debug(inst, "- resolution_changed -"); + *res_chg = true; + return 0; + } + + /* wait decode done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + 50, MTK_VDEC_CORE); + + err = vpu_dec_end(vpu); + if (err || timeout) + mtk_vcodec_debug(inst, "vp8 dec error timeout:%d err: %d pic_%d", + timeout, err, inst->ctx->decoded_frame_cnt); + + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + inst->ctx->decoded_frame_cnt, + inst->vsi->dec.crc[0], inst->vsi->dec.crc[1], + inst->vsi->dec.crc[2], inst->vsi->dec.crc[3], + inst->vsi->dec.crc[4], inst->vsi->dec.crc[5], + inst->vsi->dec.crc[6], inst->vsi->dec.crc[7]); + + inst->ctx->decoded_frame_cnt++; +error: + return err; +} + +static int vdec_vp8_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_vp8_slice_get_pic_info(inst); + break; + case GET_PARAM_CROP_INFO: + mtk_vcodec_debug(inst, "No need to get vp8 crop information."); + break; + case GET_PARAM_DPB_SIZE: + *((unsigned int *)out) = VP8_DPB_SIZE; + break; + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +static void vdec_vp8_slice_deinit(void *h_vdec) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + vdec_vp8_slice_free_working_buf(inst); + kfree(inst); +} + +const struct vdec_common_if vdec_vp8_slice_if = { + .init = vdec_vp8_slice_init, + .decode = vdec_vp8_slice_decode, + .get_param = vdec_vp8_slice_get_param, + .deinit = vdec_vp8_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c new file mode 100644 index 000000000000..023aba4ec2c4 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c @@ -0,0 +1,2030 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: George Sun <george.sun@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/videobuf2-dma-contig.h> +#include <media/v4l2-vp9.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +/* reset_frame_context defined in VP9 spec */ +#define VP9_RESET_FRAME_CONTEXT_NONE0 0 +#define VP9_RESET_FRAME_CONTEXT_NONE1 1 +#define VP9_RESET_FRAME_CONTEXT_SPEC 2 +#define VP9_RESET_FRAME_CONTEXT_ALL 3 + +#define VP9_TILE_BUF_SIZE 4096 +#define VP9_PROB_BUF_SIZE 2560 +#define VP9_COUNTS_BUF_SIZE 16384 + +#define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x)) +#define LF_FLAG(x) (!!((lf)->flags & V4L2_VP9_LOOP_FILTER_FLAG_##x)) +#define SEG_FLAG(x) (!!((seg)->flags & V4L2_VP9_SEGMENTATION_FLAG_##x)) +#define VP9_BAND_6(band) ((band) == 0 ? 3 : 6) + +/* + * struct vdec_vp9_slice_frame_ctx - vp9 prob tables footprint + */ +struct vdec_vp9_slice_frame_ctx { + struct { + u8 probs[6][3]; + u8 padding[2]; + } coef_probs[4][2][2][6]; + + u8 y_mode_prob[4][16]; + u8 switch_interp_prob[4][16]; + u8 seg[32]; /* ignore */ + u8 comp_inter_prob[16]; + u8 comp_ref_prob[16]; + u8 single_ref_prob[5][2]; + u8 single_ref_prob_padding[6]; + + u8 joint[3]; + u8 joint_padding[13]; + struct { + u8 sign; + u8 classes[10]; + u8 padding[5]; + } sign_classes[2]; + struct { + u8 class0[1]; + u8 bits[10]; + u8 padding[5]; + } class0_bits[2]; + struct { + u8 class0_fp[2][3]; + u8 fp[3]; + u8 class0_hp; + u8 hp; + u8 padding[5]; + } class0_fp_hp[2]; + + u8 uv_mode_prob[10][16]; + u8 uv_mode_prob_padding[2][16]; + + u8 partition_prob[16][4]; + + u8 inter_mode_probs[7][4]; + u8 skip_probs[4]; + + u8 tx_p8x8[2][4]; + u8 tx_p16x16[2][4]; + u8 tx_p32x32[2][4]; + u8 intra_inter_prob[8]; +}; + +/* + * struct vdec_vp9_slice_frame_counts - vp9 counts tables footprint + */ +struct vdec_vp9_slice_frame_counts { + union { + struct { + u32 band_0[3]; + u32 padding0[1]; + u32 band_1_5[5][6]; + u32 padding1[2]; + } eob_branch[4][2][2]; + u32 eob_branch_space[256 * 4]; + }; + + struct { + u32 band_0[3][4]; + u32 band_1_5[5][6][4]; + } coef_probs[4][2][2]; + + u32 intra_inter[4][2]; + u32 comp_inter[5][2]; + u32 comp_inter_padding[2]; + u32 comp_ref[5][2]; + u32 comp_ref_padding[2]; + u32 single_ref[5][2][2]; + u32 inter_mode[7][4]; + u32 y_mode[4][12]; + u32 uv_mode[10][10]; + u32 partition[16][4]; + u32 switchable_interp[4][4]; + + u32 tx_p8x8[2][2]; + u32 tx_p16x16[2][4]; + u32 tx_p32x32[2][4]; + + u32 skip[3][4]; + + u32 joint[4]; + + struct { + u32 sign[2]; + u32 class0[2]; + u32 classes[12]; + u32 bits[10][2]; + u32 padding[4]; + u32 class0_fp[2][4]; + u32 fp[4]; + u32 class0_hp[2]; + u32 hp[2]; + } mvcomp[2]; + + u32 reserved[126][4]; +}; + +/** + * struct vdec_vp9_slice_counts_map - vp9 counts tables to map + * v4l2_vp9_frame_symbol_counts + * @skip: skip counts. + * @y_mode: Y prediction mode counts. + * @filter: interpolation filter counts. + * @mv_joint: motion vector joint counts. + * @sign: motion vector sign counts. + * @classes: motion vector class counts. + * @class0: motion vector class0 bit counts. + * @bits: motion vector bits counts. + * @class0_fp: motion vector class0 fractional bit counts. + * @fp: motion vector fractional bit counts. + * @class0_hp: motion vector class0 high precision fractional bit counts. + * @hp: motion vector high precision fractional bit counts. + */ +struct vdec_vp9_slice_counts_map { + u32 skip[3][2]; + u32 y_mode[4][10]; + u32 filter[4][3]; + u32 sign[2][2]; + u32 classes[2][11]; + u32 class0[2][2]; + u32 bits[2][10][2]; + u32 class0_fp[2][2][4]; + u32 fp[2][4]; + u32 class0_hp[2][2]; + u32 hp[2][2]; +}; + +/* + * struct vdec_vp9_slice_uncompressed_header - vp9 uncompressed header syntax + * used for decoding + */ +struct vdec_vp9_slice_uncompressed_header { + u8 profile; + u8 last_frame_type; + u8 frame_type; + + u8 last_show_frame; + u8 show_frame; + u8 error_resilient_mode; + + u8 bit_depth; + u8 padding0[1]; + u16 last_frame_width; + u16 last_frame_height; + u16 frame_width; + u16 frame_height; + + u8 intra_only; + u8 reset_frame_context; + u8 ref_frame_sign_bias[4]; + u8 allow_high_precision_mv; + u8 interpolation_filter; + + u8 refresh_frame_context; + u8 frame_parallel_decoding_mode; + u8 frame_context_idx; + + /* loop_filter_params */ + u8 loop_filter_level; + u8 loop_filter_sharpness; + u8 loop_filter_delta_enabled; + s8 loop_filter_ref_deltas[4]; + s8 loop_filter_mode_deltas[2]; + + /* quantization_params */ + u8 base_q_idx; + s8 delta_q_y_dc; + s8 delta_q_uv_dc; + s8 delta_q_uv_ac; + + /* segmentation_params */ + u8 segmentation_enabled; + u8 segmentation_update_map; + u8 segmentation_tree_probs[7]; + u8 padding1[1]; + u8 segmentation_temporal_udpate; + u8 segmentation_pred_prob[3]; + u8 segmentation_update_data; + u8 segmentation_abs_or_delta_update; + u8 feature_enabled[8]; + s16 feature_value[8][4]; + + /* tile_info */ + u8 tile_cols_log2; + u8 tile_rows_log2; + u8 padding2[2]; + + u16 uncompressed_header_size; + u16 header_size_in_bytes; + + /* LAT OUT, CORE IN */ + u32 dequant[8][4]; +}; + +/* + * struct vdec_vp9_slice_compressed_header - vp9 compressed header syntax + * used for decoding. + */ +struct vdec_vp9_slice_compressed_header { + u8 tx_mode; + u8 ref_mode; + u8 comp_fixed_ref; + u8 comp_var_ref[2]; + u8 padding[3]; +}; + +/* + * struct vdec_vp9_slice_tiles - vp9 tile syntax + */ +struct vdec_vp9_slice_tiles { + u32 size[4][64]; + u32 mi_rows[4]; + u32 mi_cols[64]; + u8 actual_rows; + u8 padding[7]; +}; + +/* + * struct vdec_vp9_slice_reference - vp9 reference frame information + */ +struct vdec_vp9_slice_reference { + u16 frame_width; + u16 frame_height; + u8 bit_depth; + u8 subsampling_x; + u8 subsampling_y; + u8 padding; +}; + +/* + * struct vdec_vp9_slice_frame - vp9 syntax used for decoding + */ +struct vdec_vp9_slice_frame { + struct vdec_vp9_slice_uncompressed_header uh; + struct vdec_vp9_slice_compressed_header ch; + struct vdec_vp9_slice_tiles tiles; + struct vdec_vp9_slice_reference ref[3]; +}; + +/* + * struct vdec_vp9_slice_init_vsi - VSI used to initialize instance + */ +struct vdec_vp9_slice_init_vsi { + unsigned int architecture; + unsigned int reserved; + u64 core_vsi; + /* default frame context's position in MicroP */ + u64 default_frame_ctx; +}; + +/* + * struct vdec_vp9_slice_mem - memory address and size + */ +struct vdec_vp9_slice_mem { + union { + u64 buf; + dma_addr_t dma_addr; + }; + union { + size_t size; + dma_addr_t dma_addr_end; + u64 padding; + }; +}; + +/* + * struct vdec_vp9_slice_bs - input buffer for decoding + */ +struct vdec_vp9_slice_bs { + struct vdec_vp9_slice_mem buf; + struct vdec_vp9_slice_mem frame; +}; + +/* + * struct vdec_vp9_slice_fb - frame buffer for decoding + */ +struct vdec_vp9_slice_fb { + struct vdec_vp9_slice_mem y; + struct vdec_vp9_slice_mem c; +}; + +/* + * struct vdec_vp9_slice_state - decoding state + */ +struct vdec_vp9_slice_state { + int err; + unsigned int full; + unsigned int timeout; + unsigned int perf; + + unsigned int crc[12]; +}; + +/** + * struct vdec_vp9_slice_vsi - exchange decoding information + * between Main CPU and MicroP + * + * @bs: input buffer + * @fb: output buffer + * @ref: 3 reference buffers + * @mv: mv working buffer + * @seg: segmentation working buffer + * @tile: tile buffer + * @prob: prob table buffer, used to set/update prob table + * @counts: counts table buffer, used to update prob table + * @ube: general buffer + * @trans: trans buffer position in general buffer + * @err_map: error buffer + * @row_info: row info buffer + * @frame: decoding syntax + * @state: decoding state + */ +struct vdec_vp9_slice_vsi { + /* used in LAT stage */ + struct vdec_vp9_slice_bs bs; + /* used in Core stage */ + struct vdec_vp9_slice_fb fb; + struct vdec_vp9_slice_fb ref[3]; + + struct vdec_vp9_slice_mem mv[2]; + struct vdec_vp9_slice_mem seg[2]; + struct vdec_vp9_slice_mem tile; + struct vdec_vp9_slice_mem prob; + struct vdec_vp9_slice_mem counts; + + /* LAT stage's output, Core stage's input */ + struct vdec_vp9_slice_mem ube; + struct vdec_vp9_slice_mem trans; + struct vdec_vp9_slice_mem err_map; + struct vdec_vp9_slice_mem row_info; + + /* decoding parameters */ + struct vdec_vp9_slice_frame frame; + + struct vdec_vp9_slice_state state; +}; + +/** + * struct vdec_vp9_slice_pfc - per-frame context that contains a local vsi. + * pass it from lat to core + * + * @vsi: local vsi. copy to/from remote vsi before/after decoding + * @ref_idx: reference buffer index + * @seq: picture sequence + * @state: decoding state + */ +struct vdec_vp9_slice_pfc { + struct vdec_vp9_slice_vsi vsi; + + u64 ref_idx[3]; + + int seq; + + /* LAT/Core CRC */ + struct vdec_vp9_slice_state state[2]; +}; + +/* + * enum vdec_vp9_slice_resolution_level + */ +enum vdec_vp9_slice_resolution_level { + VP9_RES_NONE, + VP9_RES_FHD, + VP9_RES_4K, + VP9_RES_8K, +}; + +/* + * struct vdec_vp9_slice_ref - picture's width & height should kept + * for later decoding as reference picture + */ +struct vdec_vp9_slice_ref { + unsigned int width; + unsigned int height; +}; + +/** + * struct vdec_vp9_slice_instance - represent one vp9 instance + * + * @ctx: pointer to codec's context + * @vpu: VPU instance + * @seq: global picture sequence + * @level: level of current resolution + * @width: width of last picture + * @height: height of last picture + * @frame_type: frame_type of last picture + * @irq: irq to Main CPU or MicroP + * @show_frame: show_frame of last picture + * @dpb: picture information (width/height) for reference + * @mv: mv working buffer + * @seg: segmentation working buffer + * @tile: tile buffer + * @prob: prob table buffer, used to set/update prob table + * @counts: counts table buffer, used to update prob table + * @frame_ctx: 4 frame context according to VP9 Spec + * @frame_ctx_helper: 4 frame context according to newest kernel spec + * @dirty: state of each frame context + * @init_vsi: vsi used for initialized VP9 instance + * @vsi: vsi used for decoding/flush ... + * @core_vsi: vsi used for Core stage + * @counts_map: used map to counts_helper + * @counts_helper: counts table according to newest kernel spec + */ +struct vdec_vp9_slice_instance { + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + + int seq; + + enum vdec_vp9_slice_resolution_level level; + + /* for resolution change and get_pic_info */ + unsigned int width; + unsigned int height; + + /* for last_frame_type */ + unsigned int frame_type; + unsigned int irq; + + unsigned int show_frame; + + /* maintain vp9 reference frame state */ + struct vdec_vp9_slice_ref dpb[VB2_MAX_FRAME]; + + /* + * normal working buffers + * mv[0]/seg[0]/tile/prob/counts is used for LAT + * mv[1]/seg[1] is used for CORE + */ + struct mtk_vcodec_mem mv[2]; + struct mtk_vcodec_mem seg[2]; + struct mtk_vcodec_mem tile; + struct mtk_vcodec_mem prob; + struct mtk_vcodec_mem counts; + + /* 4 prob tables */ + struct vdec_vp9_slice_frame_ctx frame_ctx[4]; + /*4 helper tables */ + struct v4l2_vp9_frame_context frame_ctx_helper; + unsigned char dirty[4]; + + /* MicroP vsi */ + union { + struct vdec_vp9_slice_init_vsi *init_vsi; + struct vdec_vp9_slice_vsi *vsi; + }; + struct vdec_vp9_slice_vsi *core_vsi; + + struct vdec_vp9_slice_counts_map counts_map; + struct v4l2_vp9_frame_symbol_counts counts_helper; +}; + +/* + * all VP9 instances could share this default frame context. + */ +static struct vdec_vp9_slice_frame_ctx *vdec_vp9_slice_default_frame_ctx; +static DEFINE_MUTEX(vdec_vp9_slice_frame_ctx_lock); + +static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf); + +static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance *instance) +{ + struct vdec_vp9_slice_frame_ctx *remote_frame_ctx; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct mtk_vcodec_ctx *ctx; + struct vdec_vp9_slice_init_vsi *vsi; + int ret = 0; + + ctx = instance->ctx; + vsi = instance->vpu.vsi; + if (!ctx || !vsi) + return -EINVAL; + + remote_frame_ctx = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->default_frame_ctx); + if (!remote_frame_ctx) { + mtk_vcodec_err(instance, "failed to map default frame ctx\n"); + return -EINVAL; + } + + mutex_lock(&vdec_vp9_slice_frame_ctx_lock); + if (vdec_vp9_slice_default_frame_ctx) + goto out; + + frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + if (!frame_ctx) { + ret = -ENOMEM; + goto out; + } + + memcpy(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); + vdec_vp9_slice_default_frame_ctx = frame_ctx; + +out: + mutex_unlock(&vdec_vp9_slice_frame_ctx_lock); + + return ret; +} + +static int vdec_vp9_slice_alloc_working_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + enum vdec_vp9_slice_resolution_level level; + /* super blocks */ + unsigned int max_sb_w; + unsigned int max_sb_h; + unsigned int max_w; + unsigned int max_h; + unsigned int w; + unsigned int h; + size_t size; + int ret; + int i; + + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + + if (w > VCODEC_DEC_4K_CODED_WIDTH || + h > VCODEC_DEC_4K_CODED_HEIGHT) { + return -EINVAL; + } else if (w > MTK_VDEC_MAX_W || h > MTK_VDEC_MAX_H) { + /* 4K */ + level = VP9_RES_4K; + max_w = VCODEC_DEC_4K_CODED_WIDTH; + max_h = VCODEC_DEC_4K_CODED_HEIGHT; + } else { + /* FHD */ + level = VP9_RES_FHD; + max_w = MTK_VDEC_MAX_W; + max_h = MTK_VDEC_MAX_H; + } + + if (level == instance->level) + return 0; + + mtk_vcodec_debug(instance, "resolution level changed, from %u to %u, %ux%u", + instance->level, level, w, h); + + max_sb_w = DIV_ROUND_UP(max_w, 64); + max_sb_h = DIV_ROUND_UP(max_h, 64); + ret = -ENOMEM; + + /* + * Lat-flush must wait core idle, otherwise core will + * use released buffers + */ + + size = (max_sb_w * max_sb_h + 2) * 576; + for (i = 0; i < 2; i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + instance->mv[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->mv[i])) + goto err; + } + + size = (max_sb_w * max_sb_h * 32) + 256; + for (i = 0; i < 2; i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + instance->seg[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->seg[i])) + goto err; + } + + if (!instance->tile.va) { + instance->tile.size = VP9_TILE_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->tile)) + goto err; + } + + if (!instance->prob.va) { + instance->prob.size = VP9_PROB_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->prob)) + goto err; + } + + if (!instance->counts.va) { + instance->counts.size = VP9_COUNTS_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->counts)) + goto err; + } + + instance->level = level; + return 0; + +err: + instance->level = VP9_RES_NONE; + return ret; +} + +static void vdec_vp9_slice_free_working_buffer(struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + int i; + + for (i = 0; i < ARRAY_SIZE(instance->mv); i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + } + for (i = 0; i < ARRAY_SIZE(instance->seg); i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + } + if (instance->tile.va) + mtk_vcodec_mem_free(ctx, &instance->tile); + if (instance->prob.va) + mtk_vcodec_mem_free(ctx, &instance->prob); + if (instance->counts.va) + mtk_vcodec_mem_free(ctx, &instance->counts); + + instance->level = VP9_RES_NONE; +} + +static void vdec_vp9_slice_vsi_from_remote(struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi, + int skip) +{ + struct vdec_vp9_slice_frame *rf; + struct vdec_vp9_slice_frame *f; + + /* + * compressed header + * dequant + * buffer position + * decode state + */ + if (!skip) { + rf = &remote_vsi->frame; + f = &vsi->frame; + memcpy(&f->ch, &rf->ch, sizeof(f->ch)); + memcpy(&f->uh.dequant, &rf->uh.dequant, sizeof(f->uh.dequant)); + memcpy(&vsi->trans, &remote_vsi->trans, sizeof(vsi->trans)); + } + + memcpy(&vsi->state, &remote_vsi->state, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_vsi_to_remote(struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi) +{ + memcpy(remote_vsi, vsi, sizeof(*vsi)); +} + +static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2) +{ + int sbs = (mi_num + 7) >> 3; + int offset = ((idx * sbs) >> tile_log2) << 3; + + return offset < mi_num ? offset : mi_num; +} + +static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); + if (!src) + return -EINVAL; + + lat_buf->src_buf_req = src->vb2_buf.req_obj.req; + + dst = &lat_buf->ts_info; + v4l2_m2m_buf_copy_metadata(src, dst, true); + return 0; +} + +static void vdec_vp9_slice_setup_hdr(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame *hdr) +{ + int i; + + uh->profile = hdr->profile; + uh->last_frame_type = instance->frame_type; + uh->frame_type = !HDR_FLAG(KEY_FRAME); + uh->last_show_frame = instance->show_frame; + uh->show_frame = HDR_FLAG(SHOW_FRAME); + uh->error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + uh->bit_depth = hdr->bit_depth; + uh->last_frame_width = instance->width; + uh->last_frame_height = instance->height; + uh->frame_width = hdr->frame_width_minus_1 + 1; + uh->frame_height = hdr->frame_height_minus_1 + 1; + uh->intra_only = HDR_FLAG(INTRA_ONLY); + /* map v4l2 enum to values defined in VP9 spec for firmware */ + switch (hdr->reset_frame_context) { + case V4L2_VP9_RESET_FRAME_CTX_NONE: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + case V4L2_VP9_RESET_FRAME_CTX_SPEC: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_SPEC; + break; + case V4L2_VP9_RESET_FRAME_CTX_ALL: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_ALL; + break; + default: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + } + /* + * ref_frame_sign_bias specifies the intended direction + * of the motion vector in time for each reference frame. + * - INTRA_FRAME = 0, + * - LAST_FRAME = 1, + * - GOLDEN_FRAME = 2, + * - ALTREF_FRAME = 3, + * ref_frame_sign_bias[INTRA_FRAME] is always 0 + * and VDA only passes another 3 directions + */ + uh->ref_frame_sign_bias[0] = 0; + for (i = 0; i < 3; i++) + uh->ref_frame_sign_bias[i + 1] = + !!(hdr->ref_frame_sign_bias & (1 << i)); + uh->allow_high_precision_mv = HDR_FLAG(ALLOW_HIGH_PREC_MV); + uh->interpolation_filter = hdr->interpolation_filter; + uh->refresh_frame_context = HDR_FLAG(REFRESH_FRAME_CTX); + uh->frame_parallel_decoding_mode = HDR_FLAG(PARALLEL_DEC_MODE); + uh->frame_context_idx = hdr->frame_context_idx; + + /* tile info */ + uh->tile_cols_log2 = hdr->tile_cols_log2; + uh->tile_rows_log2 = hdr->tile_rows_log2; + + uh->uncompressed_header_size = hdr->uncompressed_header_size; + uh->header_size_in_bytes = hdr->compressed_header_size; +} + +static void vdec_vp9_slice_setup_frame_ctx(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame *hdr) +{ + int error_resilient_mode; + int reset_frame_context; + int key_frame; + int intra_only; + int i; + + key_frame = HDR_FLAG(KEY_FRAME); + intra_only = HDR_FLAG(INTRA_ONLY); + error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + reset_frame_context = uh->reset_frame_context; + + /* + * according to "6.2 Uncompressed header syntax" in + * "VP9 Bitstream & Decoding Process Specification", + * reset @frame_context_idx when (FrameIsIntra || error_resilient_mode) + */ + if (key_frame || intra_only || error_resilient_mode) { + /* + * @reset_frame_context specifies + * whether the frame context should be + * reset to default values: + * 0 or 1 means do not reset any frame context + * 2 resets just the context specified in the frame header + * 3 resets all contexts + */ + if (key_frame || error_resilient_mode || + reset_frame_context == 3) { + /* use default table */ + for (i = 0; i < 4; i++) + instance->dirty[i] = 0; + } else if (reset_frame_context == 2) { + instance->dirty[uh->frame_context_idx] = 0; + } + uh->frame_context_idx = 0; + } +} + +static void vdec_vp9_slice_setup_loop_filter(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_loop_filter *lf) +{ + int i; + + uh->loop_filter_level = lf->level; + uh->loop_filter_sharpness = lf->sharpness; + uh->loop_filter_delta_enabled = LF_FLAG(DELTA_ENABLED); + for (i = 0; i < 4; i++) + uh->loop_filter_ref_deltas[i] = lf->ref_deltas[i]; + for (i = 0; i < 2; i++) + uh->loop_filter_mode_deltas[i] = lf->mode_deltas[i]; +} + +static void vdec_vp9_slice_setup_quantization(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_quantization *quant) +{ + uh->base_q_idx = quant->base_q_idx; + uh->delta_q_y_dc = quant->delta_q_y_dc; + uh->delta_q_uv_dc = quant->delta_q_uv_dc; + uh->delta_q_uv_ac = quant->delta_q_uv_ac; +} + +static void vdec_vp9_slice_setup_segmentation(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_segmentation *seg) +{ + int i; + int j; + + uh->segmentation_enabled = SEG_FLAG(ENABLED); + uh->segmentation_update_map = SEG_FLAG(UPDATE_MAP); + for (i = 0; i < 7; i++) + uh->segmentation_tree_probs[i] = seg->tree_probs[i]; + uh->segmentation_temporal_udpate = SEG_FLAG(TEMPORAL_UPDATE); + for (i = 0; i < 3; i++) + uh->segmentation_pred_prob[i] = seg->pred_probs[i]; + uh->segmentation_update_data = SEG_FLAG(UPDATE_DATA); + uh->segmentation_abs_or_delta_update = SEG_FLAG(ABS_OR_DELTA_UPDATE); + for (i = 0; i < 8; i++) { + uh->feature_enabled[i] = seg->feature_enabled[i]; + for (j = 0; j < 4; j++) + uh->feature_value[i][j] = seg->feature_data[i][j]; + } +} + +static int vdec_vp9_slice_setup_tile(struct vdec_vp9_slice_vsi *vsi, + struct v4l2_ctrl_vp9_frame *hdr) +{ + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_rows; + unsigned int mi_cols; + struct vdec_vp9_slice_tiles *tiles; + int offset; + int start; + int end; + int i; + + rows_log2 = hdr->tile_rows_log2; + cols_log2 = hdr->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + tiles = &vsi->frame.tiles; + tiles->actual_rows = 0; + + if (rows > 4 || cols > 64) + return -EINVAL; + + /* setup mi rows/cols information */ + mi_rows = (hdr->frame_height_minus_1 + 1 + 7) >> 3; + mi_cols = (hdr->frame_width_minus_1 + 1 + 7) >> 3; + + for (i = 0; i < rows; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_rows, rows_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_rows, rows_log2); + offset = end - start; + tiles->mi_rows[i] = (offset + 7) >> 3; + if (tiles->mi_rows[i]) + tiles->actual_rows++; + } + + for (i = 0; i < cols; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_cols, cols_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_cols, cols_log2); + offset = end - start; + tiles->mi_cols[i] = (offset + 7) >> 3; + } + + return 0; +} + +static void vdec_vp9_slice_setup_state(struct vdec_vp9_slice_vsi *vsi) +{ + memset(&vsi->state, 0, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_setup_ref_idx(struct vdec_vp9_slice_pfc *pfc, + struct v4l2_ctrl_vp9_frame *hdr) +{ + pfc->ref_idx[0] = hdr->last_frame_ts; + pfc->ref_idx[1] = hdr->golden_frame_ts; + pfc->ref_idx[2] = hdr->alt_frame_ts; +} + +static int vdec_vp9_slice_setup_pfc(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc) +{ + struct v4l2_ctrl_vp9_frame *hdr; + struct vdec_vp9_slice_uncompressed_header *uh; + struct v4l2_ctrl *hdr_ctrl; + struct vdec_vp9_slice_vsi *vsi; + int ret; + + /* frame header */ + hdr_ctrl = v4l2_ctrl_find(&instance->ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_FRAME); + if (!hdr_ctrl || !hdr_ctrl->p_cur.p) + return -EINVAL; + + hdr = hdr_ctrl->p_cur.p; + vsi = &pfc->vsi; + uh = &vsi->frame.uh; + + /* setup vsi information */ + vdec_vp9_slice_setup_hdr(instance, uh, hdr); + vdec_vp9_slice_setup_frame_ctx(instance, uh, hdr); + vdec_vp9_slice_setup_loop_filter(uh, &hdr->lf); + vdec_vp9_slice_setup_quantization(uh, &hdr->quant); + vdec_vp9_slice_setup_segmentation(uh, &hdr->seg); + ret = vdec_vp9_slice_setup_tile(vsi, hdr); + if (ret) + return ret; + vdec_vp9_slice_setup_state(vsi); + + /* core stage needs buffer index to get ref y/c ... */ + vdec_vp9_slice_setup_ref_idx(pfc, hdr); + + pfc->seq = instance->seq; + instance->seq++; + + return 0; +} + +static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf) +{ + int i; + + vsi->bs.buf.dma_addr = bs->dma_addr; + vsi->bs.buf.size = bs->size; + vsi->bs.frame.dma_addr = bs->dma_addr; + vsi->bs.frame.size = bs->size; + + for (i = 0; i < 2; i++) { + vsi->mv[i].dma_addr = instance->mv[i].dma_addr; + vsi->mv[i].size = instance->mv[i].size; + } + for (i = 0; i < 2; i++) { + vsi->seg[i].dma_addr = instance->seg[i].dma_addr; + vsi->seg[i].size = instance->seg[i].size; + } + vsi->tile.dma_addr = instance->tile.dma_addr; + vsi->tile.size = instance->tile.size; + vsi->prob.dma_addr = instance->prob.dma_addr; + vsi->prob.size = instance->prob.size; + vsi->counts.dma_addr = instance->counts.dma_addr; + vsi->counts.size = instance->counts.size; + + vsi->ube.dma_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + vsi->ube.size = lat_buf->ctx->msg_queue.wdma_addr.size; + vsi->trans.dma_addr = lat_buf->ctx->msg_queue.wdma_wptr_addr; + /* used to store trans end */ + vsi->trans.dma_addr_end = lat_buf->ctx->msg_queue.wdma_rptr_addr; + vsi->err_map.dma_addr = lat_buf->wdma_err_addr.dma_addr; + vsi->err_map.size = lat_buf->wdma_err_addr.size; + + vsi->row_info.buf = 0; + vsi->row_info.size = 0; + + return 0; +} + +static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_uncompressed_header *uh; + + uh = &vsi->frame.uh; + + mtk_vcodec_debug(instance, "ctx dirty %u idx %d\n", + instance->dirty[uh->frame_context_idx], + uh->frame_context_idx); + + if (instance->dirty[uh->frame_context_idx]) + frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + else + frame_ctx = vdec_vp9_slice_default_frame_ctx; + memcpy(instance->prob.va, frame_ctx, sizeof(*frame_ctx)); + + return 0; +} + +static void vdec_vp9_slice_setup_seg_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *buf) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + + /* reset segment buffer */ + uh = &vsi->frame.uh; + if (uh->frame_type == 0 || + uh->intra_only || + uh->error_resilient_mode || + uh->frame_width != instance->width || + uh->frame_height != instance->height) { + mtk_vcodec_debug(instance, "reset seg\n"); + memset(buf->va, 0, buf->size); + } +} + +/* + * parse tiles according to `6.4 Decode tiles syntax` + * in "vp9-bitstream-specification" + * + * frame contains uncompress header, compressed header and several tiles. + * this function parses tiles' position and size, stores them to tile buffer + * for decoding. + */ +static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_row; + unsigned int mi_col; + unsigned int offset; + unsigned int pa; + unsigned int size; + struct vdec_vp9_slice_tiles *tiles; + unsigned char *pos; + unsigned char *end; + unsigned char *va; + unsigned int *tb; + int i; + int j; + + uh = &vsi->frame.uh; + rows_log2 = uh->tile_rows_log2; + cols_log2 = uh->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + + if (rows > 4 || cols > 64) { + mtk_vcodec_err(instance, "tile_rows %u tile_cols %u\n", + rows, cols); + return -EINVAL; + } + + offset = uh->uncompressed_header_size + + uh->header_size_in_bytes; + if (bs->size <= offset) { + mtk_vcodec_err(instance, "bs size %zu tile offset %u\n", + bs->size, offset); + return -EINVAL; + } + + tiles = &vsi->frame.tiles; + /* setup tile buffer */ + + va = (unsigned char *)bs->va; + pos = va + offset; + end = va + bs->size; + /* truncated */ + pa = (unsigned int)bs->dma_addr + offset; + tb = instance->tile.va; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++) { + if (i == rows - 1 && + j == cols - 1) { + size = (unsigned int)(end - pos); + } else { + if (end - pos < 4) + return -EINVAL; + + size = (pos[0] << 24) | (pos[1] << 16) | + (pos[2] << 8) | pos[3]; + pos += 4; + pa += 4; + offset += 4; + if (end - pos < size) + return -EINVAL; + } + tiles->size[i][j] = size; + if (tiles->mi_rows[i]) { + *tb++ = (size << 3) + ((offset << 3) & 0x7f); + *tb++ = pa & ~0xf; + *tb++ = (pa << 3) & 0x7f; + mi_row = (tiles->mi_rows[i] - 1) & 0x1ff; + mi_col = (tiles->mi_cols[j] - 1) & 0x3f; + *tb++ = (mi_row << 6) + mi_col; + } + pos += size; + pa += size; + offset += size; + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + ret = vdec_vp9_slice_setup_lat_from_src_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_pfc(instance, pfc); + if (ret) + goto err; + + ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); + if (ret) + goto err; + + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); + + /* setup prob/tile buffers for LAT */ + + ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + +static +void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_counts *counts, + struct v4l2_vp9_frame_symbol_counts *counts_helper) +{ + u32 l = 0, m; + + /* + * helper eo -> mtk eo + * helpre e1 -> mtk c3 + * helper c0 -> c0 + * helper c1 -> c1 + * helper c2 -> c2 + */ + for (m = 0; m < 3; m++) { + counts_helper->coeff[i][j][k][l][m] = + (u32 (*)[3]) & counts->coef_probs[i][j][k].band_0[m]; + counts_helper->eob[i][j][k][l][m][0] = + &counts->eob_branch[i][j][k].band_0[m]; + counts_helper->eob[i][j][k][l][m][1] = + &counts->coef_probs[i][j][k].band_0[m][3]; + } + + for (l = 1; l < 6; l++) { + for (m = 0; m < 6; m++) { + counts_helper->coeff[i][j][k][l][m] = + (u32 (*)[3]) & counts->coef_probs[i][j][k].band_1_5[l - 1][m]; + counts_helper->eob[i][j][k][l][m][0] = + &counts->eob_branch[i][j][k].band_1_5[l - 1][m]; + counts_helper->eob[i][j][k][l][m][1] = + &counts->coef_probs[i][j][k].band_1_5[l - 1][m][3]; + } + } +} + +static void vdec_vp9_slice_counts_map_helper(struct vdec_vp9_slice_counts_map *counts_map, + struct vdec_vp9_slice_frame_counts *counts, + struct v4l2_vp9_frame_symbol_counts *counts_helper) +{ + int i, j, k; + + counts_helper->partition = &counts->partition; + counts_helper->intra_inter = &counts->intra_inter; + counts_helper->tx32p = &counts->tx_p32x32; + counts_helper->tx16p = &counts->tx_p16x16; + counts_helper->tx8p = &counts->tx_p8x8; + counts_helper->uv_mode = &counts->uv_mode; + + counts_helper->comp = &counts->comp_inter; + counts_helper->comp_ref = &counts->comp_ref; + counts_helper->single_ref = &counts->single_ref; + counts_helper->mv_mode = &counts->inter_mode; + counts_helper->mv_joint = &counts->joint; + + for (i = 0; i < ARRAY_SIZE(counts_map->skip); i++) + memcpy(counts_map->skip[i], counts->skip[i], + sizeof(counts_map->skip[0])); + counts_helper->skip = &counts_map->skip; + + for (i = 0; i < ARRAY_SIZE(counts_map->y_mode); i++) + memcpy(counts_map->y_mode[i], counts->y_mode[i], + sizeof(counts_map->y_mode[0])); + counts_helper->y_mode = &counts_map->y_mode; + + for (i = 0; i < ARRAY_SIZE(counts_map->filter); i++) + memcpy(counts_map->filter[i], counts->switchable_interp[i], + sizeof(counts_map->filter[0])); + counts_helper->filter = &counts_map->filter; + + for (i = 0; i < ARRAY_SIZE(counts_map->sign); i++) + memcpy(counts_map->sign[i], counts->mvcomp[i].sign, + sizeof(counts_map->sign[0])); + counts_helper->sign = &counts_map->sign; + + for (i = 0; i < ARRAY_SIZE(counts_map->classes); i++) + memcpy(counts_map->classes[i], counts->mvcomp[i].classes, + sizeof(counts_map->classes[0])); + counts_helper->classes = &counts_map->classes; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0); i++) + memcpy(counts_map->class0[i], counts->mvcomp[i].class0, + sizeof(counts_map->class0[0])); + counts_helper->class0 = &counts_map->class0; + + for (i = 0; i < ARRAY_SIZE(counts_map->bits); i++) + for (j = 0; j < ARRAY_SIZE(counts_map->bits[0]); j++) + memcpy(counts_map->bits[i][j], counts->mvcomp[i].bits[j], + sizeof(counts_map->bits[0][0])); + counts_helper->bits = &counts_map->bits; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0_fp); i++) + for (j = 0; j < ARRAY_SIZE(counts_map->class0_fp[0]); j++) + memcpy(counts_map->class0_fp[i][j], counts->mvcomp[i].class0_fp[j], + sizeof(counts_map->class0_fp[0][0])); + counts_helper->class0_fp = &counts_map->class0_fp; + + for (i = 0; i < ARRAY_SIZE(counts_map->fp); i++) + memcpy(counts_map->fp[i], counts->mvcomp[i].fp, + sizeof(counts_map->fp[0])); + counts_helper->fp = &counts_map->fp; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0_hp); i++) + memcpy(counts_map->class0_hp[i], counts->mvcomp[i].class0_hp, + sizeof(counts_map->class0_hp[0])); + counts_helper->class0_hp = &counts_map->class0_hp; + + for (i = 0; i < ARRAY_SIZE(counts_map->hp); i++) + memcpy(counts_map->hp[i], counts->mvcomp[i].hp, sizeof(counts_map->hp[0])); + + counts_helper->hp = &counts_map->hp; + + for (i = 0; i < 4; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + vdec_vp9_slice_map_counts_eob_coef(i, j, k, counts, counts_helper); +} + +static void vdec_vp9_slice_map_to_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + u32 l, m; + + for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { + for (m = 0; m < VP9_BAND_6(l); m++) { + memcpy(frame_ctx_helper->coef[i][j][k][l][m], + frame_ctx->coef_probs[i][j][k][l].probs[m], + sizeof(frame_ctx_helper->coef[i][j][k][l][0])); + } + } +} + +static void vdec_vp9_slice_map_from_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + u32 l, m; + + for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { + for (m = 0; m < VP9_BAND_6(l); m++) { + memcpy(frame_ctx->coef_probs[i][j][k][l].probs[m], + frame_ctx_helper->coef[i][j][k][l][m], + sizeof(frame_ctx_helper->coef[i][j][k][l][0])); + } + } +} + +static +void vdec_vp9_slice_framectx_map_helper(bool frame_is_intra, + struct vdec_vp9_slice_frame_ctx *pre_frame_ctx, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; + u32 i, j, k; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) + for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) + vdec_vp9_slice_map_to_coef(i, j, k, pre_frame_ctx, + frame_ctx_helper); + + /* + * use previous prob when frame is not intra or + * we should use the prob updated by the compressed header parse + */ + if (!frame_is_intra) + frame_ctx = pre_frame_ctx; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) + memcpy(frame_ctx_helper->tx8[i], frame_ctx->tx_p8x8[i], + sizeof(frame_ctx_helper->tx8[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) + memcpy(frame_ctx_helper->tx16[i], frame_ctx->tx_p16x16[i], + sizeof(frame_ctx_helper->tx16[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) + memcpy(frame_ctx_helper->tx32[i], frame_ctx->tx_p32x32[i], + sizeof(frame_ctx_helper->tx32[0])); + + memcpy(frame_ctx_helper->skip, frame_ctx->skip_probs, sizeof(frame_ctx_helper->skip)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) + memcpy(frame_ctx_helper->inter_mode[i], frame_ctx->inter_mode_probs[i], + sizeof(frame_ctx_helper->inter_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) + memcpy(frame_ctx_helper->interp_filter[i], frame_ctx->switch_interp_prob[i], + sizeof(frame_ctx_helper->interp_filter[0])); + + memcpy(frame_ctx_helper->is_inter, frame_ctx->intra_inter_prob, + sizeof(frame_ctx_helper->is_inter)); + + memcpy(frame_ctx_helper->comp_mode, frame_ctx->comp_inter_prob, + sizeof(frame_ctx_helper->comp_mode)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) + memcpy(frame_ctx_helper->single_ref[i], frame_ctx->single_ref_prob[i], + sizeof(frame_ctx_helper->single_ref[0])); + + memcpy(frame_ctx_helper->comp_ref, frame_ctx->comp_ref_prob, + sizeof(frame_ctx_helper->comp_ref)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) + memcpy(frame_ctx_helper->y_mode[i], frame_ctx->y_mode_prob[i], + sizeof(frame_ctx_helper->y_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) + memcpy(frame_ctx_helper->uv_mode[i], frame_ctx->uv_mode_prob[i], + sizeof(frame_ctx_helper->uv_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) + memcpy(frame_ctx_helper->partition[i], frame_ctx->partition_prob[i], + sizeof(frame_ctx_helper->partition[0])); + + memcpy(mv->joint, frame_ctx->joint, sizeof(mv->joint)); + + for (i = 0; i < ARRAY_SIZE(mv->sign); i++) + mv->sign[i] = frame_ctx->sign_classes[i].sign; + + for (i = 0; i < ARRAY_SIZE(mv->classes); i++) + memcpy(mv->classes[i], frame_ctx->sign_classes[i].classes, + sizeof(mv->classes[i])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) + mv->class0_bit[i] = frame_ctx->class0_bits[i].class0[0]; + + for (i = 0; i < ARRAY_SIZE(mv->bits); i++) + memcpy(mv->bits[i], frame_ctx->class0_bits[i].bits, sizeof(mv->bits[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) + for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) + memcpy(mv->class0_fr[i][j], frame_ctx->class0_fp_hp[i].class0_fp[j], + sizeof(mv->class0_fr[0][0])); + + for (i = 0; i < ARRAY_SIZE(mv->fr); i++) + memcpy(mv->fr[i], frame_ctx->class0_fp_hp[i].fp, sizeof(mv->fr[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) + mv->class0_hp[i] = frame_ctx->class0_fp_hp[i].class0_hp; + + for (i = 0; i < ARRAY_SIZE(mv->hp); i++) + mv->hp[i] = frame_ctx->class0_fp_hp[i].hp; +} + +static void vdec_vp9_slice_helper_map_framectx(struct v4l2_vp9_frame_context *frame_ctx_helper, + struct vdec_vp9_slice_frame_ctx *frame_ctx) +{ + struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; + u32 i, j, k; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) + memcpy(frame_ctx->tx_p8x8[i], frame_ctx_helper->tx8[i], + sizeof(frame_ctx_helper->tx8[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) + memcpy(frame_ctx->tx_p16x16[i], frame_ctx_helper->tx16[i], + sizeof(frame_ctx_helper->tx16[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) + memcpy(frame_ctx->tx_p32x32[i], frame_ctx_helper->tx32[i], + sizeof(frame_ctx_helper->tx32[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) + for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) + vdec_vp9_slice_map_from_coef(i, j, k, frame_ctx, + frame_ctx_helper); + + memcpy(frame_ctx->skip_probs, frame_ctx_helper->skip, sizeof(frame_ctx_helper->skip)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) + memcpy(frame_ctx->inter_mode_probs[i], frame_ctx_helper->inter_mode[i], + sizeof(frame_ctx_helper->inter_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) + memcpy(frame_ctx->switch_interp_prob[i], frame_ctx_helper->interp_filter[i], + sizeof(frame_ctx_helper->interp_filter[0])); + + memcpy(frame_ctx->intra_inter_prob, frame_ctx_helper->is_inter, + sizeof(frame_ctx_helper->is_inter)); + + memcpy(frame_ctx->comp_inter_prob, frame_ctx_helper->comp_mode, + sizeof(frame_ctx_helper->comp_mode)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) + memcpy(frame_ctx->single_ref_prob[i], frame_ctx_helper->single_ref[i], + sizeof(frame_ctx_helper->single_ref[0])); + + memcpy(frame_ctx->comp_ref_prob, frame_ctx_helper->comp_ref, + sizeof(frame_ctx_helper->comp_ref)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) + memcpy(frame_ctx->y_mode_prob[i], frame_ctx_helper->y_mode[i], + sizeof(frame_ctx_helper->y_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) + memcpy(frame_ctx->uv_mode_prob[i], frame_ctx_helper->uv_mode[i], + sizeof(frame_ctx_helper->uv_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) + memcpy(frame_ctx->partition_prob[i], frame_ctx_helper->partition[i], + sizeof(frame_ctx_helper->partition[0])); + + memcpy(frame_ctx->joint, mv->joint, sizeof(mv->joint)); + + for (i = 0; i < ARRAY_SIZE(mv->sign); i++) + frame_ctx->sign_classes[i].sign = mv->sign[i]; + + for (i = 0; i < ARRAY_SIZE(mv->classes); i++) + memcpy(frame_ctx->sign_classes[i].classes, mv->classes[i], + sizeof(mv->classes[i])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) + frame_ctx->class0_bits[i].class0[0] = mv->class0_bit[i]; + + for (i = 0; i < ARRAY_SIZE(mv->bits); i++) + memcpy(frame_ctx->class0_bits[i].bits, mv->bits[i], sizeof(mv->bits[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) + for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) + memcpy(frame_ctx->class0_fp_hp[i].class0_fp[j], mv->class0_fr[i][j], + sizeof(mv->class0_fr[0][0])); + + for (i = 0; i < ARRAY_SIZE(mv->fr); i++) + memcpy(frame_ctx->class0_fp_hp[i].fp, mv->fr[i], sizeof(mv->fr[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) + frame_ctx->class0_fp_hp[i].class0_hp = mv->class0_hp[i]; + + for (i = 0; i < ARRAY_SIZE(mv->hp); i++) + frame_ctx->class0_fp_hp[i].hp = mv->hp[i]; +} + +static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct vdec_vp9_slice_frame_ctx *pre_frame_ctx; + struct v4l2_vp9_frame_context *pre_frame_ctx_helper; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_frame_counts *counts; + struct v4l2_vp9_frame_symbol_counts *counts_helper; + struct vdec_vp9_slice_uncompressed_header *uh; + bool frame_is_intra; + bool use_128; + + uh = &vsi->frame.uh; + pre_frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + pre_frame_ctx_helper = &instance->frame_ctx_helper; + frame_ctx = (struct vdec_vp9_slice_frame_ctx *)instance->prob.va; + counts = (struct vdec_vp9_slice_frame_counts *)instance->counts.va; + counts_helper = &instance->counts_helper; + + if (!uh->refresh_frame_context) + return 0; + + if (!uh->frame_parallel_decoding_mode) { + vdec_vp9_slice_counts_map_helper(&instance->counts_map, counts, counts_helper); + + frame_is_intra = !vsi->frame.uh.frame_type || vsi->frame.uh.intra_only; + /* check default prob */ + if (!instance->dirty[uh->frame_context_idx]) + vdec_vp9_slice_framectx_map_helper(frame_is_intra, + vdec_vp9_slice_default_frame_ctx, + frame_ctx, + pre_frame_ctx_helper); + else + vdec_vp9_slice_framectx_map_helper(frame_is_intra, + pre_frame_ctx, + frame_ctx, + pre_frame_ctx_helper); + + use_128 = !frame_is_intra && !vsi->frame.uh.last_frame_type; + v4l2_vp9_adapt_coef_probs(pre_frame_ctx_helper, + counts_helper, + use_128, + frame_is_intra); + if (!frame_is_intra) + v4l2_vp9_adapt_noncoef_probs(pre_frame_ctx_helper, + counts_helper, + V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, + vsi->frame.uh.interpolation_filter, + vsi->frame.ch.tx_mode, + vsi->frame.uh.allow_high_precision_mv ? + V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV : 0); + vdec_vp9_slice_helper_map_framectx(pre_frame_ctx_helper, pre_frame_ctx); + } else { + memcpy(pre_frame_ctx, frame_ctx, sizeof(*frame_ctx)); + } + + instance->dirty[uh->frame_context_idx] = 1; + + return 0; +} + +static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u LAT CRC 0x%08x %lx %lx\n", + pfc->seq, vsi->state.crc[0], + (unsigned long)vsi->trans.dma_addr, + (unsigned long)vsi->trans.dma_addr_end); + + /* buffer full, need to re-decode */ + if (vsi->state.full) { + /* buffer not enough */ + if (vsi->trans.dma_addr_end - vsi->trans.dma_addr == + vsi->ube.size) + return -ENOMEM; + return -EAGAIN; + } + + vdec_vp9_slice_update_prob(instance, vsi); + + instance->width = vsi->frame.uh.frame_width; + instance->height = vsi->frame.uh.frame_height; + instance->frame_type = vsi->frame.uh.frame_type; + instance->show_frame = vsi->frame.uh.show_frame; + + return 0; +} + +static int vdec_vp9_slice_setup_core_to_dst_buf(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *dst; + + dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); + if (!dst) + return -EINVAL; + + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst, true); + return 0; +} + +static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc, + struct vdec_vp9_slice_vsi *vsi, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_buffer *vb; + struct vb2_queue *vq; + struct vdec_vp9_slice_reference *ref; + int plane; + int size; + int idx; + int w; + int h; + int i; + + plane = instance->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + size = ALIGN(w, 64) * ALIGN(h, 64); + + /* frame buffer */ + vsi->fb.y.dma_addr = fb->base_y.dma_addr; + if (plane == 1) + vsi->fb.c.dma_addr = fb->base_y.dma_addr + size; + else + vsi->fb.c.dma_addr = fb->base_c.dma_addr; + + /* reference buffers */ + vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!vq) + return -EINVAL; + + /* get current output buffer */ + vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; + if (!vb) + return -EINVAL; + + /* update internal buffer's width/height */ + for (i = 0; i < vq->num_buffers; i++) { + if (vb == vq->bufs[i]) { + instance->dpb[i].width = w; + instance->dpb[i].height = h; + break; + } + } + + /* + * get buffer's width/height from instance + * get buffer address from vb2buf + */ + for (i = 0; i < 3; i++) { + ref = &vsi->frame.ref[i]; + idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); + if (idx < 0) { + ref->frame_width = w; + ref->frame_height = h; + memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); + } else { + ref->frame_width = instance->dpb[idx].width; + ref->frame_height = instance->dpb[idx].height; + vb = vq->bufs[idx]; + vsi->ref[i].y.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (plane == 1) + vsi->ref[i].c.dma_addr = + vsi->ref[i].y.dma_addr + size; + else + vsi->ref[i].c.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + vdec_vp9_slice_setup_state(vsi); + + ret = vdec_vp9_slice_setup_core_to_dst_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, lat_buf); + if (ret) + goto err; + + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[1]); + + return 0; + +err: + return ret; +} + +static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[1], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[0], vsi->state.crc[1], + vsi->state.crc[2], vsi->state.crc[3]); + mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[4], vsi->state.crc[5], + vsi->state.crc[6], vsi->state.crc[7]); + + return 0; +} + +static int vdec_vp9_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_init_vsi *vsi; + int ret; + + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->ctx = ctx; + instance->vpu.id = SCP_IPI_VDEC_LAT; + instance->vpu.core_id = SCP_IPI_VDEC_CORE; + instance->vpu.ctx = ctx; + instance->vpu.codec_type = ctx->current_codec; + + ret = vpu_dec_init(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "failed to init vpu dec, ret %d\n", ret); + goto error_vpu_init; + } + + /* init vsi and global flags */ + + vsi = instance->vpu.vsi; + if (!vsi) { + mtk_vcodec_err(instance, "failed to get VP9 vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + instance->init_vsi = vsi; + instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->core_vsi); + if (!instance->core_vsi) { + mtk_vcodec_err(instance, "failed to get VP9 core vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + + instance->irq = 1; + + ret = vdec_vp9_slice_init_default_frame_ctx(instance); + if (ret) + goto error_default_frame_ctx; + + ctx->drv_handle = instance; + + return 0; + +error_default_frame_ctx: +error_vsi: + vpu_dec_deinit(&instance->vpu); +error_vpu_init: + kfree(instance); + return ret; +} + +static void vdec_vp9_slice_deinit(void *h_vdec) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + if (!instance) + return; + + vpu_dec_deinit(&instance->vpu); + vdec_vp9_slice_free_working_buffer(instance); + vdec_msg_queue_deinit(&instance->ctx->msg_queue, instance->ctx); + kfree(instance); +} + +static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + mtk_vcodec_debug(instance, "flush ...\n"); + + vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); + return vpu_dec_reset(&instance->vpu); +} + +static void vdec_vp9_slice_get_pic_info(struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + unsigned int data[3]; + + mtk_vcodec_debug(instance, "w %u h %u\n", + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&instance->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); + ctx->picinfo.fb_sz[0] = instance->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = instance->vpu.fb_sz[1]; +} + +static void vdec_vp9_slice_get_dpb_size(struct vdec_vp9_slice_instance *instance, + unsigned int *dpb_sz) +{ + /* refer VP9 specification */ + *dpb_sz = 9; +} + +static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_vp9_slice_get_pic_info(instance); + break; + case GET_PARAM_DPB_SIZE: + vdec_vp9_slice_get_dpb_size(instance, out); + break; + case GET_PARAM_CROP_INFO: + mtk_vcodec_debug(instance, "No need to get vp9 crop information."); + break; + default: + mtk_vcodec_err(instance, "invalid get parameter type=%d\n", + type); + return -EINVAL; + } + + return 0; +} + +static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + struct vdec_lat_buf *lat_buf; + struct vdec_vp9_slice_pfc *pfc; + struct vdec_vp9_slice_vsi *vsi; + struct mtk_vcodec_ctx *ctx; + int ret; + + if (!instance || !instance->ctx) + return -EINVAL; + ctx = instance->ctx; + + /* init msgQ for the first time */ + if (vdec_msg_queue_init(&ctx->msg_queue, ctx, + vdec_vp9_slice_core_decode, + sizeof(*pfc))) + return -ENOMEM; + + /* bs NULL means flush decoder */ + if (!bs) + return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); + + lat_buf = vdec_msg_queue_dqbuf(&instance->ctx->msg_queue.lat_ctx); + if (!lat_buf) { + mtk_vcodec_err(instance, "Failed to get VP9 lat buf\n"); + return -EBUSY; + } + pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; + if (!pfc) + return -EINVAL; + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "Failed to setup VP9 lat ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, NULL, 0); + if (ret) { + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode timeout %d pic %d\n", ret, pfc->seq); + WRITE_ONCE(instance->vsi->state.timeout, 1); + } + vpu_dec_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); + ret = vdec_vp9_slice_update_lat(instance, lat_buf, pfc); + + /* LAT trans full, no more UBE or decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + mtk_vcodec_debug(instance, "lat dma addr: 0x%lx 0x%lx\n", + (unsigned long)pfc->vsi.trans.dma_addr, + (unsigned long)pfc->vsi.trans.dma_addr_end); + + vdec_msg_queue_update_ube_wptr(&ctx->msg_queue, + vsi->trans.dma_addr_end + + ctx->msg_queue.wdma_addr.dma_addr); + vdec_msg_queue_qbuf(&ctx->dev->msg_queue_core_ctx, lat_buf); + + return 0; +} + +static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_pfc *pfc; + struct mtk_vcodec_ctx *ctx = NULL; + struct vdec_fb *fb = NULL; + int ret = -EINVAL; + + if (!lat_buf) + goto err; + + pfc = lat_buf->private_data; + ctx = lat_buf->ctx; + if (!pfc || !ctx) + goto err; + + instance = ctx->drv_handle; + if (!instance) + goto err; + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + if (!fb) { + ret = -EBUSY; + goto err; + } + + ret = vdec_vp9_slice_setup_core(instance, fb, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_setup_core\n"); + goto err; + } + vdec_vp9_slice_vsi_to_remote(&pfc->vsi, instance->core_vsi); + + ret = vpu_dec_core(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "vpu_dec_core\n"); + goto err; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 core timeout pic %d\n", pfc->seq); + WRITE_ONCE(instance->core_vsi->state.timeout, 1); + } + vpu_dec_core_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(&pfc->vsi, instance->core_vsi, 1); + ret = vdec_vp9_slice_update_core(instance, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_update_core\n"); + goto err; + } + + pfc->vsi.trans.dma_addr_end += ctx->msg_queue.wdma_addr.dma_addr; + mtk_vcodec_debug(instance, "core dma_addr_end 0x%lx\n", + (unsigned long)pfc->vsi.trans.dma_addr_end); + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); + ctx->dev->vdec_pdata->cap_to_disp(ctx, 0, lat_buf->src_buf_req); + + return 0; + +err: + if (ctx && pfc) { + /* always update read pointer */ + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); + + if (fb) + ctx->dev->vdec_pdata->cap_to_disp(ctx, 1, lat_buf->src_buf_req); + } + return ret; +} + +const struct vdec_common_if vdec_vp9_slice_lat_if = { + .init = vdec_vp9_slice_init, + .decode = vdec_vp9_slice_lat_decode, + .get_param = vdec_vp9_slice_get_param, + .deinit = vdec_vp9_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c index 05a5b240e906..27b4b35039cf 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c @@ -16,16 +16,27 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { + enum mtk_vdec_hw_arch hw_arch = ctx->dev->vdec_pdata->hw_arch; int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: - ctx->dec_if = &vdec_h264_slice_if; + if (!ctx->dev->vdec_pdata->is_subdev_supported) { + ctx->dec_if = &vdec_h264_slice_if; + ctx->hw_id = MTK_VDEC_CORE; + } else { + ctx->dec_if = &vdec_h264_slice_multi_if; + ctx->hw_id = IS_VDEC_LAT_ARCH(hw_arch) ? MTK_VDEC_LAT0 : MTK_VDEC_CORE; + } break; case V4L2_PIX_FMT_H264: ctx->dec_if = &vdec_h264_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP8_FRAME: + ctx->dec_if = &vdec_vp8_slice_if; + ctx->hw_id = MTK_VDEC_CORE; + break; case V4L2_PIX_FMT_VP8: ctx->dec_if = &vdec_vp8_if; ctx->hw_id = MTK_VDEC_CORE; @@ -34,15 +45,17 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) ctx->dec_if = &vdec_vp9_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP9_FRAME: + ctx->dec_if = &vdec_vp9_slice_lat_if; + ctx->hw_id = MTK_VDEC_LAT0; + break; default: return -EINVAL; } - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ret = ctx->dec_if->init(ctx); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -70,15 +83,11 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, if (!ctx->drv_handle) return -EIO; - mtk_vdec_lock(ctx); - + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id); - - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -103,11 +112,9 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) if (!ctx->drv_handle) return; - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ctx->dec_if->deinit(ctx->drv_handle); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); ctx->drv_handle = NULL; } diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h index d467e8af4a84..076306ff2dd4 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h @@ -56,8 +56,11 @@ struct vdec_fb_node { extern const struct vdec_common_if vdec_h264_if; extern const struct vdec_common_if vdec_h264_slice_if; +extern const struct vdec_common_if vdec_h264_slice_multi_if; extern const struct vdec_common_if vdec_vp8_if; +extern const struct vdec_common_if vdec_vp8_slice_if; extern const struct vdec_common_if vdec_vp9_if; +extern const struct vdec_common_if vdec_vp9_slice_lat_if; /** * vdec_if_init() - initialize decode driver diff --git a/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h b/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h index bf54d6d9a857..47070be2a991 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h @@ -20,6 +20,7 @@ enum vdec_ipi_msgid { AP_IPIMSG_DEC_RESET = 0xA004, AP_IPIMSG_DEC_CORE = 0xA005, AP_IPIMSG_DEC_CORE_END = 0xA006, + AP_IPIMSG_DEC_GET_PARAM = 0xA007, VPU_IPIMSG_DEC_INIT_ACK = 0xB000, VPU_IPIMSG_DEC_START_ACK = 0xB001, @@ -28,6 +29,7 @@ enum vdec_ipi_msgid { VPU_IPIMSG_DEC_RESET_ACK = 0xB004, VPU_IPIMSG_DEC_CORE_ACK = 0xB005, VPU_IPIMSG_DEC_CORE_END_ACK = 0xB006, + VPU_IPIMSG_DEC_GET_PARAM_ACK = 0xB007, }; /** @@ -114,4 +116,38 @@ struct vdec_vpu_ipi_init_ack { uint32_t inst_id; }; +/** + * struct vdec_ap_ipi_get_param - for AP_IPIMSG_DEC_GET_PARAM + * @msg_id : AP_IPIMSG_DEC_GET_PARAM + * @inst_id : instance ID. Used if the ABI version >= 2. + * @data : picture information + * @param_type : get param type + * @codec_type : Codec fourcc + */ +struct vdec_ap_ipi_get_param { + u32 msg_id; + u32 inst_id; + u32 data[4]; + u32 param_type; + u32 codec_type; +}; + +/** + * struct vdec_vpu_ipi_get_param_ack - for VPU_IPIMSG_DEC_GET_PARAM_ACK + * @msg_id : VPU_IPIMSG_DEC_GET_PARAM_ACK + * @status : VPU execution result + * @ap_inst_addr : AP vcodec_vpu_inst instance address + * @data : picture information from SCP. + * @param_type : get param type + * @reserved : reserved param + */ +struct vdec_vpu_ipi_get_param_ack { + u32 msg_id; + s32 status; + u64 ap_inst_addr; + u32 data[4]; + u32 param_type; + u32 reserved; +}; + #endif diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c index 4b062a8128b4..ae500980ad45 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c @@ -212,11 +212,13 @@ static void vdec_msg_queue_core_work(struct work_struct *work) return; ctx = lat_buf->ctx; + mtk_vcodec_dec_enable_hardware(ctx, MTK_VDEC_CORE); mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE); lat_buf->core_decode(lat_buf); mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE); + mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE); vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf); if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) { diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h index b6ba66d3e026..c43d427f5f54 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h @@ -43,6 +43,7 @@ struct vdec_msg_queue_ctx { * @wdma_err_addr: wdma error address used for lat hardware * @slice_bc_addr: slice bc address used for lat hardware * @ts_info: need to set timestamp from output to capture + * @src_buf_req: output buffer media request object * * @private_data: shared information used to lat and core hardware * @ctx: mtk vcodec context information @@ -54,6 +55,7 @@ struct vdec_lat_buf { struct mtk_vcodec_mem wdma_err_addr; struct mtk_vcodec_mem slice_bc_addr; struct vb2_v4l2_buffer ts_info; + struct media_request *src_buf_req; void *private_data; struct mtk_vcodec_ctx *ctx; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c index dd35d2c5f920..35f4d5583084 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c @@ -6,6 +6,7 @@ #include "mtk_vcodec_drv.h" #include "mtk_vcodec_util.h" +#include "vdec_drv_if.h" #include "vdec_ipi_msg.h" #include "vdec_vpu_if.h" #include "mtk_vcodec_fw.h" @@ -33,8 +34,8 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) */ vpu->inst_id = 0xdeadbeef; - /* Firmware version field does not exist on MT8173. */ - if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) + /* VPU firmware does not contain a version field. */ + if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU) return; /* Check firmware version. */ @@ -54,6 +55,26 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) } } +static void handle_get_param_msg_ack(const struct vdec_vpu_ipi_get_param_ack *msg) +{ + struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) + (unsigned long)msg->ap_inst_addr; + + mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr); + + /* param_type is enum vdec_get_param_type */ + switch (msg->param_type) { + case GET_PARAM_PIC_INFO: + vpu->fb_sz[0] = msg->data[0]; + vpu->fb_sz[1] = msg->data[1]; + break; + default: + mtk_vcodec_err(vpu, "invalid get param type=%d", msg->param_type); + vpu->failure = 1; + break; + } +} + /* * vpu_dec_ipi_handler - Handler for VPU ipi message. * @@ -89,6 +110,9 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) case VPU_IPIMSG_DEC_CORE_END_ACK: break; + case VPU_IPIMSG_DEC_GET_PARAM_ACK: + handle_get_param_msg_ack(data); + break; default: mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id); break; @@ -217,6 +241,31 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len) return err; } +int vpu_dec_get_param(struct vdec_vpu_inst *vpu, uint32_t *data, + unsigned int len, unsigned int param_type) +{ + struct vdec_ap_ipi_get_param msg; + int err; + + mtk_vcodec_debug_enter(vpu); + + if (len > ARRAY_SIZE(msg.data)) { + mtk_vcodec_err(vpu, "invalid len = %d\n", len); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_id = AP_IPIMSG_DEC_GET_PARAM; + msg.inst_id = vpu->inst_id; + memcpy(msg.data, data, sizeof(unsigned int) * len); + msg.param_type = param_type; + msg.codec_type = vpu->codec_type; + + err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); + mtk_vcodec_debug(vpu, "- ret=%d", err); + return err; +} + int vpu_dec_core(struct vdec_vpu_inst *vpu) { return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE); diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h index 4cb3c7f5a3ad..0436bba91457 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h @@ -28,6 +28,8 @@ struct mtk_vcodec_ctx; * @wq : wait queue to wait VPU message ack * @handler : ipi handler for each decoder * @codec_type : use codec type to separate different codecs + * @capture_type: used capture type to separate different capture format + * @fb_sz : frame buffer size of each plane */ struct vdec_vpu_inst { int id; @@ -42,6 +44,8 @@ struct vdec_vpu_inst { wait_queue_head_t wq; mtk_vcodec_ipi_handler handler; unsigned int codec_type; + unsigned int capture_type; + unsigned int fb_sz[2]; }; /** @@ -104,4 +108,15 @@ int vpu_dec_core(struct vdec_vpu_inst *vpu); */ int vpu_dec_core_end(struct vdec_vpu_inst *vpu); +/** + * vpu_dec_get_param - get param from scp + * + * @vpu : instance for vdec_vpu_inst + * @data: meta data to pass bitstream info to VPU decoder + * @len : meta data length + * @param_type : get param type + */ +int vpu_dec_get_param(struct vdec_vpu_inst *vpu, uint32_t *data, + unsigned int len, unsigned int param_type); + #endif diff --git a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c index e7899d8a3e4e..d3570c4c177d 100644 --- a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c @@ -18,7 +18,7 @@ static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data) msg->vpu_inst_addr); /* Firmware version field value is unspecified on MT8173. */ - if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173) + if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU) return; /* Check firmware version. */ diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index d8e5534e80c8..88f81a134ba0 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -45,9 +45,9 @@ struct tegra_vde_h264_decoder_ctx { }; struct h264_reflists { - u8 p[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b1[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference p[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference b0[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference b1[V4L2_H264_NUM_DPB_ENTRIES]; }; static int tegra_vde_wait_mbe(struct tegra_vde *vde) @@ -765,10 +765,10 @@ static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); struct tegra_ctx_h264 *h = &ctx->h264; struct v4l2_h264_reflist_builder b; + struct v4l2_h264_reference *dpb_id; struct h264_reflists reflists; struct vb2_buffer *ref; unsigned int i; - u8 *dpb_id; int err; /* @@ -811,14 +811,16 @@ static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, } for (i = 0; i < b.num_valid; i++) { - ref = get_ref_buf(ctx, dst, dpb_id[i]); + int dpb_idx = dpb_id[i].index; - err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_id[i], + ref = get_ref_buf(ctx, dst, dpb_idx); + + err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_idx, h264->dpb_frames_nb++); if (err) return err; - if (b.refs[dpb_id[i]].pic_order_count < b.cur_pic_order_count) + if (b.refs[dpb_idx].top_field_order_cnt < b.cur_pic_order_count) h264->dpb_ref_frames_with_earlier_poc_nb++; } @@ -880,6 +882,9 @@ static int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) return -EOPNOTSUPP; + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + return -EOPNOTSUPP; + if (h->sps->profile_idc == 66) h264->baseline_profile = 1; diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig index 5afa373e534f..1ac0a6e91111 100644 --- a/drivers/media/platform/nxp/Kconfig +++ b/drivers/media/platform/nxp/Kconfig @@ -11,7 +11,6 @@ config VIDEO_IMX_MIPI_CSIS select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API - default n help Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs. @@ -21,7 +20,6 @@ config VIDEO_VIU depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C select VIDEOBUF_DMA_CONTIG - default y help Support for Freescale VIU video driver. This device captures video data, or overlays video on DIU frame buffer. diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index ae70d3a0dc24..d838e875616c 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -102,11 +102,11 @@ enum mxc_jpeg_image_format { MXC_JPEG_INVALID = -1, MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */ MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */ - MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */ + MXC_JPEG_BGR = 0x2, /* BGR packed format */ MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */ MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */ MXC_JPEG_RESERVED = 0x5, - MXC_JPEG_ARGB = 0x6, + MXC_JPEG_ABGR = 0x6, }; #include "mxc-jpeg.h" diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index d1ec1f4b506b..f36b512bae51 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -8,7 +8,7 @@ * Baseline and extended sequential jpeg decoding is supported. * Progressive jpeg decoding is not supported by the IP. * Supports encode and decode of various formats: - * YUV444, YUV422, YUV420, RGB, ARGB, Gray + * YUV444, YUV422, YUV420, BGR, ABGR, Gray * YUV420 is the only multi-planar format supported. * Minimum resolution is 64 x 64, maximum 8192 x 8192. * To achieve 8192 x 8192, modify in defconfig: CONFIG_CMA_SIZE_MBYTES=320 @@ -73,8 +73,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .flags = MXC_JPEG_FMT_TYPE_ENC, }, { - .name = "RGB", /*RGBRGB packed format*/ - .fourcc = V4L2_PIX_FMT_RGB24, + .name = "BGR", /*BGR packed format*/ + .fourcc = V4L2_PIX_FMT_BGR24, .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, @@ -82,10 +82,11 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { - .name = "ARGB", /* ARGBARGB packed format */ - .fourcc = V4L2_PIX_FMT_ARGB32, + .name = "ABGR", /* ABGR packed format */ + .fourcc = V4L2_PIX_FMT_ABGR32, .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 4, .depth = 32, @@ -93,6 +94,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ @@ -104,6 +106,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 4, .v_align = 4, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV422", /* YUYV */ @@ -115,6 +118,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 4, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV444", /* YUVYUV */ @@ -126,6 +130,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "Gray", /* Gray (Y8/Y12) or Single Comp */ @@ -137,6 +142,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, }; @@ -309,6 +315,9 @@ struct mxc_jpeg_src_buf { /* mxc-jpeg specific */ bool dht_needed; bool jpeg_parse_error; + const struct mxc_jpeg_fmt *fmt; + int w; + int h; }; static inline struct mxc_jpeg_src_buf *vb2_to_mxc_buf(struct vb2_buffer *vb) @@ -321,6 +330,9 @@ static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-3)"); +static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision); +static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q); + static void _bswap16(u16 *a) { *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); @@ -408,10 +420,10 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc) return MXC_JPEG_YUV420; case V4L2_PIX_FMT_YUV24: return MXC_JPEG_YUV444; - case V4L2_PIX_FMT_RGB24: - return MXC_JPEG_RGB; - case V4L2_PIX_FMT_ARGB32: - return MXC_JPEG_ARGB; + case V4L2_PIX_FMT_BGR24: + return MXC_JPEG_BGR; + case V4L2_PIX_FMT_ABGR32: + return MXC_JPEG_ABGR; default: return MXC_JPEG_INVALID; } @@ -684,11 +696,11 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof, sof->comp[0].h = 0x2; break; case V4L2_PIX_FMT_YUV24: - case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: default: sof->components_no = 3; break; - case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: sof->components_no = 4; break; case V4L2_PIX_FMT_GREY: @@ -716,11 +728,11 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos, sos->components_no = 3; break; case V4L2_PIX_FMT_YUV24: - case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: default: sos->components_no = 3; break; - case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: sos->components_no = 4; break; case V4L2_PIX_FMT_GREY: @@ -751,8 +763,8 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi)); offset += ARRAY_SIZE(jpeg_soi); - if (fourcc == V4L2_PIX_FMT_RGB24 || - fourcc == V4L2_PIX_FMT_ARGB32) { + if (fourcc == V4L2_PIX_FMT_BGR24 || + fourcc == V4L2_PIX_FMT_ABGR32) { memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14)); offset += sizeof(jpeg_app14); } else { @@ -916,6 +928,67 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); } +static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, + struct mxc_jpeg_src_buf *jpeg_src_buf) +{ + struct device *dev = ctx->mxc_jpeg->dev; + struct mxc_jpeg_q_data *q_data_cap; + + if (!jpeg_src_buf->fmt) + return false; + + q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (q_data_cap->fmt != jpeg_src_buf->fmt || + q_data_cap->w != jpeg_src_buf->w || + q_data_cap->h != jpeg_src_buf->h) { + dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", + q_data_cap->w, q_data_cap->h, + jpeg_src_buf->w, jpeg_src_buf->h, + (jpeg_src_buf->fmt->fourcc & 0xff), + (jpeg_src_buf->fmt->fourcc >> 8) & 0xff, + (jpeg_src_buf->fmt->fourcc >> 16) & 0xff, + (jpeg_src_buf->fmt->fourcc >> 24) & 0xff); + + /* + * set-up the capture queue with the pixelformat and resolution + * detected from the jpeg output stream + */ + q_data_cap->w = jpeg_src_buf->w; + q_data_cap->h = jpeg_src_buf->h; + q_data_cap->fmt = jpeg_src_buf->fmt; + q_data_cap->w_adjusted = q_data_cap->w; + q_data_cap->h_adjusted = q_data_cap->h; + + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data_cap->w_adjusted, + q_data_cap->w_adjusted, /* adjust up */ + MXC_JPEG_MAX_WIDTH, + q_data_cap->fmt->h_align, + &q_data_cap->h_adjusted, + q_data_cap->h_adjusted, /* adjust up */ + MXC_JPEG_MAX_HEIGHT, + q_data_cap->fmt->v_align, + 0); + + /* setup bytesperline/sizeimage for capture queue */ + mxc_jpeg_bytesperline(q_data_cap, jpeg_src_buf->fmt->precision); + mxc_jpeg_sizeimage(q_data_cap); + notify_src_chg(ctx); + ctx->source_change = 1; + } + return ctx->source_change ? true : false; +} + +static int mxc_jpeg_job_ready(void *priv) +{ + struct mxc_jpeg_ctx *ctx = priv; + + return ctx->source_change ? 0 : 1; +} + static void mxc_jpeg_device_run(void *priv) { struct mxc_jpeg_ctx *ctx = priv; @@ -963,6 +1036,13 @@ static void mxc_jpeg_device_run(void *priv) return; } + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) { + if (ctx->source_change || mxc_jpeg_source_change(ctx, jpeg_src_buf)) { + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return; + } + } mxc_jpeg_enable(reg); mxc_jpeg_set_l_endian(reg, 1); @@ -1009,6 +1089,7 @@ static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx) q->last_buffer_dequeued = true; wake_up(&q->done_wq); ctx->stopped = 0; + ctx->header_parsed = false; } static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, @@ -1081,6 +1162,8 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { + if (*nplanes != q_data->fmt->colplanes) + return -EINVAL; for (i = 0; i < *nplanes; i++) { if (sizes[i] < q_data->sizeimage[i]) return -EINVAL; @@ -1102,6 +1185,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); int ret; + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type)) + ctx->source_change = 0; dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); q_data->sequence = 0; @@ -1175,14 +1260,17 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) if (mxc_formats[i].subsampling == header->frame.subsampling && - mxc_formats[i].nc == header->frame.num_components) { + mxc_formats[i].nc == header->frame.num_components && + mxc_formats[i].precision == header->frame.precision) { fourcc = mxc_formats[i].fourcc; break; } if (fourcc == 0) { - dev_err(dev, "Could not identify image format nc=%d, subsampling=%d\n", + dev_err(dev, + "Could not identify image format nc=%d, subsampling=%d, precision=%d\n", header->frame.num_components, - header->frame.subsampling); + header->frame.subsampling, + header->frame.precision); return fourcc; } /* @@ -1190,9 +1278,9 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, * encoded with 3 components have RGB colorspace, see Recommendation * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding */ - if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_RGB24) { + if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) { if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB) - fourcc = V4L2_PIX_FMT_RGB24; + fourcc = V4L2_PIX_FMT_BGR24; else fourcc = V4L2_PIX_FMT_YUV24; } @@ -1200,26 +1288,29 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, return fourcc; } -static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, - u32 precision) +static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision) { /* Bytes distance between the leftmost pixels in two adjacent lines */ if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) { /* bytesperline unused for compressed formats */ q->bytesperline[0] = 0; q->bytesperline[1] = 0; - } else if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) { + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420) { /* When the image format is planar the bytesperline value * applies to the first plane and is divided by the same factor * as the width field for the other planes */ - q->bytesperline[0] = q->w * (precision / 8) * - (q->fmt->depth / 8); + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = q->bytesperline[0]; + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) { + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * 2; + q->bytesperline[1] = 0; + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) { + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * q->fmt->nc; + q->bytesperline[1] = 0; } else { - /* single plane formats */ - q->bytesperline[0] = q->w * (precision / 8) * - (q->fmt->depth / 8); + /* grayscale */ + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = 0; } } @@ -1245,17 +1336,17 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) } } -static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, - u8 *src_addr, u32 size, bool *dht_needed) +static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) { struct device *dev = ctx->mxc_jpeg->dev; - struct mxc_jpeg_q_data *q_data_out, *q_data_cap; - enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - bool src_chg = false; + struct mxc_jpeg_q_data *q_data_out; u32 fourcc; struct v4l2_jpeg_header header; struct mxc_jpeg_sof *psof = NULL; struct mxc_jpeg_sos *psos = NULL; + struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); + u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0); + u32 size = vb2_get_plane_payload(vb, 0); int ret; memset(&header, 0, sizeof(header)); @@ -1266,7 +1357,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, } /* if DHT marker present, no need to inject default one */ - *dht_needed = (header.num_dht == 0); + jpeg_src_buf->dht_needed = (header.num_dht == 0); q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -1274,16 +1365,15 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, dev_warn(dev, "Invalid user resolution 0x0"); dev_warn(dev, "Keeping resolution from JPEG: %dx%d", header.frame.width, header.frame.height); - q_data_out->w = header.frame.width; - q_data_out->h = header.frame.height; } else if (header.frame.width != q_data_out->w || header.frame.height != q_data_out->h) { dev_err(dev, "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)", header.frame.width, header.frame.height, q_data_out->w, q_data_out->h); - return -EINVAL; } + q_data_out->w = header.frame.width; + q_data_out->h = header.frame.height; if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) { dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n", header.frame.width, header.frame.height); @@ -1316,51 +1406,13 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, if (fourcc == 0) return -EINVAL; - /* - * set-up the capture queue with the pixelformat and resolution - * detected from the jpeg output stream - */ - q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); - if (q_data_cap->w != header.frame.width || - q_data_cap->h != header.frame.height) - src_chg = true; - q_data_cap->w = header.frame.width; - q_data_cap->h = header.frame.height; - q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc); - q_data_cap->w_adjusted = q_data_cap->w; - q_data_cap->h_adjusted = q_data_cap->h; - /* - * align up the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data_cap->w_adjusted, - q_data_cap->w_adjusted, /* adjust up */ - MXC_JPEG_MAX_WIDTH, - q_data_cap->fmt->h_align, - &q_data_cap->h_adjusted, - q_data_cap->h_adjusted, /* adjust up */ - MXC_JPEG_MAX_HEIGHT, - q_data_cap->fmt->v_align, - 0); - dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", - q_data_cap->w, q_data_cap->h, - q_data_cap->w_adjusted, q_data_cap->h_adjusted, - (fourcc & 0xff), - (fourcc >> 8) & 0xff, - (fourcc >> 16) & 0xff, - (fourcc >> 24) & 0xff); - - /* setup bytesperline/sizeimage for capture queue */ - mxc_jpeg_bytesperline(q_data_cap, header.frame.precision); - mxc_jpeg_sizeimage(q_data_cap); + jpeg_src_buf->fmt = mxc_jpeg_find_format(ctx, fourcc); + jpeg_src_buf->w = header.frame.width; + jpeg_src_buf->h = header.frame.height; + ctx->header_parsed = true; - /* - * if the CAPTURE format was updated with new values, regardless of - * whether they match the values set by the client or not, signal - * a source change event - */ - if (src_chg) - notify_src_chg(ctx); + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) + mxc_jpeg_source_change(ctx, jpeg_src_buf); return 0; } @@ -1381,10 +1433,7 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) jpeg_src_buf = vb2_to_mxc_buf(vb); jpeg_src_buf->jpeg_parse_error = false; - ret = mxc_jpeg_parse(ctx, - (u8 *)vb2_plane_vaddr(vb, 0), - vb2_get_plane_payload(vb, 0), - &jpeg_src_buf->dht_needed); + ret = mxc_jpeg_parse(ctx, vb); if (ret) jpeg_src_buf->jpeg_parse_error = true; @@ -1422,7 +1471,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) i, vb2_plane_size(vb, i), sizeimage); return -EINVAL; } - vb2_set_plane_payload(vb, i, sizeimage); } return 0; } @@ -1440,6 +1488,7 @@ static void mxc_jpeg_buf_finish(struct vb2_buffer *vb) if (list_empty(&q->done_list)) { vbuf->flags |= V4L2_BUF_FLAG_LAST; ctx->stopped = 0; + ctx->header_parsed = false; } } @@ -1470,7 +1519,6 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->mxc_jpeg->lock; src_vq->dev = ctx->mxc_jpeg->dev; - src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */ ret = vb2_queue_init(src_vq); if (ret) @@ -1510,7 +1558,7 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) q[i]->h = MXC_JPEG_DEFAULT_HEIGHT; q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH; q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT; - mxc_jpeg_bytesperline(q[i], 8); + mxc_jpeg_bytesperline(q[i], q[i]->fmt->precision); mxc_jpeg_sizeimage(q[i]); } } @@ -1569,12 +1617,8 @@ free: static int mxc_jpeg_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); - strscpy(cap->driver, MXC_JPEG_NAME " codec", sizeof(cap->driver)); strscpy(cap->card, MXC_JPEG_NAME " codec", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(mxc_jpeg->dev)); cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -1585,26 +1629,42 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type); - if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) { return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, MXC_JPEG_FMT_TYPE_ENC); - else + } else if (!ctx->header_parsed) { return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, MXC_JPEG_FMT_TYPE_RAW); + } else { + /* For the decoder CAPTURE queue, only enumerate the raw formats + * supported for the format currently active on OUTPUT + * (more precisely what was propagated on capture queue + * after jpeg parse on the output buffer) + */ + if (f->index) + return -EINVAL; + f->pixelformat = q_data->fmt->fourcc; + strscpy(f->description, q_data->fmt->name, sizeof(f->description)); + return 0; + } } static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC : + MXC_JPEG_FMT_TYPE_RAW; + int ret; + ret = enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, type); + if (ret) + return ret; if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) - return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, - MXC_JPEG_FMT_TYPE_ENC); - else - return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, - MXC_JPEG_FMT_TYPE_RAW); + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION; + return 0; } static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt, @@ -1652,7 +1712,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm } /* calculate bytesperline & sizeimage into the tmp_q */ - mxc_jpeg_bytesperline(&tmp_q, 8); + mxc_jpeg_bytesperline(&tmp_q, fmt->precision); mxc_jpeg_sizeimage(&tmp_q); /* adjust user format according to our calculations */ @@ -1819,12 +1879,40 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { int ret; + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct vb2_queue *dst_vq; + struct mxc_jpeg_q_data *q_data_cap; + enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + struct v4l2_format fc; ret = mxc_jpeg_try_fmt_vid_out(file, priv, f); if (ret) return ret; - return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + if (ret) + return ret; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE) + return 0; + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, cap_type); + if (!dst_vq) + return -EINVAL; + + if (vb2_is_busy(dst_vq)) + return 0; + + q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); + if (q_data_cap->w == f->fmt.pix_mp.width && q_data_cap->h == f->fmt.pix_mp.height) + return 0; + memset(&fc, 0, sizeof(fc)); + fc.type = cap_type; + fc.fmt.pix_mp.pixelformat = q_data_cap->fmt->fourcc; + fc.fmt.pix_mp.width = f->fmt.pix_mp.width; + fc.fmt.pix_mp.height = f->fmt.pix_mp.height; + + return mxc_jpeg_s_fmt_vid_cap(file, priv, &fc); } static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, @@ -1962,6 +2050,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = { }; static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = { + .job_ready = mxc_jpeg_job_ready, .device_run = mxc_jpeg_device_run, }; @@ -2213,9 +2302,33 @@ static int mxc_jpeg_runtime_suspend(struct device *dev) } #endif +#ifdef CONFIG_PM_SLEEP +static int mxc_jpeg_suspend(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + + v4l2_m2m_suspend(jpeg->m2m_dev); + return pm_runtime_force_suspend(dev); +} + +static int mxc_jpeg_resume(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + + v4l2_m2m_resume(jpeg->m2m_dev); + return ret; +} +#endif + static const struct dev_pm_ops mxc_jpeg_pm_ops = { SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, mxc_jpeg_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) }; static int mxc_jpeg_remove(struct platform_device *pdev) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index f53f004ba851..760eaf5387a1 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -17,7 +17,7 @@ #define MXC_JPEG_FMT_TYPE_RAW 1 #define MXC_JPEG_DEFAULT_WIDTH 1280 #define MXC_JPEG_DEFAULT_HEIGHT 720 -#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_RGB24 +#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_BGR24 #define MXC_JPEG_MIN_WIDTH 64 #define MXC_JPEG_MIN_HEIGHT 64 #define MXC_JPEG_MAX_WIDTH 0x2000 @@ -49,6 +49,7 @@ enum mxc_jpeg_mode { * @h_align: horizontal alignment order (align to 2^h_align) * @v_align: vertical alignment order (align to 2^v_align) * @flags: flags describing format applicability + * @precision: jpeg sample precision */ struct mxc_jpeg_fmt { const char *name; @@ -60,6 +61,7 @@ struct mxc_jpeg_fmt { int h_align; int v_align; u32 flags; + u8 precision; }; struct mxc_jpeg_desc { @@ -93,6 +95,8 @@ struct mxc_jpeg_ctx { unsigned int stopping; unsigned int stopped; unsigned int slot; + unsigned int source_change; + bool header_parsed; }; struct mxc_jpeg_slot_data { diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 0a72734db55e..80b1c021d14a 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -243,12 +243,6 @@ #define MIPI_CSI2_DATA_TYPE_RAW14 0x2d #define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) -enum { - ST_POWERED = 1, - ST_STREAMING = 2, - ST_SUSPENDED = 4, -}; - struct mipi_csis_event { bool debug; u32 mask; @@ -310,7 +304,7 @@ struct mipi_csis_info { unsigned int num_clocks; }; -struct csi_state { +struct mipi_csis_device { struct device *dev; void __iomem *regs; struct clk_bulk_data *clks; @@ -328,10 +322,9 @@ struct csi_state { u32 hs_settle; u32 clk_settle; - struct mutex lock; /* Protect csis_fmt, format_mbus and state */ + struct mutex lock; /* Protect csis_fmt and format_mbus */ const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM]; - u32 state; spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; @@ -470,6 +463,34 @@ static const struct csis_pix_format mipi_csis_formats[] = { .output = MEDIA_BUS_FMT_SRGGB14_1X14, .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, + }, + /* JPEG */ + { + .code = MEDIA_BUS_FMT_JPEG_1X8, + .output = MEDIA_BUS_FMT_JPEG_1X8, + /* + * Map JPEG_1X8 to the RAW8 datatype. + * + * The CSI-2 specification suggests in Annex A "JPEG8 Data + * Format (informative)" to transmit JPEG data using one of the + * Data Types aimed to represent arbitrary data, such as the + * "User Defined Data Type 1" (0x30). + * + * However, when configured with a User Defined Data Type, the + * CSIS outputs data in quad pixel mode regardless of the mode + * selected in the MIPI_CSIS_ISP_CONFIG_CH register. Neither of + * the IP cores connected to the CSIS in i.MX SoCs (CSI bridge + * or ISI) support quad pixel mode, so this will never work in + * practice. + * + * Some sensors (such as the OV5640) send JPEG data using the + * RAW8 data type. This is usable and works, so map the JPEG + * format to RAW8. If the CSIS ends up being integrated in an + * SoC that can support quad pixel mode, this will have to be + * revisited. + */ + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, } }; @@ -487,59 +508,60 @@ static const struct csis_pix_format *find_csis_format(u32 code) * Hardware configuration */ -static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) +static inline u32 mipi_csis_read(struct mipi_csis_device *csis, u32 reg) { - return readl(state->regs + reg); + return readl(csis->regs + reg); } -static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) +static inline void mipi_csis_write(struct mipi_csis_device *csis, u32 reg, + u32 val) { - writel(val, state->regs + reg); + writel(val, csis->regs + reg); } -static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) +static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, bool on) { - mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); + mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); } -static void mipi_csis_sw_reset(struct csi_state *state) +static void mipi_csis_sw_reset(struct mipi_csis_device *csis) { - u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + u32 val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_RESET); usleep_range(10, 20); } -static void mipi_csis_system_enable(struct csi_state *state, int on) +static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) { u32 val, mask; - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); if (on) val |= MIPI_CSIS_CMN_CTRL_ENABLE; else val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - val = mipi_csis_read(state, MIPI_CSIS_DPHY_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_DPHY_CMN_CTRL); val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE; if (on) { - mask = (1 << (state->bus.num_data_lanes + 1)) - 1; + mask = (1 << (csis->bus.num_data_lanes + 1)) - 1; val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); } - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); } -/* Called with the state.lock mutex held */ -static void __mipi_csis_set_format(struct csi_state *state) +/* Called with the csis.lock mutex held */ +static void __mipi_csis_set_format(struct mipi_csis_device *csis) { - struct v4l2_mbus_framefmt *mf = &state->format_mbus[CSIS_PAD_SINK]; + struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK]; u32 val; /* Color format */ - val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0)); + val = mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0)); val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK | MIPI_CSIS_ISPCFG_PIXEL_MASK); @@ -556,28 +578,28 @@ static void __mipi_csis_set_format(struct csi_state *state) * * TODO: Verify which other formats require DUAL (or QUAD) modes. */ - if (state->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) + if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; - val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type); - mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val); + val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type); + mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ val = mf->width | (mf->height << 16); - mipi_csis_write(state, MIPI_CSIS_ISP_RESOL_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val); } -static int mipi_csis_calculate_params(struct csi_state *state) +static int mipi_csis_calculate_params(struct mipi_csis_device *csis) { s64 link_freq; u32 lane_rate; /* Calculate the line rate from the pixel rate. */ - link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, - state->csis_fmt->width, - state->bus.num_data_lanes * 2); + link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler, + csis->csis_fmt->width, + csis->bus.num_data_lanes * 2); if (link_freq < 0) { - dev_err(state->dev, "Unable to obtain link frequency: %d\n", + dev_err(csis->dev, "Unable to obtain link frequency: %d\n", (int)link_freq); return link_freq; } @@ -585,7 +607,7 @@ static int mipi_csis_calculate_params(struct csi_state *state) lane_rate = link_freq * 2; if (lane_rate < 80000000 || lane_rate > 1500000000) { - dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate); + dev_dbg(csis->dev, "Out-of-bound lane rate %u\n", lane_rate); return -EINVAL; } @@ -595,57 +617,57 @@ static int mipi_csis_calculate_params(struct csi_state *state) * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until * we figure out how to compute it correctly. */ - state->hs_settle = (lane_rate - 5000000) / 45000000; - state->clk_settle = 0; + csis->hs_settle = (lane_rate - 5000000) / 45000000; + csis->clk_settle = 0; - dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", - lane_rate, state->clk_settle, state->hs_settle); + dev_dbg(csis->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", + lane_rate, csis->clk_settle, csis->hs_settle); - if (state->debug.hs_settle < 0xff) { - dev_dbg(state->dev, "overriding Ths_settle with %u\n", - state->debug.hs_settle); - state->hs_settle = state->debug.hs_settle; + if (csis->debug.hs_settle < 0xff) { + dev_dbg(csis->dev, "overriding Ths_settle with %u\n", + csis->debug.hs_settle); + csis->hs_settle = csis->debug.hs_settle; } - if (state->debug.clk_settle < 4) { - dev_dbg(state->dev, "overriding Tclk_settle with %u\n", - state->debug.clk_settle); - state->clk_settle = state->debug.clk_settle; + if (csis->debug.clk_settle < 4) { + dev_dbg(csis->dev, "overriding Tclk_settle with %u\n", + csis->debug.clk_settle); + csis->clk_settle = csis->debug.clk_settle; } return 0; } -static void mipi_csis_set_params(struct csi_state *state) +static void mipi_csis_set_params(struct mipi_csis_device *csis) { - int lanes = state->bus.num_data_lanes; + int lanes = csis->bus.num_data_lanes; u32 val; - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; - if (state->info->version == MIPI_CSIS_V3_3) + if (csis->info->version == MIPI_CSIS_V3_3) val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - __mipi_csis_set_format(state); + __mipi_csis_set_format(csis); - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, - MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) | - MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle)); + mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, + MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | + MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle)); val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET); - mipi_csis_write(state, MIPI_CSIS_ISP_SYNC_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), val); - val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL); val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; - mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val); - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_L, + mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L, MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV | MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ | MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V | @@ -653,95 +675,95 @@ static void mipi_csis_set_params(struct csi_state *state) MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV | MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV | MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000)); - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_H, 0); + mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_H, 0); /* Update the shadow register. */ - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } -static int mipi_csis_clk_enable(struct csi_state *state) +static int mipi_csis_clk_enable(struct mipi_csis_device *csis) { - return clk_bulk_prepare_enable(state->info->num_clocks, state->clks); + return clk_bulk_prepare_enable(csis->info->num_clocks, csis->clks); } -static void mipi_csis_clk_disable(struct csi_state *state) +static void mipi_csis_clk_disable(struct mipi_csis_device *csis) { - clk_bulk_disable_unprepare(state->info->num_clocks, state->clks); + clk_bulk_disable_unprepare(csis->info->num_clocks, csis->clks); } -static int mipi_csis_clk_get(struct csi_state *state) +static int mipi_csis_clk_get(struct mipi_csis_device *csis) { unsigned int i; int ret; - state->clks = devm_kcalloc(state->dev, state->info->num_clocks, - sizeof(*state->clks), GFP_KERNEL); + csis->clks = devm_kcalloc(csis->dev, csis->info->num_clocks, + sizeof(*csis->clks), GFP_KERNEL); - if (!state->clks) + if (!csis->clks) return -ENOMEM; - for (i = 0; i < state->info->num_clocks; i++) - state->clks[i].id = mipi_csis_clk_id[i]; + for (i = 0; i < csis->info->num_clocks; i++) + csis->clks[i].id = mipi_csis_clk_id[i]; - ret = devm_clk_bulk_get(state->dev, state->info->num_clocks, - state->clks); + ret = devm_clk_bulk_get(csis->dev, csis->info->num_clocks, + csis->clks); if (ret < 0) return ret; /* Set clock rate */ - ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk, - state->clk_frequency); + ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk, + csis->clk_frequency); if (ret < 0) - dev_err(state->dev, "set rate=%d failed: %d\n", - state->clk_frequency, ret); + dev_err(csis->dev, "set rate=%d failed: %d\n", + csis->clk_frequency, ret); return ret; } -static void mipi_csis_start_stream(struct csi_state *state) +static void mipi_csis_start_stream(struct mipi_csis_device *csis) { - mipi_csis_sw_reset(state); - mipi_csis_set_params(state); - mipi_csis_system_enable(state, true); - mipi_csis_enable_interrupts(state, true); + mipi_csis_sw_reset(csis); + mipi_csis_set_params(csis); + mipi_csis_system_enable(csis, true); + mipi_csis_enable_interrupts(csis, true); } -static void mipi_csis_stop_stream(struct csi_state *state) +static void mipi_csis_stop_stream(struct mipi_csis_device *csis) { - mipi_csis_enable_interrupts(state, false); - mipi_csis_system_enable(state, false); + mipi_csis_enable_interrupts(csis, false); + mipi_csis_system_enable(csis, false); } static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) { - struct csi_state *state = dev_id; + struct mipi_csis_device *csis = dev_id; unsigned long flags; unsigned int i; u32 status; u32 dbg_status; - status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); - dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC); + status = mipi_csis_read(csis, MIPI_CSIS_INT_SRC); + dbg_status = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC); - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); /* Update the event/error counters */ - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) { + if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) { for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { - struct mipi_csis_event *event = &state->events[i]; + struct mipi_csis_event *event = &csis->events[i]; if ((!event->debug && (status & event->mask)) || (event->debug && (dbg_status & event->mask))) event->counter++; } } - spin_unlock_irqrestore(&state->slock, flags); + spin_unlock_irqrestore(&csis->slock, flags); - mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status); + mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status); + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, dbg_status); return IRQ_HANDLED; } @@ -750,47 +772,47 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) * PHY regulator and reset */ -static int mipi_csis_phy_enable(struct csi_state *state) +static int mipi_csis_phy_enable(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; - return regulator_enable(state->mipi_phy_regulator); + return regulator_enable(csis->mipi_phy_regulator); } -static int mipi_csis_phy_disable(struct csi_state *state) +static int mipi_csis_phy_disable(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; - return regulator_disable(state->mipi_phy_regulator); + return regulator_disable(csis->mipi_phy_regulator); } -static void mipi_csis_phy_reset(struct csi_state *state) +static void mipi_csis_phy_reset(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return; - reset_control_assert(state->mrst); + reset_control_assert(csis->mrst); msleep(20); - reset_control_deassert(state->mrst); + reset_control_deassert(csis->mrst); } -static int mipi_csis_phy_init(struct csi_state *state) +static int mipi_csis_phy_init(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; /* Get MIPI PHY reset and regulator. */ - state->mrst = devm_reset_control_get_exclusive(state->dev, NULL); - if (IS_ERR(state->mrst)) - return PTR_ERR(state->mrst); + csis->mrst = devm_reset_control_get_exclusive(csis->dev, NULL); + if (IS_ERR(csis->mrst)) + return PTR_ERR(csis->mrst); - state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); - if (IS_ERR(state->mipi_phy_regulator)) - return PTR_ERR(state->mipi_phy_regulator); + csis->mipi_phy_regulator = devm_regulator_get(csis->dev, "phy"); + if (IS_ERR(csis->mipi_phy_regulator)) + return PTR_ERR(csis->mipi_phy_regulator); - return regulator_set_voltage(state->mipi_phy_regulator, 1000000, + return regulator_set_voltage(csis->mipi_phy_regulator, 1000000, 1000000); } @@ -798,36 +820,36 @@ static int mipi_csis_phy_init(struct csi_state *state) * Debug */ -static void mipi_csis_clear_counters(struct csi_state *state) +static void mipi_csis_clear_counters(struct mipi_csis_device *csis) { unsigned long flags; unsigned int i; - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) - state->events[i].counter = 0; - spin_unlock_irqrestore(&state->slock, flags); + csis->events[i].counter = 0; + spin_unlock_irqrestore(&csis->slock, flags); } -static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) +static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_errors) { unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 8; unsigned long flags; unsigned int i; - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); for (i = 0; i < num_events; ++i) { - if (state->events[i].counter > 0 || state->debug.enable) - dev_info(state->dev, "%s events: %d\n", - state->events[i].name, - state->events[i].counter); + if (csis->events[i].counter > 0 || csis->debug.enable) + dev_info(csis->dev, "%s events: %d\n", + csis->events[i].name, + csis->events[i].counter); } - spin_unlock_irqrestore(&state->slock, flags); + spin_unlock_irqrestore(&csis->slock, flags); } -static int mipi_csis_dump_regs(struct csi_state *state) +static int mipi_csis_dump_regs(struct mipi_csis_device *csis) { static const struct { u32 offset; @@ -851,135 +873,134 @@ static int mipi_csis_dump_regs(struct csi_state *state) unsigned int i; u32 cfg; - dev_info(state->dev, "--- REGISTERS ---\n"); + if (!pm_runtime_get_if_in_use(csis->dev)) + return 0; + + dev_info(csis->dev, "--- REGISTERS ---\n"); for (i = 0; i < ARRAY_SIZE(registers); i++) { - cfg = mipi_csis_read(state, registers[i].offset); - dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg); + cfg = mipi_csis_read(csis, registers[i].offset); + dev_info(csis->dev, "%14s: 0x%08x\n", registers[i].name, cfg); } + pm_runtime_put(csis->dev); + return 0; } static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) { - struct csi_state *state = m->private; + struct mipi_csis_device *csis = m->private; - return mipi_csis_dump_regs(state); + return mipi_csis_dump_regs(csis); } DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); -static void mipi_csis_debugfs_init(struct csi_state *state) +static void mipi_csis_debugfs_init(struct mipi_csis_device *csis) { - state->debug.hs_settle = UINT_MAX; - state->debug.clk_settle = UINT_MAX; + csis->debug.hs_settle = UINT_MAX; + csis->debug.clk_settle = UINT_MAX; - state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); + csis->debugfs_root = debugfs_create_dir(dev_name(csis->dev), NULL); - debugfs_create_bool("debug_enable", 0600, state->debugfs_root, - &state->debug.enable); - debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, + debugfs_create_bool("debug_enable", 0600, csis->debugfs_root, + &csis->debug.enable); + debugfs_create_file("dump_regs", 0600, csis->debugfs_root, csis, &mipi_csis_dump_regs_fops); - debugfs_create_u32("tclk_settle", 0600, state->debugfs_root, - &state->debug.clk_settle); - debugfs_create_u32("ths_settle", 0600, state->debugfs_root, - &state->debug.hs_settle); + debugfs_create_u32("tclk_settle", 0600, csis->debugfs_root, + &csis->debug.clk_settle); + debugfs_create_u32("ths_settle", 0600, csis->debugfs_root, + &csis->debug.hs_settle); } -static void mipi_csis_debugfs_exit(struct csi_state *state) +static void mipi_csis_debugfs_exit(struct mipi_csis_device *csis) { - debugfs_remove_recursive(state->debugfs_root); + debugfs_remove_recursive(csis->debugfs_root); } /* ----------------------------------------------------------------------------- * V4L2 subdev operations */ -static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) +static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev) { - return container_of(sdev, struct csi_state, sd); + return container_of(sdev, struct mipi_csis_device, sd); } static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret; - if (enable) { - ret = mipi_csis_calculate_params(state); - if (ret < 0) - return ret; + if (!enable) { + mutex_lock(&csis->lock); - mipi_csis_clear_counters(state); + v4l2_subdev_call(csis->src_sd, video, s_stream, 0); - ret = pm_runtime_resume_and_get(state->dev); - if (ret < 0) - return ret; + mipi_csis_stop_stream(csis); + if (csis->debug.enable) + mipi_csis_log_counters(csis, true); + + mutex_unlock(&csis->lock); - ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - goto done; + pm_runtime_put(csis->dev); + + return 0; } - mutex_lock(&state->lock); + ret = mipi_csis_calculate_params(csis); + if (ret < 0) + return ret; - if (enable) { - if (state->state & ST_SUSPENDED) { - ret = -EBUSY; - goto unlock; - } + mipi_csis_clear_counters(csis); - mipi_csis_start_stream(state); - ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); - if (ret < 0) - goto unlock; + ret = pm_runtime_resume_and_get(csis->dev); + if (ret < 0) + return ret; - mipi_csis_log_counters(state, true); + mutex_lock(&csis->lock); - state->state |= ST_STREAMING; - } else { - v4l2_subdev_call(state->src_sd, video, s_stream, 0); - ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); - if (ret == -ENOIOCTLCMD) - ret = 0; - mipi_csis_stop_stream(state); - state->state &= ~ST_STREAMING; - if (state->debug.enable) - mipi_csis_log_counters(state, true); - } + mipi_csis_start_stream(csis); + ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); + if (ret < 0) + goto error; -unlock: - mutex_unlock(&state->lock); + mipi_csis_log_counters(csis, true); -done: - if (!enable || ret < 0) - pm_runtime_put(state->dev); + mutex_unlock(&csis->lock); + + return 0; + +error: + mipi_csis_stop_stream(csis); + mutex_unlock(&csis->lock); + pm_runtime_put(csis->dev); return ret; } static struct v4l2_mbus_framefmt * -mipi_csis_get_format(struct csi_state *state, +mipi_csis_get_format(struct mipi_csis_device *csis, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which, unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&state->sd, sd_state, pad); + return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad); - return &state->format_mbus[pad]; + return &csis->format_mbus[pad]; } static int mipi_csis_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; enum v4l2_subdev_format_whence which; which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK); + fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK); fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; @@ -993,15 +1014,7 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *sd, V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, fmt_sink->ycbcr_enc); - /* - * When called from mipi_csis_subdev_init() to initialize the active - * configuration, cfg is NULL, which indicates there's no source pad - * configuration to set. - */ - if (!sd_state) - return 0; - - fmt_source = mipi_csis_get_format(state, sd_state, which, + fmt_source = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SOURCE); *fmt_source = *fmt_sink; @@ -1012,15 +1025,15 @@ static int mipi_csis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_framefmt *fmt; - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, sdformat->pad); - mutex_lock(&state->lock); + mutex_lock(&csis->lock); sdformat->format = *fmt; - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return 0; } @@ -1029,7 +1042,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); /* * The CSIS can't transcode in any way, the source format is identical @@ -1041,7 +1054,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = mipi_csis_get_format(state, sd_state, code->which, + fmt = mipi_csis_get_format(csis, sd_state, code->which, code->pad); code->code = fmt->code; return 0; @@ -1062,7 +1075,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -1110,10 +1123,10 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, sdformat->pad); - mutex_lock(&state->lock); + mutex_lock(&csis->lock); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; @@ -1126,7 +1139,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, CSIS_PAD_SOURCE); *fmt = sdformat->format; @@ -1135,22 +1148,20 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, /* Store the CSIS format descriptor for active formats. */ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - state->csis_fmt = csis_fmt; + csis->csis_fmt = csis_fmt; - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return 0; } static int mipi_csis_log_status(struct v4l2_subdev *sd) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - mutex_lock(&state->lock); - mipi_csis_log_counters(state, true); - if (state->debug.enable && (state->state & ST_POWERED)) - mipi_csis_dump_regs(state); - mutex_unlock(&state->lock); + mipi_csis_log_counters(csis, true); + if (csis->debug.enable) + mipi_csis_dump_regs(csis); return 0; } @@ -1185,10 +1196,10 @@ static int mipi_csis_link_setup(struct media_entity *entity, const struct media_pad *remote_pad, u32 flags) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_subdev *remote_sd; - dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, + dev_dbg(csis->dev, "link setup %s -> %s", remote_pad->entity->name, local_pad->entity->name); /* We only care about the link to the source. */ @@ -1198,12 +1209,12 @@ static int mipi_csis_link_setup(struct media_entity *entity, remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); if (flags & MEDIA_LNK_FL_ENABLED) { - if (state->src_sd) + if (csis->src_sd) return -EBUSY; - state->src_sd = remote_sd; + csis->src_sd = remote_sd; } else { - state->src_sd = NULL; + csis->src_sd = NULL; } return 0; @@ -1219,18 +1230,18 @@ static const struct media_entity_operations mipi_csis_entity_ops = { * Async subdev notifier */ -static struct csi_state * +static struct mipi_csis_device * mipi_notifier_to_csis_state(struct v4l2_async_notifier *n) { - return container_of(n, struct csi_state, notifier); + return container_of(n, struct mipi_csis_device, notifier); } static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { - struct csi_state *state = mipi_notifier_to_csis_state(notifier); - struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK]; + struct mipi_csis_device *csis = mipi_notifier_to_csis_state(notifier); + struct media_pad *sink = &csis->sd.entity.pads[CSIS_PAD_SINK]; return v4l2_create_fwnode_links_to_pad(sd, sink, 0); } @@ -1239,7 +1250,7 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = { .bound = mipi_csis_notify_bound, }; -static int mipi_csis_async_register(struct csi_state *state) +static int mipi_csis_async_register(struct mipi_csis_device *csis) { struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY, @@ -1249,9 +1260,9 @@ static int mipi_csis_async_register(struct csi_state *state) unsigned int i; int ret; - v4l2_async_nf_init(&state->notifier); + v4l2_async_nf_init(&csis->notifier); - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); if (!ep) return -ENOTCONN; @@ -1262,19 +1273,19 @@ static int mipi_csis_async_register(struct csi_state *state) for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) { if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) { - dev_err(state->dev, + dev_err(csis->dev, "data lanes reordering is not supported"); ret = -EINVAL; goto err_parse; } } - state->bus = vep.bus.mipi_csi2; + csis->bus = vep.bus.mipi_csi2; - dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes); - dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags); + dev_dbg(csis->dev, "data lanes: %d\n", csis->bus.num_data_lanes); + dev_dbg(csis->dev, "flags: 0x%08x\n", csis->bus.flags); - asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep, + asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep, struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); @@ -1283,13 +1294,13 @@ static int mipi_csis_async_register(struct csi_state *state) fwnode_handle_put(ep); - state->notifier.ops = &mipi_csis_notify_ops; + csis->notifier.ops = &mipi_csis_notify_ops; - ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier); + ret = v4l2_async_subdev_nf_register(&csis->sd, &csis->notifier); if (ret) return ret; - return v4l2_async_register_subdev(&state->sd); + return v4l2_async_register_subdev(&csis->sd); err_parse: fwnode_handle_put(ep); @@ -1301,97 +1312,63 @@ err_parse: * Suspend/resume */ -static int mipi_csis_pm_suspend(struct device *dev, bool runtime) +static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret = 0; - mutex_lock(&state->lock); - if (state->state & ST_POWERED) { - mipi_csis_stop_stream(state); - ret = mipi_csis_phy_disable(state); - if (ret) - goto unlock; - mipi_csis_clk_disable(state); - state->state &= ~ST_POWERED; - if (!runtime) - state->state |= ST_SUSPENDED; - } + mutex_lock(&csis->lock); + + ret = mipi_csis_phy_disable(csis); + if (ret) + goto unlock; + + mipi_csis_clk_disable(csis); unlock: - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return ret ? -EAGAIN : 0; } -static int mipi_csis_pm_resume(struct device *dev, bool runtime) +static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret = 0; - mutex_lock(&state->lock); - if (!runtime && !(state->state & ST_SUSPENDED)) - goto unlock; - - if (!(state->state & ST_POWERED)) { - ret = mipi_csis_phy_enable(state); - if (ret) - goto unlock; + mutex_lock(&csis->lock); - state->state |= ST_POWERED; - mipi_csis_clk_enable(state); - } - if (state->state & ST_STREAMING) - mipi_csis_start_stream(state); + ret = mipi_csis_phy_enable(csis); + if (ret) + goto unlock; - state->state &= ~ST_SUSPENDED; + mipi_csis_clk_enable(csis); unlock: - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return ret ? -EAGAIN : 0; } -static int __maybe_unused mipi_csis_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, false); -} - -static int __maybe_unused mipi_csis_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, false); -} - -static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, true); -} - -static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, true); -} - static const struct dev_pm_ops mipi_csis_pm_ops = { SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) }; /* ----------------------------------------------------------------------------- * Probe/remove & platform driver */ -static int mipi_csis_subdev_init(struct csi_state *state) +static int mipi_csis_subdev_init(struct mipi_csis_device *csis) { - struct v4l2_subdev *sd = &state->sd; + struct v4l2_subdev *sd = &csis->sd; v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner = THIS_MODULE; snprintf(sd->name, sizeof(sd->name), "csis-%s", - dev_name(state->dev)); + dev_name(csis->dev)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->ctrl_handler = NULL; @@ -1399,26 +1376,26 @@ static int mipi_csis_subdev_init(struct csi_state *state) sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; sd->entity.ops = &mipi_csis_entity_ops; - sd->dev = state->dev; + sd->dev = csis->dev; - state->csis_fmt = &mipi_csis_formats[0]; + csis->csis_fmt = &mipi_csis_formats[0]; mipi_csis_init_cfg(sd, NULL); - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK + csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, - state->pads); + csis->pads); } -static int mipi_csis_parse_dt(struct csi_state *state) +static int mipi_csis_parse_dt(struct mipi_csis_device *csis) { - struct device_node *node = state->dev->of_node; + struct device_node *node = csis->dev->of_node; if (of_property_read_u32(node, "clock-frequency", - &state->clk_frequency)) - state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + &csis->clk_frequency)) + csis->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; return 0; } @@ -1426,102 +1403,102 @@ static int mipi_csis_parse_dt(struct csi_state *state) static int mipi_csis_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct csi_state *state; + struct mipi_csis_device *csis; int irq; int ret; - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); - if (!state) + csis = devm_kzalloc(dev, sizeof(*csis), GFP_KERNEL); + if (!csis) return -ENOMEM; - mutex_init(&state->lock); - spin_lock_init(&state->slock); + mutex_init(&csis->lock); + spin_lock_init(&csis->slock); - state->dev = dev; - state->info = of_device_get_match_data(dev); + csis->dev = dev; + csis->info = of_device_get_match_data(dev); - memcpy(state->events, mipi_csis_events, sizeof(state->events)); + memcpy(csis->events, mipi_csis_events, sizeof(csis->events)); /* Parse DT properties. */ - ret = mipi_csis_parse_dt(state); + ret = mipi_csis_parse_dt(csis); if (ret < 0) { dev_err(dev, "Failed to parse device tree: %d\n", ret); return ret; } /* Acquire resources. */ - state->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(state->regs)) - return PTR_ERR(state->regs); + csis->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(csis->regs)) + return PTR_ERR(csis->regs); irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - ret = mipi_csis_phy_init(state); + ret = mipi_csis_phy_init(csis); if (ret < 0) return ret; - ret = mipi_csis_clk_get(state); + ret = mipi_csis_clk_get(csis); if (ret < 0) return ret; /* Reset PHY and enable the clocks. */ - mipi_csis_phy_reset(state); + mipi_csis_phy_reset(csis); - ret = mipi_csis_clk_enable(state); + ret = mipi_csis_clk_enable(csis); if (ret < 0) { - dev_err(state->dev, "failed to enable clocks: %d\n", ret); + dev_err(csis->dev, "failed to enable clocks: %d\n", ret); return ret; } /* Now that the hardware is initialized, request the interrupt. */ ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, - dev_name(dev), state); + dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); goto disable_clock; } /* Initialize and register the subdev. */ - ret = mipi_csis_subdev_init(state); + ret = mipi_csis_subdev_init(csis); if (ret < 0) goto disable_clock; - platform_set_drvdata(pdev, &state->sd); + platform_set_drvdata(pdev, &csis->sd); - ret = mipi_csis_async_register(state); + ret = mipi_csis_async_register(csis); if (ret < 0) { dev_err(dev, "async register failed: %d\n", ret); goto cleanup; } /* Initialize debugfs. */ - mipi_csis_debugfs_init(state); + mipi_csis_debugfs_init(csis); /* Enable runtime PM. */ pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { - ret = mipi_csis_pm_resume(dev, true); + ret = mipi_csis_runtime_resume(dev); if (ret < 0) goto unregister_all; } dev_info(dev, "lanes: %d, freq: %u\n", - state->bus.num_data_lanes, state->clk_frequency); + csis->bus.num_data_lanes, csis->clk_frequency); return 0; unregister_all: - mipi_csis_debugfs_exit(state); + mipi_csis_debugfs_exit(csis); cleanup: - media_entity_cleanup(&state->sd.entity); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); + media_entity_cleanup(&csis->sd.entity); + v4l2_async_nf_unregister(&csis->notifier); + v4l2_async_nf_cleanup(&csis->notifier); + v4l2_async_unregister_subdev(&csis->sd); disable_clock: - mipi_csis_clk_disable(state); - mutex_destroy(&state->lock); + mipi_csis_clk_disable(csis); + mutex_destroy(&csis->lock); return ret; } @@ -1529,18 +1506,18 @@ disable_clock: static int mipi_csis_remove(struct platform_device *pdev) { struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - mipi_csis_debugfs_exit(state); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); + mipi_csis_debugfs_exit(csis); + v4l2_async_nf_unregister(&csis->notifier); + v4l2_async_nf_cleanup(&csis->notifier); + v4l2_async_unregister_subdev(&csis->sd); pm_runtime_disable(&pdev->dev); - mipi_csis_pm_suspend(&pdev->dev, true); - mipi_csis_clk_disable(state); - media_entity_cleanup(&state->sd.entity); - mutex_destroy(&state->lock); + mipi_csis_runtime_suspend(&pdev->dev); + mipi_csis_clk_disable(csis); + media_entity_cleanup(&csis->sd.entity); + mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); return 0; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 5dc1ddbe6d65..307bb1dc4589 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -576,12 +576,8 @@ static const struct vb2_ops msm_video_vb2_q_ops = { static int video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct camss_video *video = video_drvdata(file); - strscpy(cap->driver, "qcom-camss", sizeof(cap->driver)); strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(video->camss->dev)); return 0; } diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index c3023340d95c..d33825553edc 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -261,6 +261,7 @@ struct venc_controls { u32 header_mode; bool aud_enable; + u32 intra_refresh_type; u32 intra_refresh_period; struct { diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 0bca95d01650..5c1104379c49 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -90,12 +90,28 @@ bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) } EXPORT_SYMBOL_GPL(venus_helper_check_codec); +static void free_dpb_buf(struct venus_inst *inst, struct intbuf *buf) +{ + ida_free(&inst->dpb_ids, buf->dpb_out_tag); + + list_del_init(&buf->list); + dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, + buf->attrs); + kfree(buf); +} + int venus_helper_queue_dpb_bufs(struct venus_inst *inst) { - struct intbuf *buf; + struct intbuf *buf, *next; + unsigned int dpb_size = 0; int ret = 0; - list_for_each_entry(buf, &inst->dpbbufs, list) { + if (inst->dpb_buftype == HFI_BUFFER_OUTPUT) + dpb_size = inst->output_buf_size; + else if (inst->dpb_buftype == HFI_BUFFER_OUTPUT2) + dpb_size = inst->output2_buf_size; + + list_for_each_entry_safe(buf, next, &inst->dpbbufs, list) { struct hfi_frame_data fdata; memset(&fdata, 0, sizeof(fdata)); @@ -106,6 +122,12 @@ int venus_helper_queue_dpb_bufs(struct venus_inst *inst) if (buf->owned_by == FIRMWARE) continue; + /* free buffer from previous sequence which was released later */ + if (dpb_size > buf->size) { + free_dpb_buf(inst, buf); + continue; + } + fdata.clnt_data = buf->dpb_out_tag; ret = hfi_session_process_buf(inst, &fdata); @@ -127,13 +149,7 @@ int venus_helper_free_dpb_bufs(struct venus_inst *inst) list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) { if (buf->owned_by == FIRMWARE) continue; - - ida_free(&inst->dpb_ids, buf->dpb_out_tag); - - list_del_init(&buf->list); - dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, - buf->attrs); - kfree(buf); + free_dpb_buf(inst, buf); } if (list_empty(&inst->dpbbufs)) @@ -592,6 +608,10 @@ static u32 to_hfi_raw_fmt(u32 v4l2_fmt) return HFI_COLOR_FORMAT_NV12; case V4L2_PIX_FMT_NV21: return HFI_COLOR_FORMAT_NV21; + case V4L2_PIX_FMT_QC08C: + return HFI_COLOR_FORMAT_NV12_UBWC; + case V4L2_PIX_FMT_QC10C: + return HFI_COLOR_FORMAT_YUV420_TP10_UBWC; default: break; } @@ -1174,7 +1194,8 @@ int venus_helper_set_format_constraints(struct venus_inst *inst) if (!IS_V6(inst->core)) return 0; - if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC) + if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC || + inst->opb_fmt == HFI_COLOR_FORMAT_YUV420_TP10_UBWC) return 0; pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; @@ -1745,27 +1766,6 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, if (!caps) return -EINVAL; - if (inst->bit_depth == VIDC_BITDEPTH_10 && - inst->session_type == VIDC_SESSION_TYPE_DEC) { - found_ubwc = - find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, - HFI_COLOR_FORMAT_YUV420_TP10_UBWC); - found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, - HFI_COLOR_FORMAT_NV12); - if (found_ubwc && found) { - /* - * Hard-code DPB buffers to be 10bit UBWC and decoder - * output buffers in 8bit NV12 until V4L2 is able to - * expose compressed/tiled formats to applications. - */ - *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC; - *out2_fmt = HFI_COLOR_FORMAT_NV12; - return 0; - } - - return -EINVAL; - } - if (ubwc) { ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE; found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, @@ -1797,6 +1797,29 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, } EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts); +bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) +{ + struct venus_core *core = inst->core; + u32 fmt = to_hfi_raw_fmt(v4l2_pixfmt); + struct hfi_plat_caps *caps; + u32 buftype; + + if (!fmt) + return false; + + caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type); + if (!caps) + return false; + + if (inst->session_type == VIDC_SESSION_TYPE_DEC) + buftype = HFI_BUFFER_OUTPUT2; + else + buftype = HFI_BUFFER_OUTPUT; + + return find_fmt_from_caps(caps, buftype, fmt); +} +EXPORT_SYMBOL_GPL(venus_helper_check_format); + int venus_helper_set_stride(struct venus_inst *inst, unsigned int width, unsigned int height) { diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 32619c3e8c97..358e4f39c9c0 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -55,6 +55,7 @@ void venus_helper_init_instance(struct venus_inst *inst); int venus_helper_session_init(struct venus_inst *inst); int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt, u32 *out2_fmt, bool ubwc); +bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt); int venus_helper_alloc_dpb_bufs(struct venus_inst *inst); int venus_helper_free_dpb_bufs(struct venus_inst *inst); int venus_helper_intbufs_alloc(struct venus_inst *inst); diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 4e2151fb47f0..1968f09ad177 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -104,6 +104,9 @@ int hfi_core_deinit(struct venus_core *core, bool blocking) mutex_lock(&core->lock); } + if (!core->ops) + goto unlock; + ret = core->ops->core_deinit(core); if (!ret) diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c index 3f7f5277a50e..e3f0a90a567b 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v4.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c @@ -55,7 +55,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_VP8, @@ -106,7 +106,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_MPEG2, diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c index c10618e44f5d..4e8af645f8b9 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c @@ -55,7 +55,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_VP8, @@ -106,7 +106,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_MPEG2, diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 3a75a27632fb..9a34662fea38 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -1583,8 +1583,10 @@ static int venus_suspend_3xx(struct venus_core *core) */ ret = readx_poll_timeout(venus_cpu_and_video_core_idle, hdev, val, val, 1500, 100 * 1500); - if (ret) + if (ret) { + dev_err(dev, "wait for cpu and video core idle fail (%d)\n", ret); return ret; + } ret = venus_prepare_power_collapse(hdev, false); if (ret) { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 91da3f509724..ac0bb45d07f4 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -31,6 +31,14 @@ */ static const struct venus_format vdec_formats[] = { { + .pixfmt = V4L2_PIX_FMT_QC08C, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, { + .pixfmt = V4L2_PIX_FMT_QC10C, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + },{ .pixfmt = V4L2_PIX_FMT_NV12, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, @@ -106,6 +114,14 @@ find_format(struct venus_inst *inst, u32 pixfmt, u32 type) !venus_helper_check_codec(inst, fmt[i].pixfmt)) return NULL; + if (V4L2_TYPE_IS_CAPTURE(type) && + !venus_helper_check_format(inst, fmt[i].pixfmt)) + return NULL; + + if (V4L2_TYPE_IS_CAPTURE(type) && fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && + !(inst->bit_depth == VIDC_BITDEPTH_10)) + return NULL; + return &fmt[i]; } @@ -124,8 +140,17 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) if (fmt[i].type != type) continue; - valid = type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || - venus_helper_check_codec(inst, fmt[i].pixfmt); + + if (V4L2_TYPE_IS_OUTPUT(type)) { + valid = venus_helper_check_codec(inst, fmt[i].pixfmt); + } else if (V4L2_TYPE_IS_CAPTURE(type)) { + valid = venus_helper_check_format(inst, fmt[i].pixfmt); + + if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && + !(inst->bit_depth == VIDC_BITDEPTH_10)) + valid = false; + } + if (k == index && valid) break; if (valid) @@ -676,8 +701,8 @@ static int vdec_output_conf(struct venus_inst *inst) struct venus_core *core = inst->core; struct hfi_enable en = { .enable = 1 }; struct hfi_buffer_requirements bufreq; - u32 width = inst->out_width; - u32 height = inst->out_height; + u32 width = inst->width; + u32 height = inst->height; u32 out_fmt, out2_fmt; bool ubwc = false; u32 ptype; @@ -1200,6 +1225,8 @@ static void vdec_stop_streaming(struct vb2_queue *q) struct venus_inst *inst = vb2_get_drv_priv(q); int ret = -EINVAL; + vdec_pm_get_put(inst); + mutex_lock(&inst->lock); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -1525,7 +1552,7 @@ static const struct hfi_inst_ops vdec_hfi_ops = { static void vdec_inst_init(struct venus_inst *inst) { inst->hfi_codec = HFI_VIDEO_CODEC_H264; - inst->fmt_out = &vdec_formats[6]; + inst->fmt_out = &vdec_formats[8]; inst->fmt_cap = &vdec_formats[0]; inst->width = frame_width_min(inst); inst->height = ALIGN(frame_height_min(inst), 32); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index adea4c3b8c20..86918aea1d24 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -893,8 +893,12 @@ static int venc_set_properties(struct venus_inst *inst) mbs++; mbs /= ctr->intra_refresh_period; - intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; intra_refresh.cir_mbs = mbs; + if (ctr->intra_refresh_type == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) + intra_refresh.mode = HFI_INTRA_REFRESH_CYCLIC; + else + intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; } ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ea5805e71c14..ed44e5800759 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -316,6 +316,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: ctr->mastering = *ctrl->p_new.p_hdr10_mastering; break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: + ctr->intra_refresh_type = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: ctr->intra_refresh_period = ctrl->val; break; @@ -582,6 +585,11 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + 0, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, ((4096 * 2304) >> 8), 1, 0); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 64cb05b3907c..49bdcfba010b 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -94,8 +94,6 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name)); strscpy(mdev->model, match->compatible, sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); @@ -891,7 +889,6 @@ static const struct media_device_ops rvin_csi2_media_ops = { static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id, const struct rvin_group_route *route) - { struct media_entity *source = &group->remotes[route->csi].subdev->entity; struct media_entity *sink = &group->vin[id]->vdev.entity; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 2272f1c96aaf..6644b498929d 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -77,6 +77,7 @@ /* Register bit fields for R-Car VIN */ /* Video n Main Control Register bits */ +#define VNMC_INF_MASK (7 << 16) #define VNMC_DPINE (1 << 27) /* Gen3 specific */ #define VNMC_SCLE (1 << 26) /* Gen3 specific */ #define VNMC_FOC (1 << 21) @@ -88,6 +89,7 @@ #define VNMC_INF_RAW8 (4 << 16) #define VNMC_INF_YUV16 (5 << 16) #define VNMC_INF_RGB888 (6 << 16) +#define VNMC_INF_RGB666 (7 << 16) #define VNMC_VUP (1 << 10) #define VNMC_IM_ODD (0 << 3) #define VNMC_IM_ODD_EVEN (1 << 3) @@ -707,6 +709,29 @@ static int rvin_setup(struct rvin_dev *vin) break; } + /* Make sure input interface and input format is valid. */ + if (vin->info->model == RCAR_GEN3) { + switch (vnmc & VNMC_INF_MASK) { + case VNMC_INF_YUV8_BT656: + case VNMC_INF_YUV10_BT656: + case VNMC_INF_YUV16: + case VNMC_INF_RGB666: + if (vin->is_csi) { + vin_err(vin, "Invalid setting in MIPI CSI2\n"); + return -EINVAL; + } + break; + case VNMC_INF_RAW8: + if (!vin->is_csi) { + vin_err(vin, "Invalid setting in Digital Pins\n"); + return -EINVAL; + } + break; + default: + break; + } + } + /* Enable VSYNC Field Toggle mode after one VSYNC input */ if (vin->info->model == RCAR_GEN3) dmr2 = VNDMR2_FTEV; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 2e60b9fce03b..2e2aa9d746ee 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -255,6 +255,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, { struct v4l2_subdev *sd = vin_to_source(vin); struct v4l2_subdev_state *sd_state; + static struct lock_class_key key; struct v4l2_subdev_format format = { .which = which, .pad = vin->parallel.source_pad, @@ -263,7 +264,11 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, u32 width, height; int ret; - sd_state = v4l2_subdev_alloc_state(sd); + /* + * FIXME: Drop this call, drivers are not supposed to use + * __v4l2_subdev_state_alloc(). + */ + sd_state = __v4l2_subdev_state_alloc(sd, "rvin:state->lock", &key); if (IS_ERR(sd_state)) return PTR_ERR(sd_state); @@ -299,7 +304,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, rvin_format_align(vin, pix); done: - v4l2_subdev_free_state(sd_state); + __v4l2_subdev_state_free(sd_state); return ret; } @@ -307,12 +312,8 @@ done: static int rvin_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct rvin_dev *vin = video_drvdata(file); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "R_Car_VIN", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vin->dev)); return 0; } diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 293beba131e2..2f4377cfbb42 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -670,8 +670,6 @@ static int jpu_querycap(struct file *file, void *priv, strscpy(cap->card, DRV_NAME " decoder", sizeof(cap->card)); strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(ctx->jpu->dev)); memset(cap->reserved, 0, sizeof(cap->reserved)); return 0; diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index 2e8dbacc414e..f70f91b006b7 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -1606,15 +1606,15 @@ struct ceu_data { u32 irq_mask; }; -static const struct ceu_data ceu_data_rz = { - .irq_mask = CEU_CETCR_ALL_IRQS_RZ, -}; - static const struct ceu_data ceu_data_sh4 = { .irq_mask = CEU_CETCR_ALL_IRQS_SH4, }; #if IS_ENABLED(CONFIG_OF) +static const struct ceu_data ceu_data_rz = { + .irq_mask = CEU_CETCR_ALL_IRQS_RZ, +}; + static const struct of_device_id ceu_of_match[] = { { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz }, { .compatible = "renesas,r8a7740-ceu", .data = &ceu_data_rz }, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 502c7d9d6890..1f73c48eb738 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -243,8 +243,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) mdev->dev = vsp1->dev; mdev->hw_revision = vsp1->version; strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); vsp1->media_ops.link_setup = vsp1_entity_link_setup; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 823c15facd1b..a116a3362f9e 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -613,6 +613,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, const char *name, unsigned int num_pads, const struct v4l2_subdev_ops *ops, u32 function) { + static struct lock_class_key key; struct v4l2_subdev *subdev; unsigned int i; int ret; @@ -675,7 +676,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, * Allocate the pad configuration to store formats and selection * rectangles. */ - entity->config = v4l2_subdev_alloc_state(&entity->subdev); + /* + * FIXME: Drop this call, drivers are not supposed to use + * __v4l2_subdev_state_alloc(). + */ + entity->config = __v4l2_subdev_state_alloc(&entity->subdev, + "vsp1:config->lock", &key); if (IS_ERR(entity->config)) { media_entity_cleanup(&entity->subdev.entity); return PTR_ERR(entity->config); @@ -690,6 +696,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity) entity->ops->destroy(entity); if (entity->subdev.ctrl_handler) v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); - v4l2_subdev_free_state(entity->config); + __v4l2_subdev_state_free(entity->config); media_entity_cleanup(&entity->subdev.entity); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index 5e5013d2cd2a..f22449dd654c 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -434,8 +434,6 @@ static int histo_v4l2_querycap(struct file *file, void *fh, strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, histo->video.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(histo->entity.vsp1->dev)); return 0; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c index 85587c1b6a37..75083cb234fe 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c @@ -291,11 +291,11 @@ static void rpf_configure_partition(struct vsp1_entity *entity, + crop.left * fmtinfo->bpp[0] / 8; if (format->num_planes > 1) { + unsigned int bpl = format->plane_fmt[1].bytesperline; unsigned int offset; - offset = crop.top * format->plane_fmt[1].bytesperline - + crop.left / fmtinfo->hsub - * fmtinfo->bpp[1] / 8; + offset = crop.top / fmtinfo->vsub * bpl + + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8; mem.addr[1] += offset; mem.addr[2] += offset; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 044eb5778820..51219b1b6ea9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -959,8 +959,6 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, video->video.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(video->vsp1->dev)); return 0; } @@ -1032,7 +1030,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) struct vsp1_pipeline *pipe; int ret; - if (video->queue.owner && video->queue.owner != file->private_data) + if (vb2_queue_is_busy(&video->queue, file)) return -EBUSY; /* @@ -1129,21 +1127,11 @@ static int vsp1_video_open(struct file *file) static int vsp1_video_release(struct file *file) { struct vsp1_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - mutex_lock(&video->lock); - if (video->queue.owner == vfh) { - vb2_queue_release(&video->queue); - video->queue.owner = NULL; - } - mutex_unlock(&video->lock); + vb2_fop_release(file); vsp1_device_put(video->vsp1); - v4l2_fh_release(file); - - file->private_data = NULL; - return 0; } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 3d3d1062e212..2f8df74ad0fd 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -865,7 +865,7 @@ static int rga_probe(struct platform_device *pdev) ret = pm_runtime_resume_and_get(rga->dev); if (ret < 0) - goto rel_vdev; + goto rel_m2m; rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; @@ -881,7 +881,7 @@ static int rga_probe(struct platform_device *pdev) DMA_ATTR_WRITE_COMBINE); if (!rga->cmdbuf_virt) { ret = -ENOMEM; - goto rel_vdev; + goto rel_m2m; } rga->src_mmu_pages = @@ -918,6 +918,8 @@ free_src_pages: free_dma: dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); +rel_m2m: + v4l2_m2m_release(rga->m2m_dev); rel_vdev: video_device_release(vfd); unreg_v4l2_dev: diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 2a35bf24e54e..4415c7248c2f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -14,6 +14,8 @@ #include <linux/pm_runtime.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> + +#include <media/mipi-csi2.h> #include <media/v4l2-event.h> #include "rkisp1-common.h" @@ -62,112 +64,112 @@ static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { }, { .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index d326214c7e07..82f8d33d98b3 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -333,17 +333,6 @@ /* MIPI_DATA_SEL */ #define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) #define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) -/* MIPI DATA_TYPE */ -#define RKISP1_CIF_CSI2_DT_YUV420_8b 0x18 -#define RKISP1_CIF_CSI2_DT_YUV420_10b 0x19 -#define RKISP1_CIF_CSI2_DT_YUV422_8b 0x1E -#define RKISP1_CIF_CSI2_DT_YUV422_10b 0x1F -#define RKISP1_CIF_CSI2_DT_RGB565 0x22 -#define RKISP1_CIF_CSI2_DT_RGB666 0x23 -#define RKISP1_CIF_CSI2_DT_RGB888 0x24 -#define RKISP1_CIF_CSI2_DT_RAW8 0x2A -#define RKISP1_CIF_CSI2_DT_RAW10 0x2B -#define RKISP1_CIF_CSI2_DT_RAW12 0x2C /* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ #define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index f1cf847d1cc2..b7854ce5fb8e 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -285,13 +285,8 @@ static const struct vb2_ops gsc_m2m_qops = { static int gsc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct gsc_ctx *ctx = fh_to_ctx(fh); - struct gsc_dev *gsc = ctx->gsc_dev; - strscpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&gsc->pdev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c index 023f624d29d5..26ee2388edfd 100644 --- a/drivers/media/platform/samsung/exynos4-is/common.c +++ b/drivers/media/platform/samsung/exynos4-is/common.c @@ -41,8 +41,6 @@ void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap) { strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, dev->driver->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(dev)); } EXPORT_SYMBOL(__fimc_vidioc_querycap); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index e55e411038f4..e3072d69c49f 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -140,7 +140,7 @@ static int fimc_is_enable_clocks(struct fimc_is *is) dev_err(&is->pdev->dev, "clock %s enable failed\n", fimc_is_clocks[i]); for (--i; i >= 0; i--) - clk_disable(is->clocks[i]); + clk_disable_unprepare(is->clocks[i]); return ret; } pr_debug("enabled clock: %s\n", fimc_is_clocks[i]); @@ -830,7 +830,7 @@ static int fimc_is_probe(struct platform_device *pdev) ret = pm_runtime_resume_and_get(dev); if (ret < 0) - goto err_irq; + goto err_pm_disable; vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); @@ -864,6 +864,8 @@ err_pm: pm_runtime_put_noidle(dev); if (!pm_runtime_enabled(dev)) fimc_is_runtime_suspend(dev); +err_pm_disable: + pm_runtime_disable(dev); err_irq: free_irq(is->irq, is); err_clk: diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h index edcb3a5e3cb9..2dd4ddbc748a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h @@ -32,7 +32,7 @@ static inline int fimc_isp_video_device_register(struct fimc_isp *isp, return 0; } -void fimc_isp_video_device_unregister(struct fimc_isp *isp, +static inline void fimc_isp_video_device_unregister(struct fimc_isp *isp, enum v4l2_buf_type type) { } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 2e8f476efc5c..1a396b7cd9a9 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -646,12 +646,8 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r) static int fimc_lite_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct fimc_lite *fimc = video_drvdata(file); - strscpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&fimc->pdev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 5479bc8d474d..456287186ad8 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -1257,8 +1257,6 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, strscpy(cap->card, S5P_JPEG_M2M_NAME " decoder", sizeof(cap->card)); } - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(ctx->jpeg->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c index 01b47b3df1e7..33e6e85dfd78 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c @@ -52,7 +52,6 @@ void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) { unsigned long reg, m; - m = S5P_PROC_MODE_DECOMPR; if (mode == S5P_JPEG_ENCODE) m = S5P_PROC_MODE_COMPR; else diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 4b89df8bfd18..268ffe4da53c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -288,8 +288,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index a8877d805b29..b65e506665af 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1309,8 +1309,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 5aa79d9277c8..dd74cc43920d 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -1394,8 +1394,7 @@ err_remove: bdisp_debugfs_remove(bdisp); v4l2_device_unregister(&bdisp->v4l2_dev); err_clk: - if (!IS_ERR(bdisp->clock)) - clk_unprepare(bdisp->clock); + clk_unprepare(bdisp->clock); err_wq: destroy_workqueue(bdisp->work_queue); return ret; diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h index 5ab7ca448cf9..f8d97841f366 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h @@ -13,7 +13,6 @@ #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #include <linux/gpio.h> -#include <linux/version.h> #include <media/dmxdev.h> #include <media/dvb_demux.h> diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index c887a31ebb54..420ad4d8df5d 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1859,7 +1859,7 @@ static int delta_probe(struct platform_device *pdev) if (ret) { dev_err(delta->dev, "%s failed to initialize firmware ipc channel\n", DELTA_PREFIX); - goto err; + goto err_pm_disable; } /* register all available decoders */ @@ -1873,7 +1873,7 @@ static int delta_probe(struct platform_device *pdev) if (ret) { dev_err(delta->dev, "%s failed to register V4L2 device\n", DELTA_PREFIX); - goto err; + goto err_pm_disable; } delta->work_queue = create_workqueue(DELTA_NAME); @@ -1898,6 +1898,8 @@ err_work_queue: destroy_workqueue(delta->work_queue); err_v4l2: v4l2_device_unregister(&delta->v4l2_dev); +err_pm_disable: + pm_runtime_disable(dev); err: return ret; } diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index c4c65d852525..09a743cd7004 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -1997,8 +1997,6 @@ static int dcmi_probe(struct platform_device *pdev) /* Initialize media device */ strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); - snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), - "platform:%s", DRV_NAME); dcmi->mdev.dev = &pdev->dev; media_device_init(&dcmi->mdev); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 80a10f238bbe..18e6c65f4737 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -173,8 +173,6 @@ static int sun4i_csi_probe(struct platform_device *pdev) strscpy(csi->mdev.model, "Allwinner Video Capture Device", sizeof(csi->mdev.model)); csi->mdev.hw_revision = 0; - snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), "platform:%s", - dev_name(csi->dev)); media_device_init(&csi->mdev); csi->v4l.mdev = &csi->mdev; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c index 3872027ed2fa..48702134ccc5 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -53,12 +53,8 @@ const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc, static int sun4i_csi_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct sun4i_csi *csi = video_drvdata(file); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "sun4i-csi", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(csi->dev)); return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index fc96921b0583..a971587dbbd1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -733,8 +733,6 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) strscpy(csi->media_dev.model, "Allwinner Video Capture Device", sizeof(csi->media_dev.model)); csi->media_dev.hw_revision = 0; - snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info), - "platform:%s", dev_name(csi->dev)); media_device_init(&csi->media_dev); v4l2_async_nf_init(&csi->notifier); diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index 6b43a1525b45..e69fed117fea 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -583,6 +583,33 @@ done: return ret; } +int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc *desc) +{ + struct media_pad *pad; + int ret; + + if (!phy->source) + return -EPIPE; + + pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]); + if (!pad) + return -EPIPE; + + ret = v4l2_subdev_call(phy->source, pad, get_frame_desc, pad->index, + desc); + if (ret) + return ret; + + if (desc->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(phy->cal->dev, + "Frame descriptor does not describe CSI-2 link"); + return -EINVAL; + } + + return 0; +} + /* ------------------------------------------------------------------ * V4L2 Subdev Operations * ------------------------------------------------------------------ diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 3e936a2ca36c..07ae1a34e6b0 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -47,13 +47,9 @@ static char *fourcc_to_str(u32 fmt) static int cal_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cal_ctx *ctx = video_drvdata(file); - strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(ctx->cal->dev)); return 0; } diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 4a4a6c5983f7..425b4f4b7ed7 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -469,10 +469,57 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) return stopped; } +static int +cal_get_remote_frame_desc_entry(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc_entry *entry) +{ + struct v4l2_mbus_frame_desc fd; + int ret; + + ret = cal_camerarx_get_remote_frame_desc(phy, &fd); + if (ret) { + if (ret != -ENOIOCTLCMD) + dev_err(phy->cal->dev, + "Failed to get remote frame desc: %d\n", ret); + return ret; + } + + if (fd.num_entries == 0) { + dev_err(phy->cal->dev, + "No streams found in the remote frame descriptor\n"); + + return -ENODEV; + } + + if (fd.num_entries > 1) + dev_dbg(phy->cal->dev, + "Multiple streams not supported in remote frame descriptor, using the first one\n"); + + *entry = fd.entry[0]; + + return 0; +} + int cal_ctx_prepare(struct cal_ctx *ctx) { + struct v4l2_mbus_frame_desc_entry entry; int ret; + ret = cal_get_remote_frame_desc_entry(ctx->phy, &entry); + + if (ret == -ENOIOCTLCMD) { + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; + } else if (!ret) { + ctx_dbg(2, ctx, "Framedesc: len %u, vc %u, dt %#x\n", + entry.length, entry.bus.csi2.vc, entry.bus.csi2.dt); + + ctx->vc = entry.bus.csi2.vc; + ctx->datatype = entry.bus.csi2.dt; + } else { + return ret; + } + ctx->use_pix_proc = !ctx->fmtinfo->meta; if (ctx->use_pix_proc) { @@ -884,8 +931,6 @@ static int cal_media_init(struct cal_dev *cal) mdev->dev = cal->dev; mdev->hw_revision = cal->revision; strscpy(mdev->model, "CAL", sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); /* @@ -936,8 +981,6 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->dma_ctx = inst; ctx->csi2_ctx = inst; ctx->cport = inst; - ctx->vc = 0; - ctx->datatype = CAL_CSI2_CTX_DT_ANY; ret = cal_ctx_v4l2_init(ctx); if (ret) diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h index 527e22d022f3..61409ddced98 100644 --- a/drivers/media/platform/ti/cal/cal.h +++ b/drivers/media/platform/ti/cal/cal.h @@ -323,6 +323,8 @@ const struct cal_format_info *cal_format_by_code(u32 code); void cal_quickdump_regs(struct cal_dev *cal); +int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc *desc); void cal_camerarx_disable(struct cal_camerarx *phy); void cal_camerarx_i913_errata(struct cal_camerarx *phy); struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, diff --git a/drivers/media/platform/ti/davinci/dm355_ccdc.c b/drivers/media/platform/ti/davinci/dm355_ccdc.c index e06d113dfe96..8fe55d1b972c 100644 --- a/drivers/media/platform/ti/davinci/dm355_ccdc.c +++ b/drivers/media/platform/ti/davinci/dm355_ccdc.c @@ -918,8 +918,7 @@ static int dm355_ccdc_remove(struct platform_device *pdev) iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); return 0; } diff --git a/drivers/media/platform/ti/davinci/dm644x_ccdc.c b/drivers/media/platform/ti/davinci/dm644x_ccdc.c index c6378c4e0074..e4073e99914c 100644 --- a/drivers/media/platform/ti/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/ti/davinci/dm644x_ccdc.c @@ -839,8 +839,7 @@ static int dm644x_ccdc_remove(struct platform_device *pdev) iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); return 0; } diff --git a/drivers/media/platform/ti/davinci/isif.c b/drivers/media/platform/ti/davinci/isif.c index c53cecd072b1..69e862de014f 100644 --- a/drivers/media/platform/ti/davinci/isif.c +++ b/drivers/media/platform/ti/davinci/isif.c @@ -1107,8 +1107,7 @@ static int isif_remove(struct platform_device *pdev) isif_cfg.linear_tbl1_addr = NULL; while (i < 3) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); i++; } vpfe_unregister_ccdc_device(&isif_hw_dev); diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c index bf3c3e76b921..9ea70817538e 100644 --- a/drivers/media/platform/ti/davinci/vpbe_display.c +++ b/drivers/media/platform/ti/davinci/vpbe_display.c @@ -630,8 +630,6 @@ static int vpbe_display_querycap(struct file *file, void *priv, snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpbe_dev->pdev)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpbe_dev->pdev)); strscpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); return 0; diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index bf76c5c83743..b91eec899eb5 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -1067,8 +1067,6 @@ static int vpif_querycap(struct file *file, void *priv, struct vpif_capture_config *config = vpif_dev->platform_data; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpif_dev)); strscpy(cap->card, config->card_name, sizeof(cap->card)); return 0; diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index fca148b66471..5d524acc995d 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -585,8 +585,6 @@ static int vpif_querycap(struct file *file, void *priv, struct vpif_display_config *config = vpif_dev->platform_data; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpif_dev)); strscpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -1286,8 +1284,7 @@ static __init int vpif_probe(struct platform_device *pdev) goto probe_subdev_out; } - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; + vpif_obj.sd[i]->grp_id = 1 << i; } err = vpif_probe_complete(); if (err) diff --git a/drivers/media/platform/ti/omap3isp/ispcsiphy.c b/drivers/media/platform/ti/omap3isp/ispcsiphy.c index 6dc7359c5131..1bde76c0adbe 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/ti/omap3isp/ispcsiphy.c @@ -31,7 +31,8 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, switch (iface) { default: - /* Should not happen in practice, but let's keep the compiler happy. */ + /* Should not happen in practice, but let's keep the compiler happy. */ + return; case ISP_INTERFACE_CCP2B_PHY1: reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2; shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index fda8fc0e4814..b31e5913a4cd 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -442,9 +442,7 @@ static int video_mux_probe(struct platform_device *pdev) vmux->mux = devm_mux_control_get(dev, NULL); if (IS_ERR(vmux->mux)) { ret = PTR_ERR(vmux->mux); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get mux: %d\n", ret); - return ret; + return dev_err_probe(dev, ret, "Failed to get mux\n"); } mutex_init(&vmux->lock); |