CHROMIUM: s5p-mfc: Fix input/output format reporting
[cascardo/linux.git] / drivers / media / video / s5p-mfc / s5p_mfc_dec.c
index 8344ce5..d15f0a6 100644 (file)
 #include <linux/workqueue.h>
 #include <media/v4l2-ctrls.h>
 #include <media/videobuf2-core.h>
-#include "regs-mfc.h"
 #include "s5p_mfc_common.h"
 #include "s5p_mfc_debug.h"
 #include "s5p_mfc_dec.h"
 #include "s5p_mfc_intr.h"
-#include "s5p_mfc_opr.h"
 #include "s5p_mfc_pm.h"
-#include "s5p_mfc_shm.h"
+
+#define DEF_SRC_FMT    4
+#define DEF_DST_FMT    0
 
 static struct s5p_mfc_fmt formats[] = {
+       {
+               .name           = "4:2:0 2 Planes 16x16 Tiles",
+               .fourcc         = V4L2_PIX_FMT_NV12MT_16X16,
+               .codec_mode     = S5P_FIMV_CODEC_NONE,
+               .type           = MFC_FMT_RAW,
+               .num_planes     = 2,
+       },
        {
                .name           = "4:2:0 2 Planes 64x32 Tiles",
                .fourcc         = V4L2_PIX_FMT_NV12MT,
                .codec_mode     = S5P_FIMV_CODEC_NONE,
                .type           = MFC_FMT_RAW,
                .num_planes     = 2,
-        },
+       },
+       {
+               .name           = "4:2:0 2 Planes Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV12M,
+               .codec_mode     = S5P_FIMV_CODEC_NONE,
+               .type           = MFC_FMT_RAW,
+               .num_planes     = 2,
+       },
+       {
+               .name           = "4:2:0 2 Planes Y/CrCb",
+               .fourcc         = V4L2_PIX_FMT_NV21M,
+               .codec_mode     = S5P_FIMV_CODEC_NONE,
+               .type           = MFC_FMT_RAW,
+               .num_planes     = 2,
+       },
+       {
+               .name           = "H264 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_H264,
+               .codec_mode     = S5P_FIMV_CODEC_H264_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
+       },
        {
-               .name = "4:2:0 2 Planes",
-               .fourcc = V4L2_PIX_FMT_NV12M,
-               .codec_mode = S5P_FIMV_CODEC_NONE,
-               .type = MFC_FMT_RAW,
-               .num_planes = 2,
+               .name           = "H264/MVC Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_H264_MVC,
+               .codec_mode     = S5P_FIMV_CODEC_H264_MVC_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "H264 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_H264,
-               .codec_mode = S5P_FIMV_CODEC_H264_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "H263 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_H263,
+               .codec_mode     = S5P_FIMV_CODEC_H263_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "H263 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_H263,
-               .codec_mode = S5P_FIMV_CODEC_H263_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "MPEG1 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_MPEG1,
+               .codec_mode     = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "MPEG1 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG1,
-               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "MPEG2 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_MPEG2,
+               .codec_mode     = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "MPEG2 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG2,
-               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "MPEG4 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_MPEG4,
+               .codec_mode     = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "MPEG4 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG4,
-               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "XviD Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_XVID,
+               .codec_mode     = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "XviD Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_XVID,
-               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "VC1 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_VC1_ANNEX_G,
+               .codec_mode     = S5P_FIMV_CODEC_VC1_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "VC1 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
-               .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "VC1 RCV Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_VC1_ANNEX_L,
+               .codec_mode     = S5P_FIMV_CODEC_VC1RCV_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
        {
-               .name = "VC1 RCV Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
-               .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
-               .type = MFC_FMT_DEC,
-               .num_planes = 1,
+               .name           = "VC8 Encoded Stream",
+               .fourcc         = V4L2_PIX_FMT_VP8,
+               .codec_mode     = S5P_FIMV_CODEC_VP8_DEC,
+               .type           = MFC_FMT_DEC,
+               .num_planes     = 1,
        },
 };
 
@@ -167,6 +195,27 @@ static struct mfc_control controls[] = {
                .default_value = 1,
                .is_volatile = 1,
        },
+       {
+               .id = V4L2_CID_CODEC_DISPLAY_STATUS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Display Status",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+               .default_value = 0,
+               .is_volatile = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Check State",
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+               .default_value = 0,
+               .is_volatile = 1,
+               .flags = V4L2_CTRL_FLAG_READ_ONLY,
+       },
 };
 
 #define NUM_CTRLS ARRAY_SIZE(controls)
@@ -308,7 +357,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
                pix_mp->num_planes = 2;
                /* Set pixelformat to the format in which MFC
                   outputs the decoded frame */
-               pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+               pix_mp->pixelformat = ctx->dst_fmt->fourcc;
                pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
@@ -336,21 +385,50 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 /* Try format */
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
+       struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               mfc_err("This node supports decoding only\n");
-               return -EINVAL;
-       }
-       fmt = find_format(f, MFC_FMT_DEC);
-       if (!fmt) {
-               mfc_err("Unsupported format\n");
-               return -EINVAL;
-       }
-       if (fmt->type != MFC_FMT_DEC) {
-               mfc_err("\n");
-               return -EINVAL;
+       mfc_debug(2, "Type is %d\n", f->type);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               fmt = find_format(f, MFC_FMT_DEC);
+               if (!fmt) {
+                       mfc_err("Unsupported format for source.\n");
+                       return -EINVAL;
+               }
+               if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+                       mfc_err("Unknown codec\n");
+                       return -EINVAL;
+               }
+               if (!IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               fmt = find_format(f, MFC_FMT_RAW);
+               if (!fmt) {
+                       mfc_err("Unsupported format for destination.\n");
+                       return -EINVAL;
+               }
+               if (IS_MFCV6(dev)) {
+                       switch (fmt->fourcc) {
+                       case V4L2_PIX_FMT_NV12M:
+                       case V4L2_PIX_FMT_NV21M:
+                       case V4L2_PIX_FMT_NV12MT_16X16:
+                               break;
+                       default:
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       if (fmt->fourcc != V4L2_PIX_FMT_NV12MT) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
        }
+
        return 0;
 }
 
@@ -360,7 +438,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        int ret = 0;
-       struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_mp;
 
        mfc_debug_enter();
@@ -373,30 +450,33 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                ret = -EBUSY;
                goto out;
        }
-       fmt = find_format(f, MFC_FMT_DEC);
-       if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
-               mfc_err("Unknown codec\n");
-               ret = -EINVAL;
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               /* dst_fmt is validated by call to vidioc_try_fmt */
+               ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
+               ret = 0;
                goto out;
-       }
-       if (fmt->type != MFC_FMT_DEC) {
-               mfc_err("Wrong format selected, you should choose "
-                                       "format for decoding\n");
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* src_fmt is validated by call to vidioc_try_fmt */
+               ctx->src_fmt = find_format(f, MFC_FMT_DEC);
+               ctx->codec_mode = ctx->src_fmt->codec_mode;
+               mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+               pix_mp->height = 0;
+               pix_mp->width = 0;
+               if (pix_mp->plane_fmt[0].sizeimage)
+                       ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+               else
+                       pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+                                                               DEF_CPB_SIZE;
+               pix_mp->plane_fmt[0].bytesperline = 0;
+               ctx->state = MFCINST_INIT;
+               ret = 0;
+               goto out;
+       } else {
+               mfc_err("Wrong type error for S_FMT : %d", f->type);
                ret = -EINVAL;
                goto out;
        }
-       ctx->src_fmt = fmt;
-       ctx->codec_mode = fmt->codec_mode;
-       mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
-       pix_mp->height = 0;
-       pix_mp->width = 0;
-       if (pix_mp->plane_fmt[0].sizeimage)
-               ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
-       else
-               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
-                                                               DEF_CPB_SIZE;
-       pix_mp->plane_fmt[0].bytesperline = 0;
-       ctx->state = MFCINST_INIT;
+
 out:
        mfc_debug_leave();
        return ret;
@@ -498,7 +578,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                }
                s5p_mfc_try_run(dev);
                s5p_mfc_wait_for_done_ctx(ctx,
-                                        S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
+                                       S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
        }
        return ret;
 }
@@ -569,16 +649,12 @@ static int vidioc_expbuf(struct file *file, void *priv,
        struct v4l2_exportbuffer *eb)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-       int ret;
 
-       if (eb->mem_offset < DST_QUEUE_OFF_BASE)
+       if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
                return vb2_expbuf(&ctx->vq_src, eb);
-
-       eb->mem_offset -= DST_QUEUE_OFF_BASE;
-       ret = vb2_expbuf(&ctx->vq_dst, eb);
-       eb->mem_offset += DST_QUEUE_OFF_BASE;
-
-       return ret;
+       else if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_expbuf(&ctx->vq_dst, eb);
+       return -EINVAL;
 }
 
 /* Stream on */
@@ -644,13 +720,13 @@ static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
-               ctx->loop_filter_mpeg4 = ctrl->val;
+               ctx->display_delay = ctrl->val;
                break;
        case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
                ctx->display_delay_enable = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
-               ctx->display_delay = ctrl->val;
+               ctx->loop_filter_mpeg4 = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
                ctx->slice_interface = ctrl->val;
@@ -689,6 +765,20 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
                        return -EINVAL;
                }
                break;
+       case V4L2_CID_CODEC_DISPLAY_STATUS:
+               ctrl->val = s5p_mfc_get_dspl_status()
+                               & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
+               if (ctx->state == MFCINST_RES_CHANGE_FLUSH
+                               || ctx->state == MFCINST_RES_CHANGE_END
+                               || ctx->state == MFCINST_HEAD_PARSED)
+                       ctrl->val = MFCSTATE_DEC_RES_DETECT;
+               else if (ctx->state == MFCINST_FINISHING)
+                       ctrl->val = MFCSTATE_DEC_TERMINATING;
+               else
+                       ctrl->val = MFCSTATE_PROCESSING;
+               break;
        }
        return 0;
 }
@@ -713,10 +803,10 @@ static int vidioc_g_crop(struct file *file, void *priv,
                        return -EINVAL;
                }
        if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
-               left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
+               left = s5p_mfc_read_info(ctx, CROP_INFO_H);
                right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
                left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
-               top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
+               top = s5p_mfc_read_info(ctx, CROP_INFO_V);
                bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
                top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
                cr->c.left = left;
@@ -768,6 +858,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
                        void *allocators[])
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
 
        /* Video output for decoding (source)
         * this can be set after getting an instance */
@@ -803,7 +894,11 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
            vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                psize[0] = ctx->luma_size;
                psize[1] = ctx->chroma_size;
-               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+
+               if (IS_MFCV6(dev))
+                       allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+               else
+                       allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
                allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
        } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
                   ctx->state == MFCINST_INIT) {
@@ -841,7 +936,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
        if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                if (ctx->capture_state == QUEUE_BUFS_MMAPED)
                        return 0;
-               for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+               for (i = 0; i <= ctx->src_fmt->num_planes; i++) {
                        if (IS_ERR_OR_NULL(ERR_PTR(
                                        vb2_dma_contig_plane_dma_addr(vb, i)))) {
                                mfc_err("Plane mem not allocated\n");
@@ -918,22 +1013,35 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q)
                                        S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
                aborted = 1;
        }
-       spin_lock_irqsave(&dev->irqlock, flags);
+
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               spin_lock_irqsave(&dev->irqlock, flags);
                s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
-               ctx->dpb_flush_flag = 1;
+               ctx->dpb_flush = 1;
                ctx->dec_dst_flag = 0;
-       }
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               if (IS_MFCV6(dev) && (ctx->state == MFCINST_RUNNING)) {
+                       ctx->state = MFCINST_FLUSH;
+                       spin_lock_irqsave(&dev->condlock, flags);
+                       set_bit(ctx->num, &dev->ctx_work_bits);
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       s5p_mfc_try_run(dev);
+                       if (s5p_mfc_wait_for_done_ctx(ctx,
+                               S5P_FIMV_R2H_CMD_DPB_FLUSH_RET, 0))
+                               mfc_err("Err flushing buffers\n");
+               }
+       } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               spin_lock_irqsave(&dev->irqlock, flags);
                s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
        }
        if (aborted)
                ctx->state = MFCINST_RUNNING;
-       spin_unlock_irqrestore(&dev->irqlock, flags);
        return 0;
 }
 
@@ -1014,6 +1122,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
 
        for (i = 0; i < NUM_CTRLS; i++) {
                if (IS_MFC51_PRIV(controls[i].id)) {
+                       memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
                        cfg.ops = &s5p_mfc_dec_ctrl_ops;
                        cfg.id = controls[i].id;
                        cfg.min = controls[i].minimum;
@@ -1023,6 +1132,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
                        cfg.type = controls[i].type;
 
                        cfg.step = controls[i].step;
+                       cfg.flags = controls[i].flags;
                        cfg.menu_skip_mask = 0;
 
                        ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
@@ -1053,3 +1163,8 @@ void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
                ctx->ctrls[i] = NULL;
 }
 
+void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
+{
+       ctx->src_fmt = &formats[DEF_SRC_FMT];
+       ctx->dst_fmt = &formats[DEF_DST_FMT];
+}