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;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
u32 framerate;
u16 bitrate;
+ u32 slice_max_bits;
u32 slice_max_mb;
};
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;
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",
}
/* 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);
/* 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);
}
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;
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);
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) {
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;
}
"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;
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:
{
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,
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,
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;
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;
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);
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);
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);
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);
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");