[media] coda: allocate bitstream buffer from REQBUFS, size depends on the format
[firefly-linux-kernel-4.4.55.git] / drivers / media / platform / coda / coda-bit.c
index 856b542b35b9c4a3c6d2930edcf8773304003d5e..5aa8d8774d0c6acd0f4241d8a2e2f7e1c7c09d25 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clk.h>
 #include <linux/irqreturn.h>
 #include <linux/kernel.h>
+#include <linux/log2.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
@@ -36,6 +37,8 @@
 #define CODA_DEFAULT_GAMMA     4096
 #define CODA9_DEFAULT_GAMMA    24576   /* 0.75 * 32768 */
 
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx);
+
 static inline int coda_is_initialized(struct coda_dev *dev)
 {
        return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
@@ -389,21 +392,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
        if (dev->devtype->product == CODA_DX6)
                return 0;
 
-       if (ctx->psbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->slicebuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->workbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
-               ret = -EBUSY;
-               return -ENOMEM;
-       }
-
-       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+       if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
                /* worst case slice size */
                size = (DIV_ROUND_UP(q_data->width, 16) *
                        DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
@@ -417,7 +406,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
                }
        }
 
-       if (dev->devtype->product == CODA_7541) {
+       if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) {
                ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
                                             CODA7_PS_BUF_SIZE, "psbuf");
                if (ret < 0) {
@@ -427,16 +416,19 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
                }
        }
 
-       size = dev->devtype->workbuf_size;
-       if (dev->devtype->product == CODA_960 &&
-           q_data->fourcc == V4L2_PIX_FMT_H264)
-               size += CODA9_PS_SAVE_SIZE;
-       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to allocate %d byte context buffer",
-                        ctx->workbuf.size);
-               goto err;
+       if (!ctx->workbuf.vaddr) {
+               size = dev->devtype->workbuf_size;
+               if (dev->devtype->product == CODA_960 &&
+                   q_data->fourcc == V4L2_PIX_FMT_H264)
+                       size += CODA9_PS_SAVE_SIZE;
+               ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size,
+                                            "workbuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate %d byte context buffer",
+                                ctx->workbuf.size);
+                       goto err;
+               }
        }
 
        return 0;
@@ -709,6 +701,27 @@ err_clk_per:
  * Encoder context operations
  */
 
+static int coda_encoder_reqbufs(struct coda_ctx *ctx,
+                               struct v4l2_requestbuffers *rb)
+{
+       struct coda_q_data *q_data_src;
+       int ret;
+
+       if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return 0;
+
+       if (rb->count) {
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               ret = coda_alloc_context_buffers(ctx, q_data_src);
+               if (ret < 0)
+                       return ret;
+       } else {
+               coda_free_context_buffers(ctx);
+       }
+
+       return 0;
+}
+
 static int coda_start_encoding(struct coda_ctx *ctx)
 {
        struct coda_dev *dev = ctx->dev;
@@ -725,11 +738,6 @@ static int coda_start_encoding(struct coda_ctx *ctx)
        q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        dst_fourcc = q_data_dst->fourcc;
 
-       /* Allocate per-instance buffers */
-       ret = coda_alloc_context_buffers(ctx, q_data_src);
-       if (ret < 0)
-               return ret;
-
        buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
        bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
        bitstream_size = q_data_dst->sizeimage;
@@ -1311,7 +1319,6 @@ static void coda_seq_end_work(struct work_struct *work)
                ctx->bitstream.vaddr, ctx->bitstream.size);
 
        coda_free_framebuffers(ctx);
-       coda_free_context_buffers(ctx);
 
        mutex_unlock(&dev->coda_mutex);
        mutex_unlock(&ctx->buffer_mutex);
@@ -1322,11 +1329,13 @@ static void coda_bit_release(struct coda_ctx *ctx)
        mutex_lock(&ctx->buffer_mutex);
        coda_free_framebuffers(ctx);
        coda_free_context_buffers(ctx);
+       coda_free_bitstream_buffer(ctx);
        mutex_unlock(&ctx->buffer_mutex);
 }
 
 const struct coda_context_ops coda_bit_encode_ops = {
        .queue_init = coda_encoder_queue_init,
+       .reqbufs = coda_encoder_reqbufs,
        .start_streaming = coda_start_encoding,
        .prepare_run = coda_prepare_encode,
        .finish_run = coda_finish_encode,
@@ -1338,6 +1347,65 @@ const struct coda_context_ops coda_bit_encode_ops = {
  * Decoder context operations
  */
 
+static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
+                                      struct coda_q_data *q_data)
+{
+       if (ctx->bitstream.vaddr)
+               return 0;
+
+       ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
+       ctx->bitstream.vaddr = dma_alloc_writecombine(
+                       &ctx->dev->plat_dev->dev, ctx->bitstream.size,
+                       &ctx->bitstream.paddr, GFP_KERNEL);
+       if (!ctx->bitstream.vaddr) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "failed to allocate bitstream ringbuffer");
+               return -ENOMEM;
+       }
+       kfifo_init(&ctx->bitstream_fifo,
+                  ctx->bitstream.vaddr, ctx->bitstream.size);
+
+       return 0;
+}
+
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
+{
+       if (ctx->bitstream.vaddr == NULL)
+               return;
+
+       dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
+                             ctx->bitstream.vaddr, ctx->bitstream.paddr);
+       ctx->bitstream.vaddr = NULL;
+       kfifo_init(&ctx->bitstream_fifo, NULL, 0);
+}
+
+static int coda_decoder_reqbufs(struct coda_ctx *ctx,
+                               struct v4l2_requestbuffers *rb)
+{
+       struct coda_q_data *q_data_src;
+       int ret;
+
+       if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return 0;
+
+       if (rb->count) {
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               ret = coda_alloc_context_buffers(ctx, q_data_src);
+               if (ret < 0)
+                       return ret;
+               ret = coda_alloc_bitstream_buffer(ctx, q_data_src);
+               if (ret < 0) {
+                       coda_free_context_buffers(ctx);
+                       return ret;
+               }
+       } else {
+               coda_free_bitstream_buffer(ctx);
+               coda_free_context_buffers(ctx);
+       }
+
+       return 0;
+}
+
 static int __coda_start_decoding(struct coda_ctx *ctx)
 {
        struct coda_q_data *q_data_src, *q_data_dst;
@@ -1356,11 +1424,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
        src_fourcc = q_data_src->fourcc;
        dst_fourcc = q_data_dst->fourcc;
 
-       /* Allocate per-instance buffers */
-       ret = coda_alloc_context_buffers(ctx, q_data_src);
-       if (ret < 0)
-               return ret;
-
        coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
 
        /* Update coda bitstream read and write pointers from kfifo */
@@ -1704,7 +1767,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
         * by up to 512 bytes
         */
        if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
-               if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+               if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512)
                        kfifo_init(&ctx->bitstream_fifo,
                                ctx->bitstream.vaddr, ctx->bitstream.size);
        }
@@ -1906,6 +1969,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
 
 const struct coda_context_ops coda_bit_decode_ops = {
        .queue_init = coda_decoder_queue_init,
+       .reqbufs = coda_decoder_reqbufs,
        .start_streaming = coda_start_decoding,
        .prepare_run = coda_prepare_decode,
        .finish_run = coda_finish_decode,