|
@@ -18,6 +18,7 @@
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/irq.h>
|
|
|
+#include <linux/kfifo.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/platform_device.h>
|
|
@@ -182,6 +183,7 @@ struct coda_ctx {
|
|
|
int streamon_out;
|
|
|
int streamon_cap;
|
|
|
u32 isequence;
|
|
|
+ u32 qsequence;
|
|
|
struct coda_q_data q_data[2];
|
|
|
enum coda_inst_type inst_type;
|
|
|
struct coda_codec *codec;
|
|
@@ -193,6 +195,9 @@ struct coda_ctx {
|
|
|
int gopcounter;
|
|
|
char vpu_header[3][64];
|
|
|
int vpu_header_size[3];
|
|
|
+ struct kfifo bitstream_fifo;
|
|
|
+ struct mutex bitstream_mutex;
|
|
|
+ struct coda_aux_buf bitstream;
|
|
|
struct coda_aux_buf parabuf;
|
|
|
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
|
|
|
struct coda_aux_buf workbuf;
|
|
@@ -200,6 +205,7 @@ struct coda_ctx {
|
|
|
int idx;
|
|
|
int reg_idx;
|
|
|
struct coda_iram_info iram_info;
|
|
|
+ u32 bit_stream_param;
|
|
|
};
|
|
|
|
|
|
static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
|
|
@@ -249,6 +255,8 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd)
|
|
|
|
|
|
if (dev->devtype->product == CODA_7541) {
|
|
|
/* Restore context related registers to CODA */
|
|
|
+ coda_write(dev, ctx->bit_stream_param,
|
|
|
+ CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
|
coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
|
|
|
}
|
|
|
|
|
@@ -692,6 +700,105 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
|
|
|
.vidioc_streamoff = vidioc_streamoff,
|
|
|
};
|
|
|
|
|
|
+static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
|
|
|
+{
|
|
|
+ return kfifo_len(&ctx->bitstream_fifo);
|
|
|
+}
|
|
|
+
|
|
|
+static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
|
|
|
+{
|
|
|
+ struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
|
|
|
+ struct coda_dev *dev = ctx->dev;
|
|
|
+ u32 rd_ptr;
|
|
|
+
|
|
|
+ rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
|
|
|
+ kfifo->out = (kfifo->in & ~kfifo->mask) |
|
|
|
+ (rd_ptr - ctx->bitstream.paddr);
|
|
|
+ if (kfifo->out > kfifo->in)
|
|
|
+ kfifo->out -= kfifo->mask + 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
|
|
|
+{
|
|
|
+ struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
|
|
|
+ struct coda_dev *dev = ctx->dev;
|
|
|
+ u32 rd_ptr, wr_ptr;
|
|
|
+
|
|
|
+ rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
|
|
|
+ coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
|
|
|
+ wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
|
|
|
+ coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
|
|
|
+}
|
|
|
+
|
|
|
+static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
|
|
|
+{
|
|
|
+ struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
|
|
|
+ struct coda_dev *dev = ctx->dev;
|
|
|
+ u32 wr_ptr;
|
|
|
+
|
|
|
+ wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
|
|
|
+ coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
|
|
|
+}
|
|
|
+
|
|
|
+static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf)
|
|
|
+{
|
|
|
+ u32 src_size = vb2_get_plane_payload(src_buf, 0);
|
|
|
+ u32 n;
|
|
|
+
|
|
|
+ n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size);
|
|
|
+ if (n < src_size)
|
|
|
+ return -ENOSPC;
|
|
|
+
|
|
|
+ dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
|
|
|
+ ctx->bitstream.size, DMA_TO_DEVICE);
|
|
|
+
|
|
|
+ ctx->qsequence++;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
|
|
|
+ struct vb2_buffer *src_buf)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (coda_get_bitstream_payload(ctx) +
|
|
|
+ vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (vb2_plane_vaddr(src_buf, 0) == NULL) {
|
|
|
+ v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = coda_bitstream_queue(ctx, src_buf);
|
|
|
+ if (ret < 0) {
|
|
|
+ v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* Sync read pointer to device */
|
|
|
+ if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
|
|
|
+ coda_kfifo_sync_to_device_write(ctx);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void coda_fill_bitstream(struct coda_ctx *ctx)
|
|
|
+{
|
|
|
+ struct vb2_buffer *src_buf;
|
|
|
+
|
|
|
+ while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
|
|
|
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
|
|
|
+
|
|
|
+ if (coda_bitstream_try_queue(ctx, src_buf)) {
|
|
|
+ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
|
|
|
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Mem-to-mem operations.
|
|
|
*/
|
|
@@ -842,15 +949,22 @@ static int coda_job_ready(void *m2m_priv)
|
|
|
|
|
|
/*
|
|
|
* For both 'P' and 'key' frame cases 1 picture
|
|
|
- * and 1 frame are needed.
|
|
|
+ * and 1 frame are needed. In the decoder case,
|
|
|
+ * the compressed frame can be in the bitstream.
|
|
|
*/
|
|
|
- if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) ||
|
|
|
- !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
|
|
|
+ if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
|
|
|
+ ctx->inst_type != CODA_INST_DECODER) {
|
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
"not ready: not enough video buffers.\n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ if (!v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
|
|
|
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
+ "not ready: not enough video capture buffers.\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
if (ctx->aborting) {
|
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
"not ready: aborting\n");
|
|
@@ -1785,6 +1899,18 @@ static int coda_open(struct file *file)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ kfifo_init(&ctx->bitstream_fifo,
|
|
|
+ ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
|
+ mutex_init(&ctx->bitstream_mutex);
|
|
|
+
|
|
|
coda_lock(ctx);
|
|
|
list_add(&ctx->list, &dev->instances);
|
|
|
coda_unlock(ctx);
|
|
@@ -1816,6 +1942,8 @@ static int coda_release(struct file *file)
|
|
|
list_del(&ctx->list);
|
|
|
coda_unlock(ctx);
|
|
|
|
|
|
+ dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
|
|
|
+ ctx->bitstream.vaddr, ctx->bitstream.paddr);
|
|
|
coda_free_context_buffers(ctx);
|
|
|
if (ctx->dev->devtype->product == CODA_DX6)
|
|
|
coda_free_aux_buf(dev, &ctx->workbuf);
|