This patch splits the global workbuf into a global tempbuf and a per-context
workbuf, adds the codec mode aux register, and restores the work buffer
pointer on commands. With the new firmware, there is only a single set of
read/write pointers which need to be restored between context switches.
This allows more than four active contexts at the same time.
All auxiliary buffers are now allocated through a helper function to avoid
code duplication.

Signed-off-by: Philipp Zabel <p.za...@pengutronix.de>
---
 drivers/media/platform/coda.c | 235 +++++++++++++++++++++++++++++++-----------
 drivers/media/platform/coda.h |   9 ++
 2 files changed, 182 insertions(+), 62 deletions(-)

diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 6d76f1d..28ee3f7 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -41,7 +41,8 @@
 
 #define CODA_FMO_BUF_SIZE      32
 #define CODADX6_WORK_BUF_SIZE  (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
-#define CODA7_WORK_BUF_SIZE    (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA7_WORK_BUF_SIZE    (128 * 1024)
+#define CODA7_TEMP_BUF_SIZE    (304 * 1024)
 #define CODA_PARA_BUF_SIZE     (10 * 1024)
 #define CODA_ISRAM_SIZE        (2048 * 2)
 #define CODADX6_IRAM_SIZE      0xb000
@@ -129,6 +130,7 @@ struct coda_dev {
        struct clk              *clk_ahb;
 
        struct coda_aux_buf     codebuf;
+       struct coda_aux_buf     tempbuf;
        struct coda_aux_buf     workbuf;
        struct gen_pool         *iram_pool;
        long unsigned int       iram_vaddr;
@@ -153,6 +155,7 @@ struct coda_params {
        u8                      mpeg4_inter_qp;
        u8                      gop_size;
        int                     codec_mode;
+       int                     codec_mode_aux;
        enum v4l2_mpeg_video_multi_slice_mode slice_mode;
        u32                     framerate;
        u16                     bitrate;
@@ -192,8 +195,10 @@ struct coda_ctx {
        int                             vpu_header_size[3];
        struct coda_aux_buf             parabuf;
        struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
+       struct coda_aux_buf             workbuf;
        int                             num_internal_frames;
        int                             idx;
+       int                             reg_idx;
        struct coda_iram_info           iram_info;
 };
 
@@ -241,10 +246,18 @@ static int coda_wait_timeout(struct coda_dev *dev)
 static void coda_command_async(struct coda_ctx *ctx, int cmd)
 {
        struct coda_dev *dev = ctx->dev;
+
+       if (dev->devtype->product == CODA_7541) {
+               /* Restore context related registers to CODA */
+               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+
        coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
 
        coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
        coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+
        coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
 }
 
@@ -959,21 +972,6 @@ static void coda_wait_finish(struct vb2_queue *q)
        coda_lock(ctx);
 }
 
-static void coda_free_framebuffers(struct coda_ctx *ctx)
-{
-       int i;
-
-       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) {
-               if (ctx->internal_frames[i].vaddr) {
-                       dma_free_coherent(&ctx->dev->plat_dev->dev,
-                               ctx->internal_frames[i].size,
-                               ctx->internal_frames[i].vaddr,
-                               ctx->internal_frames[i].paddr);
-                       ctx->internal_frames[i].vaddr = NULL;
-               }
-       }
-}
-
 static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
 {
        struct coda_dev *dev = ctx->dev;
@@ -985,28 +983,69 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int 
index, u32 value)
                p[index ^ 1] = value;
 }
 
+static int coda_alloc_aux_buf(struct coda_dev *dev,
+                             struct coda_aux_buf *buf, size_t size)
+{
+       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+                                       GFP_KERNEL);
+       if (!buf->vaddr)
+               return -ENOMEM;
+
+       buf->size = size;
+
+       return 0;
+}
+
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+                                        struct coda_aux_buf *buf, size_t size)
+{
+       return coda_alloc_aux_buf(ctx->dev, buf, size);
+}
+
+static void coda_free_aux_buf(struct coda_dev *dev,
+                             struct coda_aux_buf *buf)
+{
+       if (buf->vaddr) {
+               dma_free_coherent(&dev->plat_dev->dev, buf->size,
+                                 buf->vaddr, buf->paddr);
+               buf->vaddr = NULL;
+               buf->size = 0;
+       }
+}
+
+static void coda_free_framebuffers(struct coda_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
+               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+}
+
 static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data 
*q_data, u32 fourcc)
 {
        struct coda_dev *dev = ctx->dev;
-
        int height = q_data->height;
        dma_addr_t paddr;
        int ysize;
+       int ret;
        int i;
 
+       if (ctx->codec && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
+               height = round_up(height, 16);
        ysize = round_up(q_data->width, 8) * height;
 
        /* Allocate frame buffers */
        for (i = 0; i < ctx->num_internal_frames; i++) {
-               ctx->internal_frames[i].size = q_data->sizeimage;
-               if (fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != 
CODA_DX6)
+               size_t size;
+
+               size = q_data->sizeimage;
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
                        ctx->internal_frames[i].size += ysize/4;
-               ctx->internal_frames[i].vaddr = dma_alloc_coherent(
-                               &dev->plat_dev->dev, 
ctx->internal_frames[i].size,
-                               &ctx->internal_frames[i].paddr, GFP_KERNEL);
-               if (!ctx->internal_frames[i].vaddr) {
+               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], 
size);
+               if (ret < 0) {
                        coda_free_framebuffers(ctx);
-                       return -ENOMEM;
+                       return ret;
                }
        }
 
@@ -1017,10 +1056,20 @@ static int coda_alloc_framebuffers(struct coda_ctx 
*ctx, struct coda_q_data *q_d
                coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
                coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* 
Cr */
 
-               if (dev->devtype->product != CODA_DX6 && fourcc == 
V4L2_PIX_FMT_H264)
-                       coda_parabuf_write(ctx, 96 + i, 
ctx->internal_frames[i].paddr + ysize + ysize/4 + ysize/4);
+               /* mvcol buffer for h.264 */
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       coda_parabuf_write(ctx, 96 + i,
+                                          ctx->internal_frames[i].paddr +
+                                          ysize + ysize/4 + ysize/4);
        }
 
+       /* mvcol buffer for mpeg4 */
+       if ((dev->devtype->product != CODA_DX6) &&
+           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
+               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
+                                           ysize + ysize/4 + ysize/4);
+
        return 0;
 }
 
@@ -1146,6 +1195,49 @@ out:
        }
 }
 
+static void coda_free_context_buffers(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+}
+
+static int coda_alloc_context_buffers(struct coda_ctx *ctx,
+                                     struct coda_q_data *q_data)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t size;
+       int ret;
+
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               size = CODA7_WORK_BUF_SIZE;
+               break;
+       default:
+               return 0;
+       }
+
+       if (ctx->workbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
+               ret = -EBUSY;
+               return -ENOMEM;
+       }
+
+       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context 
buffer",
+                        ctx->workbuf.size);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       coda_free_context_buffers(ctx);
+       return ret;
+}
+
 static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
                              int header_code, u8 *header, int *size)
 {
@@ -1161,7 +1253,7 @@ static int coda_encode_header(struct coda_ctx *ctx, 
struct vb2_buffer *buf,
                v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER 
timeout\n");
                return ret;
        }
-       *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+       *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
                coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
        memcpy(header, vb2_plane_vaddr(buf, 0), *size);
 
@@ -1214,6 +1306,11 @@ static int coda_start_streaming(struct vb2_queue *q, 
unsigned int count)
                return -EINVAL;
        }
 
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
        if (!coda_is_initialized(dev)) {
                v4l2_err(v4l2_dev, "coda is not initialized.\n");
                return -EFAULT;
@@ -1222,8 +1319,8 @@ static int coda_start_streaming(struct vb2_queue *q, 
unsigned int count)
        mutex_lock(&dev->coda_mutex);
 
        coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
        switch (dev->devtype->product) {
        case CODA_DX6:
                coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
@@ -1648,7 +1745,13 @@ static int coda_open(struct file *file)
        v4l2_fh_add(&ctx->fh);
        ctx->dev = dev;
        ctx->idx = idx;
-
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               ctx->reg_idx = 0;
+               break;
+       default:
+               ctx->reg_idx = idx;
+       }
        set_default_params(ctx);
        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
                                         &coda_queue_init);
@@ -1667,11 +1770,9 @@ static int coda_open(struct file *file)
 
        ctx->fh.ctrl_handler = &ctx->ctrls;
 
-       ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
-                       CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
-       if (!ctx->parabuf.vaddr) {
+       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE);
+       if (ret < 0) {
                v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
-               ret = -ENOMEM;
                goto err;
        }
 
@@ -1706,9 +1807,11 @@ static int coda_release(struct file *file)
        list_del(&ctx->list);
        coda_unlock(ctx);
 
-       dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
-               ctx->parabuf.vaddr, ctx->parabuf.paddr);
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       coda_free_context_buffers(ctx);
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+
+       coda_free_aux_buf(dev, &ctx->parabuf);
        v4l2_ctrl_handler_free(&ctx->ctrls);
        clk_disable_unprepare(dev->clk_per);
        clk_disable_unprepare(dev->clk_ahb);
@@ -1788,7 +1891,8 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
        /* Get results from the coda */
        coda_read(dev, CODA_RET_ENC_PIC_TYPE);
        start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
-       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
+       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+
        /* Calculate bytesused field */
        if (dst_buf->v4l2_buf.sequence == 0) {
                vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
@@ -1858,7 +1962,7 @@ static void coda_timeout(struct work_struct *work)
 
 static u32 coda_supported_firmwares[] = {
        CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
-       CODA_FIRMWARE_VERNUM(CODA_7541, 13, 4, 29),
+       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
 };
 
 static bool coda_firmware_supported(u32 vernum)
@@ -1923,8 +2027,13 @@ static int coda_hw_init(struct coda_dev *dev)
                coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
 
        /* Tell the BIT where to find everything it needs */
-       coda_write(dev, dev->workbuf.paddr,
-                     CODA_REG_BIT_WORK_BUF_ADDR);
+       if (dev->devtype->product == CODA_7541) {
+               coda_write(dev, dev->tempbuf.paddr,
+                               CODA_REG_BIT_TEMP_BUF_ADDR);
+       } else {
+               coda_write(dev, dev->workbuf.paddr,
+                             CODA_REG_BIT_WORK_BUF_ADDR);
+       }
        coda_write(dev, dev->codebuf.paddr,
                      CODA_REG_BIT_CODE_BUF_ADDR);
        coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
@@ -2011,11 +2120,8 @@ static void coda_fw_callback(const struct firmware *fw, 
void *context)
        }
 
        /* allocate auxiliary per-device code buffer for the BIT processor */
-       dev->codebuf.size = fw->size;
-       dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
-                                                   &dev->codebuf.paddr,
-                                                   GFP_KERNEL);
-       if (!dev->codebuf.vaddr) {
+       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size);
+       if (ret < 0) {
                dev_err(&pdev->dev, "failed to allocate code buffer\n");
                return;
        }
@@ -2205,18 +2311,26 @@ static int coda_probe(struct platform_device *pdev)
        /* allocate auxiliary per-device buffers for the BIT processor */
        switch (dev->devtype->product) {
        case CODA_DX6:
-               dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
+               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
+                                        CODADX6_WORK_BUF_SIZE);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+               break;
+       case CODA_7541:
+               dev->tempbuf.size = CODA7_TEMP_BUF_SIZE;
                break;
-       default:
-               dev->workbuf.size = CODA7_WORK_BUF_SIZE;
        }
-       dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
-                                                   &dev->workbuf.paddr,
-                                                   GFP_KERNEL);
-       if (!dev->workbuf.vaddr) {
-               dev_err(&pdev->dev, "failed to allocate work buffer\n");
-               v4l2_device_unregister(&dev->v4l2_dev);
-               return -ENOMEM;
+       if (dev->tempbuf.size) {
+               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
+                                        dev->tempbuf.size);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
        }
 
        if (dev->devtype->product == CODA_DX6)
@@ -2248,12 +2362,9 @@ static int coda_remove(struct platform_device *pdev)
        v4l2_device_unregister(&dev->v4l2_dev);
        if (dev->iram_vaddr)
                gen_pool_free(dev->iram_pool, dev->iram_vaddr, dev->iram_size);
-       if (dev->codebuf.vaddr)
-               dma_free_coherent(&pdev->dev, dev->codebuf.size,
-                                 &dev->codebuf.vaddr, dev->codebuf.paddr);
-       if (dev->workbuf.vaddr)
-               dma_free_coherent(&pdev->dev, dev->workbuf.size, 
&dev->workbuf.vaddr,
-                         dev->workbuf.paddr);
+       coda_free_aux_buf(dev, &dev->codebuf);
+       coda_free_aux_buf(dev, &dev->tempbuf);
+       coda_free_aux_buf(dev, &dev->workbuf);
        return 0;
 }
 
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
index 39c17c6..b2b5b1d 100644
--- a/drivers/media/platform/coda.h
+++ b/drivers/media/platform/coda.h
@@ -43,6 +43,7 @@
 #define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
 #define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
 #define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
+#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
 #define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
 #define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
 #define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
@@ -91,6 +92,14 @@
 #define        CODA_MODE_INVALID               0xffff
 #define CODA_REG_BIT_INT_ENABLE                0x170
 #define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
+#define CODA7_REG_BIT_RUN_AUX_STD              0x178
+#define                CODA_MP4_AUX_MPEG4              0
+#define                CODA_MP4_AUX_DIVX3              1
+#define                CODA_VPX_AUX_THO                0
+#define                CODA_VPX_AUX_VP6                1
+#define                CODA_VPX_AUX_VP8                2
+#define                CODA_H264_AUX_AVC               0
+#define                CODA_H264_AUX_MVC               1
 
 /*
  * Commands' mailbox:
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to