media: coda: store device pointer in driver structure instead of pdev
[linux-2.6-microblaze.git] / drivers / media / platform / coda / coda-common.c
index 6238047..f43f388 100644 (file)
@@ -74,7 +74,7 @@ MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain
 
 void coda_write(struct coda_dev *dev, u32 data, u32 reg)
 {
-       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+       v4l2_dbg(3, coda_debug, &dev->v4l2_dev,
                 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
        writel(data, dev->regs_base + reg);
 }
@@ -84,7 +84,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg)
        u32 data;
 
        data = readl(dev->regs_base + reg);
-       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+       v4l2_dbg(3, coda_debug, &dev->v4l2_dev,
                 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
        return data;
 }
@@ -879,14 +879,25 @@ static int coda_qbuf(struct file *file, void *priv,
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
+       if (ctx->inst_type == CODA_INST_DECODER &&
+           buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               buf->flags &= ~V4L2_BUF_FLAG_LAST;
+
        return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
 }
 
-static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
-                                     struct vb2_v4l2_buffer *buf)
+static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
-       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
-               (buf->sequence == (ctx->qsequence - 1)));
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
+
+       if (ctx->inst_type == CODA_INST_DECODER &&
+           buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               buf->flags &= ~V4L2_BUF_FLAG_LAST;
+
+       return ret;
 }
 
 void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
@@ -896,11 +907,8 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
                .type = V4L2_EVENT_EOS
        };
 
-       if (coda_buf_is_end_of_stream(ctx, buf)) {
-               buf->flags |= V4L2_BUF_FLAG_LAST;
-
+       if (buf->flags & V4L2_BUF_FLAG_LAST)
                v4l2_event_queue_fh(&ctx->fh, &eos_event);
-       }
 
        v4l2_m2m_buf_done(buf, state);
 }
@@ -1001,36 +1009,52 @@ static int coda_try_encoder_cmd(struct file *file, void *fh,
        if (ctx->inst_type != CODA_INST_ENCODER)
                return -ENOTTY;
 
-       if (ec->cmd != V4L2_ENC_CMD_STOP)
-               return -EINVAL;
+       return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
+}
 
-       if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
-               return -EINVAL;
+static void coda_wake_up_capture_queue(struct coda_ctx *ctx)
+{
+       struct vb2_queue *dst_vq;
 
-       return 0;
+       coda_dbg(1, ctx, "waking up capture queue\n");
+
+       dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_vq->last_buffer_dequeued = true;
+       wake_up(&dst_vq->done_wq);
 }
 
 static int coda_encoder_cmd(struct file *file, void *fh,
                            struct v4l2_encoder_cmd *ec)
 {
        struct coda_ctx *ctx = fh_to_ctx(fh);
-       struct vb2_queue *dst_vq;
+       struct vb2_v4l2_buffer *buf;
        int ret;
 
        ret = coda_try_encoder_cmd(file, fh, ec);
        if (ret < 0)
                return ret;
 
-       /* Set the stream-end flag on this context */
-       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+       mutex_lock(&ctx->wakeup_mutex);
+       buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
+       if (buf) {
+               /*
+                * If the last output buffer is still on the queue, make sure
+                * that decoder finish_run will see the last flag and report it
+                * to userspace.
+                */
+               buf->flags |= V4L2_BUF_FLAG_LAST;
+       } else {
+               /* Set the stream-end flag on this context */
+               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
 
-       /* If there is no buffer in flight, wake up */
-       if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) {
-               dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
-                                        V4L2_BUF_TYPE_VIDEO_CAPTURE);
-               dst_vq->last_buffer_dequeued = true;
-               wake_up(&dst_vq->done_wq);
+               /*
+                * If the last output buffer has already been taken from the
+                * queue, wake up the capture queue and signal end of stream
+                * via the -EPIPE mechanism.
+                */
+               coda_wake_up_capture_queue(ctx);
        }
+       mutex_unlock(&ctx->wakeup_mutex);
 
        return 0;
 }
@@ -1043,32 +1067,89 @@ static int coda_try_decoder_cmd(struct file *file, void *fh,
        if (ctx->inst_type != CODA_INST_DECODER)
                return -ENOTTY;
 
-       if (dc->cmd != V4L2_DEC_CMD_STOP)
-               return -EINVAL;
-
-       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
-               return -EINVAL;
-
-       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
-               return -EINVAL;
-
-       return 0;
+       return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
 }
 
 static int coda_decoder_cmd(struct file *file, void *fh,
                            struct v4l2_decoder_cmd *dc)
 {
        struct coda_ctx *ctx = fh_to_ctx(fh);
+       struct coda_dev *dev = ctx->dev;
+       struct vb2_v4l2_buffer *buf;
+       struct vb2_queue *dst_vq;
+       bool stream_end;
+       bool wakeup;
        int ret;
 
        ret = coda_try_decoder_cmd(file, fh, dc);
        if (ret < 0)
                return ret;
 
-       /* Set the stream-end flag on this context */
-       coda_bit_stream_end_flag(ctx);
-       ctx->hold = false;
-       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+       switch (dc->cmd) {
+       case V4L2_DEC_CMD_START:
+               mutex_lock(&ctx->bitstream_mutex);
+               mutex_lock(&dev->coda_mutex);
+               coda_bitstream_flush(ctx);
+               mutex_unlock(&dev->coda_mutex);
+               dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+                                        V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               vb2_clear_last_buffer_dequeued(dst_vq);
+               ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG;
+               coda_fill_bitstream(ctx, NULL);
+               mutex_unlock(&ctx->bitstream_mutex);
+               break;
+       case V4L2_DEC_CMD_STOP:
+               stream_end = false;
+               wakeup = false;
+
+               buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
+               if (buf) {
+                       coda_dbg(1, ctx, "marking last pending buffer\n");
+
+                       /* Mark last buffer */
+                       buf->flags |= V4L2_BUF_FLAG_LAST;
+
+                       if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) {
+                               coda_dbg(1, ctx, "all remaining buffers queued\n");
+                               stream_end = true;
+                       }
+               } else {
+                       coda_dbg(1, ctx, "marking last meta\n");
+
+                       /* Mark last meta */
+                       spin_lock(&ctx->buffer_meta_lock);
+                       if (!list_empty(&ctx->buffer_meta_list)) {
+                               struct coda_buffer_meta *meta;
+
+                               meta = list_last_entry(&ctx->buffer_meta_list,
+                                                      struct coda_buffer_meta,
+                                                      list);
+                               meta->last = true;
+                               stream_end = true;
+                       } else {
+                               wakeup = true;
+                       }
+                       spin_unlock(&ctx->buffer_meta_lock);
+               }
+
+               if (stream_end) {
+                       coda_dbg(1, ctx, "all remaining buffers queued\n");
+
+                       /* Set the stream-end flag on this context */
+                       coda_bit_stream_end_flag(ctx);
+                       ctx->hold = false;
+                       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+               }
+
+               if (wakeup) {
+                       /* If there is no buffer in flight, wake up */
+                       coda_wake_up_capture_queue(ctx);
+               }
+
+               break;
+       default:
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1243,9 +1324,16 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 static int coda_subscribe_event(struct v4l2_fh *fh,
                                const struct v4l2_event_subscription *sub)
 {
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+
        switch (sub->type) {
        case V4L2_EVENT_EOS:
                return v4l2_event_subscribe(fh, sub, 0, NULL);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               if (ctx->inst_type == CODA_INST_DECODER)
+                       return v4l2_event_subscribe(fh, sub, 0, NULL);
+               else
+                       return -EINVAL;
        default:
                return v4l2_ctrl_subscribe_event(fh, sub);
        }
@@ -1269,7 +1357,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
 
        .vidioc_qbuf            = coda_qbuf,
        .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
-       .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_dqbuf           = coda_dqbuf,
        .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
        .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
 
@@ -1325,7 +1413,7 @@ static void coda_pic_run_work(struct work_struct *work)
 
        if (!wait_for_completion_timeout(&ctx->completion,
                                         msecs_to_jiffies(1000))) {
-               dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+               dev_err(dev->dev, "CODA PIC_RUN timeout\n");
 
                ctx->hold = true;
 
@@ -1412,7 +1500,7 @@ static int coda_job_ready(void *m2m_priv)
                return 0;
        }
 
-       coda_dbg(1, ctx, "job ready\n");
+       coda_dbg(2, ctx, "job ready\n");
 
        return 1;
 }
@@ -1563,42 +1651,81 @@ static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value)
        v4l2_ctrl_unlock(ctrl);
 }
 
-static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx)
+void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc,
+                                    u8 level_idc)
 {
        const char * const *profile_names;
+       const char * const *level_names;
+       struct v4l2_ctrl *profile_ctrl;
+       struct v4l2_ctrl *level_ctrl;
+       const char *codec_name;
+       u32 profile_cid;
+       u32 level_cid;
        int profile;
+       int level;
 
-       profile = coda_h264_profile(ctx->params.h264_profile_idc);
-       if (profile < 0) {
-               v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Profile: %u\n",
-                         ctx->params.h264_profile_idc);
+       switch (ctx->codec->src_fourcc) {
+       case V4L2_PIX_FMT_H264:
+               codec_name = "H264";
+               profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
+               level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
+               profile_ctrl = ctx->h264_profile_ctrl;
+               level_ctrl = ctx->h264_level_ctrl;
+               profile = coda_h264_profile(profile_idc);
+               level = coda_h264_level(level_idc);
+               break;
+       case V4L2_PIX_FMT_MPEG2:
+               codec_name = "MPEG-2";
+               profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE;
+               level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL;
+               profile_ctrl = ctx->mpeg2_profile_ctrl;
+               level_ctrl = ctx->mpeg2_level_ctrl;
+               profile = coda_mpeg2_profile(profile_idc);
+               level = coda_mpeg2_level(level_idc);
+               break;
+       case V4L2_PIX_FMT_MPEG4:
+               codec_name = "MPEG-4";
+               profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
+               level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
+               profile_ctrl = ctx->mpeg4_profile_ctrl;
+               level_ctrl = ctx->mpeg4_level_ctrl;
+               profile = coda_mpeg4_profile(profile_idc);
+               level = coda_mpeg4_level(level_idc);
+               break;
+       default:
                return;
        }
 
-       coda_update_menu_ctrl(ctx->h264_profile_ctrl, profile);
-
-       profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
-
-       coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]);
-}
+       profile_names = v4l2_ctrl_get_menu(profile_cid);
+       level_names = v4l2_ctrl_get_menu(level_cid);
 
-static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
-{
-       const char * const *level_names;
-       int level;
+       if (profile < 0) {
+               v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n",
+                         codec_name, profile_idc);
+       } else {
+               coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name,
+                        profile_names[profile]);
+               coda_update_menu_ctrl(profile_ctrl, profile);
+       }
 
-       level = coda_h264_level(ctx->params.h264_level_idc);
        if (level < 0) {
-               v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Level: %u\n",
-                         ctx->params.h264_level_idc);
-               return;
+               v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n",
+                         codec_name, level_idc);
+       } else {
+               coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name,
+                        level_names[level]);
+               coda_update_menu_ctrl(level_ctrl, level);
        }
+}
 
-       coda_update_menu_ctrl(ctx->h264_level_ctrl, level);
-
-       level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+static void coda_queue_source_change_event(struct coda_ctx *ctx)
+{
+       static const struct v4l2_event source_change_event = {
+               .type = V4L2_EVENT_SOURCE_CHANGE,
+               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+       };
 
-       coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]);
+       v4l2_event_queue_fh(&ctx->fh, &source_change_event);
 }
 
 static void coda_buf_queue(struct vb2_buffer *vb)
@@ -1631,8 +1758,9 @@ static void coda_buf_queue(struct vb2_buffer *vb)
                         */
                        if (!ctx->params.h264_profile_idc) {
                                coda_sps_parse_profile(ctx, vb);
-                               coda_update_h264_profile_ctrl(ctx);
-                               coda_update_h264_level_ctrl(ctx);
+                               coda_update_profile_level_ctrls(ctx,
+                                               ctx->params.h264_profile_idc,
+                                               ctx->params.h264_level_idc);
                        }
                }
 
@@ -1642,6 +1770,22 @@ static void coda_buf_queue(struct vb2_buffer *vb)
                        /* This set buf->sequence = ctx->qsequence++ */
                        coda_fill_bitstream(ctx, NULL);
                mutex_unlock(&ctx->bitstream_mutex);
+
+               if (!ctx->initialized) {
+                       /*
+                        * Run sequence initialization in case the queued
+                        * buffer contained headers.
+                        */
+                       if (vb2_is_streaming(vb->vb2_queue) &&
+                           ctx->ops->seq_init_work) {
+                               queue_work(ctx->dev->workqueue,
+                                          &ctx->seq_init_work);
+                               flush_work(&ctx->seq_init_work);
+                       }
+
+                       if (ctx->initialized)
+                               coda_queue_source_change_event(ctx);
+               }
        } else {
                if (ctx->inst_type == CODA_INST_ENCODER &&
                    vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -1653,7 +1797,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
 int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
                       size_t size, const char *name, struct dentry *parent)
 {
-       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+       buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr,
                                        GFP_KERNEL);
        if (!buf->vaddr) {
                v4l2_err(&dev->v4l2_dev,
@@ -1670,7 +1814,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
                buf->dentry = debugfs_create_blob(name, 0644, parent,
                                                  &buf->blob);
                if (!buf->dentry)
-                       dev_warn(&dev->plat_dev->dev,
+                       dev_warn(dev->dev,
                                 "failed to create debugfs entry %s\n", name);
        }
 
@@ -1681,8 +1825,7 @@ void coda_free_aux_buf(struct coda_dev *dev,
                       struct coda_aux_buf *buf)
 {
        if (buf->vaddr) {
-               dma_free_coherent(&dev->plat_dev->dev, buf->size,
-                                 buf->vaddr, buf->paddr);
+               dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr);
                buf->vaddr = NULL;
                buf->size = 0;
                debugfs_remove(buf->dentry);
@@ -1715,10 +1858,21 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                        coda_fill_bitstream(ctx, &list);
                        mutex_unlock(&ctx->bitstream_mutex);
 
-                       if (coda_get_bitstream_payload(ctx) < 512) {
+                       if (ctx->dev->devtype->product != CODA_960 &&
+                           coda_get_bitstream_payload(ctx) < 512) {
+                               v4l2_err(v4l2_dev, "start payload < 512\n");
                                ret = -EINVAL;
                                goto err;
                        }
+
+                       if (!ctx->initialized) {
+                               /* Run sequence initialization */
+                               if (ctx->ops->seq_init_work) {
+                                       queue_work(ctx->dev->workqueue,
+                                                  &ctx->seq_init_work);
+                                       flush_work(&ctx->seq_init_work);
+                               }
+                       }
                }
 
                ctx->streamon_out = 1;
@@ -1853,11 +2007,16 @@ static const struct vb2_ops coda_qops = {
 
 static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id);
        struct coda_ctx *ctx =
                        container_of(ctrl->handler, struct coda_ctx, ctrls);
 
-       coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
-                ctrl->id, ctrl->name, ctrl->val);
+       if (val_names)
+               coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n",
+                        ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]);
+       else
+               coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
+                        ctrl->id, ctrl->name, ctrl->val);
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
@@ -1919,6 +2078,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
                ctx->params.mpeg4_inter_qp = ctrl->val;
                break;
+       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
        case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
                /* nothing to do, these are fixed */
@@ -2040,7 +2201,7 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
        }
        v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
-               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
+               V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0,
                V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
@@ -2098,6 +2259,34 @@ static void coda_decode_ctrls(struct coda_ctx *ctx)
                &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max);
        if (ctx->h264_level_ctrl)
                ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+               &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE,
+               V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0,
+               V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH);
+       if (ctx->mpeg2_profile_ctrl)
+               ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+               &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL,
+               V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0,
+               V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH);
+       if (ctx->mpeg2_level_ctrl)
+               ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+               &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+               V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0,
+               V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY);
+       if (ctx->mpeg4_profile_ctrl)
+               ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+               &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+               V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0,
+               V4L2_MPEG_VIDEO_MPEG4_LEVEL_5);
+       if (ctx->mpeg4_level_ctrl)
+               ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 }
 
 static int coda_ctrls_setup(struct coda_ctx *ctx)
@@ -2154,7 +2343,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
         * queues to have at least one buffer queued.
         */
        vq->min_buffers_needed = 1;
-       vq->dev = &ctx->dev->plat_dev->dev;
+       vq->dev = ctx->dev->dev;
 
        return vb2_queue_init(vq);
 }
@@ -2240,6 +2429,8 @@ static int coda_open(struct file *file)
        ctx->use_bit = !ctx->cvd->direct;
        init_completion(&ctx->completion);
        INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+       if (ctx->ops->seq_init_work)
+               INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work);
        if (ctx->ops->seq_end_work)
                INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
        v4l2_fh_init(&ctx->fh, video_devdata(file));
@@ -2277,7 +2468,7 @@ static int coda_open(struct file *file)
        ctx->use_vdoa = false;
 
        /* Power up and upload firmware if necessary */
-       ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+       ret = pm_runtime_get_sync(dev->dev);
        if (ret < 0) {
                v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
                goto err_pm_get;
@@ -2312,6 +2503,7 @@ static int coda_open(struct file *file)
 
        mutex_init(&ctx->bitstream_mutex);
        mutex_init(&ctx->buffer_mutex);
+       mutex_init(&ctx->wakeup_mutex);
        INIT_LIST_HEAD(&ctx->buffer_meta_list);
        spin_lock_init(&ctx->buffer_meta_lock);
 
@@ -2324,7 +2516,7 @@ err_ctx_init:
 err_clk_ahb:
        clk_disable_unprepare(dev->clk_per);
 err_clk_per:
-       pm_runtime_put_sync(&dev->plat_dev->dev);
+       pm_runtime_put_sync(dev->dev);
 err_pm_get:
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
@@ -2363,7 +2555,7 @@ static int coda_release(struct file *file)
        v4l2_ctrl_handler_free(&ctx->ctrls);
        clk_disable_unprepare(dev->clk_ahb);
        clk_disable_unprepare(dev->clk_per);
-       pm_runtime_put_sync(&dev->plat_dev->dev);
+       pm_runtime_put_sync(dev->dev);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
        ida_free(&dev->ida, ctx->idx);
@@ -2486,9 +2678,12 @@ err_clk_per:
 static int coda_register_device(struct coda_dev *dev, int i)
 {
        struct video_device *vfd = &dev->vfd[i];
+       enum coda_inst_type type;
+       int ret;
 
        if (i >= dev->devtype->num_vdevs)
                return -EINVAL;
+       type = dev->devtype->vdevs[i]->type;
 
        strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name));
        vfd->fops       = &coda_fops;
@@ -2504,7 +2699,12 @@ 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);
 
-       return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (!ret)
+               v4l2_info(&dev->v4l2_dev, "%s registered as %s\n",
+                         type == CODA_INST_ENCODER ? "encoder" : "decoder",
+                         video_device_node_name(vfd));
+       return ret;
 }
 
 static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf,
@@ -2550,18 +2750,16 @@ static int coda_firmware_request(struct coda_dev *dev)
 
        fw = dev->devtype->firmware[dev->firmware];
 
-       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+       dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw,
                coda_product_name(dev->devtype->product));
 
-       return request_firmware_nowait(THIS_MODULE, true, fw,
-                                      &dev->plat_dev->dev, GFP_KERNEL, dev,
-                                      coda_fw_callback);
+       return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev,
+                                      GFP_KERNEL, dev, coda_fw_callback);
 }
 
 static void coda_fw_callback(const struct firmware *fw, void *context)
 {
        struct coda_dev *dev = context;
-       struct platform_device *pdev = dev->plat_dev;
        int i, ret;
 
        if (!fw) {
@@ -2579,7 +2777,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
                 * firmware requests, report that the fallback firmware was
                 * found.
                 */
-               dev_info(&pdev->dev, "Using fallback firmware %s\n",
+               dev_info(dev->dev, "Using fallback firmware %s\n",
                         dev->devtype->firmware[dev->firmware]);
        }
 
@@ -2618,10 +2816,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
                }
        }
 
-       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
-                 dev->vfd[0].num, dev->vfd[i - 1].num);
-
-       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_put_sync(dev->dev);
        return;
 
 rel_vfd:
@@ -2629,7 +2824,7 @@ rel_vfd:
                video_unregister_device(&dev->vfd[i]);
        v4l2_m2m_release(dev->m2m_dev);
 put_pm:
-       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_put_sync(dev->dev);
 }
 
 enum coda_platform {
@@ -2744,7 +2939,6 @@ static int coda_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct gen_pool *pool;
        struct coda_dev *dev;
-       struct resource *res;
        int ret, irq;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -2762,7 +2956,7 @@ static int coda_probe(struct platform_device *pdev)
 
        spin_lock_init(&dev->irqlock);
 
-       dev->plat_dev = pdev;
+       dev->dev = &pdev->dev;
        dev->clk_per = devm_clk_get(&pdev->dev, "per");
        if (IS_ERR(dev->clk_per)) {
                dev_err(&pdev->dev, "Could not get per clock\n");
@@ -2776,8 +2970,7 @@ static int coda_probe(struct platform_device *pdev)
        }
 
        /* Get  memory for physical registers */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+       dev->regs_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dev->regs_base))
                return PTR_ERR(dev->regs_base);
 
@@ -2790,8 +2983,8 @@ static int coda_probe(struct platform_device *pdev)
                return irq;
        }
 
-       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
-                       IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+       ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0,
+                              dev_name(&pdev->dev), dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
                return ret;