]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/media/platform/coda.c
[media] coda: Fix 'driver_data' for mx53
[karo-tx-linux.git] / drivers / media / platform / coda.c
index 7a41ea1bec34be7762c834d6fec0d67bf8835f7a..7b8b547f2d51867115f9bf5a510495e6c35baebb 100644 (file)
@@ -137,9 +137,11 @@ struct coda_dev {
        struct list_head        instances;
        unsigned long           instance_mask;
        struct delayed_work     timeout;
+       struct completion       done;
 };
 
 struct coda_params {
+       u8                      rot_mode;
        u8                      h264_intra_qp;
        u8                      h264_inter_qp;
        u8                      mpeg4_intra_qp;
@@ -149,6 +151,7 @@ struct coda_params {
        enum v4l2_mpeg_video_multi_slice_mode slice_mode;
        u32                     framerate;
        u16                     bitrate;
+       u32                     slice_max_bits;
        u32                     slice_max_mb;
 };
 
@@ -411,8 +414,8 @@ static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
                                      W_ALIGN, &f->fmt.pix.height,
                                      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
                f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
-               f->fmt.pix.sizeimage = f->fmt.pix.height *
-                                       f->fmt.pix.bytesperline;
+               f->fmt.pix.sizeimage = f->fmt.pix.width *
+                                       f->fmt.pix.height * 3 / 2;
        } else { /*encoded formats h.264/mpeg4 */
                f->fmt.pix.bytesperline = 0;
                f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
@@ -496,11 +499,7 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
        q_data->fmt = find_format(ctx->dev, f);
        q_data->width = f->fmt.pix.width;
        q_data->height = f->fmt.pix.height;
-       if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) {
-               q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
-       } else { /* encoded format h.264/mpeg-4 */
-               q_data->sizeimage = CODA_MAX_FRAME_SIZE;
-       }
+       q_data->sizeimage = f->fmt.pix.sizeimage;
 
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
@@ -703,7 +702,7 @@ static void coda_device_run(void *m2m_priv)
        }
 
        /* submit */
-       coda_write(dev, 0, CODA_CMD_ENC_PIC_ROT_MODE);
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
        coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
 
 
@@ -731,6 +730,7 @@ static void coda_device_run(void *m2m_priv)
        /* 1 second timeout in case CODA locks up */
        schedule_delayed_work(&dev->timeout, HZ);
 
+       INIT_COMPLETION(dev->done);
        coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
 }
 
@@ -818,18 +818,11 @@ static int coda_queue_setup(struct vb2_queue *vq,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
        struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+       struct coda_q_data *q_data;
        unsigned int size;
 
-       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               if (fmt)
-                       size = fmt->fmt.pix.width *
-                               fmt->fmt.pix.height * 3 / 2;
-               else
-                       size = MAX_W *
-                               MAX_H * 3 / 2;
-       } else {
-               size = CODA_MAX_FRAME_SIZE;
-       }
+       q_data = get_q_data(ctx, vq->type);
+       size = q_data->sizeimage;
 
        *nplanes = 1;
        sizes[0] = size;
@@ -975,6 +968,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        if (!(ctx->rawstreamon & ctx->compstreamon))
                return 0;
 
+       if (coda_isbusy(dev))
+               if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0)
+                       return -EBUSY;
+
        ctx->gopcounter = ctx->params.gop_size - 1;
 
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -1058,12 +1055,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                return -EINVAL;
        }
 
-       value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-       value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-       if (ctx->params.slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB)
+       switch (ctx->params.slice_mode) {
+       case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+               value = 0;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+               value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
+               value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
                value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+               value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
+               value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
+               value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       }
        coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
-       value  =  ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+       value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
        coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
 
        if (ctx->params.bitrate) {
@@ -1229,20 +1237,29 @@ static int coda_stop_streaming(struct vb2_queue *q)
                ctx->compstreamon = 0;
        }
 
-       if (!ctx->rawstreamon && !ctx->compstreamon) {
-               cancel_delayed_work(&dev->timeout);
+       /* Don't stop the coda unless both queues are off */
+       if (ctx->rawstreamon || ctx->compstreamon)
+               return 0;
 
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "%s: sent command 'SEQ_END' to coda\n", __func__);
-               if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
-                       v4l2_err(&ctx->dev->v4l2_dev,
-                                "CODA_COMMAND_SEQ_END failed\n");
-                       return -ETIMEDOUT;
+       if (coda_isbusy(dev)) {
+               if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0) {
+                       v4l2_warn(&dev->v4l2_dev,
+                                 "%s: timeout, sending SEQ_END anyway\n", __func__);
                }
+       }
 
-               coda_free_framebuffers(ctx);
+       cancel_delayed_work(&dev->timeout);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%s: sent command 'SEQ_END' to coda\n", __func__);
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "CODA_COMMAND_SEQ_END failed\n");
+               return -ETIMEDOUT;
        }
 
+       coda_free_framebuffers(ctx);
+
        return 0;
 }
 
@@ -1265,6 +1282,18 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
                 "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
 
        switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_HOR;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_HOR;
+               break;
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_VER;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_VER;
+               break;
        case V4L2_CID_MPEG_VIDEO_BITRATE:
                ctx->params.bitrate = ctrl->val / 1000;
                break;
@@ -1289,6 +1318,9 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
                ctx->params.slice_max_mb = ctrl->val;
                break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+               ctx->params.slice_max_bits = ctrl->val * 8;
+               break;
        case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
                break;
        default:
@@ -1309,6 +1341,10 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
 {
        v4l2_ctrl_handler_init(&ctx->ctrls, 9);
 
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_VFLIP, 0, 1, 1, 0);
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -1323,10 +1359,12 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
                V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
        v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
-               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 0,
-               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB);
+               V4L2_MPEG_VIDEO_MULTI_SICE_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);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500);
        v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_HEADER_MODE,
                V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
@@ -1349,7 +1387,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
        int ret;
 
        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       src_vq->io_modes = VB2_MMAP;
+       src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
        src_vq->drv_priv = ctx;
        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        src_vq->ops = &coda_qops;
@@ -1360,7 +1398,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
                return ret;
 
        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       dst_vq->io_modes = VB2_MMAP;
+       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
        dst_vq->drv_priv = ctx;
        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        dst_vq->ops = &coda_qops;
@@ -1502,7 +1540,7 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
        u32 wr_ptr, start_ptr;
        struct coda_ctx *ctx;
 
-       __cancel_delayed_work(&dev->timeout);
+       cancel_delayed_work(&dev->timeout);
 
        /* read status register to attend the IRQ */
        coda_read(dev, CODA_REG_BIT_INT_STATUS);
@@ -1527,6 +1565,8 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
                return IRQ_NONE;
        }
 
+       complete(&dev->done);
+
        src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
@@ -1582,6 +1622,11 @@ static void coda_timeout(struct work_struct *work)
        struct coda_dev *dev = container_of(to_delayed_work(work),
                                            struct coda_dev, timeout);
 
+       if (completion_done(&dev->done))
+               return;
+
+       complete(&dev->done);
+
        v4l2_err(&dev->v4l2_dev, "CODA PIC_RUN timeout, stopping all streams\n");
 
        mutex_lock(&dev->dev_mutex);
@@ -1832,7 +1877,7 @@ static const struct coda_devtype coda_devdata[] = {
 
 static struct platform_device_id coda_platform_ids[] = {
        { .name = "coda-imx27", .driver_data = CODA_IMX27 },
-       { .name = "coda-imx53", .driver_data = CODA_7541 },
+       { .name = "coda-imx53", .driver_data = CODA_IMX53 },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(platform, coda_platform_ids);
@@ -1865,6 +1910,8 @@ static int __devinit coda_probe(struct platform_device *pdev)
        spin_lock_init(&dev->irqlock);
        INIT_LIST_HEAD(&dev->instances);
        INIT_DELAYED_WORK(&dev->timeout, coda_timeout);
+       init_completion(&dev->done);
+       complete(&dev->done);
 
        dev->plat_dev = pdev;
        dev->clk_per = devm_clk_get(&pdev->dev, "per");