struct coda_dev {
struct v4l2_device v4l2_dev;
- struct video_device vfd;
+ struct video_device vfd[2];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
static void set_default_params(struct coda_ctx *ctx)
{
+ u32 src_fourcc, dst_fourcc;
int max_w;
int max_h;
- ctx->codec = &ctx->dev->devtype->codecs[0];
+ if (ctx->inst_type == CODA_INST_ENCODER) {
+ src_fourcc = V4L2_PIX_FMT_YUV420;
+ dst_fourcc = V4L2_PIX_FMT_H264;
+ } else {
+ src_fourcc = V4L2_PIX_FMT_H264;
+ dst_fourcc = V4L2_PIX_FMT_YUV420;
+ }
+ ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
max_w = ctx->codec->max_w;
max_h = ctx->codec->max_h;
- ctx->params.codec_mode = CODA_MODE_INVALID;
+ ctx->params.codec_mode = ctx->codec->mode;
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->params.framerate = 30;
ctx->aborting = 0;
ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
ctx->q_data[V4L2_M2M_SRC].width = max_w;
ctx->q_data[V4L2_M2M_SRC].height = max_h;
- ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
ctx->q_data[V4L2_M2M_DST].width = max_w;
ctx->q_data[V4L2_M2M_DST].height = max_h;
- ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
- ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
+ ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+ ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+ } else {
+ ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
+ ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
+ }
ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
}
ctx->streamon_out = 1;
-
- if (coda_format_is_yuv(q_data_src->fourcc))
- ctx->inst_type = CODA_INST_ENCODER;
- else
- ctx->inst_type = CODA_INST_DECODER;
} else {
if (count < 1)
return -EINVAL;
}
}
-static struct vb2_ops coda_qops = {
+static const struct vb2_ops coda_qops = {
.queue_setup = coda_queue_setup,
.buf_prepare = coda_buf_prepare,
.buf_queue = coda_buf_queue,
return v4l2_ctrl_handler_setup(&ctx->ctrls);
}
-static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
- struct vb2_queue *dst_vq)
+static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
+{
+ vq->drv_priv = ctx;
+ vq->ops = &coda_qops;
+ vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ vq->lock = &ctx->dev->dev_mutex;
+
+ return vb2_queue_init(vq);
+}
+
+static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
{
- struct coda_ctx *ctx = priv;
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
- src_vq->drv_priv = ctx;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- src_vq->lock = &ctx->dev->dev_mutex;
- ret = vb2_queue_init(src_vq);
+ ret = coda_queue_init(priv, src_vq);
if (ret)
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
- dst_vq->drv_priv = ctx;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- dst_vq->lock = &ctx->dev->dev_mutex;
- return vb2_queue_init(dst_vq);
+ return coda_queue_init(priv, dst_vq);
+}
+
+static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ ret = coda_queue_init(priv, src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+ return coda_queue_init(priv, dst_vq);
}
static int coda_next_free_instance(struct coda_dev *dev)
return idx;
}
-static int coda_open(struct file *file)
+static int coda_open(struct file *file, enum coda_inst_type inst_type)
{
+ int (*queue_init)(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
struct coda_dev *dev = video_drvdata(file);
struct coda_ctx *ctx = NULL;
char *name;
ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
kfree(name);
+ ctx->inst_type = inst_type;
init_completion(&ctx->completion);
INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
goto err_clk_ahb;
set_default_params(ctx);
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
- &coda_queue_init);
+ if (inst_type == CODA_INST_ENCODER)
+ queue_init = coda_encoder_queue_init;
+ else
+ queue_init = coda_decoder_queue_init;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
return ret;
}
+static int coda_encoder_open(struct file *file)
+{
+ return coda_open(file, CODA_INST_ENCODER);
+}
+
+static int coda_decoder_open(struct file *file)
+{
+ return coda_open(file, CODA_INST_DECODER);
+}
+
static int coda_release(struct file *file)
{
struct coda_dev *dev = video_drvdata(file);
return 0;
}
-static const struct v4l2_file_operations coda_fops = {
+static const struct v4l2_file_operations coda_encoder_fops = {
.owner = THIS_MODULE,
- .open = coda_open,
+ .open = coda_encoder_open,
+ .release = coda_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_file_operations coda_decoder_fops = {
+ .owner = THIS_MODULE,
+ .open = coda_decoder_open,
.release = coda_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
return ret;
}
+static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+{
+ vfd->release = video_device_release_empty,
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->vfl_dir = VFL_DIR_M2M;
+ video_set_drvdata(vfd, dev);
+
+ return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+}
+
static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
return;
}
- dev->vfd.fops = &coda_fops,
- dev->vfd.ioctl_ops = &coda_ioctl_ops;
- dev->vfd.release = video_device_release_empty,
- dev->vfd.lock = &dev->dev_mutex;
- dev->vfd.v4l2_dev = &dev->v4l2_dev;
- dev->vfd.vfl_dir = VFL_DIR_M2M;
- snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
- video_set_drvdata(&dev->vfd, dev);
-
dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(dev->alloc_ctx)) {
v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
goto rel_ctx;
}
- ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
+ dev->vfd[0].fops = &coda_encoder_fops,
+ dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
+ snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
+ ret = coda_register_device(dev, &dev->vfd[0]);
if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to register encoder video device\n");
goto rel_m2m;
}
- v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
- dev->vfd.num);
+
+ dev->vfd[1].fops = &coda_decoder_fops,
+ dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
+ snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
+ ret = coda_register_device(dev, &dev->vfd[1]);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to register decoder video device\n");
+ goto rel_m2m;
+ }
+
+ v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
+ dev->vfd[0].num, dev->vfd[1].num);
return;
{
struct coda_dev *dev = platform_get_drvdata(pdev);
- video_unregister_device(&dev->vfd);
+ video_unregister_device(&dev->vfd[0]);
+ video_unregister_device(&dev->vfd[1]);
if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev);
pm_runtime_disable(&pdev->dev);