diff options
Diffstat (limited to 'drivers/media/platform/coda')
-rw-r--r-- | drivers/media/platform/coda/coda-bit.c | 25 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 165 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda_regs.h | 4 |
4 files changed, 131 insertions, 65 deletions
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b4029ae293d3..856b542b35b9 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -718,6 +718,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) struct vb2_buffer *buf; int gamma, ret, value; u32 dst_fourcc; + int num_fb; u32 stride; q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); @@ -983,12 +984,14 @@ static int coda_start_encoding(struct coda_ctx *ctx) v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); goto out; } + num_fb = 2; stride = q_data_src->bytesperline; } else { ctx->num_internal_frames = 0; + num_fb = 0; stride = 0; } - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); if (dev->devtype->product == CODA_7541) { @@ -1316,8 +1319,10 @@ static void coda_seq_end_work(struct work_struct *work) static void coda_bit_release(struct coda_ctx *ctx) { + mutex_lock(&ctx->buffer_mutex); coda_free_framebuffers(ctx); coda_free_context_buffers(ctx); + mutex_unlock(&ctx->buffer_mutex); } const struct coda_context_ops coda_bit_encode_ops = { @@ -1431,9 +1436,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) height = val & CODA7_PICHEIGHT_MASK; } - if (width > q_data_dst->width || height > q_data_dst->height) { + if (width > q_data_dst->bytesperline || height > q_data_dst->height) { v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->width, q_data_dst->height); + width, height, q_data_dst->bytesperline, + q_data_dst->height); return -EINVAL; } @@ -1565,6 +1571,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct vb2_buffer *dst_buf; struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; + struct coda_buffer_meta *meta; u32 reg_addr, reg_stride; dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1643,12 +1650,12 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { - struct coda_buffer_meta *meta; + meta = list_first_entry_or_null(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + + if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { /* If this is the last buffer in the bitstream, add padding */ - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); if (meta->end == (ctx->bitstream_fifo.kfifo.in & ctx->bitstream_fifo.kfifo.mask)) { static unsigned char buf[512]; @@ -1665,6 +1672,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_kfifo_sync_to_device_full(ctx); + /* Clear decode success flag */ + coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); return 0; @@ -1821,6 +1831,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) memset(&ctx->frame_metas[decoded_idx], 0, sizeof(struct coda_buffer_meta)); ctx->frame_metas[decoded_idx].sequence = val; + ctx->sequence_offset++; } mutex_unlock(&ctx->bitstream_mutex); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 39330a70f752..6f32e6d6b156 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -37,6 +37,7 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-core.h> #include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-vmalloc.h> #include "coda.h" @@ -180,6 +181,7 @@ struct coda_video_device { const char *name; enum coda_inst_type type; const struct coda_context_ops *ops; + bool direct; u32 src_formats[CODA_MAX_FORMATS]; u32 dst_formats[CODA_MAX_FORMATS]; }; @@ -468,6 +470,18 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) return 0; } +static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, + u32 width, u32 height) +{ + /* + * This is a rough estimate for sensible compressed buffer + * sizes (between 1 and 16 bits per pixel). This could be + * improved by better format specific worst case estimates. + */ + return round_up(clamp(sizeimage, width * height / 8, + width * height * 2), PAGE_SIZE); +} + static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, struct v4l2_format *f) { @@ -513,15 +527,10 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_MPEG4: f->fmt.pix.bytesperline = 0; - /* - * This is a rough estimate for sensible compressed buffer - * sizes (between 1 and 16 bits per pixel). This could be - * improved by better format specific worst case estimates. - */ - f->fmt.pix.sizeimage = round_up(clamp(f->fmt.pix.sizeimage, - f->fmt.pix.width * f->fmt.pix.height / 8, - f->fmt.pix.width * f->fmt.pix.height * 2), - PAGE_SIZE); + f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, + f->fmt.pix.sizeimage, + f->fmt.pix.width, + f->fmt.pix.height); break; default: BUG(); @@ -592,7 +601,11 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, if (ret < 0) return ret; - if (!f->fmt.pix.colorspace) { + switch (f->fmt.pix.colorspace) { + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_JPEG: + break; + default: if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; else @@ -670,6 +683,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ctx->colorspace = f->fmt.pix.colorspace; + memset(&f_cap, 0, sizeof(f_cap)); f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; coda_g_fmt(file, priv, &f_cap); f_cap.fmt.pix.width = f->fmt.pix.width; @@ -908,7 +922,8 @@ static void coda_pic_run_work(struct work_struct *work) ctx->ops->finish_run(ctx); } - if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) + if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) && + ctx->ops->seq_end_work) queue_work(dev->workqueue, &ctx->seq_end_work); mutex_unlock(&dev->coda_mutex); @@ -939,15 +954,43 @@ static int coda_job_ready(void *m2m_priv) return 0; } - if (ctx->hold || - ((ctx->inst_type == CODA_INST_DECODER) && - !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - (coda_get_bitstream_payload(ctx) < 512) && - !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: not enough bitstream data.\n", - ctx->idx); - return 0; + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { + struct list_head *meta; + bool stream_end; + int num_metas; + int src_bufs; + + if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: on hold for more buffers.\n", + ctx->idx); + return 0; + } + + stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + + num_metas = 0; + list_for_each(meta, &ctx->buffer_meta_list) + num_metas++; + + src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); + + if (!stream_end && (num_metas + src_bufs) < 2) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: need 2 buffers available (%d, %d)\n", + ctx->idx, num_metas, src_bufs); + return 0; + } + + + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && + !stream_end && (coda_get_bitstream_payload(ctx) < 512)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: not enough bitstream data (%d).\n", + ctx->idx, coda_get_bitstream_payload(ctx)); + return 0; + } } if (ctx->aborting) { @@ -1023,13 +1066,14 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) static void set_default_params(struct coda_ctx *ctx) { - unsigned int max_w, max_h, size; + unsigned int max_w, max_h, usize, csize; ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], ctx->cvd->dst_formats[0]); max_w = min(ctx->codec->max_w, 1920U); max_h = min(ctx->codec->max_h, 1088U); - size = max_w * max_h * 3 / 2; + usize = max_w * max_h * 3 / 2; + csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); ctx->params.codec_mode = ctx->codec->mode; ctx->colorspace = V4L2_COLORSPACE_REC709; @@ -1044,14 +1088,14 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].height = max_h; 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 = size; + ctx->q_data[V4L2_M2M_SRC].sizeimage = usize; ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_SIZE); + ctx->q_data[V4L2_M2M_DST].sizeimage = csize; } else { ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; - ctx->q_data[V4L2_M2M_SRC].sizeimage = round_up(size, PAGE_SIZE); + ctx->q_data[V4L2_M2M_SRC].sizeimage = csize; ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; - ctx->q_data[V4L2_M2M_DST].sizeimage = size; + ctx->q_data[V4L2_M2M_DST].sizeimage = usize; } ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; @@ -1080,6 +1124,7 @@ static int coda_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; + /* Set to vb2-dma-contig allocator context, ignored by vb2-vmalloc */ alloc_ctxs[0] = ctx->dev->alloc_ctx; v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, @@ -1109,6 +1154,7 @@ static int coda_buf_prepare(struct vb2_buffer *vb) static void coda_buf_queue(struct vb2_buffer *vb) { struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *vq = vb->vb2_queue; struct coda_q_data *q_data; q_data = get_q_data(ctx, vb->vb2_queue->type); @@ -1117,8 +1163,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) * In the decoder case, immediately try to copy the buffer into the * bitstream ringbuffer and mark it as ready to be dequeued. */ - if (ctx->inst_type == CODA_INST_DECODER && - vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* * For backwards compatibility, queuing an empty buffer marks * the stream end @@ -1218,7 +1263,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return 0; /* Allow BIT decoder device_run with no new buffers queued */ - if (ctx->inst_type == CODA_INST_DECODER) + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); ctx->gopcounter = ctx->params.gop_size - 1; @@ -1271,7 +1316,7 @@ static void coda_stop_streaming(struct vb2_queue *q) coda_bit_stream_end_flag(ctx); - ctx->isequence = 0; + ctx->qsequence = 0; while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); @@ -1290,6 +1335,10 @@ static void coda_stop_streaming(struct vb2_queue *q) if (!ctx->streamon_out && !ctx->streamon_cap) { struct coda_buffer_meta *meta; + if (ctx->ops->seq_end_work) { + queue_work(dev->workqueue, &ctx->seq_end_work); + flush_work(&ctx->seq_end_work); + } mutex_lock(&ctx->bitstream_mutex); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, @@ -1300,6 +1349,7 @@ static void coda_stop_streaming(struct vb2_queue *q) mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); + ctx->initialized = 0; ctx->runcounter = 0; ctx->aborting = 0; } @@ -1521,8 +1571,8 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_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; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + src_vq->mem_ops = &vb2_vmalloc_memops; ret = coda_queue_init(priv, src_vq); if (ret) @@ -1577,9 +1627,11 @@ static int coda_open(struct file *file) ctx->cvd = to_coda_video_device(vdev); ctx->inst_type = ctx->cvd->type; ctx->ops = ctx->cvd->ops; + ctx->use_bit = !ctx->cvd->direct; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_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)); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -1630,22 +1682,25 @@ static int coda_open(struct file *file) ctx->fh.ctrl_handler = &ctx->ctrls; - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, - CODA_PARA_BUF_SIZE, "parabuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); - goto err_dma_alloc; + if (ctx->use_bit) { + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, + CODA_PARA_BUF_SIZE, "parabuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); + goto err_dma_alloc; + } } - - ctx->bitstream.size = CODA_MAX_FRAME_SIZE; - ctx->bitstream.vaddr = dma_alloc_writecombine( - &dev->plat_dev->dev, ctx->bitstream.size, - &ctx->bitstream.paddr, GFP_KERNEL); - if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate bitstream ringbuffer"); - ret = -ENOMEM; - goto err_dma_writecombine; + if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) { + ctx->bitstream.size = CODA_MAX_FRAME_SIZE; + ctx->bitstream.vaddr = dma_alloc_writecombine( + &dev->plat_dev->dev, ctx->bitstream.size, + &ctx->bitstream.paddr, GFP_KERNEL); + if (!ctx->bitstream.vaddr) { + v4l2_err(&dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); + ret = -ENOMEM; + goto err_dma_writecombine; + } } kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); @@ -1693,16 +1748,14 @@ static int coda_release(struct file *file) v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", ctx); - debugfs_remove_recursive(ctx->debugfs_entry); - - if (ctx->inst_type == CODA_INST_DECODER) + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) coda_bit_stream_end_flag(ctx); /* If this instance is running, call .job_abort and wait for it to end */ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized) { + if (ctx->initialized && ctx->ops->seq_end_work) { queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } @@ -1728,6 +1781,7 @@ static int coda_release(struct file *file) clear_bit(ctx->idx, &dev->instance_mask); if (ctx->ops->release) ctx->ops->release(ctx); + debugfs_remove_recursive(ctx->debugfs_entry); kfree(ctx); return 0; @@ -1844,10 +1898,11 @@ static int coda_register_device(struct coda_dev *dev, int i) { struct video_device *vfd = &dev->vfd[i]; - if (i > ARRAY_SIZE(dev->vfd)) + if (i >= dev->devtype->num_vdevs) return -EINVAL; - snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name); + snprintf(vfd->name, sizeof(vfd->name), "%s", + dev->devtype->vdevs[i]->name); vfd->fops = &coda_fops; vfd->ioctl_ops = &coda_ioctl_ops; vfd->release = video_device_release_empty, @@ -2001,7 +2056,6 @@ 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_IMX53 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, coda_platform_ids); @@ -2142,6 +2196,7 @@ static int coda_probe(struct platform_device *pdev) if (!dev->iram.vaddr) { dev_warn(&pdev->dev, "unable to alloc iram\n"); } else { + memset(dev->iram.vaddr, 0, dev->iram.size); dev->iram.blob.data = dev->iram.vaddr; dev->iram.blob.size = dev->iram.size; dev->iram.dentry = debugfs_create_blob("iram", 0644, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 5dd47e5f97c1..0c35cd5032ff 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -198,7 +198,6 @@ struct coda_ctx { int initialized; int streamon_out; int streamon_cap; - u32 isequence; u32 qsequence; u32 osequence; u32 sequence_offset; @@ -236,6 +235,7 @@ struct coda_ctx { u32 frame_mem_ctrl; int display_idx; struct dentry *debugfs_entry; + bool use_bit; }; extern int coda_debug; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 8e015b8aa8fa..7d026241171b 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -304,9 +304,9 @@ #define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 #define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 #define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 -#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f +#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7fff #define CODA_RATECONTROL_BITRATE_OFFSET 1 -#define CODA_RATECONTROL_BITRATE_MASK 0x7f +#define CODA_RATECONTROL_BITRATE_MASK 0x7fff #define CODA_RATECONTROL_ENABLE_OFFSET 0 #define CODA_RATECONTROL_ENABLE_MASK 0x01 #define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 |