164441979SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-or-later
264441979SMauro Carvalho Chehab /*
364441979SMauro Carvalho Chehab  * Coda multi-standard codec IP - BIT processor functions
464441979SMauro Carvalho Chehab  *
564441979SMauro Carvalho Chehab  * Copyright (C) 2012 Vista Silicon S.L.
664441979SMauro Carvalho Chehab  *    Javier Martin, <javier.martin@vista-silicon.com>
764441979SMauro Carvalho Chehab  *    Xavier Duret
864441979SMauro Carvalho Chehab  * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
964441979SMauro Carvalho Chehab  */
1064441979SMauro Carvalho Chehab 
1164441979SMauro Carvalho Chehab #include <linux/clk.h>
1264441979SMauro Carvalho Chehab #include <linux/irqreturn.h>
1364441979SMauro Carvalho Chehab #include <linux/kernel.h>
1464441979SMauro Carvalho Chehab #include <linux/log2.h>
1564441979SMauro Carvalho Chehab #include <linux/platform_device.h>
1664441979SMauro Carvalho Chehab #include <linux/ratelimit.h>
1764441979SMauro Carvalho Chehab #include <linux/reset.h>
1864441979SMauro Carvalho Chehab #include <linux/slab.h>
1964441979SMauro Carvalho Chehab #include <linux/videodev2.h>
2064441979SMauro Carvalho Chehab 
2164441979SMauro Carvalho Chehab #include <media/v4l2-common.h>
2264441979SMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
2364441979SMauro Carvalho Chehab #include <media/v4l2-fh.h>
2464441979SMauro Carvalho Chehab #include <media/v4l2-mem2mem.h>
2564441979SMauro Carvalho Chehab #include <media/videobuf2-v4l2.h>
2664441979SMauro Carvalho Chehab #include <media/videobuf2-dma-contig.h>
2764441979SMauro Carvalho Chehab #include <media/videobuf2-vmalloc.h>
2864441979SMauro Carvalho Chehab 
2964441979SMauro Carvalho Chehab #include "coda.h"
3064441979SMauro Carvalho Chehab #include "imx-vdoa.h"
3164441979SMauro Carvalho Chehab #define CREATE_TRACE_POINTS
3264441979SMauro Carvalho Chehab #include "trace.h"
3364441979SMauro Carvalho Chehab 
3464441979SMauro Carvalho Chehab #define CODA_PARA_BUF_SIZE	(10 * 1024)
3564441979SMauro Carvalho Chehab #define CODA7_PS_BUF_SIZE	0x28000
3664441979SMauro Carvalho Chehab #define CODA9_PS_SAVE_SIZE	(512 * 1024)
3764441979SMauro Carvalho Chehab 
3864441979SMauro Carvalho Chehab #define CODA_DEFAULT_GAMMA	4096
3964441979SMauro Carvalho Chehab #define CODA9_DEFAULT_GAMMA	24576	/* 0.75 * 32768 */
4064441979SMauro Carvalho Chehab 
4164441979SMauro Carvalho Chehab static void coda_free_bitstream_buffer(struct coda_ctx *ctx);
4264441979SMauro Carvalho Chehab 
coda_is_initialized(struct coda_dev * dev)4364441979SMauro Carvalho Chehab static inline int coda_is_initialized(struct coda_dev *dev)
4464441979SMauro Carvalho Chehab {
4564441979SMauro Carvalho Chehab 	return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
4664441979SMauro Carvalho Chehab }
4764441979SMauro Carvalho Chehab 
coda_isbusy(struct coda_dev * dev)4864441979SMauro Carvalho Chehab static inline unsigned long coda_isbusy(struct coda_dev *dev)
4964441979SMauro Carvalho Chehab {
5064441979SMauro Carvalho Chehab 	return coda_read(dev, CODA_REG_BIT_BUSY);
5164441979SMauro Carvalho Chehab }
5264441979SMauro Carvalho Chehab 
coda_wait_timeout(struct coda_dev * dev)5364441979SMauro Carvalho Chehab static int coda_wait_timeout(struct coda_dev *dev)
5464441979SMauro Carvalho Chehab {
5564441979SMauro Carvalho Chehab 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
5664441979SMauro Carvalho Chehab 
5764441979SMauro Carvalho Chehab 	while (coda_isbusy(dev)) {
5864441979SMauro Carvalho Chehab 		if (time_after(jiffies, timeout))
5964441979SMauro Carvalho Chehab 			return -ETIMEDOUT;
6064441979SMauro Carvalho Chehab 	}
6164441979SMauro Carvalho Chehab 	return 0;
6264441979SMauro Carvalho Chehab }
6364441979SMauro Carvalho Chehab 
coda_command_async(struct coda_ctx * ctx,int cmd)6464441979SMauro Carvalho Chehab static void coda_command_async(struct coda_ctx *ctx, int cmd)
6564441979SMauro Carvalho Chehab {
6664441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
6764441979SMauro Carvalho Chehab 
6864441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_HX4 ||
6964441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_7541 ||
7064441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_960) {
7164441979SMauro Carvalho Chehab 		/* Restore context related registers to CODA */
7264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->bit_stream_param,
7364441979SMauro Carvalho Chehab 				CODA_REG_BIT_BIT_STREAM_PARAM);
7464441979SMauro Carvalho Chehab 		coda_write(dev, ctx->frm_dis_flg,
7564441979SMauro Carvalho Chehab 				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
7664441979SMauro Carvalho Chehab 		coda_write(dev, ctx->frame_mem_ctrl,
7764441979SMauro Carvalho Chehab 				CODA_REG_BIT_FRAME_MEM_CTRL);
7864441979SMauro Carvalho Chehab 		coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
7964441979SMauro Carvalho Chehab 	}
8064441979SMauro Carvalho Chehab 
8164441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
8264441979SMauro Carvalho Chehab 		coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
8364441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
8464441979SMauro Carvalho Chehab 	}
8564441979SMauro Carvalho Chehab 
8664441979SMauro Carvalho Chehab 	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
8764441979SMauro Carvalho Chehab 
8864441979SMauro Carvalho Chehab 	coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
8964441979SMauro Carvalho Chehab 	coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
9064441979SMauro Carvalho Chehab 	coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
9164441979SMauro Carvalho Chehab 
9264441979SMauro Carvalho Chehab 	trace_coda_bit_run(ctx, cmd);
9364441979SMauro Carvalho Chehab 
9464441979SMauro Carvalho Chehab 	coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
9564441979SMauro Carvalho Chehab }
9664441979SMauro Carvalho Chehab 
coda_command_sync(struct coda_ctx * ctx,int cmd)9764441979SMauro Carvalho Chehab static int coda_command_sync(struct coda_ctx *ctx, int cmd)
9864441979SMauro Carvalho Chehab {
9964441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
10064441979SMauro Carvalho Chehab 	int ret;
10164441979SMauro Carvalho Chehab 
10264441979SMauro Carvalho Chehab 	lockdep_assert_held(&dev->coda_mutex);
10364441979SMauro Carvalho Chehab 
10464441979SMauro Carvalho Chehab 	coda_command_async(ctx, cmd);
10564441979SMauro Carvalho Chehab 	ret = coda_wait_timeout(dev);
10664441979SMauro Carvalho Chehab 	trace_coda_bit_done(ctx);
10764441979SMauro Carvalho Chehab 
10864441979SMauro Carvalho Chehab 	return ret;
10964441979SMauro Carvalho Chehab }
11064441979SMauro Carvalho Chehab 
coda_hw_reset(struct coda_ctx * ctx)11164441979SMauro Carvalho Chehab int coda_hw_reset(struct coda_ctx *ctx)
11264441979SMauro Carvalho Chehab {
11364441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
11464441979SMauro Carvalho Chehab 	unsigned long timeout;
11564441979SMauro Carvalho Chehab 	unsigned int idx;
11664441979SMauro Carvalho Chehab 	int ret;
11764441979SMauro Carvalho Chehab 
11864441979SMauro Carvalho Chehab 	lockdep_assert_held(&dev->coda_mutex);
11964441979SMauro Carvalho Chehab 
12064441979SMauro Carvalho Chehab 	if (!dev->rstc)
12164441979SMauro Carvalho Chehab 		return -ENOENT;
12264441979SMauro Carvalho Chehab 
12364441979SMauro Carvalho Chehab 	idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
12464441979SMauro Carvalho Chehab 
12564441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
12664441979SMauro Carvalho Chehab 		timeout = jiffies + msecs_to_jiffies(100);
12764441979SMauro Carvalho Chehab 		coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
12864441979SMauro Carvalho Chehab 		while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
12964441979SMauro Carvalho Chehab 			if (time_after(jiffies, timeout))
13064441979SMauro Carvalho Chehab 				return -ETIME;
13164441979SMauro Carvalho Chehab 			cpu_relax();
13264441979SMauro Carvalho Chehab 		}
13364441979SMauro Carvalho Chehab 	}
13464441979SMauro Carvalho Chehab 
13564441979SMauro Carvalho Chehab 	ret = reset_control_reset(dev->rstc);
13664441979SMauro Carvalho Chehab 	if (ret < 0)
13764441979SMauro Carvalho Chehab 		return ret;
13864441979SMauro Carvalho Chehab 
13964441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
14064441979SMauro Carvalho Chehab 		coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
14164441979SMauro Carvalho Chehab 	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
14264441979SMauro Carvalho Chehab 	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
14364441979SMauro Carvalho Chehab 	ret = coda_wait_timeout(dev);
14464441979SMauro Carvalho Chehab 	coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
14564441979SMauro Carvalho Chehab 
14664441979SMauro Carvalho Chehab 	return ret;
14764441979SMauro Carvalho Chehab }
14864441979SMauro Carvalho Chehab 
coda_kfifo_sync_from_device(struct coda_ctx * ctx)14964441979SMauro Carvalho Chehab static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
15064441979SMauro Carvalho Chehab {
15164441979SMauro Carvalho Chehab 	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
15264441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
15364441979SMauro Carvalho Chehab 	u32 rd_ptr;
15464441979SMauro Carvalho Chehab 
15564441979SMauro Carvalho Chehab 	rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
15664441979SMauro Carvalho Chehab 	kfifo->out = (kfifo->in & ~kfifo->mask) |
15764441979SMauro Carvalho Chehab 		      (rd_ptr - ctx->bitstream.paddr);
15864441979SMauro Carvalho Chehab 	if (kfifo->out > kfifo->in)
15964441979SMauro Carvalho Chehab 		kfifo->out -= kfifo->mask + 1;
16064441979SMauro Carvalho Chehab }
16164441979SMauro Carvalho Chehab 
coda_kfifo_sync_to_device_full(struct coda_ctx * ctx)16264441979SMauro Carvalho Chehab static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
16364441979SMauro Carvalho Chehab {
16464441979SMauro Carvalho Chehab 	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
16564441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
16664441979SMauro Carvalho Chehab 	u32 rd_ptr, wr_ptr;
16764441979SMauro Carvalho Chehab 
16864441979SMauro Carvalho Chehab 	rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
16964441979SMauro Carvalho Chehab 	coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
17064441979SMauro Carvalho Chehab 	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
17164441979SMauro Carvalho Chehab 	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
17264441979SMauro Carvalho Chehab }
17364441979SMauro Carvalho Chehab 
coda_kfifo_sync_to_device_write(struct coda_ctx * ctx)17464441979SMauro Carvalho Chehab static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
17564441979SMauro Carvalho Chehab {
17664441979SMauro Carvalho Chehab 	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
17764441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
17864441979SMauro Carvalho Chehab 	u32 wr_ptr;
17964441979SMauro Carvalho Chehab 
18064441979SMauro Carvalho Chehab 	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
18164441979SMauro Carvalho Chehab 	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
18264441979SMauro Carvalho Chehab }
18364441979SMauro Carvalho Chehab 
coda_h264_bitstream_pad(struct coda_ctx * ctx,u32 size)18464441979SMauro Carvalho Chehab static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size)
18564441979SMauro Carvalho Chehab {
18664441979SMauro Carvalho Chehab 	unsigned char *buf;
18764441979SMauro Carvalho Chehab 	u32 n;
18864441979SMauro Carvalho Chehab 
18964441979SMauro Carvalho Chehab 	if (size < 6)
19064441979SMauro Carvalho Chehab 		size = 6;
19164441979SMauro Carvalho Chehab 
19264441979SMauro Carvalho Chehab 	buf = kmalloc(size, GFP_KERNEL);
19364441979SMauro Carvalho Chehab 	if (!buf)
19464441979SMauro Carvalho Chehab 		return -ENOMEM;
19564441979SMauro Carvalho Chehab 
19664441979SMauro Carvalho Chehab 	coda_h264_filler_nal(size, buf);
19764441979SMauro Carvalho Chehab 	n = kfifo_in(&ctx->bitstream_fifo, buf, size);
19864441979SMauro Carvalho Chehab 	kfree(buf);
19964441979SMauro Carvalho Chehab 
20064441979SMauro Carvalho Chehab 	return (n < size) ? -ENOSPC : 0;
20164441979SMauro Carvalho Chehab }
20264441979SMauro Carvalho Chehab 
coda_bitstream_flush(struct coda_ctx * ctx)20364441979SMauro Carvalho Chehab int coda_bitstream_flush(struct coda_ctx *ctx)
20464441979SMauro Carvalho Chehab {
20564441979SMauro Carvalho Chehab 	int ret;
20664441979SMauro Carvalho Chehab 
20764441979SMauro Carvalho Chehab 	if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit)
20864441979SMauro Carvalho Chehab 		return 0;
20964441979SMauro Carvalho Chehab 
21064441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH);
21164441979SMauro Carvalho Chehab 	if (ret < 0) {
21264441979SMauro Carvalho Chehab 		v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n");
21364441979SMauro Carvalho Chehab 		return ret;
21464441979SMauro Carvalho Chehab 	}
21564441979SMauro Carvalho Chehab 
21664441979SMauro Carvalho Chehab 	kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr,
21764441979SMauro Carvalho Chehab 		   ctx->bitstream.size);
21864441979SMauro Carvalho Chehab 	coda_kfifo_sync_to_device_full(ctx);
21964441979SMauro Carvalho Chehab 
22064441979SMauro Carvalho Chehab 	return 0;
22164441979SMauro Carvalho Chehab }
22264441979SMauro Carvalho Chehab 
coda_bitstream_queue(struct coda_ctx * ctx,const u8 * buf,u32 size)22364441979SMauro Carvalho Chehab static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size)
22464441979SMauro Carvalho Chehab {
22564441979SMauro Carvalho Chehab 	u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size);
22664441979SMauro Carvalho Chehab 
22764441979SMauro Carvalho Chehab 	return (n < size) ? -ENOSPC : 0;
22864441979SMauro Carvalho Chehab }
22964441979SMauro Carvalho Chehab 
coda_buffer_parse_headers(struct coda_ctx * ctx,struct vb2_v4l2_buffer * src_buf,u32 payload)23064441979SMauro Carvalho Chehab static u32 coda_buffer_parse_headers(struct coda_ctx *ctx,
23164441979SMauro Carvalho Chehab 				     struct vb2_v4l2_buffer *src_buf,
23264441979SMauro Carvalho Chehab 				     u32 payload)
23364441979SMauro Carvalho Chehab {
23464441979SMauro Carvalho Chehab 	u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
23564441979SMauro Carvalho Chehab 	u32 size = 0;
23664441979SMauro Carvalho Chehab 
23764441979SMauro Carvalho Chehab 	switch (ctx->codec->src_fourcc) {
23864441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_MPEG2:
23964441979SMauro Carvalho Chehab 		size = coda_mpeg2_parse_headers(ctx, vaddr, payload);
24064441979SMauro Carvalho Chehab 		break;
24164441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_MPEG4:
24264441979SMauro Carvalho Chehab 		size = coda_mpeg4_parse_headers(ctx, vaddr, payload);
24364441979SMauro Carvalho Chehab 		break;
24464441979SMauro Carvalho Chehab 	default:
24564441979SMauro Carvalho Chehab 		break;
24664441979SMauro Carvalho Chehab 	}
24764441979SMauro Carvalho Chehab 
24864441979SMauro Carvalho Chehab 	return size;
24964441979SMauro Carvalho Chehab }
25064441979SMauro Carvalho Chehab 
coda_bitstream_try_queue(struct coda_ctx * ctx,struct vb2_v4l2_buffer * src_buf)25164441979SMauro Carvalho Chehab static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
25264441979SMauro Carvalho Chehab 				     struct vb2_v4l2_buffer *src_buf)
25364441979SMauro Carvalho Chehab {
25464441979SMauro Carvalho Chehab 	unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
25564441979SMauro Carvalho Chehab 	u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
25664441979SMauro Carvalho Chehab 	int ret;
25764441979SMauro Carvalho Chehab 	int i;
25864441979SMauro Carvalho Chehab 
25964441979SMauro Carvalho Chehab 	if (coda_get_bitstream_payload(ctx) + payload + 512 >=
26064441979SMauro Carvalho Chehab 	    ctx->bitstream.size)
26164441979SMauro Carvalho Chehab 		return false;
26264441979SMauro Carvalho Chehab 
26364441979SMauro Carvalho Chehab 	if (!vaddr) {
26464441979SMauro Carvalho Chehab 		v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
26564441979SMauro Carvalho Chehab 		return true;
26664441979SMauro Carvalho Chehab 	}
26764441979SMauro Carvalho Chehab 
26864441979SMauro Carvalho Chehab 	if (ctx->qsequence == 0 && payload < 512) {
26964441979SMauro Carvalho Chehab 		/*
27064441979SMauro Carvalho Chehab 		 * Add padding after the first buffer, if it is too small to be
27164441979SMauro Carvalho Chehab 		 * fetched by the CODA, by repeating the headers. Without
27264441979SMauro Carvalho Chehab 		 * repeated headers, or the first frame already queued, decoder
27364441979SMauro Carvalho Chehab 		 * sequence initialization fails with error code 0x2000 on i.MX6
27464441979SMauro Carvalho Chehab 		 * or error code 0x1 on i.MX51.
27564441979SMauro Carvalho Chehab 		 */
27664441979SMauro Carvalho Chehab 		u32 header_size = coda_buffer_parse_headers(ctx, src_buf,
27764441979SMauro Carvalho Chehab 							    payload);
27864441979SMauro Carvalho Chehab 
27964441979SMauro Carvalho Chehab 		if (header_size) {
28064441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "pad with %u-byte header\n",
28164441979SMauro Carvalho Chehab 				 header_size);
28264441979SMauro Carvalho Chehab 			for (i = payload; i < 512; i += header_size) {
28364441979SMauro Carvalho Chehab 				ret = coda_bitstream_queue(ctx, vaddr,
28464441979SMauro Carvalho Chehab 							   header_size);
28564441979SMauro Carvalho Chehab 				if (ret < 0) {
28664441979SMauro Carvalho Chehab 					v4l2_err(&ctx->dev->v4l2_dev,
28764441979SMauro Carvalho Chehab 						 "bitstream buffer overflow\n");
28864441979SMauro Carvalho Chehab 					return false;
28964441979SMauro Carvalho Chehab 				}
29064441979SMauro Carvalho Chehab 				if (ctx->dev->devtype->product == CODA_960)
29164441979SMauro Carvalho Chehab 					break;
29264441979SMauro Carvalho Chehab 			}
29364441979SMauro Carvalho Chehab 		} else {
29464441979SMauro Carvalho Chehab 			coda_dbg(1, ctx,
29564441979SMauro Carvalho Chehab 				 "could not parse header, sequence initialization might fail\n");
29664441979SMauro Carvalho Chehab 		}
29764441979SMauro Carvalho Chehab 
29864441979SMauro Carvalho Chehab 		/* Add padding before the first buffer, if it is too small */
29964441979SMauro Carvalho Chehab 		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
30064441979SMauro Carvalho Chehab 			coda_h264_bitstream_pad(ctx, 512 - payload);
30164441979SMauro Carvalho Chehab 	}
30264441979SMauro Carvalho Chehab 
30364441979SMauro Carvalho Chehab 	ret = coda_bitstream_queue(ctx, vaddr, payload);
30464441979SMauro Carvalho Chehab 	if (ret < 0) {
30564441979SMauro Carvalho Chehab 		v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
30664441979SMauro Carvalho Chehab 		return false;
30764441979SMauro Carvalho Chehab 	}
30864441979SMauro Carvalho Chehab 
30964441979SMauro Carvalho Chehab 	src_buf->sequence = ctx->qsequence++;
31064441979SMauro Carvalho Chehab 
31164441979SMauro Carvalho Chehab 	/* Sync read pointer to device */
31264441979SMauro Carvalho Chehab 	if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
31364441979SMauro Carvalho Chehab 		coda_kfifo_sync_to_device_write(ctx);
31464441979SMauro Carvalho Chehab 
31564441979SMauro Carvalho Chehab 	/* Set the stream-end flag after the last buffer is queued */
31664441979SMauro Carvalho Chehab 	if (src_buf->flags & V4L2_BUF_FLAG_LAST)
31764441979SMauro Carvalho Chehab 		coda_bit_stream_end_flag(ctx);
31864441979SMauro Carvalho Chehab 	ctx->hold = false;
31964441979SMauro Carvalho Chehab 
32064441979SMauro Carvalho Chehab 	return true;
32164441979SMauro Carvalho Chehab }
32264441979SMauro Carvalho Chehab 
coda_fill_bitstream(struct coda_ctx * ctx,struct list_head * buffer_list)32364441979SMauro Carvalho Chehab void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
32464441979SMauro Carvalho Chehab {
32564441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf;
32664441979SMauro Carvalho Chehab 	struct coda_buffer_meta *meta;
32764441979SMauro Carvalho Chehab 	u32 start;
32864441979SMauro Carvalho Chehab 
32987e0ce68SPhilipp Zabel 	lockdep_assert_held(&ctx->bitstream_mutex);
33087e0ce68SPhilipp Zabel 
33164441979SMauro Carvalho Chehab 	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
33264441979SMauro Carvalho Chehab 		return;
33364441979SMauro Carvalho Chehab 
33464441979SMauro Carvalho Chehab 	while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
33564441979SMauro Carvalho Chehab 		/*
33664441979SMauro Carvalho Chehab 		 * Only queue two JPEGs into the bitstream buffer to keep
33764441979SMauro Carvalho Chehab 		 * latency low. We need at least one complete buffer and the
33864441979SMauro Carvalho Chehab 		 * header of another buffer (for prescan) in the bitstream.
33964441979SMauro Carvalho Chehab 		 */
34064441979SMauro Carvalho Chehab 		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
34164441979SMauro Carvalho Chehab 		    ctx->num_metas > 1)
34264441979SMauro Carvalho Chehab 			break;
34364441979SMauro Carvalho Chehab 
34464441979SMauro Carvalho Chehab 		if (ctx->num_internal_frames &&
34564441979SMauro Carvalho Chehab 		    ctx->num_metas >= ctx->num_internal_frames) {
34664441979SMauro Carvalho Chehab 			meta = list_first_entry(&ctx->buffer_meta_list,
34764441979SMauro Carvalho Chehab 						struct coda_buffer_meta, list);
34864441979SMauro Carvalho Chehab 
34964441979SMauro Carvalho Chehab 			/*
35064441979SMauro Carvalho Chehab 			 * If we managed to fill in at least a full reorder
35164441979SMauro Carvalho Chehab 			 * window of buffers (num_internal_frames is a
35264441979SMauro Carvalho Chehab 			 * conservative estimate for this) and the bitstream
35364441979SMauro Carvalho Chehab 			 * prefetcher has at least 2 256 bytes periods beyond
35464441979SMauro Carvalho Chehab 			 * the first buffer to fetch, we can safely stop queuing
35564441979SMauro Carvalho Chehab 			 * in order to limit the decoder drain latency.
35664441979SMauro Carvalho Chehab 			 */
35764441979SMauro Carvalho Chehab 			if (coda_bitstream_can_fetch_past(ctx, meta->end))
35864441979SMauro Carvalho Chehab 				break;
35964441979SMauro Carvalho Chehab 		}
36064441979SMauro Carvalho Chehab 
36164441979SMauro Carvalho Chehab 		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
36264441979SMauro Carvalho Chehab 
36364441979SMauro Carvalho Chehab 		/* Drop frames that do not start/end with a SOI/EOI markers */
36464441979SMauro Carvalho Chehab 		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
36564441979SMauro Carvalho Chehab 		    !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) {
36664441979SMauro Carvalho Chehab 			v4l2_err(&ctx->dev->v4l2_dev,
36764441979SMauro Carvalho Chehab 				 "dropping invalid JPEG frame %d\n",
36864441979SMauro Carvalho Chehab 				 ctx->qsequence);
36964441979SMauro Carvalho Chehab 			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
37064441979SMauro Carvalho Chehab 			if (buffer_list) {
37164441979SMauro Carvalho Chehab 				struct v4l2_m2m_buffer *m2m_buf;
37264441979SMauro Carvalho Chehab 
37364441979SMauro Carvalho Chehab 				m2m_buf = container_of(src_buf,
37464441979SMauro Carvalho Chehab 						       struct v4l2_m2m_buffer,
37564441979SMauro Carvalho Chehab 						       vb);
37664441979SMauro Carvalho Chehab 				list_add_tail(&m2m_buf->list, buffer_list);
37764441979SMauro Carvalho Chehab 			} else {
37864441979SMauro Carvalho Chehab 				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
37964441979SMauro Carvalho Chehab 			}
38064441979SMauro Carvalho Chehab 			continue;
38164441979SMauro Carvalho Chehab 		}
38264441979SMauro Carvalho Chehab 
38364441979SMauro Carvalho Chehab 		/* Dump empty buffers */
38464441979SMauro Carvalho Chehab 		if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) {
38564441979SMauro Carvalho Chehab 			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
38664441979SMauro Carvalho Chehab 			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
38764441979SMauro Carvalho Chehab 			continue;
38864441979SMauro Carvalho Chehab 		}
38964441979SMauro Carvalho Chehab 
39064441979SMauro Carvalho Chehab 		/* Buffer start position */
39164441979SMauro Carvalho Chehab 		start = ctx->bitstream_fifo.kfifo.in;
39264441979SMauro Carvalho Chehab 
39364441979SMauro Carvalho Chehab 		if (coda_bitstream_try_queue(ctx, src_buf)) {
39464441979SMauro Carvalho Chehab 			/*
39564441979SMauro Carvalho Chehab 			 * Source buffer is queued in the bitstream ringbuffer;
39664441979SMauro Carvalho Chehab 			 * queue the timestamp and mark source buffer as done
39764441979SMauro Carvalho Chehab 			 */
39864441979SMauro Carvalho Chehab 			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
39964441979SMauro Carvalho Chehab 
40064441979SMauro Carvalho Chehab 			meta = kmalloc(sizeof(*meta), GFP_KERNEL);
40164441979SMauro Carvalho Chehab 			if (meta) {
40264441979SMauro Carvalho Chehab 				meta->sequence = src_buf->sequence;
40364441979SMauro Carvalho Chehab 				meta->timecode = src_buf->timecode;
40464441979SMauro Carvalho Chehab 				meta->timestamp = src_buf->vb2_buf.timestamp;
40564441979SMauro Carvalho Chehab 				meta->start = start;
40664441979SMauro Carvalho Chehab 				meta->end = ctx->bitstream_fifo.kfifo.in;
40764441979SMauro Carvalho Chehab 				meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST;
40864441979SMauro Carvalho Chehab 				if (meta->last)
40964441979SMauro Carvalho Chehab 					coda_dbg(1, ctx, "marking last meta");
41064441979SMauro Carvalho Chehab 				spin_lock(&ctx->buffer_meta_lock);
41164441979SMauro Carvalho Chehab 				list_add_tail(&meta->list,
41264441979SMauro Carvalho Chehab 					      &ctx->buffer_meta_list);
41364441979SMauro Carvalho Chehab 				ctx->num_metas++;
41464441979SMauro Carvalho Chehab 				spin_unlock(&ctx->buffer_meta_lock);
41564441979SMauro Carvalho Chehab 
41664441979SMauro Carvalho Chehab 				trace_coda_bit_queue(ctx, src_buf, meta);
41764441979SMauro Carvalho Chehab 			}
41864441979SMauro Carvalho Chehab 
41964441979SMauro Carvalho Chehab 			if (buffer_list) {
42064441979SMauro Carvalho Chehab 				struct v4l2_m2m_buffer *m2m_buf;
42164441979SMauro Carvalho Chehab 
42264441979SMauro Carvalho Chehab 				m2m_buf = container_of(src_buf,
42364441979SMauro Carvalho Chehab 						       struct v4l2_m2m_buffer,
42464441979SMauro Carvalho Chehab 						       vb);
42564441979SMauro Carvalho Chehab 				list_add_tail(&m2m_buf->list, buffer_list);
42664441979SMauro Carvalho Chehab 			} else {
42764441979SMauro Carvalho Chehab 				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
42864441979SMauro Carvalho Chehab 			}
42964441979SMauro Carvalho Chehab 		} else {
43064441979SMauro Carvalho Chehab 			break;
43164441979SMauro Carvalho Chehab 		}
43264441979SMauro Carvalho Chehab 	}
43364441979SMauro Carvalho Chehab }
43464441979SMauro Carvalho Chehab 
coda_bit_stream_end_flag(struct coda_ctx * ctx)43564441979SMauro Carvalho Chehab void coda_bit_stream_end_flag(struct coda_ctx *ctx)
43664441979SMauro Carvalho Chehab {
43764441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
43864441979SMauro Carvalho Chehab 
43964441979SMauro Carvalho Chehab 	ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
44064441979SMauro Carvalho Chehab 
44164441979SMauro Carvalho Chehab 	/* If this context is currently running, update the hardware flag */
44264441979SMauro Carvalho Chehab 	if ((dev->devtype->product == CODA_960) &&
44364441979SMauro Carvalho Chehab 	    coda_isbusy(dev) &&
44464441979SMauro Carvalho Chehab 	    (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
44564441979SMauro Carvalho Chehab 		coda_write(dev, ctx->bit_stream_param,
44664441979SMauro Carvalho Chehab 			   CODA_REG_BIT_BIT_STREAM_PARAM);
44764441979SMauro Carvalho Chehab 	}
44864441979SMauro Carvalho Chehab }
44964441979SMauro Carvalho Chehab 
coda_parabuf_write(struct coda_ctx * ctx,int index,u32 value)45064441979SMauro Carvalho Chehab static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
45164441979SMauro Carvalho Chehab {
45264441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
45364441979SMauro Carvalho Chehab 	u32 *p = ctx->parabuf.vaddr;
45464441979SMauro Carvalho Chehab 
45564441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_DX6)
45664441979SMauro Carvalho Chehab 		p[index] = value;
45764441979SMauro Carvalho Chehab 	else
45864441979SMauro Carvalho Chehab 		p[index ^ 1] = value;
45964441979SMauro Carvalho Chehab }
46064441979SMauro Carvalho Chehab 
coda_alloc_context_buf(struct coda_ctx * ctx,struct coda_aux_buf * buf,size_t size,const char * name)46164441979SMauro Carvalho Chehab static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
46264441979SMauro Carvalho Chehab 					 struct coda_aux_buf *buf, size_t size,
46364441979SMauro Carvalho Chehab 					 const char *name)
46464441979SMauro Carvalho Chehab {
46564441979SMauro Carvalho Chehab 	return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
46664441979SMauro Carvalho Chehab }
46764441979SMauro Carvalho Chehab 
46864441979SMauro Carvalho Chehab 
coda_free_framebuffers(struct coda_ctx * ctx)46964441979SMauro Carvalho Chehab static void coda_free_framebuffers(struct coda_ctx *ctx)
47064441979SMauro Carvalho Chehab {
47164441979SMauro Carvalho Chehab 	int i;
47264441979SMauro Carvalho Chehab 
47364441979SMauro Carvalho Chehab 	for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
47464441979SMauro Carvalho Chehab 		coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf);
47564441979SMauro Carvalho Chehab }
47664441979SMauro Carvalho Chehab 
coda_alloc_framebuffers(struct coda_ctx * ctx,struct coda_q_data * q_data,u32 fourcc)47764441979SMauro Carvalho Chehab static int coda_alloc_framebuffers(struct coda_ctx *ctx,
47864441979SMauro Carvalho Chehab 				   struct coda_q_data *q_data, u32 fourcc)
47964441979SMauro Carvalho Chehab {
48064441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
48164441979SMauro Carvalho Chehab 	unsigned int ysize, ycbcr_size;
48264441979SMauro Carvalho Chehab 	int ret;
48364441979SMauro Carvalho Chehab 	int i;
48464441979SMauro Carvalho Chehab 
48564441979SMauro Carvalho Chehab 	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
48664441979SMauro Carvalho Chehab 	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 ||
48764441979SMauro Carvalho Chehab 	    ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 ||
48864441979SMauro Carvalho Chehab 	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4)
48964441979SMauro Carvalho Chehab 		ysize = round_up(q_data->rect.width, 16) *
49064441979SMauro Carvalho Chehab 			round_up(q_data->rect.height, 16);
49164441979SMauro Carvalho Chehab 	else
49264441979SMauro Carvalho Chehab 		ysize = round_up(q_data->rect.width, 8) * q_data->rect.height;
49364441979SMauro Carvalho Chehab 
49464441979SMauro Carvalho Chehab 	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
49564441979SMauro Carvalho Chehab 		ycbcr_size = round_up(ysize, 4096) + ysize / 2;
49664441979SMauro Carvalho Chehab 	else
49764441979SMauro Carvalho Chehab 		ycbcr_size = ysize + ysize / 2;
49864441979SMauro Carvalho Chehab 
49964441979SMauro Carvalho Chehab 	/* Allocate frame buffers */
50064441979SMauro Carvalho Chehab 	for (i = 0; i < ctx->num_internal_frames; i++) {
50164441979SMauro Carvalho Chehab 		size_t size = ycbcr_size;
50264441979SMauro Carvalho Chehab 		char *name;
50364441979SMauro Carvalho Chehab 
50464441979SMauro Carvalho Chehab 		/* Add space for mvcol buffers */
50564441979SMauro Carvalho Chehab 		if (dev->devtype->product != CODA_DX6 &&
50664441979SMauro Carvalho Chehab 		    (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
50764441979SMauro Carvalho Chehab 		     (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0)))
50864441979SMauro Carvalho Chehab 			size += ysize / 4;
50964441979SMauro Carvalho Chehab 		name = kasprintf(GFP_KERNEL, "fb%d", i);
51064441979SMauro Carvalho Chehab 		if (!name) {
51164441979SMauro Carvalho Chehab 			coda_free_framebuffers(ctx);
51264441979SMauro Carvalho Chehab 			return -ENOMEM;
51364441979SMauro Carvalho Chehab 		}
51464441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf,
51564441979SMauro Carvalho Chehab 					     size, name);
51664441979SMauro Carvalho Chehab 		kfree(name);
51764441979SMauro Carvalho Chehab 		if (ret < 0) {
51864441979SMauro Carvalho Chehab 			coda_free_framebuffers(ctx);
51964441979SMauro Carvalho Chehab 			return ret;
52064441979SMauro Carvalho Chehab 		}
52164441979SMauro Carvalho Chehab 	}
52264441979SMauro Carvalho Chehab 
52364441979SMauro Carvalho Chehab 	/* Register frame buffers in the parameter buffer */
52464441979SMauro Carvalho Chehab 	for (i = 0; i < ctx->num_internal_frames; i++) {
52564441979SMauro Carvalho Chehab 		u32 y, cb, cr, mvcol;
52664441979SMauro Carvalho Chehab 
52764441979SMauro Carvalho Chehab 		/* Start addresses of Y, Cb, Cr planes */
52864441979SMauro Carvalho Chehab 		y = ctx->internal_frames[i].buf.paddr;
52964441979SMauro Carvalho Chehab 		cb = y + ysize;
53064441979SMauro Carvalho Chehab 		cr = y + ysize + ysize/4;
53164441979SMauro Carvalho Chehab 		mvcol = y + ysize + ysize/4 + ysize/4;
53264441979SMauro Carvalho Chehab 		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) {
53364441979SMauro Carvalho Chehab 			cb = round_up(cb, 4096);
53464441979SMauro Carvalho Chehab 			mvcol = cb + ysize/2;
53564441979SMauro Carvalho Chehab 			cr = 0;
53664441979SMauro Carvalho Chehab 			/* Packed 20-bit MSB of base addresses */
53764441979SMauro Carvalho Chehab 			/* YYYYYCCC, CCyyyyyc, cccc.... */
53864441979SMauro Carvalho Chehab 			y = (y & 0xfffff000) | cb >> 20;
53964441979SMauro Carvalho Chehab 			cb = (cb & 0x000ff000) << 12;
54064441979SMauro Carvalho Chehab 		}
54164441979SMauro Carvalho Chehab 		coda_parabuf_write(ctx, i * 3 + 0, y);
54264441979SMauro Carvalho Chehab 		coda_parabuf_write(ctx, i * 3 + 1, cb);
54364441979SMauro Carvalho Chehab 		coda_parabuf_write(ctx, i * 3 + 2, cr);
54464441979SMauro Carvalho Chehab 
54564441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_DX6)
54664441979SMauro Carvalho Chehab 			continue;
54764441979SMauro Carvalho Chehab 
54864441979SMauro Carvalho Chehab 		/* mvcol buffer for h.264 and mpeg4 */
54964441979SMauro Carvalho Chehab 		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
55064441979SMauro Carvalho Chehab 			coda_parabuf_write(ctx, 96 + i, mvcol);
55164441979SMauro Carvalho Chehab 		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0)
55264441979SMauro Carvalho Chehab 			coda_parabuf_write(ctx, 97, mvcol);
55364441979SMauro Carvalho Chehab 	}
55464441979SMauro Carvalho Chehab 
55564441979SMauro Carvalho Chehab 	return 0;
55664441979SMauro Carvalho Chehab }
55764441979SMauro Carvalho Chehab 
coda_free_context_buffers(struct coda_ctx * ctx)55864441979SMauro Carvalho Chehab static void coda_free_context_buffers(struct coda_ctx *ctx)
55964441979SMauro Carvalho Chehab {
56064441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
56164441979SMauro Carvalho Chehab 
56264441979SMauro Carvalho Chehab 	coda_free_aux_buf(dev, &ctx->slicebuf);
56364441979SMauro Carvalho Chehab 	coda_free_aux_buf(dev, &ctx->psbuf);
56464441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6)
56564441979SMauro Carvalho Chehab 		coda_free_aux_buf(dev, &ctx->workbuf);
56664441979SMauro Carvalho Chehab 	coda_free_aux_buf(dev, &ctx->parabuf);
56764441979SMauro Carvalho Chehab }
56864441979SMauro Carvalho Chehab 
coda_alloc_context_buffers(struct coda_ctx * ctx,struct coda_q_data * q_data)56964441979SMauro Carvalho Chehab static int coda_alloc_context_buffers(struct coda_ctx *ctx,
57064441979SMauro Carvalho Chehab 				      struct coda_q_data *q_data)
57164441979SMauro Carvalho Chehab {
57264441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
57364441979SMauro Carvalho Chehab 	size_t size;
57464441979SMauro Carvalho Chehab 	int ret;
57564441979SMauro Carvalho Chehab 
57664441979SMauro Carvalho Chehab 	if (!ctx->parabuf.vaddr) {
57764441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
57864441979SMauro Carvalho Chehab 					     CODA_PARA_BUF_SIZE, "parabuf");
57964441979SMauro Carvalho Chehab 		if (ret < 0)
58064441979SMauro Carvalho Chehab 			return ret;
58164441979SMauro Carvalho Chehab 	}
58264441979SMauro Carvalho Chehab 
58364441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_DX6)
58464441979SMauro Carvalho Chehab 		return 0;
58564441979SMauro Carvalho Chehab 
58664441979SMauro Carvalho Chehab 	if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
58764441979SMauro Carvalho Chehab 		/* worst case slice size */
58864441979SMauro Carvalho Chehab 		size = (DIV_ROUND_UP(q_data->rect.width, 16) *
58964441979SMauro Carvalho Chehab 			DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512;
59064441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
59164441979SMauro Carvalho Chehab 					     "slicebuf");
59264441979SMauro Carvalho Chehab 		if (ret < 0)
59364441979SMauro Carvalho Chehab 			goto err;
59464441979SMauro Carvalho Chehab 	}
59564441979SMauro Carvalho Chehab 
59664441979SMauro Carvalho Chehab 	if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 ||
59764441979SMauro Carvalho Chehab 				  dev->devtype->product == CODA_7541)) {
59864441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
59964441979SMauro Carvalho Chehab 					     CODA7_PS_BUF_SIZE, "psbuf");
60064441979SMauro Carvalho Chehab 		if (ret < 0)
60164441979SMauro Carvalho Chehab 			goto err;
60264441979SMauro Carvalho Chehab 	}
60364441979SMauro Carvalho Chehab 
60464441979SMauro Carvalho Chehab 	if (!ctx->workbuf.vaddr) {
60564441979SMauro Carvalho Chehab 		size = dev->devtype->workbuf_size;
60664441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960 &&
60764441979SMauro Carvalho Chehab 		    q_data->fourcc == V4L2_PIX_FMT_H264)
60864441979SMauro Carvalho Chehab 			size += CODA9_PS_SAVE_SIZE;
60964441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size,
61064441979SMauro Carvalho Chehab 					     "workbuf");
61164441979SMauro Carvalho Chehab 		if (ret < 0)
61264441979SMauro Carvalho Chehab 			goto err;
61364441979SMauro Carvalho Chehab 	}
61464441979SMauro Carvalho Chehab 
61564441979SMauro Carvalho Chehab 	return 0;
61664441979SMauro Carvalho Chehab 
61764441979SMauro Carvalho Chehab err:
61864441979SMauro Carvalho Chehab 	coda_free_context_buffers(ctx);
61964441979SMauro Carvalho Chehab 	return ret;
62064441979SMauro Carvalho Chehab }
62164441979SMauro Carvalho Chehab 
coda_encode_header(struct coda_ctx * ctx,struct vb2_v4l2_buffer * buf,int header_code,u8 * header,int * size)62264441979SMauro Carvalho Chehab static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
62364441979SMauro Carvalho Chehab 			      int header_code, u8 *header, int *size)
62464441979SMauro Carvalho Chehab {
62564441979SMauro Carvalho Chehab 	struct vb2_buffer *vb = &buf->vb2_buf;
62664441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
62764441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src;
62864441979SMauro Carvalho Chehab 	struct v4l2_rect *r;
62964441979SMauro Carvalho Chehab 	size_t bufsize;
63064441979SMauro Carvalho Chehab 	int ret;
63164441979SMauro Carvalho Chehab 	int i;
63264441979SMauro Carvalho Chehab 
63364441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
63464441979SMauro Carvalho Chehab 		memset(vb2_plane_vaddr(vb, 0), 0, 64);
63564441979SMauro Carvalho Chehab 
63664441979SMauro Carvalho Chehab 	coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0),
63764441979SMauro Carvalho Chehab 		   CODA_CMD_ENC_HEADER_BB_START);
63864441979SMauro Carvalho Chehab 	bufsize = vb2_plane_size(vb, 0);
63964441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
64064441979SMauro Carvalho Chehab 		bufsize /= 1024;
64164441979SMauro Carvalho Chehab 	coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
64264441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960 &&
64364441979SMauro Carvalho Chehab 	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 &&
64464441979SMauro Carvalho Chehab 	    header_code == CODA_HEADER_H264_SPS) {
64564441979SMauro Carvalho Chehab 		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
64664441979SMauro Carvalho Chehab 		r = &q_data_src->rect;
64764441979SMauro Carvalho Chehab 
64864441979SMauro Carvalho Chehab 		if (r->width % 16 || r->height % 16) {
64964441979SMauro Carvalho Chehab 			u32 crop_right = round_up(r->width, 16) -  r->width;
65064441979SMauro Carvalho Chehab 			u32 crop_bottom = round_up(r->height, 16) - r->height;
65164441979SMauro Carvalho Chehab 
65264441979SMauro Carvalho Chehab 			coda_write(dev, crop_right,
65364441979SMauro Carvalho Chehab 				   CODA9_CMD_ENC_HEADER_FRAME_CROP_H);
65464441979SMauro Carvalho Chehab 			coda_write(dev, crop_bottom,
65564441979SMauro Carvalho Chehab 				   CODA9_CMD_ENC_HEADER_FRAME_CROP_V);
65664441979SMauro Carvalho Chehab 			header_code |= CODA9_HEADER_FRAME_CROP;
65764441979SMauro Carvalho Chehab 		}
65864441979SMauro Carvalho Chehab 	}
65964441979SMauro Carvalho Chehab 	coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
66064441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
66164441979SMauro Carvalho Chehab 	if (ret < 0) {
66264441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
66364441979SMauro Carvalho Chehab 		return ret;
66464441979SMauro Carvalho Chehab 	}
66564441979SMauro Carvalho Chehab 
66664441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
66764441979SMauro Carvalho Chehab 		for (i = 63; i > 0; i--)
66864441979SMauro Carvalho Chehab 			if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0)
66964441979SMauro Carvalho Chehab 				break;
67064441979SMauro Carvalho Chehab 		*size = i + 1;
67164441979SMauro Carvalho Chehab 	} else {
67264441979SMauro Carvalho Chehab 		*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
67364441979SMauro Carvalho Chehab 			coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
67464441979SMauro Carvalho Chehab 	}
67564441979SMauro Carvalho Chehab 	memcpy(header, vb2_plane_vaddr(vb, 0), *size);
67664441979SMauro Carvalho Chehab 
67764441979SMauro Carvalho Chehab 	return 0;
67864441979SMauro Carvalho Chehab }
67964441979SMauro Carvalho Chehab 
coda_slice_mode(struct coda_ctx * ctx)68064441979SMauro Carvalho Chehab static u32 coda_slice_mode(struct coda_ctx *ctx)
68164441979SMauro Carvalho Chehab {
68264441979SMauro Carvalho Chehab 	int size, unit;
68364441979SMauro Carvalho Chehab 
68464441979SMauro Carvalho Chehab 	switch (ctx->params.slice_mode) {
68564441979SMauro Carvalho Chehab 	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
68664441979SMauro Carvalho Chehab 	default:
68764441979SMauro Carvalho Chehab 		return 0;
68864441979SMauro Carvalho Chehab 	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB:
68964441979SMauro Carvalho Chehab 		size = ctx->params.slice_max_mb;
69064441979SMauro Carvalho Chehab 		unit = 1;
69164441979SMauro Carvalho Chehab 		break;
69264441979SMauro Carvalho Chehab 	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES:
69364441979SMauro Carvalho Chehab 		size = ctx->params.slice_max_bits;
69464441979SMauro Carvalho Chehab 		unit = 0;
69564441979SMauro Carvalho Chehab 		break;
69664441979SMauro Carvalho Chehab 	}
69764441979SMauro Carvalho Chehab 
69864441979SMauro Carvalho Chehab 	return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) |
69964441979SMauro Carvalho Chehab 	       ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) |
70064441979SMauro Carvalho Chehab 	       ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET);
70164441979SMauro Carvalho Chehab }
70264441979SMauro Carvalho Chehab 
coda_enc_param_change(struct coda_ctx * ctx)70364441979SMauro Carvalho Chehab static int coda_enc_param_change(struct coda_ctx *ctx)
70464441979SMauro Carvalho Chehab {
70564441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
70664441979SMauro Carvalho Chehab 	u32 change_enable = 0;
70764441979SMauro Carvalho Chehab 	u32 success;
70864441979SMauro Carvalho Chehab 	int ret;
70964441979SMauro Carvalho Chehab 
71064441979SMauro Carvalho Chehab 	if (ctx->params.gop_size_changed) {
71164441979SMauro Carvalho Chehab 		change_enable |= CODA_PARAM_CHANGE_RC_GOP;
71264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->params.gop_size,
71364441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_PARAM_RC_GOP);
71464441979SMauro Carvalho Chehab 		ctx->gopcounter = ctx->params.gop_size - 1;
71564441979SMauro Carvalho Chehab 		ctx->params.gop_size_changed = false;
71664441979SMauro Carvalho Chehab 	}
71764441979SMauro Carvalho Chehab 	if (ctx->params.h264_intra_qp_changed) {
71864441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "parameter change: intra Qp %u\n",
71964441979SMauro Carvalho Chehab 			 ctx->params.h264_intra_qp);
72064441979SMauro Carvalho Chehab 
72164441979SMauro Carvalho Chehab 		if (ctx->params.bitrate) {
72264441979SMauro Carvalho Chehab 			change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP;
72364441979SMauro Carvalho Chehab 			coda_write(dev, ctx->params.h264_intra_qp,
72464441979SMauro Carvalho Chehab 				   CODA_CMD_ENC_PARAM_RC_INTRA_QP);
72564441979SMauro Carvalho Chehab 		}
72664441979SMauro Carvalho Chehab 		ctx->params.h264_intra_qp_changed = false;
72764441979SMauro Carvalho Chehab 	}
72864441979SMauro Carvalho Chehab 	if (ctx->params.bitrate_changed) {
72964441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n",
73064441979SMauro Carvalho Chehab 			 ctx->params.bitrate);
73164441979SMauro Carvalho Chehab 		change_enable |= CODA_PARAM_CHANGE_RC_BITRATE;
73264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->params.bitrate,
73364441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_PARAM_RC_BITRATE);
73464441979SMauro Carvalho Chehab 		ctx->params.bitrate_changed = false;
73564441979SMauro Carvalho Chehab 	}
73664441979SMauro Carvalho Chehab 	if (ctx->params.framerate_changed) {
73764441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n",
73864441979SMauro Carvalho Chehab 			 ctx->params.framerate & 0xffff,
73964441979SMauro Carvalho Chehab 			 (ctx->params.framerate >> 16) + 1);
74064441979SMauro Carvalho Chehab 		change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE;
74164441979SMauro Carvalho Chehab 		coda_write(dev, ctx->params.framerate,
74264441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_PARAM_RC_FRAME_RATE);
74364441979SMauro Carvalho Chehab 		ctx->params.framerate_changed = false;
74464441979SMauro Carvalho Chehab 	}
74564441979SMauro Carvalho Chehab 	if (ctx->params.intra_refresh_changed) {
74664441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n",
74764441979SMauro Carvalho Chehab 			 ctx->params.intra_refresh);
74864441979SMauro Carvalho Chehab 		change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM;
74964441979SMauro Carvalho Chehab 		coda_write(dev, ctx->params.intra_refresh,
75064441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_PARAM_INTRA_MB_NUM);
75164441979SMauro Carvalho Chehab 		ctx->params.intra_refresh_changed = false;
75264441979SMauro Carvalho Chehab 	}
75364441979SMauro Carvalho Chehab 	if (ctx->params.slice_mode_changed) {
75464441979SMauro Carvalho Chehab 		change_enable |= CODA_PARAM_CHANGE_SLICE_MODE;
75564441979SMauro Carvalho Chehab 		coda_write(dev, coda_slice_mode(ctx),
75664441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_PARAM_SLICE_MODE);
75764441979SMauro Carvalho Chehab 		ctx->params.slice_mode_changed = false;
75864441979SMauro Carvalho Chehab 	}
75964441979SMauro Carvalho Chehab 
76064441979SMauro Carvalho Chehab 	if (!change_enable)
76164441979SMauro Carvalho Chehab 		return 0;
76264441979SMauro Carvalho Chehab 
76364441979SMauro Carvalho Chehab 	coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE);
76464441979SMauro Carvalho Chehab 
76564441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER);
76664441979SMauro Carvalho Chehab 	if (ret < 0)
76764441979SMauro Carvalho Chehab 		return ret;
76864441979SMauro Carvalho Chehab 
76964441979SMauro Carvalho Chehab 	success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS);
77064441979SMauro Carvalho Chehab 	if (success != 1)
77164441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "parameter change failed: %u\n", success);
77264441979SMauro Carvalho Chehab 
77364441979SMauro Carvalho Chehab 	return 0;
77464441979SMauro Carvalho Chehab }
77564441979SMauro Carvalho Chehab 
coda_iram_alloc(struct coda_iram_info * iram,size_t size)77664441979SMauro Carvalho Chehab static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
77764441979SMauro Carvalho Chehab {
77864441979SMauro Carvalho Chehab 	phys_addr_t ret;
77964441979SMauro Carvalho Chehab 
78064441979SMauro Carvalho Chehab 	size = round_up(size, 1024);
78164441979SMauro Carvalho Chehab 	if (size > iram->remaining)
78264441979SMauro Carvalho Chehab 		return 0;
78364441979SMauro Carvalho Chehab 	iram->remaining -= size;
78464441979SMauro Carvalho Chehab 
78564441979SMauro Carvalho Chehab 	ret = iram->next_paddr;
78664441979SMauro Carvalho Chehab 	iram->next_paddr += size;
78764441979SMauro Carvalho Chehab 
78864441979SMauro Carvalho Chehab 	return ret;
78964441979SMauro Carvalho Chehab }
79064441979SMauro Carvalho Chehab 
coda_setup_iram(struct coda_ctx * ctx)79164441979SMauro Carvalho Chehab static void coda_setup_iram(struct coda_ctx *ctx)
79264441979SMauro Carvalho Chehab {
79364441979SMauro Carvalho Chehab 	struct coda_iram_info *iram_info = &ctx->iram_info;
79464441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
79564441979SMauro Carvalho Chehab 	int w64, w128;
79664441979SMauro Carvalho Chehab 	int mb_width;
79764441979SMauro Carvalho Chehab 	int dbk_bits;
79864441979SMauro Carvalho Chehab 	int bit_bits;
79964441979SMauro Carvalho Chehab 	int ip_bits;
80064441979SMauro Carvalho Chehab 	int me_bits;
80164441979SMauro Carvalho Chehab 
80264441979SMauro Carvalho Chehab 	memset(iram_info, 0, sizeof(*iram_info));
80364441979SMauro Carvalho Chehab 	iram_info->next_paddr = dev->iram.paddr;
80464441979SMauro Carvalho Chehab 	iram_info->remaining = dev->iram.size;
80564441979SMauro Carvalho Chehab 
80664441979SMauro Carvalho Chehab 	if (!dev->iram.vaddr)
80764441979SMauro Carvalho Chehab 		return;
80864441979SMauro Carvalho Chehab 
80964441979SMauro Carvalho Chehab 	switch (dev->devtype->product) {
81064441979SMauro Carvalho Chehab 	case CODA_HX4:
81164441979SMauro Carvalho Chehab 		dbk_bits = CODA7_USE_HOST_DBK_ENABLE;
81264441979SMauro Carvalho Chehab 		bit_bits = CODA7_USE_HOST_BIT_ENABLE;
81364441979SMauro Carvalho Chehab 		ip_bits = CODA7_USE_HOST_IP_ENABLE;
81464441979SMauro Carvalho Chehab 		me_bits = CODA7_USE_HOST_ME_ENABLE;
81564441979SMauro Carvalho Chehab 		break;
81664441979SMauro Carvalho Chehab 	case CODA_7541:
81764441979SMauro Carvalho Chehab 		dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
81864441979SMauro Carvalho Chehab 		bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
81964441979SMauro Carvalho Chehab 		ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
82064441979SMauro Carvalho Chehab 		me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE;
82164441979SMauro Carvalho Chehab 		break;
82264441979SMauro Carvalho Chehab 	case CODA_960:
82364441979SMauro Carvalho Chehab 		dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
82464441979SMauro Carvalho Chehab 		bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
82564441979SMauro Carvalho Chehab 		ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
82664441979SMauro Carvalho Chehab 		me_bits = 0;
82764441979SMauro Carvalho Chehab 		break;
82864441979SMauro Carvalho Chehab 	default: /* CODA_DX6 */
82964441979SMauro Carvalho Chehab 		return;
83064441979SMauro Carvalho Chehab 	}
83164441979SMauro Carvalho Chehab 
83264441979SMauro Carvalho Chehab 	if (ctx->inst_type == CODA_INST_ENCODER) {
83364441979SMauro Carvalho Chehab 		struct coda_q_data *q_data_src;
83464441979SMauro Carvalho Chehab 
83564441979SMauro Carvalho Chehab 		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
83664441979SMauro Carvalho Chehab 		mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16);
83764441979SMauro Carvalho Chehab 		w128 = mb_width * 128;
83864441979SMauro Carvalho Chehab 		w64 = mb_width * 64;
83964441979SMauro Carvalho Chehab 
84064441979SMauro Carvalho Chehab 		/* Prioritize in case IRAM is too small for everything */
84164441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_HX4 ||
84264441979SMauro Carvalho Chehab 		    dev->devtype->product == CODA_7541) {
84364441979SMauro Carvalho Chehab 			iram_info->search_ram_size = round_up(mb_width * 16 *
84464441979SMauro Carvalho Chehab 							      36 + 2048, 1024);
84564441979SMauro Carvalho Chehab 			iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
84664441979SMauro Carvalho Chehab 						iram_info->search_ram_size);
84764441979SMauro Carvalho Chehab 			if (!iram_info->search_ram_paddr) {
84864441979SMauro Carvalho Chehab 				pr_err("IRAM is smaller than the search ram size\n");
84964441979SMauro Carvalho Chehab 				goto out;
85064441979SMauro Carvalho Chehab 			}
85164441979SMauro Carvalho Chehab 			iram_info->axi_sram_use |= me_bits;
85264441979SMauro Carvalho Chehab 		}
85364441979SMauro Carvalho Chehab 
85464441979SMauro Carvalho Chehab 		/* Only H.264BP and H.263P3 are considered */
85564441979SMauro Carvalho Chehab 		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
85664441979SMauro Carvalho Chehab 		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
8576b808223SJiasheng Jiang 		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
85864441979SMauro Carvalho Chehab 			goto out;
85964441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= dbk_bits;
86064441979SMauro Carvalho Chehab 
86164441979SMauro Carvalho Chehab 		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
86264441979SMauro Carvalho Chehab 		if (!iram_info->buf_bit_use)
86364441979SMauro Carvalho Chehab 			goto out;
86464441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= bit_bits;
86564441979SMauro Carvalho Chehab 
86664441979SMauro Carvalho Chehab 		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
86764441979SMauro Carvalho Chehab 		if (!iram_info->buf_ip_ac_dc_use)
86864441979SMauro Carvalho Chehab 			goto out;
86964441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= ip_bits;
87064441979SMauro Carvalho Chehab 
87164441979SMauro Carvalho Chehab 		/* OVL and BTP disabled for encoder */
87264441979SMauro Carvalho Chehab 	} else if (ctx->inst_type == CODA_INST_DECODER) {
87364441979SMauro Carvalho Chehab 		struct coda_q_data *q_data_dst;
87464441979SMauro Carvalho Chehab 
87564441979SMauro Carvalho Chehab 		q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
87664441979SMauro Carvalho Chehab 		mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
87764441979SMauro Carvalho Chehab 		w128 = mb_width * 128;
87864441979SMauro Carvalho Chehab 
87964441979SMauro Carvalho Chehab 		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
88064441979SMauro Carvalho Chehab 		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
8816b808223SJiasheng Jiang 		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
88264441979SMauro Carvalho Chehab 			goto out;
88364441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= dbk_bits;
88464441979SMauro Carvalho Chehab 
88564441979SMauro Carvalho Chehab 		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
88664441979SMauro Carvalho Chehab 		if (!iram_info->buf_bit_use)
88764441979SMauro Carvalho Chehab 			goto out;
88864441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= bit_bits;
88964441979SMauro Carvalho Chehab 
89064441979SMauro Carvalho Chehab 		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
89164441979SMauro Carvalho Chehab 		if (!iram_info->buf_ip_ac_dc_use)
89264441979SMauro Carvalho Chehab 			goto out;
89364441979SMauro Carvalho Chehab 		iram_info->axi_sram_use |= ip_bits;
89464441979SMauro Carvalho Chehab 
89564441979SMauro Carvalho Chehab 		/* OVL and BTP unused as there is no VC1 support yet */
89664441979SMauro Carvalho Chehab 	}
89764441979SMauro Carvalho Chehab 
89864441979SMauro Carvalho Chehab out:
89964441979SMauro Carvalho Chehab 	if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
90064441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "IRAM smaller than needed\n");
90164441979SMauro Carvalho Chehab 
90264441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_HX4 ||
90364441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_7541) {
90464441979SMauro Carvalho Chehab 		/* TODO - Enabling these causes picture errors on CODA7541 */
90564441979SMauro Carvalho Chehab 		if (ctx->inst_type == CODA_INST_DECODER) {
90664441979SMauro Carvalho Chehab 			/* fw 1.4.50 */
90764441979SMauro Carvalho Chehab 			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
90864441979SMauro Carvalho Chehab 						     CODA7_USE_IP_ENABLE);
90964441979SMauro Carvalho Chehab 		} else {
91064441979SMauro Carvalho Chehab 			/* fw 13.4.29 */
91164441979SMauro Carvalho Chehab 			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
91264441979SMauro Carvalho Chehab 						     CODA7_USE_HOST_DBK_ENABLE |
91364441979SMauro Carvalho Chehab 						     CODA7_USE_IP_ENABLE |
91464441979SMauro Carvalho Chehab 						     CODA7_USE_DBK_ENABLE);
91564441979SMauro Carvalho Chehab 		}
91664441979SMauro Carvalho Chehab 	}
91764441979SMauro Carvalho Chehab }
91864441979SMauro Carvalho Chehab 
91964441979SMauro Carvalho Chehab static u32 coda_supported_firmwares[] = {
92064441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
92164441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50),
92264441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
92364441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
92464441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9),
92564441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10),
92664441979SMauro Carvalho Chehab 	CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1),
92764441979SMauro Carvalho Chehab };
92864441979SMauro Carvalho Chehab 
coda_firmware_supported(u32 vernum)92964441979SMauro Carvalho Chehab static bool coda_firmware_supported(u32 vernum)
93064441979SMauro Carvalho Chehab {
93164441979SMauro Carvalho Chehab 	int i;
93264441979SMauro Carvalho Chehab 
93364441979SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
93464441979SMauro Carvalho Chehab 		if (vernum == coda_supported_firmwares[i])
93564441979SMauro Carvalho Chehab 			return true;
93664441979SMauro Carvalho Chehab 	return false;
93764441979SMauro Carvalho Chehab }
93864441979SMauro Carvalho Chehab 
coda_check_firmware(struct coda_dev * dev)93964441979SMauro Carvalho Chehab int coda_check_firmware(struct coda_dev *dev)
94064441979SMauro Carvalho Chehab {
94164441979SMauro Carvalho Chehab 	u16 product, major, minor, release;
94264441979SMauro Carvalho Chehab 	u32 data;
94364441979SMauro Carvalho Chehab 	int ret;
94464441979SMauro Carvalho Chehab 
94564441979SMauro Carvalho Chehab 	ret = clk_prepare_enable(dev->clk_per);
94664441979SMauro Carvalho Chehab 	if (ret)
94764441979SMauro Carvalho Chehab 		goto err_clk_per;
94864441979SMauro Carvalho Chehab 
94964441979SMauro Carvalho Chehab 	ret = clk_prepare_enable(dev->clk_ahb);
95064441979SMauro Carvalho Chehab 	if (ret)
95164441979SMauro Carvalho Chehab 		goto err_clk_ahb;
95264441979SMauro Carvalho Chehab 
95364441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
95464441979SMauro Carvalho Chehab 	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
95564441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
95664441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
95764441979SMauro Carvalho Chehab 	coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
95864441979SMauro Carvalho Chehab 	if (coda_wait_timeout(dev)) {
95964441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
96064441979SMauro Carvalho Chehab 		ret = -EIO;
96164441979SMauro Carvalho Chehab 		goto err_run_cmd;
96264441979SMauro Carvalho Chehab 	}
96364441979SMauro Carvalho Chehab 
96464441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
96564441979SMauro Carvalho Chehab 		data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
96664441979SMauro Carvalho Chehab 		v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
96764441979SMauro Carvalho Chehab 			  data);
96864441979SMauro Carvalho Chehab 	}
96964441979SMauro Carvalho Chehab 
97064441979SMauro Carvalho Chehab 	/* Check we are compatible with the loaded firmware */
97164441979SMauro Carvalho Chehab 	data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
97264441979SMauro Carvalho Chehab 	product = CODA_FIRMWARE_PRODUCT(data);
97364441979SMauro Carvalho Chehab 	major = CODA_FIRMWARE_MAJOR(data);
97464441979SMauro Carvalho Chehab 	minor = CODA_FIRMWARE_MINOR(data);
97564441979SMauro Carvalho Chehab 	release = CODA_FIRMWARE_RELEASE(data);
97664441979SMauro Carvalho Chehab 
97764441979SMauro Carvalho Chehab 	clk_disable_unprepare(dev->clk_per);
97864441979SMauro Carvalho Chehab 	clk_disable_unprepare(dev->clk_ahb);
97964441979SMauro Carvalho Chehab 
98064441979SMauro Carvalho Chehab 	if (product != dev->devtype->product) {
98164441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
98264441979SMauro Carvalho Chehab 			 "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n",
98364441979SMauro Carvalho Chehab 			 coda_product_name(dev->devtype->product),
98464441979SMauro Carvalho Chehab 			 coda_product_name(product), major, minor, release);
98564441979SMauro Carvalho Chehab 		return -EINVAL;
98664441979SMauro Carvalho Chehab 	}
98764441979SMauro Carvalho Chehab 
98864441979SMauro Carvalho Chehab 	v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
98964441979SMauro Carvalho Chehab 		  coda_product_name(product));
99064441979SMauro Carvalho Chehab 
99164441979SMauro Carvalho Chehab 	if (coda_firmware_supported(data)) {
99264441979SMauro Carvalho Chehab 		v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
99364441979SMauro Carvalho Chehab 			  major, minor, release);
99464441979SMauro Carvalho Chehab 	} else {
99564441979SMauro Carvalho Chehab 		v4l2_warn(&dev->v4l2_dev,
99664441979SMauro Carvalho Chehab 			  "Unsupported firmware version: %u.%u.%u\n",
99764441979SMauro Carvalho Chehab 			  major, minor, release);
99864441979SMauro Carvalho Chehab 	}
99964441979SMauro Carvalho Chehab 
100064441979SMauro Carvalho Chehab 	return 0;
100164441979SMauro Carvalho Chehab 
100264441979SMauro Carvalho Chehab err_run_cmd:
100364441979SMauro Carvalho Chehab 	clk_disable_unprepare(dev->clk_ahb);
100464441979SMauro Carvalho Chehab err_clk_ahb:
100564441979SMauro Carvalho Chehab 	clk_disable_unprepare(dev->clk_per);
100664441979SMauro Carvalho Chehab err_clk_per:
100764441979SMauro Carvalho Chehab 	return ret;
100864441979SMauro Carvalho Chehab }
100964441979SMauro Carvalho Chehab 
coda9_set_frame_cache(struct coda_ctx * ctx,u32 fourcc)101064441979SMauro Carvalho Chehab static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc)
101164441979SMauro Carvalho Chehab {
101264441979SMauro Carvalho Chehab 	u32 cache_size, cache_config;
101364441979SMauro Carvalho Chehab 
101464441979SMauro Carvalho Chehab 	if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) {
101564441979SMauro Carvalho Chehab 		/* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */
101664441979SMauro Carvalho Chehab 		cache_size = 0x20262024;
101764441979SMauro Carvalho Chehab 		cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET;
101864441979SMauro Carvalho Chehab 	} else {
101964441979SMauro Carvalho Chehab 		/* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */
102064441979SMauro Carvalho Chehab 		cache_size = 0x02440243;
102164441979SMauro Carvalho Chehab 		cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET;
102264441979SMauro Carvalho Chehab 	}
102364441979SMauro Carvalho Chehab 	coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE);
102464441979SMauro Carvalho Chehab 	if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) {
102564441979SMauro Carvalho Chehab 		cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
102664441979SMauro Carvalho Chehab 				16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET |
102764441979SMauro Carvalho Chehab 				0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET;
102864441979SMauro Carvalho Chehab 	} else {
102964441979SMauro Carvalho Chehab 		cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
103064441979SMauro Carvalho Chehab 				8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET |
103164441979SMauro Carvalho Chehab 				8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET;
103264441979SMauro Carvalho Chehab 	}
103364441979SMauro Carvalho Chehab 	coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG);
103464441979SMauro Carvalho Chehab }
103564441979SMauro Carvalho Chehab 
103664441979SMauro Carvalho Chehab /*
103764441979SMauro Carvalho Chehab  * Encoder context operations
103864441979SMauro Carvalho Chehab  */
103964441979SMauro Carvalho Chehab 
coda_encoder_reqbufs(struct coda_ctx * ctx,struct v4l2_requestbuffers * rb)104064441979SMauro Carvalho Chehab static int coda_encoder_reqbufs(struct coda_ctx *ctx,
104164441979SMauro Carvalho Chehab 				struct v4l2_requestbuffers *rb)
104264441979SMauro Carvalho Chehab {
104364441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src;
104464441979SMauro Carvalho Chehab 	int ret;
104564441979SMauro Carvalho Chehab 
104664441979SMauro Carvalho Chehab 	if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
104764441979SMauro Carvalho Chehab 		return 0;
104864441979SMauro Carvalho Chehab 
104964441979SMauro Carvalho Chehab 	if (rb->count) {
105064441979SMauro Carvalho Chehab 		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
105164441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buffers(ctx, q_data_src);
105264441979SMauro Carvalho Chehab 		if (ret < 0)
105364441979SMauro Carvalho Chehab 			return ret;
105464441979SMauro Carvalho Chehab 	} else {
105564441979SMauro Carvalho Chehab 		coda_free_context_buffers(ctx);
105664441979SMauro Carvalho Chehab 	}
105764441979SMauro Carvalho Chehab 
105864441979SMauro Carvalho Chehab 	return 0;
105964441979SMauro Carvalho Chehab }
106064441979SMauro Carvalho Chehab 
coda_start_encoding(struct coda_ctx * ctx)106164441979SMauro Carvalho Chehab static int coda_start_encoding(struct coda_ctx *ctx)
106264441979SMauro Carvalho Chehab {
106364441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
106464441979SMauro Carvalho Chehab 	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
106564441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src, *q_data_dst;
106664441979SMauro Carvalho Chehab 	u32 bitstream_buf, bitstream_size;
106764441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *buf;
106864441979SMauro Carvalho Chehab 	int gamma, ret, value;
106964441979SMauro Carvalho Chehab 	u32 dst_fourcc;
107064441979SMauro Carvalho Chehab 	int num_fb;
107164441979SMauro Carvalho Chehab 	u32 stride;
107264441979SMauro Carvalho Chehab 
107364441979SMauro Carvalho Chehab 	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
107464441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
107564441979SMauro Carvalho Chehab 	dst_fourcc = q_data_dst->fourcc;
107664441979SMauro Carvalho Chehab 
107764441979SMauro Carvalho Chehab 	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
107864441979SMauro Carvalho Chehab 	bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0);
107964441979SMauro Carvalho Chehab 	bitstream_size = q_data_dst->sizeimage;
108064441979SMauro Carvalho Chehab 
108164441979SMauro Carvalho Chehab 	if (!coda_is_initialized(dev)) {
108264441979SMauro Carvalho Chehab 		v4l2_err(v4l2_dev, "coda is not initialized.\n");
108364441979SMauro Carvalho Chehab 		return -EFAULT;
108464441979SMauro Carvalho Chehab 	}
108564441979SMauro Carvalho Chehab 
108664441979SMauro Carvalho Chehab 	if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
1087*6e5e5defSJiasheng Jiang 		if (!ctx->params.jpeg_qmat_tab[0]) {
108864441979SMauro Carvalho Chehab 			ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
1089*6e5e5defSJiasheng Jiang 			if (!ctx->params.jpeg_qmat_tab[0])
1090*6e5e5defSJiasheng Jiang 				return -ENOMEM;
1091*6e5e5defSJiasheng Jiang 		}
1092*6e5e5defSJiasheng Jiang 		if (!ctx->params.jpeg_qmat_tab[1]) {
109364441979SMauro Carvalho Chehab 			ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
1094*6e5e5defSJiasheng Jiang 			if (!ctx->params.jpeg_qmat_tab[1])
1095*6e5e5defSJiasheng Jiang 				return -ENOMEM;
1096*6e5e5defSJiasheng Jiang 		}
109764441979SMauro Carvalho Chehab 		coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
109864441979SMauro Carvalho Chehab 	}
109964441979SMauro Carvalho Chehab 
110064441979SMauro Carvalho Chehab 	mutex_lock(&dev->coda_mutex);
110164441979SMauro Carvalho Chehab 
110264441979SMauro Carvalho Chehab 	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
110364441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
110464441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
110564441979SMauro Carvalho Chehab 	switch (dev->devtype->product) {
110664441979SMauro Carvalho Chehab 	case CODA_DX6:
110764441979SMauro Carvalho Chehab 		coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
110864441979SMauro Carvalho Chehab 			CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
110964441979SMauro Carvalho Chehab 		break;
111064441979SMauro Carvalho Chehab 	case CODA_960:
111164441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
111264441979SMauro Carvalho Chehab 		fallthrough;
111364441979SMauro Carvalho Chehab 	case CODA_HX4:
111464441979SMauro Carvalho Chehab 	case CODA_7541:
111564441979SMauro Carvalho Chehab 		coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
111664441979SMauro Carvalho Chehab 			CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
111764441979SMauro Carvalho Chehab 		break;
111864441979SMauro Carvalho Chehab 	}
111964441979SMauro Carvalho Chehab 
112064441979SMauro Carvalho Chehab 	ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
112164441979SMauro Carvalho Chehab 				 CODA9_FRAME_TILED2LINEAR);
112264441979SMauro Carvalho Chehab 	if (q_data_src->fourcc == V4L2_PIX_FMT_NV12)
112364441979SMauro Carvalho Chehab 		ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
112464441979SMauro Carvalho Chehab 	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
112564441979SMauro Carvalho Chehab 		ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR;
112664441979SMauro Carvalho Chehab 	coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
112764441979SMauro Carvalho Chehab 
112864441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_DX6) {
112964441979SMauro Carvalho Chehab 		/* Configure the coda */
113064441979SMauro Carvalho Chehab 		coda_write(dev, dev->iram.paddr,
113164441979SMauro Carvalho Chehab 			   CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
113264441979SMauro Carvalho Chehab 	}
113364441979SMauro Carvalho Chehab 
113464441979SMauro Carvalho Chehab 	/* Could set rotation here if needed */
113564441979SMauro Carvalho Chehab 	value = 0;
113664441979SMauro Carvalho Chehab 	switch (dev->devtype->product) {
113764441979SMauro Carvalho Chehab 	case CODA_DX6:
113864441979SMauro Carvalho Chehab 		value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK)
113964441979SMauro Carvalho Chehab 			<< CODADX6_PICWIDTH_OFFSET;
114064441979SMauro Carvalho Chehab 		value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK)
114164441979SMauro Carvalho Chehab 			 << CODA_PICHEIGHT_OFFSET;
114264441979SMauro Carvalho Chehab 		break;
114364441979SMauro Carvalho Chehab 	case CODA_HX4:
114464441979SMauro Carvalho Chehab 	case CODA_7541:
114564441979SMauro Carvalho Chehab 		if (dst_fourcc == V4L2_PIX_FMT_H264) {
114664441979SMauro Carvalho Chehab 			value = (round_up(q_data_src->rect.width, 16) &
114764441979SMauro Carvalho Chehab 				 CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
114864441979SMauro Carvalho Chehab 			value |= (round_up(q_data_src->rect.height, 16) &
114964441979SMauro Carvalho Chehab 				 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
115064441979SMauro Carvalho Chehab 			break;
115164441979SMauro Carvalho Chehab 		}
115264441979SMauro Carvalho Chehab 		fallthrough;
115364441979SMauro Carvalho Chehab 	case CODA_960:
115464441979SMauro Carvalho Chehab 		value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK)
115564441979SMauro Carvalho Chehab 			<< CODA7_PICWIDTH_OFFSET;
115664441979SMauro Carvalho Chehab 		value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK)
115764441979SMauro Carvalho Chehab 			 << CODA_PICHEIGHT_OFFSET;
115864441979SMauro Carvalho Chehab 	}
115964441979SMauro Carvalho Chehab 	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
116064441979SMauro Carvalho Chehab 	if (dst_fourcc == V4L2_PIX_FMT_JPEG)
116164441979SMauro Carvalho Chehab 		ctx->params.framerate = 0;
116264441979SMauro Carvalho Chehab 	coda_write(dev, ctx->params.framerate,
116364441979SMauro Carvalho Chehab 		   CODA_CMD_ENC_SEQ_SRC_F_RATE);
116464441979SMauro Carvalho Chehab 
116564441979SMauro Carvalho Chehab 	ctx->params.codec_mode = ctx->codec->mode;
116664441979SMauro Carvalho Chehab 	switch (dst_fourcc) {
116764441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_MPEG4:
116864441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960)
116964441979SMauro Carvalho Chehab 			coda_write(dev, CODA9_STD_MPEG4,
117064441979SMauro Carvalho Chehab 				   CODA_CMD_ENC_SEQ_COD_STD);
117164441979SMauro Carvalho Chehab 		else
117264441979SMauro Carvalho Chehab 			coda_write(dev, CODA_STD_MPEG4,
117364441979SMauro Carvalho Chehab 				   CODA_CMD_ENC_SEQ_COD_STD);
117464441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
117564441979SMauro Carvalho Chehab 		break;
117664441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_H264:
117764441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960)
117864441979SMauro Carvalho Chehab 			coda_write(dev, CODA9_STD_H264,
117964441979SMauro Carvalho Chehab 				   CODA_CMD_ENC_SEQ_COD_STD);
118064441979SMauro Carvalho Chehab 		else
118164441979SMauro Carvalho Chehab 			coda_write(dev, CODA_STD_H264,
118264441979SMauro Carvalho Chehab 				   CODA_CMD_ENC_SEQ_COD_STD);
118364441979SMauro Carvalho Chehab 		value = ((ctx->params.h264_disable_deblocking_filter_idc &
118464441979SMauro Carvalho Chehab 			  CODA_264PARAM_DISABLEDEBLK_MASK) <<
118564441979SMauro Carvalho Chehab 			 CODA_264PARAM_DISABLEDEBLK_OFFSET) |
118664441979SMauro Carvalho Chehab 			((ctx->params.h264_slice_alpha_c0_offset_div2 &
118764441979SMauro Carvalho Chehab 			  CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
118864441979SMauro Carvalho Chehab 			 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
118964441979SMauro Carvalho Chehab 			((ctx->params.h264_slice_beta_offset_div2 &
119064441979SMauro Carvalho Chehab 			  CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
119164441979SMauro Carvalho Chehab 			 CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) |
119264441979SMauro Carvalho Chehab 			(ctx->params.h264_constrained_intra_pred_flag <<
119364441979SMauro Carvalho Chehab 			 CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) |
119464441979SMauro Carvalho Chehab 			(ctx->params.h264_chroma_qp_index_offset &
119564441979SMauro Carvalho Chehab 			 CODA_264PARAM_CHROMAQPOFFSET_MASK);
119664441979SMauro Carvalho Chehab 		coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
119764441979SMauro Carvalho Chehab 		break;
119864441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_JPEG:
119964441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA);
120064441979SMauro Carvalho Chehab 		coda_write(dev, ctx->params.jpeg_restart_interval,
120164441979SMauro Carvalho Chehab 				CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL);
120264441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN);
120364441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE);
120464441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET);
120564441979SMauro Carvalho Chehab 
120664441979SMauro Carvalho Chehab 		coda_jpeg_write_tables(ctx);
120764441979SMauro Carvalho Chehab 		break;
120864441979SMauro Carvalho Chehab 	default:
120964441979SMauro Carvalho Chehab 		v4l2_err(v4l2_dev,
121064441979SMauro Carvalho Chehab 			 "dst format (0x%08x) invalid.\n", dst_fourcc);
121164441979SMauro Carvalho Chehab 		ret = -EINVAL;
121264441979SMauro Carvalho Chehab 		goto out;
121364441979SMauro Carvalho Chehab 	}
121464441979SMauro Carvalho Chehab 
121564441979SMauro Carvalho Chehab 	/*
121664441979SMauro Carvalho Chehab 	 * slice mode and GOP size registers are used for thumb size/offset
121764441979SMauro Carvalho Chehab 	 * in JPEG mode
121864441979SMauro Carvalho Chehab 	 */
121964441979SMauro Carvalho Chehab 	if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
122064441979SMauro Carvalho Chehab 		value = coda_slice_mode(ctx);
122164441979SMauro Carvalho Chehab 		coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
122264441979SMauro Carvalho Chehab 		value = ctx->params.gop_size;
122364441979SMauro Carvalho Chehab 		coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
122464441979SMauro Carvalho Chehab 	}
122564441979SMauro Carvalho Chehab 
122664441979SMauro Carvalho Chehab 	if (ctx->params.bitrate && (ctx->params.frame_rc_enable ||
122764441979SMauro Carvalho Chehab 				    ctx->params.mb_rc_enable)) {
122864441979SMauro Carvalho Chehab 		ctx->params.bitrate_changed = false;
122964441979SMauro Carvalho Chehab 		ctx->params.h264_intra_qp_changed = false;
123064441979SMauro Carvalho Chehab 
123164441979SMauro Carvalho Chehab 		/* Rate control enabled */
123264441979SMauro Carvalho Chehab 		value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
123364441979SMauro Carvalho Chehab 			<< CODA_RATECONTROL_BITRATE_OFFSET;
123464441979SMauro Carvalho Chehab 		value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
123564441979SMauro Carvalho Chehab 		value |= (ctx->params.vbv_delay &
123664441979SMauro Carvalho Chehab 			  CODA_RATECONTROL_INITIALDELAY_MASK)
123764441979SMauro Carvalho Chehab 			 << CODA_RATECONTROL_INITIALDELAY_OFFSET;
123864441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960)
123964441979SMauro Carvalho Chehab 			value |= BIT(31); /* disable autoskip */
124064441979SMauro Carvalho Chehab 	} else {
124164441979SMauro Carvalho Chehab 		value = 0;
124264441979SMauro Carvalho Chehab 	}
124364441979SMauro Carvalho Chehab 	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
124464441979SMauro Carvalho Chehab 
124564441979SMauro Carvalho Chehab 	coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
124664441979SMauro Carvalho Chehab 	coda_write(dev, ctx->params.intra_refresh,
124764441979SMauro Carvalho Chehab 		   CODA_CMD_ENC_SEQ_INTRA_REFRESH);
124864441979SMauro Carvalho Chehab 
124964441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
125064441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
125164441979SMauro Carvalho Chehab 
125264441979SMauro Carvalho Chehab 
125364441979SMauro Carvalho Chehab 	value = 0;
125464441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
125564441979SMauro Carvalho Chehab 		gamma = CODA9_DEFAULT_GAMMA;
125664441979SMauro Carvalho Chehab 	else
125764441979SMauro Carvalho Chehab 		gamma = CODA_DEFAULT_GAMMA;
125864441979SMauro Carvalho Chehab 	if (gamma > 0) {
125964441979SMauro Carvalho Chehab 		coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
126064441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_SEQ_RC_GAMMA);
126164441979SMauro Carvalho Chehab 	}
126264441979SMauro Carvalho Chehab 
126364441979SMauro Carvalho Chehab 	if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
126464441979SMauro Carvalho Chehab 		coda_write(dev,
126564441979SMauro Carvalho Chehab 			   ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
126664441979SMauro Carvalho Chehab 			   ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
126764441979SMauro Carvalho Chehab 			   CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
126864441979SMauro Carvalho Chehab 	}
126964441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
127064441979SMauro Carvalho Chehab 		if (ctx->params.h264_max_qp)
127164441979SMauro Carvalho Chehab 			value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
127264441979SMauro Carvalho Chehab 		if (CODA_DEFAULT_GAMMA > 0)
127364441979SMauro Carvalho Chehab 			value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
127464441979SMauro Carvalho Chehab 	} else {
127564441979SMauro Carvalho Chehab 		if (CODA_DEFAULT_GAMMA > 0) {
127664441979SMauro Carvalho Chehab 			if (dev->devtype->product == CODA_DX6)
127764441979SMauro Carvalho Chehab 				value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
127864441979SMauro Carvalho Chehab 			else
127964441979SMauro Carvalho Chehab 				value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
128064441979SMauro Carvalho Chehab 		}
128164441979SMauro Carvalho Chehab 		if (ctx->params.h264_min_qp)
128264441979SMauro Carvalho Chehab 			value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
128364441979SMauro Carvalho Chehab 		if (ctx->params.h264_max_qp)
128464441979SMauro Carvalho Chehab 			value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
128564441979SMauro Carvalho Chehab 	}
128664441979SMauro Carvalho Chehab 	coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
128764441979SMauro Carvalho Chehab 
128864441979SMauro Carvalho Chehab 	if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable)
128964441979SMauro Carvalho Chehab 		value = 1;
129064441979SMauro Carvalho Chehab 	else
129164441979SMauro Carvalho Chehab 		value = 0;
129264441979SMauro Carvalho Chehab 	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
129364441979SMauro Carvalho Chehab 
129464441979SMauro Carvalho Chehab 	coda_setup_iram(ctx);
129564441979SMauro Carvalho Chehab 
129664441979SMauro Carvalho Chehab 	if (dst_fourcc == V4L2_PIX_FMT_H264) {
129764441979SMauro Carvalho Chehab 		switch (dev->devtype->product) {
129864441979SMauro Carvalho Chehab 		case CODA_DX6:
129964441979SMauro Carvalho Chehab 			value = FMO_SLICE_SAVE_BUF_SIZE << 7;
130064441979SMauro Carvalho Chehab 			coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
130164441979SMauro Carvalho Chehab 			break;
130264441979SMauro Carvalho Chehab 		case CODA_HX4:
130364441979SMauro Carvalho Chehab 		case CODA_7541:
130464441979SMauro Carvalho Chehab 			coda_write(dev, ctx->iram_info.search_ram_paddr,
130564441979SMauro Carvalho Chehab 					CODA7_CMD_ENC_SEQ_SEARCH_BASE);
130664441979SMauro Carvalho Chehab 			coda_write(dev, ctx->iram_info.search_ram_size,
130764441979SMauro Carvalho Chehab 					CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
130864441979SMauro Carvalho Chehab 			break;
130964441979SMauro Carvalho Chehab 		case CODA_960:
131064441979SMauro Carvalho Chehab 			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
131164441979SMauro Carvalho Chehab 			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
131264441979SMauro Carvalho Chehab 		}
131364441979SMauro Carvalho Chehab 	}
131464441979SMauro Carvalho Chehab 
131564441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
131664441979SMauro Carvalho Chehab 	if (ret < 0) {
131764441979SMauro Carvalho Chehab 		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
131864441979SMauro Carvalho Chehab 		goto out;
131964441979SMauro Carvalho Chehab 	}
132064441979SMauro Carvalho Chehab 
132164441979SMauro Carvalho Chehab 	if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
132264441979SMauro Carvalho Chehab 		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
132364441979SMauro Carvalho Chehab 		ret = -EFAULT;
132464441979SMauro Carvalho Chehab 		goto out;
132564441979SMauro Carvalho Chehab 	}
132664441979SMauro Carvalho Chehab 	ctx->initialized = 1;
132764441979SMauro Carvalho Chehab 
132864441979SMauro Carvalho Chehab 	if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
132964441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960)
133064441979SMauro Carvalho Chehab 			ctx->num_internal_frames = 4;
133164441979SMauro Carvalho Chehab 		else
133264441979SMauro Carvalho Chehab 			ctx->num_internal_frames = 2;
133364441979SMauro Carvalho Chehab 		ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
133464441979SMauro Carvalho Chehab 		if (ret < 0) {
133564441979SMauro Carvalho Chehab 			v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
133664441979SMauro Carvalho Chehab 			goto out;
133764441979SMauro Carvalho Chehab 		}
133864441979SMauro Carvalho Chehab 		num_fb = 2;
133964441979SMauro Carvalho Chehab 		stride = q_data_src->bytesperline;
134064441979SMauro Carvalho Chehab 	} else {
134164441979SMauro Carvalho Chehab 		ctx->num_internal_frames = 0;
134264441979SMauro Carvalho Chehab 		num_fb = 0;
134364441979SMauro Carvalho Chehab 		stride = 0;
134464441979SMauro Carvalho Chehab 	}
134564441979SMauro Carvalho Chehab 	coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM);
134664441979SMauro Carvalho Chehab 	coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
134764441979SMauro Carvalho Chehab 
134864441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_HX4 ||
134964441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_7541) {
135064441979SMauro Carvalho Chehab 		coda_write(dev, q_data_src->bytesperline,
135164441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
135264441979SMauro Carvalho Chehab 	}
135364441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6) {
135464441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_bit_use,
135564441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
135664441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
135764441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
135864441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
135964441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
136064441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
136164441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
136264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_ovl_use,
136364441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
136464441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960) {
136564441979SMauro Carvalho Chehab 			coda_write(dev, ctx->iram_info.buf_btp_use,
136664441979SMauro Carvalho Chehab 					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
136764441979SMauro Carvalho Chehab 
136864441979SMauro Carvalho Chehab 			coda9_set_frame_cache(ctx, q_data_src->fourcc);
136964441979SMauro Carvalho Chehab 
137064441979SMauro Carvalho Chehab 			/* FIXME */
137164441979SMauro Carvalho Chehab 			coda_write(dev, ctx->internal_frames[2].buf.paddr,
137264441979SMauro Carvalho Chehab 				   CODA9_CMD_SET_FRAME_SUBSAMP_A);
137364441979SMauro Carvalho Chehab 			coda_write(dev, ctx->internal_frames[3].buf.paddr,
137464441979SMauro Carvalho Chehab 				   CODA9_CMD_SET_FRAME_SUBSAMP_B);
137564441979SMauro Carvalho Chehab 		}
137664441979SMauro Carvalho Chehab 	}
137764441979SMauro Carvalho Chehab 
137864441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
137964441979SMauro Carvalho Chehab 	if (ret < 0) {
138064441979SMauro Carvalho Chehab 		v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
138164441979SMauro Carvalho Chehab 		goto out;
138264441979SMauro Carvalho Chehab 	}
138364441979SMauro Carvalho Chehab 
138464441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n",
138564441979SMauro Carvalho Chehab 		 q_data_src->rect.width, q_data_src->rect.height,
138664441979SMauro Carvalho Chehab 		 (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc,
138764441979SMauro Carvalho Chehab 		 ctx->params.framerate & 0xffff,
138864441979SMauro Carvalho Chehab 		 (ctx->params.framerate >> 16) + 1);
138964441979SMauro Carvalho Chehab 
139064441979SMauro Carvalho Chehab 	/* Save stream headers */
139164441979SMauro Carvalho Chehab 	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
139264441979SMauro Carvalho Chehab 	switch (dst_fourcc) {
139364441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_H264:
139464441979SMauro Carvalho Chehab 		/*
139564441979SMauro Carvalho Chehab 		 * Get SPS in the first frame and copy it to an
139664441979SMauro Carvalho Chehab 		 * intermediate buffer.
139764441979SMauro Carvalho Chehab 		 */
139864441979SMauro Carvalho Chehab 		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
139964441979SMauro Carvalho Chehab 					 &ctx->vpu_header[0][0],
140064441979SMauro Carvalho Chehab 					 &ctx->vpu_header_size[0]);
140164441979SMauro Carvalho Chehab 		if (ret < 0)
140264441979SMauro Carvalho Chehab 			goto out;
140364441979SMauro Carvalho Chehab 
140464441979SMauro Carvalho Chehab 		/*
140564441979SMauro Carvalho Chehab 		 * If visible width or height are not aligned to macroblock
140664441979SMauro Carvalho Chehab 		 * size, the crop_right and crop_bottom SPS fields must be set
140764441979SMauro Carvalho Chehab 		 * to the difference between visible and coded size.  This is
140864441979SMauro Carvalho Chehab 		 * only supported by CODA960 firmware. All others do not allow
140964441979SMauro Carvalho Chehab 		 * writing frame cropping parameters, so we have to manually
141064441979SMauro Carvalho Chehab 		 * fix up the SPS RBSP (Sequence Parameter Set Raw Byte
141164441979SMauro Carvalho Chehab 		 * Sequence Payload) ourselves.
141264441979SMauro Carvalho Chehab 		 */
141364441979SMauro Carvalho Chehab 		if (ctx->dev->devtype->product != CODA_960 &&
141464441979SMauro Carvalho Chehab 		    ((q_data_src->rect.width % 16) ||
141564441979SMauro Carvalho Chehab 		     (q_data_src->rect.height % 16))) {
141664441979SMauro Carvalho Chehab 			ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width,
141764441979SMauro Carvalho Chehab 						  q_data_src->rect.height,
141864441979SMauro Carvalho Chehab 						  &ctx->vpu_header[0][0],
141964441979SMauro Carvalho Chehab 						  &ctx->vpu_header_size[0],
142064441979SMauro Carvalho Chehab 						  sizeof(ctx->vpu_header[0]));
142164441979SMauro Carvalho Chehab 			if (ret < 0)
142264441979SMauro Carvalho Chehab 				goto out;
142364441979SMauro Carvalho Chehab 		}
142464441979SMauro Carvalho Chehab 
142564441979SMauro Carvalho Chehab 		/*
142664441979SMauro Carvalho Chehab 		 * Get PPS in the first frame and copy it to an
142764441979SMauro Carvalho Chehab 		 * intermediate buffer.
142864441979SMauro Carvalho Chehab 		 */
142964441979SMauro Carvalho Chehab 		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
143064441979SMauro Carvalho Chehab 					 &ctx->vpu_header[1][0],
143164441979SMauro Carvalho Chehab 					 &ctx->vpu_header_size[1]);
143264441979SMauro Carvalho Chehab 		if (ret < 0)
143364441979SMauro Carvalho Chehab 			goto out;
143464441979SMauro Carvalho Chehab 
143564441979SMauro Carvalho Chehab 		/*
143664441979SMauro Carvalho Chehab 		 * Length of H.264 headers is variable and thus it might not be
143764441979SMauro Carvalho Chehab 		 * aligned for the coda to append the encoded frame. In that is
143864441979SMauro Carvalho Chehab 		 * the case a filler NAL must be added to header 2.
143964441979SMauro Carvalho Chehab 		 */
144064441979SMauro Carvalho Chehab 		ctx->vpu_header_size[2] = coda_h264_padding(
144164441979SMauro Carvalho Chehab 					(ctx->vpu_header_size[0] +
144264441979SMauro Carvalho Chehab 					 ctx->vpu_header_size[1]),
144364441979SMauro Carvalho Chehab 					 ctx->vpu_header[2]);
144464441979SMauro Carvalho Chehab 		break;
144564441979SMauro Carvalho Chehab 	case V4L2_PIX_FMT_MPEG4:
144664441979SMauro Carvalho Chehab 		/*
144764441979SMauro Carvalho Chehab 		 * Get VOS in the first frame and copy it to an
144864441979SMauro Carvalho Chehab 		 * intermediate buffer
144964441979SMauro Carvalho Chehab 		 */
145064441979SMauro Carvalho Chehab 		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
145164441979SMauro Carvalho Chehab 					 &ctx->vpu_header[0][0],
145264441979SMauro Carvalho Chehab 					 &ctx->vpu_header_size[0]);
145364441979SMauro Carvalho Chehab 		if (ret < 0)
145464441979SMauro Carvalho Chehab 			goto out;
145564441979SMauro Carvalho Chehab 
145664441979SMauro Carvalho Chehab 		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
145764441979SMauro Carvalho Chehab 					 &ctx->vpu_header[1][0],
145864441979SMauro Carvalho Chehab 					 &ctx->vpu_header_size[1]);
145964441979SMauro Carvalho Chehab 		if (ret < 0)
146064441979SMauro Carvalho Chehab 			goto out;
146164441979SMauro Carvalho Chehab 
146264441979SMauro Carvalho Chehab 		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
146364441979SMauro Carvalho Chehab 					 &ctx->vpu_header[2][0],
146464441979SMauro Carvalho Chehab 					 &ctx->vpu_header_size[2]);
146564441979SMauro Carvalho Chehab 		if (ret < 0)
146664441979SMauro Carvalho Chehab 			goto out;
146764441979SMauro Carvalho Chehab 		break;
146864441979SMauro Carvalho Chehab 	default:
146964441979SMauro Carvalho Chehab 		/* No more formats need to save headers at the moment */
147064441979SMauro Carvalho Chehab 		break;
147164441979SMauro Carvalho Chehab 	}
147264441979SMauro Carvalho Chehab 
147364441979SMauro Carvalho Chehab out:
147464441979SMauro Carvalho Chehab 	mutex_unlock(&dev->coda_mutex);
147564441979SMauro Carvalho Chehab 	return ret;
147664441979SMauro Carvalho Chehab }
147764441979SMauro Carvalho Chehab 
coda_prepare_encode(struct coda_ctx * ctx)147864441979SMauro Carvalho Chehab static int coda_prepare_encode(struct coda_ctx *ctx)
147964441979SMauro Carvalho Chehab {
148064441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src, *q_data_dst;
148164441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
148264441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
148364441979SMauro Carvalho Chehab 	int force_ipicture;
148464441979SMauro Carvalho Chehab 	int quant_param = 0;
148564441979SMauro Carvalho Chehab 	u32 pic_stream_buffer_addr, pic_stream_buffer_size;
148664441979SMauro Carvalho Chehab 	u32 rot_mode = 0;
148764441979SMauro Carvalho Chehab 	u32 dst_fourcc;
148864441979SMauro Carvalho Chehab 	u32 reg;
148964441979SMauro Carvalho Chehab 	int ret;
149064441979SMauro Carvalho Chehab 
149164441979SMauro Carvalho Chehab 	ret = coda_enc_param_change(ctx);
149264441979SMauro Carvalho Chehab 	if (ret < 0) {
149364441979SMauro Carvalho Chehab 		v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n",
149464441979SMauro Carvalho Chehab 			  ret);
149564441979SMauro Carvalho Chehab 	}
149664441979SMauro Carvalho Chehab 
149764441979SMauro Carvalho Chehab 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
149864441979SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
149964441979SMauro Carvalho Chehab 	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
150064441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
150164441979SMauro Carvalho Chehab 	dst_fourcc = q_data_dst->fourcc;
150264441979SMauro Carvalho Chehab 
150364441979SMauro Carvalho Chehab 	src_buf->sequence = ctx->osequence;
150464441979SMauro Carvalho Chehab 	dst_buf->sequence = ctx->osequence;
150564441979SMauro Carvalho Chehab 	ctx->osequence++;
150664441979SMauro Carvalho Chehab 
150764441979SMauro Carvalho Chehab 	force_ipicture = ctx->params.force_ipicture;
150864441979SMauro Carvalho Chehab 	if (force_ipicture)
150964441979SMauro Carvalho Chehab 		ctx->params.force_ipicture = false;
151064441979SMauro Carvalho Chehab 	else if (ctx->params.gop_size != 0 &&
151164441979SMauro Carvalho Chehab 		 (src_buf->sequence % ctx->params.gop_size) == 0)
151264441979SMauro Carvalho Chehab 		force_ipicture = 1;
151364441979SMauro Carvalho Chehab 
151464441979SMauro Carvalho Chehab 	/*
151564441979SMauro Carvalho Chehab 	 * Workaround coda firmware BUG that only marks the first
151664441979SMauro Carvalho Chehab 	 * frame as IDR. This is a problem for some decoders that can't
151764441979SMauro Carvalho Chehab 	 * recover when a frame is lost.
151864441979SMauro Carvalho Chehab 	 */
151964441979SMauro Carvalho Chehab 	if (!force_ipicture) {
152064441979SMauro Carvalho Chehab 		src_buf->flags |= V4L2_BUF_FLAG_PFRAME;
152164441979SMauro Carvalho Chehab 		src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
152264441979SMauro Carvalho Chehab 	} else {
152364441979SMauro Carvalho Chehab 		src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
152464441979SMauro Carvalho Chehab 		src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME;
152564441979SMauro Carvalho Chehab 	}
152664441979SMauro Carvalho Chehab 
152764441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
152864441979SMauro Carvalho Chehab 		coda_set_gdi_regs(ctx);
152964441979SMauro Carvalho Chehab 
153064441979SMauro Carvalho Chehab 	/*
153164441979SMauro Carvalho Chehab 	 * Copy headers in front of the first frame and forced I frames for
153264441979SMauro Carvalho Chehab 	 * H.264 only. In MPEG4 they are already copied by the CODA.
153364441979SMauro Carvalho Chehab 	 */
153464441979SMauro Carvalho Chehab 	if (src_buf->sequence == 0 || force_ipicture) {
153564441979SMauro Carvalho Chehab 		pic_stream_buffer_addr =
153664441979SMauro Carvalho Chehab 			vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) +
153764441979SMauro Carvalho Chehab 			ctx->vpu_header_size[0] +
153864441979SMauro Carvalho Chehab 			ctx->vpu_header_size[1] +
153964441979SMauro Carvalho Chehab 			ctx->vpu_header_size[2];
154064441979SMauro Carvalho Chehab 		pic_stream_buffer_size = q_data_dst->sizeimage -
154164441979SMauro Carvalho Chehab 			ctx->vpu_header_size[0] -
154264441979SMauro Carvalho Chehab 			ctx->vpu_header_size[1] -
154364441979SMauro Carvalho Chehab 			ctx->vpu_header_size[2];
154464441979SMauro Carvalho Chehab 		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0),
154564441979SMauro Carvalho Chehab 		       &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
154664441979SMauro Carvalho Chehab 		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0)
154764441979SMauro Carvalho Chehab 			+ ctx->vpu_header_size[0], &ctx->vpu_header[1][0],
154864441979SMauro Carvalho Chehab 			ctx->vpu_header_size[1]);
154964441979SMauro Carvalho Chehab 		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0)
155064441979SMauro Carvalho Chehab 			+ ctx->vpu_header_size[0] + ctx->vpu_header_size[1],
155164441979SMauro Carvalho Chehab 			&ctx->vpu_header[2][0], ctx->vpu_header_size[2]);
155264441979SMauro Carvalho Chehab 	} else {
155364441979SMauro Carvalho Chehab 		pic_stream_buffer_addr =
155464441979SMauro Carvalho Chehab 			vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
155564441979SMauro Carvalho Chehab 		pic_stream_buffer_size = q_data_dst->sizeimage;
155664441979SMauro Carvalho Chehab 	}
155764441979SMauro Carvalho Chehab 
155864441979SMauro Carvalho Chehab 	if (force_ipicture) {
155964441979SMauro Carvalho Chehab 		switch (dst_fourcc) {
156064441979SMauro Carvalho Chehab 		case V4L2_PIX_FMT_H264:
156164441979SMauro Carvalho Chehab 			quant_param = ctx->params.h264_intra_qp;
156264441979SMauro Carvalho Chehab 			break;
156364441979SMauro Carvalho Chehab 		case V4L2_PIX_FMT_MPEG4:
156464441979SMauro Carvalho Chehab 			quant_param = ctx->params.mpeg4_intra_qp;
156564441979SMauro Carvalho Chehab 			break;
156664441979SMauro Carvalho Chehab 		case V4L2_PIX_FMT_JPEG:
156764441979SMauro Carvalho Chehab 			quant_param = 30;
156864441979SMauro Carvalho Chehab 			break;
156964441979SMauro Carvalho Chehab 		default:
157064441979SMauro Carvalho Chehab 			v4l2_warn(&ctx->dev->v4l2_dev,
157164441979SMauro Carvalho Chehab 				"cannot set intra qp, fmt not supported\n");
157264441979SMauro Carvalho Chehab 			break;
157364441979SMauro Carvalho Chehab 		}
157464441979SMauro Carvalho Chehab 	} else {
157564441979SMauro Carvalho Chehab 		switch (dst_fourcc) {
157664441979SMauro Carvalho Chehab 		case V4L2_PIX_FMT_H264:
157764441979SMauro Carvalho Chehab 			quant_param = ctx->params.h264_inter_qp;
157864441979SMauro Carvalho Chehab 			break;
157964441979SMauro Carvalho Chehab 		case V4L2_PIX_FMT_MPEG4:
158064441979SMauro Carvalho Chehab 			quant_param = ctx->params.mpeg4_inter_qp;
158164441979SMauro Carvalho Chehab 			break;
158264441979SMauro Carvalho Chehab 		default:
158364441979SMauro Carvalho Chehab 			v4l2_warn(&ctx->dev->v4l2_dev,
158464441979SMauro Carvalho Chehab 				"cannot set inter qp, fmt not supported\n");
158564441979SMauro Carvalho Chehab 			break;
158664441979SMauro Carvalho Chehab 		}
158764441979SMauro Carvalho Chehab 	}
158864441979SMauro Carvalho Chehab 
158964441979SMauro Carvalho Chehab 	/* submit */
159064441979SMauro Carvalho Chehab 	if (ctx->params.rot_mode)
159164441979SMauro Carvalho Chehab 		rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
159264441979SMauro Carvalho Chehab 	coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
159364441979SMauro Carvalho Chehab 	coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
159464441979SMauro Carvalho Chehab 
159564441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960) {
159664441979SMauro Carvalho Chehab 		coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
159764441979SMauro Carvalho Chehab 		coda_write(dev, q_data_src->bytesperline,
159864441979SMauro Carvalho Chehab 			   CODA9_CMD_ENC_PIC_SRC_STRIDE);
159964441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
160064441979SMauro Carvalho Chehab 
160164441979SMauro Carvalho Chehab 		reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y;
160264441979SMauro Carvalho Chehab 	} else {
160364441979SMauro Carvalho Chehab 		reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y;
160464441979SMauro Carvalho Chehab 	}
160564441979SMauro Carvalho Chehab 	coda_write_base(ctx, q_data_src, src_buf, reg);
160664441979SMauro Carvalho Chehab 
160764441979SMauro Carvalho Chehab 	coda_write(dev, force_ipicture << 1 & 0x2,
160864441979SMauro Carvalho Chehab 		   CODA_CMD_ENC_PIC_OPTION);
160964441979SMauro Carvalho Chehab 
161064441979SMauro Carvalho Chehab 	coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
161164441979SMauro Carvalho Chehab 	coda_write(dev, pic_stream_buffer_size / 1024,
161264441979SMauro Carvalho Chehab 		   CODA_CMD_ENC_PIC_BB_SIZE);
161364441979SMauro Carvalho Chehab 
161464441979SMauro Carvalho Chehab 	if (!ctx->streamon_out) {
161564441979SMauro Carvalho Chehab 		/* After streamoff on the output side, set stream end flag */
161664441979SMauro Carvalho Chehab 		ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
161764441979SMauro Carvalho Chehab 		coda_write(dev, ctx->bit_stream_param,
161864441979SMauro Carvalho Chehab 			   CODA_REG_BIT_BIT_STREAM_PARAM);
161964441979SMauro Carvalho Chehab 	}
162064441979SMauro Carvalho Chehab 
162164441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6)
162264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.axi_sram_use,
162364441979SMauro Carvalho Chehab 				CODA7_REG_BIT_AXI_SRAM_USE);
162464441979SMauro Carvalho Chehab 
162564441979SMauro Carvalho Chehab 	trace_coda_enc_pic_run(ctx, src_buf);
162664441979SMauro Carvalho Chehab 
162764441979SMauro Carvalho Chehab 	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
162864441979SMauro Carvalho Chehab 
162964441979SMauro Carvalho Chehab 	return 0;
163064441979SMauro Carvalho Chehab }
163164441979SMauro Carvalho Chehab 
coda_frame_type_char(u32 flags)163264441979SMauro Carvalho Chehab static char coda_frame_type_char(u32 flags)
163364441979SMauro Carvalho Chehab {
163464441979SMauro Carvalho Chehab 	return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
163564441979SMauro Carvalho Chehab 	       (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' :
163664441979SMauro Carvalho Chehab 	       (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?';
163764441979SMauro Carvalho Chehab }
163864441979SMauro Carvalho Chehab 
coda_finish_encode(struct coda_ctx * ctx)163964441979SMauro Carvalho Chehab static void coda_finish_encode(struct coda_ctx *ctx)
164064441979SMauro Carvalho Chehab {
164164441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
164264441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
164364441979SMauro Carvalho Chehab 	u32 wr_ptr, start_ptr;
164464441979SMauro Carvalho Chehab 
164564441979SMauro Carvalho Chehab 	if (ctx->aborting)
164664441979SMauro Carvalho Chehab 		return;
164764441979SMauro Carvalho Chehab 
164864441979SMauro Carvalho Chehab 	/*
164964441979SMauro Carvalho Chehab 	 * Lock to make sure that an encoder stop command running in parallel
165064441979SMauro Carvalho Chehab 	 * will either already have marked src_buf as last, or it will wake up
165164441979SMauro Carvalho Chehab 	 * the capture queue after the buffers are returned.
165264441979SMauro Carvalho Chehab 	 */
165364441979SMauro Carvalho Chehab 	mutex_lock(&ctx->wakeup_mutex);
165464441979SMauro Carvalho Chehab 	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
165564441979SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
165664441979SMauro Carvalho Chehab 
165764441979SMauro Carvalho Chehab 	trace_coda_enc_pic_done(ctx, dst_buf);
165864441979SMauro Carvalho Chehab 
165964441979SMauro Carvalho Chehab 	/* Get results from the coda */
166064441979SMauro Carvalho Chehab 	start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
166164441979SMauro Carvalho Chehab 	wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
166264441979SMauro Carvalho Chehab 
166364441979SMauro Carvalho Chehab 	/* Calculate bytesused field */
166464441979SMauro Carvalho Chehab 	if (dst_buf->sequence == 0 ||
166564441979SMauro Carvalho Chehab 	    src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) {
166664441979SMauro Carvalho Chehab 		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
166764441979SMauro Carvalho Chehab 					ctx->vpu_header_size[0] +
166864441979SMauro Carvalho Chehab 					ctx->vpu_header_size[1] +
166964441979SMauro Carvalho Chehab 					ctx->vpu_header_size[2]);
167064441979SMauro Carvalho Chehab 	} else {
167164441979SMauro Carvalho Chehab 		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr);
167264441979SMauro Carvalho Chehab 	}
167364441979SMauro Carvalho Chehab 
167464441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr);
167564441979SMauro Carvalho Chehab 
167664441979SMauro Carvalho Chehab 	coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
167764441979SMauro Carvalho Chehab 	coda_read(dev, CODA_RET_ENC_PIC_FLAG);
167864441979SMauro Carvalho Chehab 
167964441979SMauro Carvalho Chehab 	dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
168064441979SMauro Carvalho Chehab 			    V4L2_BUF_FLAG_PFRAME |
168164441979SMauro Carvalho Chehab 			    V4L2_BUF_FLAG_LAST);
168264441979SMauro Carvalho Chehab 	if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0)
168364441979SMauro Carvalho Chehab 		dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
168464441979SMauro Carvalho Chehab 	else
168564441979SMauro Carvalho Chehab 		dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
168664441979SMauro Carvalho Chehab 	dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST;
168764441979SMauro Carvalho Chehab 
168864441979SMauro Carvalho Chehab 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
168964441979SMauro Carvalho Chehab 
169064441979SMauro Carvalho Chehab 	v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
169164441979SMauro Carvalho Chehab 
169264441979SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
169364441979SMauro Carvalho Chehab 	coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
169464441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->wakeup_mutex);
169564441979SMauro Carvalho Chehab 
169664441979SMauro Carvalho Chehab 	ctx->gopcounter--;
169764441979SMauro Carvalho Chehab 	if (ctx->gopcounter < 0)
169864441979SMauro Carvalho Chehab 		ctx->gopcounter = ctx->params.gop_size - 1;
169964441979SMauro Carvalho Chehab 
170064441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n",
170164441979SMauro Carvalho Chehab 		 coda_frame_type_char(dst_buf->flags), dst_buf->sequence,
170264441979SMauro Carvalho Chehab 		 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : "");
170364441979SMauro Carvalho Chehab }
170464441979SMauro Carvalho Chehab 
coda_seq_end_work(struct work_struct * work)170564441979SMauro Carvalho Chehab static void coda_seq_end_work(struct work_struct *work)
170664441979SMauro Carvalho Chehab {
170764441979SMauro Carvalho Chehab 	struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
170864441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
170964441979SMauro Carvalho Chehab 
171064441979SMauro Carvalho Chehab 	mutex_lock(&ctx->buffer_mutex);
171164441979SMauro Carvalho Chehab 	mutex_lock(&dev->coda_mutex);
171264441979SMauro Carvalho Chehab 
171364441979SMauro Carvalho Chehab 	if (ctx->initialized == 0)
171464441979SMauro Carvalho Chehab 		goto out;
171564441979SMauro Carvalho Chehab 
171664441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__);
171764441979SMauro Carvalho Chehab 	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
171864441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
171964441979SMauro Carvalho Chehab 			 "CODA_COMMAND_SEQ_END failed\n");
172064441979SMauro Carvalho Chehab 	}
172164441979SMauro Carvalho Chehab 
172264441979SMauro Carvalho Chehab 	/*
172364441979SMauro Carvalho Chehab 	 * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing
172464441979SMauro Carvalho Chehab 	 * from the output stream after the h.264 decoder has run. Resetting the
172564441979SMauro Carvalho Chehab 	 * hardware after the decoder has finished seems to help.
172664441979SMauro Carvalho Chehab 	 */
172764441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
172864441979SMauro Carvalho Chehab 		coda_hw_reset(ctx);
172964441979SMauro Carvalho Chehab 
173064441979SMauro Carvalho Chehab 	kfifo_init(&ctx->bitstream_fifo,
173164441979SMauro Carvalho Chehab 		ctx->bitstream.vaddr, ctx->bitstream.size);
173264441979SMauro Carvalho Chehab 
173364441979SMauro Carvalho Chehab 	coda_free_framebuffers(ctx);
173464441979SMauro Carvalho Chehab 
173564441979SMauro Carvalho Chehab 	ctx->initialized = 0;
173664441979SMauro Carvalho Chehab 
173764441979SMauro Carvalho Chehab out:
173864441979SMauro Carvalho Chehab 	mutex_unlock(&dev->coda_mutex);
173964441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->buffer_mutex);
174064441979SMauro Carvalho Chehab }
174164441979SMauro Carvalho Chehab 
coda_bit_release(struct coda_ctx * ctx)174264441979SMauro Carvalho Chehab static void coda_bit_release(struct coda_ctx *ctx)
174364441979SMauro Carvalho Chehab {
174464441979SMauro Carvalho Chehab 	mutex_lock(&ctx->buffer_mutex);
174564441979SMauro Carvalho Chehab 	coda_free_framebuffers(ctx);
174664441979SMauro Carvalho Chehab 	coda_free_context_buffers(ctx);
174764441979SMauro Carvalho Chehab 	coda_free_bitstream_buffer(ctx);
174864441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->buffer_mutex);
174964441979SMauro Carvalho Chehab }
175064441979SMauro Carvalho Chehab 
175164441979SMauro Carvalho Chehab const struct coda_context_ops coda_bit_encode_ops = {
175264441979SMauro Carvalho Chehab 	.queue_init = coda_encoder_queue_init,
175364441979SMauro Carvalho Chehab 	.reqbufs = coda_encoder_reqbufs,
175464441979SMauro Carvalho Chehab 	.start_streaming = coda_start_encoding,
175564441979SMauro Carvalho Chehab 	.prepare_run = coda_prepare_encode,
175664441979SMauro Carvalho Chehab 	.finish_run = coda_finish_encode,
175764441979SMauro Carvalho Chehab 	.seq_end_work = coda_seq_end_work,
175864441979SMauro Carvalho Chehab 	.release = coda_bit_release,
175964441979SMauro Carvalho Chehab };
176064441979SMauro Carvalho Chehab 
176164441979SMauro Carvalho Chehab /*
176264441979SMauro Carvalho Chehab  * Decoder context operations
176364441979SMauro Carvalho Chehab  */
176464441979SMauro Carvalho Chehab 
coda_alloc_bitstream_buffer(struct coda_ctx * ctx,struct coda_q_data * q_data)176564441979SMauro Carvalho Chehab static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
176664441979SMauro Carvalho Chehab 				       struct coda_q_data *q_data)
176764441979SMauro Carvalho Chehab {
176864441979SMauro Carvalho Chehab 	if (ctx->bitstream.vaddr)
176964441979SMauro Carvalho Chehab 		return 0;
177064441979SMauro Carvalho Chehab 
177164441979SMauro Carvalho Chehab 	ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
177264441979SMauro Carvalho Chehab 	ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size,
177364441979SMauro Carvalho Chehab 					    &ctx->bitstream.paddr, GFP_KERNEL);
177464441979SMauro Carvalho Chehab 	if (!ctx->bitstream.vaddr) {
177564441979SMauro Carvalho Chehab 		v4l2_err(&ctx->dev->v4l2_dev,
177664441979SMauro Carvalho Chehab 			 "failed to allocate bitstream ringbuffer");
177764441979SMauro Carvalho Chehab 		return -ENOMEM;
177864441979SMauro Carvalho Chehab 	}
177964441979SMauro Carvalho Chehab 	kfifo_init(&ctx->bitstream_fifo,
178064441979SMauro Carvalho Chehab 		   ctx->bitstream.vaddr, ctx->bitstream.size);
178164441979SMauro Carvalho Chehab 
178264441979SMauro Carvalho Chehab 	return 0;
178364441979SMauro Carvalho Chehab }
178464441979SMauro Carvalho Chehab 
coda_free_bitstream_buffer(struct coda_ctx * ctx)178564441979SMauro Carvalho Chehab static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
178664441979SMauro Carvalho Chehab {
178764441979SMauro Carvalho Chehab 	if (ctx->bitstream.vaddr == NULL)
178864441979SMauro Carvalho Chehab 		return;
178964441979SMauro Carvalho Chehab 
179064441979SMauro Carvalho Chehab 	dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr,
179164441979SMauro Carvalho Chehab 		    ctx->bitstream.paddr);
179264441979SMauro Carvalho Chehab 	ctx->bitstream.vaddr = NULL;
179364441979SMauro Carvalho Chehab 	kfifo_init(&ctx->bitstream_fifo, NULL, 0);
179464441979SMauro Carvalho Chehab }
179564441979SMauro Carvalho Chehab 
coda_decoder_reqbufs(struct coda_ctx * ctx,struct v4l2_requestbuffers * rb)179664441979SMauro Carvalho Chehab static int coda_decoder_reqbufs(struct coda_ctx *ctx,
179764441979SMauro Carvalho Chehab 				struct v4l2_requestbuffers *rb)
179864441979SMauro Carvalho Chehab {
179964441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src;
180064441979SMauro Carvalho Chehab 	int ret;
180164441979SMauro Carvalho Chehab 
180264441979SMauro Carvalho Chehab 	if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
180364441979SMauro Carvalho Chehab 		return 0;
180464441979SMauro Carvalho Chehab 
180564441979SMauro Carvalho Chehab 	if (rb->count) {
180664441979SMauro Carvalho Chehab 		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
180764441979SMauro Carvalho Chehab 		ret = coda_alloc_context_buffers(ctx, q_data_src);
180864441979SMauro Carvalho Chehab 		if (ret < 0)
180964441979SMauro Carvalho Chehab 			return ret;
181064441979SMauro Carvalho Chehab 		ret = coda_alloc_bitstream_buffer(ctx, q_data_src);
181164441979SMauro Carvalho Chehab 		if (ret < 0) {
181264441979SMauro Carvalho Chehab 			coda_free_context_buffers(ctx);
181364441979SMauro Carvalho Chehab 			return ret;
181464441979SMauro Carvalho Chehab 		}
181564441979SMauro Carvalho Chehab 	} else {
181664441979SMauro Carvalho Chehab 		coda_free_bitstream_buffer(ctx);
181764441979SMauro Carvalho Chehab 		coda_free_context_buffers(ctx);
181864441979SMauro Carvalho Chehab 	}
181964441979SMauro Carvalho Chehab 
182064441979SMauro Carvalho Chehab 	return 0;
182164441979SMauro Carvalho Chehab }
182264441979SMauro Carvalho Chehab 
coda_reorder_enable(struct coda_ctx * ctx)182364441979SMauro Carvalho Chehab static bool coda_reorder_enable(struct coda_ctx *ctx)
182464441979SMauro Carvalho Chehab {
182564441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
182664441979SMauro Carvalho Chehab 	int profile;
182764441979SMauro Carvalho Chehab 
182864441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_HX4 &&
182964441979SMauro Carvalho Chehab 	    dev->devtype->product != CODA_7541 &&
183064441979SMauro Carvalho Chehab 	    dev->devtype->product != CODA_960)
183164441979SMauro Carvalho Chehab 		return false;
183264441979SMauro Carvalho Chehab 
183364441979SMauro Carvalho Chehab 	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
183464441979SMauro Carvalho Chehab 		return false;
183564441979SMauro Carvalho Chehab 
183664441979SMauro Carvalho Chehab 	if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264)
183764441979SMauro Carvalho Chehab 		return true;
183864441979SMauro Carvalho Chehab 
183964441979SMauro Carvalho Chehab 	profile = coda_h264_profile(ctx->params.h264_profile_idc);
184064441979SMauro Carvalho Chehab 	if (profile < 0)
184164441979SMauro Carvalho Chehab 		v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n",
184264441979SMauro Carvalho Chehab 			  ctx->params.h264_profile_idc);
184364441979SMauro Carvalho Chehab 
184464441979SMauro Carvalho Chehab 	/* Baseline profile does not support reordering */
184564441979SMauro Carvalho Chehab 	return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
184664441979SMauro Carvalho Chehab }
184764441979SMauro Carvalho Chehab 
coda_decoder_drop_used_metas(struct coda_ctx * ctx)184864441979SMauro Carvalho Chehab static void coda_decoder_drop_used_metas(struct coda_ctx *ctx)
184964441979SMauro Carvalho Chehab {
185064441979SMauro Carvalho Chehab 	struct coda_buffer_meta *meta, *tmp;
185164441979SMauro Carvalho Chehab 
185264441979SMauro Carvalho Chehab 	/*
185364441979SMauro Carvalho Chehab 	 * All metas that end at or before the RD pointer (fifo out),
185464441979SMauro Carvalho Chehab 	 * are now consumed by the VPU and should be released.
185564441979SMauro Carvalho Chehab 	 */
185664441979SMauro Carvalho Chehab 	spin_lock(&ctx->buffer_meta_lock);
185764441979SMauro Carvalho Chehab 	list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) {
185864441979SMauro Carvalho Chehab 		if (ctx->bitstream_fifo.kfifo.out >= meta->end) {
185964441979SMauro Carvalho Chehab 			coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n",
186064441979SMauro Carvalho Chehab 				 meta->sequence, meta->start, meta->end);
186164441979SMauro Carvalho Chehab 
186264441979SMauro Carvalho Chehab 			list_del(&meta->list);
186364441979SMauro Carvalho Chehab 			ctx->num_metas--;
186464441979SMauro Carvalho Chehab 			ctx->first_frame_sequence++;
186564441979SMauro Carvalho Chehab 			kfree(meta);
186664441979SMauro Carvalho Chehab 		}
186764441979SMauro Carvalho Chehab 	}
186864441979SMauro Carvalho Chehab 	spin_unlock(&ctx->buffer_meta_lock);
186964441979SMauro Carvalho Chehab }
187064441979SMauro Carvalho Chehab 
__coda_decoder_seq_init(struct coda_ctx * ctx)187164441979SMauro Carvalho Chehab static int __coda_decoder_seq_init(struct coda_ctx *ctx)
187264441979SMauro Carvalho Chehab {
187364441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src, *q_data_dst;
187464441979SMauro Carvalho Chehab 	u32 bitstream_buf, bitstream_size;
187564441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
187664441979SMauro Carvalho Chehab 	int width, height;
187764441979SMauro Carvalho Chehab 	u32 src_fourcc, dst_fourcc;
187864441979SMauro Carvalho Chehab 	u32 val;
187964441979SMauro Carvalho Chehab 	int ret;
188064441979SMauro Carvalho Chehab 
188164441979SMauro Carvalho Chehab 	lockdep_assert_held(&dev->coda_mutex);
188264441979SMauro Carvalho Chehab 
188364441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "Video Data Order Adapter: %s\n",
188464441979SMauro Carvalho Chehab 		 ctx->use_vdoa ? "Enabled" : "Disabled");
188564441979SMauro Carvalho Chehab 
188664441979SMauro Carvalho Chehab 	/* Start decoding */
188764441979SMauro Carvalho Chehab 	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
188864441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
188964441979SMauro Carvalho Chehab 	bitstream_buf = ctx->bitstream.paddr;
189064441979SMauro Carvalho Chehab 	bitstream_size = ctx->bitstream.size;
189164441979SMauro Carvalho Chehab 	src_fourcc = q_data_src->fourcc;
189264441979SMauro Carvalho Chehab 	dst_fourcc = q_data_dst->fourcc;
189364441979SMauro Carvalho Chehab 
189464441979SMauro Carvalho Chehab 	/* Update coda bitstream read and write pointers from kfifo */
189564441979SMauro Carvalho Chehab 	coda_kfifo_sync_to_device_full(ctx);
189664441979SMauro Carvalho Chehab 
189764441979SMauro Carvalho Chehab 	ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
189864441979SMauro Carvalho Chehab 				 CODA9_FRAME_TILED2LINEAR);
189964441979SMauro Carvalho Chehab 	if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
190064441979SMauro Carvalho Chehab 		ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
190164441979SMauro Carvalho Chehab 	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
190264441979SMauro Carvalho Chehab 		ctx->frame_mem_ctrl |= (0x3 << 9) |
190364441979SMauro Carvalho Chehab 			((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
190464441979SMauro Carvalho Chehab 	coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
190564441979SMauro Carvalho Chehab 
190664441979SMauro Carvalho Chehab 	ctx->display_idx = -1;
190764441979SMauro Carvalho Chehab 	ctx->frm_dis_flg = 0;
190864441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
190964441979SMauro Carvalho Chehab 
191064441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
191164441979SMauro Carvalho Chehab 	coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
191264441979SMauro Carvalho Chehab 	val = 0;
191364441979SMauro Carvalho Chehab 	if (coda_reorder_enable(ctx))
191464441979SMauro Carvalho Chehab 		val |= CODA_REORDER_ENABLE;
191564441979SMauro Carvalho Chehab 	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
191664441979SMauro Carvalho Chehab 		val |= CODA_NO_INT_ENABLE;
191764441979SMauro Carvalho Chehab 	coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
191864441979SMauro Carvalho Chehab 
191964441979SMauro Carvalho Chehab 	ctx->params.codec_mode = ctx->codec->mode;
192064441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960 &&
192164441979SMauro Carvalho Chehab 	    src_fourcc == V4L2_PIX_FMT_MPEG4)
192264441979SMauro Carvalho Chehab 		ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
192364441979SMauro Carvalho Chehab 	else
192464441979SMauro Carvalho Chehab 		ctx->params.codec_mode_aux = 0;
192564441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_MPEG4) {
192664441979SMauro Carvalho Chehab 		coda_write(dev, CODA_MP4_CLASS_MPEG4,
192764441979SMauro Carvalho Chehab 			   CODA_CMD_DEC_SEQ_MP4_ASP_CLASS);
192864441979SMauro Carvalho Chehab 	}
192964441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_H264) {
193064441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_HX4 ||
193164441979SMauro Carvalho Chehab 		    dev->devtype->product == CODA_7541) {
193264441979SMauro Carvalho Chehab 			coda_write(dev, ctx->psbuf.paddr,
193364441979SMauro Carvalho Chehab 					CODA_CMD_DEC_SEQ_PS_BB_START);
193464441979SMauro Carvalho Chehab 			coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
193564441979SMauro Carvalho Chehab 					CODA_CMD_DEC_SEQ_PS_BB_SIZE);
193664441979SMauro Carvalho Chehab 		}
193764441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960) {
193864441979SMauro Carvalho Chehab 			coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
193964441979SMauro Carvalho Chehab 			coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
194064441979SMauro Carvalho Chehab 		}
194164441979SMauro Carvalho Chehab 	}
194264441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_JPEG)
194364441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN);
194464441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_960)
194564441979SMauro Carvalho Chehab 		coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
194664441979SMauro Carvalho Chehab 
194764441979SMauro Carvalho Chehab 	ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE;
194864441979SMauro Carvalho Chehab 	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
194964441979SMauro Carvalho Chehab 	ctx->bit_stream_param = 0;
195064441979SMauro Carvalho Chehab 	if (ret) {
195164441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
195264441979SMauro Carvalho Chehab 		return ret;
195364441979SMauro Carvalho Chehab 	}
195464441979SMauro Carvalho Chehab 	ctx->sequence_offset = ~0U;
195564441979SMauro Carvalho Chehab 	ctx->initialized = 1;
195664441979SMauro Carvalho Chehab 	ctx->first_frame_sequence = 0;
195764441979SMauro Carvalho Chehab 
195864441979SMauro Carvalho Chehab 	/* Update kfifo out pointer from coda bitstream read pointer */
195964441979SMauro Carvalho Chehab 	coda_kfifo_sync_from_device(ctx);
196064441979SMauro Carvalho Chehab 
196164441979SMauro Carvalho Chehab 	/*
196264441979SMauro Carvalho Chehab 	 * After updating the read pointer, we need to check if
196364441979SMauro Carvalho Chehab 	 * any metas are consumed and should be released.
196464441979SMauro Carvalho Chehab 	 */
196564441979SMauro Carvalho Chehab 	coda_decoder_drop_used_metas(ctx);
196664441979SMauro Carvalho Chehab 
196764441979SMauro Carvalho Chehab 	if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
196864441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
196964441979SMauro Carvalho Chehab 			"CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n",
197064441979SMauro Carvalho Chehab 			coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
197164441979SMauro Carvalho Chehab 		return -EAGAIN;
197264441979SMauro Carvalho Chehab 	}
197364441979SMauro Carvalho Chehab 
197464441979SMauro Carvalho Chehab 	val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
197564441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_DX6) {
197664441979SMauro Carvalho Chehab 		width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
197764441979SMauro Carvalho Chehab 		height = val & CODADX6_PICHEIGHT_MASK;
197864441979SMauro Carvalho Chehab 	} else {
197964441979SMauro Carvalho Chehab 		width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
198064441979SMauro Carvalho Chehab 		height = val & CODA7_PICHEIGHT_MASK;
198164441979SMauro Carvalho Chehab 	}
198264441979SMauro Carvalho Chehab 
198364441979SMauro Carvalho Chehab 	if (width > q_data_dst->bytesperline || height > q_data_dst->height) {
198464441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
198564441979SMauro Carvalho Chehab 			 width, height, q_data_dst->bytesperline,
198664441979SMauro Carvalho Chehab 			 q_data_dst->height);
198764441979SMauro Carvalho Chehab 		return -EINVAL;
198864441979SMauro Carvalho Chehab 	}
198964441979SMauro Carvalho Chehab 
199064441979SMauro Carvalho Chehab 	width = round_up(width, 16);
199164441979SMauro Carvalho Chehab 	height = round_up(height, 16);
199264441979SMauro Carvalho Chehab 
199364441979SMauro Carvalho Chehab 	coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height);
199464441979SMauro Carvalho Chehab 
199564441979SMauro Carvalho Chehab 	ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
199664441979SMauro Carvalho Chehab 	/*
199764441979SMauro Carvalho Chehab 	 * If the VDOA is used, the decoder needs one additional frame,
199864441979SMauro Carvalho Chehab 	 * because the frames are freed when the next frame is decoded.
199964441979SMauro Carvalho Chehab 	 * Otherwise there are visible errors in the decoded frames (green
200064441979SMauro Carvalho Chehab 	 * regions in displayed frames) and a broken order of frames (earlier
200164441979SMauro Carvalho Chehab 	 * frames are sporadically displayed after later frames).
200264441979SMauro Carvalho Chehab 	 */
200364441979SMauro Carvalho Chehab 	if (ctx->use_vdoa)
200464441979SMauro Carvalho Chehab 		ctx->num_internal_frames += 1;
200564441979SMauro Carvalho Chehab 	if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
200664441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
200764441979SMauro Carvalho Chehab 			 "not enough framebuffers to decode (%d < %d)\n",
200864441979SMauro Carvalho Chehab 			 CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
200964441979SMauro Carvalho Chehab 		return -EINVAL;
201064441979SMauro Carvalho Chehab 	}
201164441979SMauro Carvalho Chehab 
201264441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_H264) {
201364441979SMauro Carvalho Chehab 		u32 left_right;
201464441979SMauro Carvalho Chehab 		u32 top_bottom;
201564441979SMauro Carvalho Chehab 
201664441979SMauro Carvalho Chehab 		left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
201764441979SMauro Carvalho Chehab 		top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
201864441979SMauro Carvalho Chehab 
201964441979SMauro Carvalho Chehab 		q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
202064441979SMauro Carvalho Chehab 		q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
202164441979SMauro Carvalho Chehab 		q_data_dst->rect.width = width - q_data_dst->rect.left -
202264441979SMauro Carvalho Chehab 					 (left_right & 0x3ff);
202364441979SMauro Carvalho Chehab 		q_data_dst->rect.height = height - q_data_dst->rect.top -
202464441979SMauro Carvalho Chehab 					  (top_bottom & 0x3ff);
202564441979SMauro Carvalho Chehab 	}
202664441979SMauro Carvalho Chehab 
202764441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6) {
202864441979SMauro Carvalho Chehab 		u8 profile, level;
202964441979SMauro Carvalho Chehab 
203064441979SMauro Carvalho Chehab 		val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT);
203164441979SMauro Carvalho Chehab 		profile = val & 0xff;
203264441979SMauro Carvalho Chehab 		level = (val >> 8) & 0x7f;
203364441979SMauro Carvalho Chehab 
203464441979SMauro Carvalho Chehab 		if (profile || level)
203564441979SMauro Carvalho Chehab 			coda_update_profile_level_ctrls(ctx, profile, level);
203664441979SMauro Carvalho Chehab 	}
203764441979SMauro Carvalho Chehab 
203864441979SMauro Carvalho Chehab 	return 0;
203964441979SMauro Carvalho Chehab }
204064441979SMauro Carvalho Chehab 
coda_dec_seq_init_work(struct work_struct * work)204164441979SMauro Carvalho Chehab static void coda_dec_seq_init_work(struct work_struct *work)
204264441979SMauro Carvalho Chehab {
204364441979SMauro Carvalho Chehab 	struct coda_ctx *ctx = container_of(work,
204464441979SMauro Carvalho Chehab 					    struct coda_ctx, seq_init_work);
204564441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
204664441979SMauro Carvalho Chehab 
204764441979SMauro Carvalho Chehab 	mutex_lock(&ctx->buffer_mutex);
204864441979SMauro Carvalho Chehab 	mutex_lock(&dev->coda_mutex);
204964441979SMauro Carvalho Chehab 
205064441979SMauro Carvalho Chehab 	if (!ctx->initialized)
205164441979SMauro Carvalho Chehab 		__coda_decoder_seq_init(ctx);
205264441979SMauro Carvalho Chehab 
205364441979SMauro Carvalho Chehab 	mutex_unlock(&dev->coda_mutex);
205464441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->buffer_mutex);
205564441979SMauro Carvalho Chehab }
205664441979SMauro Carvalho Chehab 
__coda_start_decoding(struct coda_ctx * ctx)205764441979SMauro Carvalho Chehab static int __coda_start_decoding(struct coda_ctx *ctx)
205864441979SMauro Carvalho Chehab {
205964441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src, *q_data_dst;
206064441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
206164441979SMauro Carvalho Chehab 	u32 src_fourcc, dst_fourcc;
206264441979SMauro Carvalho Chehab 	int ret;
206364441979SMauro Carvalho Chehab 
206464441979SMauro Carvalho Chehab 	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
206564441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
206664441979SMauro Carvalho Chehab 	src_fourcc = q_data_src->fourcc;
206764441979SMauro Carvalho Chehab 	dst_fourcc = q_data_dst->fourcc;
206864441979SMauro Carvalho Chehab 
206964441979SMauro Carvalho Chehab 	if (!ctx->initialized) {
207064441979SMauro Carvalho Chehab 		ret = __coda_decoder_seq_init(ctx);
207164441979SMauro Carvalho Chehab 		if (ret < 0)
207264441979SMauro Carvalho Chehab 			return ret;
207364441979SMauro Carvalho Chehab 	} else {
207464441979SMauro Carvalho Chehab 		ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
207564441979SMauro Carvalho Chehab 					 CODA9_FRAME_TILED2LINEAR);
207664441979SMauro Carvalho Chehab 		if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
207764441979SMauro Carvalho Chehab 			ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
207864441979SMauro Carvalho Chehab 		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
207964441979SMauro Carvalho Chehab 			ctx->frame_mem_ctrl |= (0x3 << 9) |
208064441979SMauro Carvalho Chehab 				((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
208164441979SMauro Carvalho Chehab 	}
208264441979SMauro Carvalho Chehab 
208364441979SMauro Carvalho Chehab 	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
208464441979SMauro Carvalho Chehab 
208564441979SMauro Carvalho Chehab 	ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
208664441979SMauro Carvalho Chehab 	if (ret < 0) {
208764441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
208864441979SMauro Carvalho Chehab 		return ret;
208964441979SMauro Carvalho Chehab 	}
209064441979SMauro Carvalho Chehab 
209164441979SMauro Carvalho Chehab 	/* Tell the decoder how many frame buffers we allocated. */
209264441979SMauro Carvalho Chehab 	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
209364441979SMauro Carvalho Chehab 	coda_write(dev, round_up(q_data_dst->rect.width, 16),
209464441979SMauro Carvalho Chehab 		   CODA_CMD_SET_FRAME_BUF_STRIDE);
209564441979SMauro Carvalho Chehab 
209664441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6) {
209764441979SMauro Carvalho Chehab 		/* Set secondary AXI IRAM */
209864441979SMauro Carvalho Chehab 		coda_setup_iram(ctx);
209964441979SMauro Carvalho Chehab 
210064441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_bit_use,
210164441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
210264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
210364441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
210464441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
210564441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
210664441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
210764441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
210864441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.buf_ovl_use,
210964441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
211064441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960) {
211164441979SMauro Carvalho Chehab 			coda_write(dev, ctx->iram_info.buf_btp_use,
211264441979SMauro Carvalho Chehab 					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
211364441979SMauro Carvalho Chehab 
211464441979SMauro Carvalho Chehab 			coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
211564441979SMauro Carvalho Chehab 			coda9_set_frame_cache(ctx, dst_fourcc);
211664441979SMauro Carvalho Chehab 		}
211764441979SMauro Carvalho Chehab 	}
211864441979SMauro Carvalho Chehab 
211964441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_H264) {
212064441979SMauro Carvalho Chehab 		coda_write(dev, ctx->slicebuf.paddr,
212164441979SMauro Carvalho Chehab 				CODA_CMD_SET_FRAME_SLICE_BB_START);
212264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->slicebuf.size / 1024,
212364441979SMauro Carvalho Chehab 				CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
212464441979SMauro Carvalho Chehab 	}
212564441979SMauro Carvalho Chehab 
212664441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_HX4 ||
212764441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_7541) {
212864441979SMauro Carvalho Chehab 		int max_mb_x = 1920 / 16;
212964441979SMauro Carvalho Chehab 		int max_mb_y = 1088 / 16;
213064441979SMauro Carvalho Chehab 		int max_mb_num = max_mb_x * max_mb_y;
213164441979SMauro Carvalho Chehab 
213264441979SMauro Carvalho Chehab 		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
213364441979SMauro Carvalho Chehab 				CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
213464441979SMauro Carvalho Chehab 	} else if (dev->devtype->product == CODA_960) {
213564441979SMauro Carvalho Chehab 		int max_mb_x = 1920 / 16;
213664441979SMauro Carvalho Chehab 		int max_mb_y = 1088 / 16;
213764441979SMauro Carvalho Chehab 		int max_mb_num = max_mb_x * max_mb_y;
213864441979SMauro Carvalho Chehab 
213964441979SMauro Carvalho Chehab 		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
214064441979SMauro Carvalho Chehab 				CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
214164441979SMauro Carvalho Chehab 	}
214264441979SMauro Carvalho Chehab 
214364441979SMauro Carvalho Chehab 	if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
214464441979SMauro Carvalho Chehab 		v4l2_err(&ctx->dev->v4l2_dev,
214564441979SMauro Carvalho Chehab 			 "CODA_COMMAND_SET_FRAME_BUF timeout\n");
214664441979SMauro Carvalho Chehab 		return -ETIMEDOUT;
214764441979SMauro Carvalho Chehab 	}
214864441979SMauro Carvalho Chehab 
214964441979SMauro Carvalho Chehab 	return 0;
215064441979SMauro Carvalho Chehab }
215164441979SMauro Carvalho Chehab 
coda_start_decoding(struct coda_ctx * ctx)215264441979SMauro Carvalho Chehab static int coda_start_decoding(struct coda_ctx *ctx)
215364441979SMauro Carvalho Chehab {
215464441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
215564441979SMauro Carvalho Chehab 	int ret;
215664441979SMauro Carvalho Chehab 
215764441979SMauro Carvalho Chehab 	mutex_lock(&dev->coda_mutex);
215864441979SMauro Carvalho Chehab 	ret = __coda_start_decoding(ctx);
215964441979SMauro Carvalho Chehab 	mutex_unlock(&dev->coda_mutex);
216064441979SMauro Carvalho Chehab 
216164441979SMauro Carvalho Chehab 	return ret;
216264441979SMauro Carvalho Chehab }
216364441979SMauro Carvalho Chehab 
coda_prepare_decode(struct coda_ctx * ctx)216464441979SMauro Carvalho Chehab static int coda_prepare_decode(struct coda_ctx *ctx)
216564441979SMauro Carvalho Chehab {
216664441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *dst_buf;
216764441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
216864441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_dst;
216964441979SMauro Carvalho Chehab 	struct coda_buffer_meta *meta;
217064441979SMauro Carvalho Chehab 	u32 rot_mode = 0;
217164441979SMauro Carvalho Chehab 	u32 reg_addr, reg_stride;
217264441979SMauro Carvalho Chehab 
217364441979SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
217464441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
217564441979SMauro Carvalho Chehab 
217664441979SMauro Carvalho Chehab 	/* Try to copy source buffer contents into the bitstream ringbuffer */
217764441979SMauro Carvalho Chehab 	mutex_lock(&ctx->bitstream_mutex);
217864441979SMauro Carvalho Chehab 	coda_fill_bitstream(ctx, NULL);
217964441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->bitstream_mutex);
218064441979SMauro Carvalho Chehab 
218164441979SMauro Carvalho Chehab 	if (coda_get_bitstream_payload(ctx) < 512 &&
218264441979SMauro Carvalho Chehab 	    (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
218364441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "bitstream payload: %d, skipping\n",
218464441979SMauro Carvalho Chehab 			 coda_get_bitstream_payload(ctx));
218564441979SMauro Carvalho Chehab 		return -EAGAIN;
218664441979SMauro Carvalho Chehab 	}
218764441979SMauro Carvalho Chehab 
218864441979SMauro Carvalho Chehab 	/* Run coda_start_decoding (again) if not yet initialized */
218964441979SMauro Carvalho Chehab 	if (!ctx->initialized) {
219064441979SMauro Carvalho Chehab 		int ret = __coda_start_decoding(ctx);
219164441979SMauro Carvalho Chehab 
219264441979SMauro Carvalho Chehab 		if (ret < 0) {
219364441979SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
219464441979SMauro Carvalho Chehab 			return -EAGAIN;
219564441979SMauro Carvalho Chehab 		} else {
219664441979SMauro Carvalho Chehab 			ctx->initialized = 1;
219764441979SMauro Carvalho Chehab 		}
219864441979SMauro Carvalho Chehab 	}
219964441979SMauro Carvalho Chehab 
220064441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_960)
220164441979SMauro Carvalho Chehab 		coda_set_gdi_regs(ctx);
220264441979SMauro Carvalho Chehab 
220364441979SMauro Carvalho Chehab 	if (ctx->use_vdoa &&
220464441979SMauro Carvalho Chehab 	    ctx->display_idx >= 0 &&
220564441979SMauro Carvalho Chehab 	    ctx->display_idx < ctx->num_internal_frames) {
220664441979SMauro Carvalho Chehab 		vdoa_device_run(ctx->vdoa,
220764441979SMauro Carvalho Chehab 				vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0),
220864441979SMauro Carvalho Chehab 				ctx->internal_frames[ctx->display_idx].buf.paddr);
220964441979SMauro Carvalho Chehab 	} else {
221064441979SMauro Carvalho Chehab 		if (dev->devtype->product == CODA_960) {
221164441979SMauro Carvalho Chehab 			/*
221264441979SMauro Carvalho Chehab 			 * It was previously assumed that the CODA960 has an
221364441979SMauro Carvalho Chehab 			 * internal list of 64 buffer entries that contains
221464441979SMauro Carvalho Chehab 			 * both the registered internal frame buffers as well
221564441979SMauro Carvalho Chehab 			 * as the rotator buffer output, and that the ROT_INDEX
221664441979SMauro Carvalho Chehab 			 * register must be set to a value between the last
221764441979SMauro Carvalho Chehab 			 * internal frame buffers' index and 64.
221864441979SMauro Carvalho Chehab 			 * At least on firmware version 3.1.1 it turns out that
221964441979SMauro Carvalho Chehab 			 * setting ROT_INDEX to any value >= 32 causes CODA
222064441979SMauro Carvalho Chehab 			 * hangups that it can not recover from with the SRC VPU
222164441979SMauro Carvalho Chehab 			 * reset.
222264441979SMauro Carvalho Chehab 			 * It does appear to work however, to just set it to a
222364441979SMauro Carvalho Chehab 			 * fixed value in the [ctx->num_internal_frames, 31]
222464441979SMauro Carvalho Chehab 			 * range, for example CODA_MAX_FRAMEBUFFERS.
222564441979SMauro Carvalho Chehab 			 */
222664441979SMauro Carvalho Chehab 			coda_write(dev, CODA_MAX_FRAMEBUFFERS,
222764441979SMauro Carvalho Chehab 				   CODA9_CMD_DEC_PIC_ROT_INDEX);
222864441979SMauro Carvalho Chehab 
222964441979SMauro Carvalho Chehab 			reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
223064441979SMauro Carvalho Chehab 			reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE;
223164441979SMauro Carvalho Chehab 		} else {
223264441979SMauro Carvalho Chehab 			reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y;
223364441979SMauro Carvalho Chehab 			reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE;
223464441979SMauro Carvalho Chehab 		}
223564441979SMauro Carvalho Chehab 		coda_write_base(ctx, q_data_dst, dst_buf, reg_addr);
223664441979SMauro Carvalho Chehab 		coda_write(dev, q_data_dst->bytesperline, reg_stride);
223764441979SMauro Carvalho Chehab 
223864441979SMauro Carvalho Chehab 		rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
223964441979SMauro Carvalho Chehab 	}
224064441979SMauro Carvalho Chehab 
224164441979SMauro Carvalho Chehab 	coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE);
224264441979SMauro Carvalho Chehab 
224364441979SMauro Carvalho Chehab 	switch (dev->devtype->product) {
224464441979SMauro Carvalho Chehab 	case CODA_DX6:
224564441979SMauro Carvalho Chehab 		/* TBD */
224664441979SMauro Carvalho Chehab 	case CODA_HX4:
224764441979SMauro Carvalho Chehab 	case CODA_7541:
224864441979SMauro Carvalho Chehab 		coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
224964441979SMauro Carvalho Chehab 		break;
225064441979SMauro Carvalho Chehab 	case CODA_960:
225164441979SMauro Carvalho Chehab 		/* 'hardcode to use interrupt disable mode'? */
225264441979SMauro Carvalho Chehab 		coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION);
225364441979SMauro Carvalho Chehab 		break;
225464441979SMauro Carvalho Chehab 	}
225564441979SMauro Carvalho Chehab 
225664441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
225764441979SMauro Carvalho Chehab 
225864441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
225964441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
226064441979SMauro Carvalho Chehab 
226164441979SMauro Carvalho Chehab 	if (dev->devtype->product != CODA_DX6)
226264441979SMauro Carvalho Chehab 		coda_write(dev, ctx->iram_info.axi_sram_use,
226364441979SMauro Carvalho Chehab 				CODA7_REG_BIT_AXI_SRAM_USE);
226464441979SMauro Carvalho Chehab 
226564441979SMauro Carvalho Chehab 	spin_lock(&ctx->buffer_meta_lock);
226664441979SMauro Carvalho Chehab 	meta = list_first_entry_or_null(&ctx->buffer_meta_list,
226764441979SMauro Carvalho Chehab 					struct coda_buffer_meta, list);
226864441979SMauro Carvalho Chehab 
226964441979SMauro Carvalho Chehab 	if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
227064441979SMauro Carvalho Chehab 
227164441979SMauro Carvalho Chehab 		/* If this is the last buffer in the bitstream, add padding */
227264441979SMauro Carvalho Chehab 		if (meta->end == ctx->bitstream_fifo.kfifo.in) {
227364441979SMauro Carvalho Chehab 			static unsigned char buf[512];
227464441979SMauro Carvalho Chehab 			unsigned int pad;
227564441979SMauro Carvalho Chehab 
227664441979SMauro Carvalho Chehab 			/* Pad to multiple of 256 and then add 256 more */
227764441979SMauro Carvalho Chehab 			pad = ((0 - meta->end) & 0xff) + 256;
227864441979SMauro Carvalho Chehab 
227964441979SMauro Carvalho Chehab 			memset(buf, 0xff, sizeof(buf));
228064441979SMauro Carvalho Chehab 
228164441979SMauro Carvalho Chehab 			kfifo_in(&ctx->bitstream_fifo, buf, pad);
228264441979SMauro Carvalho Chehab 		}
228364441979SMauro Carvalho Chehab 	}
228464441979SMauro Carvalho Chehab 	spin_unlock(&ctx->buffer_meta_lock);
228564441979SMauro Carvalho Chehab 
228664441979SMauro Carvalho Chehab 	coda_kfifo_sync_to_device_full(ctx);
228764441979SMauro Carvalho Chehab 
228864441979SMauro Carvalho Chehab 	/* Clear decode success flag */
228964441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
229064441979SMauro Carvalho Chehab 
229164441979SMauro Carvalho Chehab 	/* Clear error return value */
229264441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB);
229364441979SMauro Carvalho Chehab 
229464441979SMauro Carvalho Chehab 	trace_coda_dec_pic_run(ctx, meta);
229564441979SMauro Carvalho Chehab 
229664441979SMauro Carvalho Chehab 	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
229764441979SMauro Carvalho Chehab 
229864441979SMauro Carvalho Chehab 	return 0;
229964441979SMauro Carvalho Chehab }
230064441979SMauro Carvalho Chehab 
coda_finish_decode(struct coda_ctx * ctx)230164441979SMauro Carvalho Chehab static void coda_finish_decode(struct coda_ctx *ctx)
230264441979SMauro Carvalho Chehab {
230364441979SMauro Carvalho Chehab 	struct coda_dev *dev = ctx->dev;
230464441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_src;
230564441979SMauro Carvalho Chehab 	struct coda_q_data *q_data_dst;
230664441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *dst_buf;
230764441979SMauro Carvalho Chehab 	struct coda_buffer_meta *meta;
230864441979SMauro Carvalho Chehab 	int width, height;
230964441979SMauro Carvalho Chehab 	int decoded_idx;
231064441979SMauro Carvalho Chehab 	int display_idx;
231164441979SMauro Carvalho Chehab 	struct coda_internal_frame *decoded_frame = NULL;
231264441979SMauro Carvalho Chehab 	u32 src_fourcc;
231364441979SMauro Carvalho Chehab 	int success;
231464441979SMauro Carvalho Chehab 	u32 err_mb;
231564441979SMauro Carvalho Chehab 	int err_vdoa = 0;
231664441979SMauro Carvalho Chehab 	u32 val;
231764441979SMauro Carvalho Chehab 
231864441979SMauro Carvalho Chehab 	if (ctx->aborting)
231964441979SMauro Carvalho Chehab 		return;
232064441979SMauro Carvalho Chehab 
232164441979SMauro Carvalho Chehab 	/* Update kfifo out pointer from coda bitstream read pointer */
232264441979SMauro Carvalho Chehab 	coda_kfifo_sync_from_device(ctx);
232364441979SMauro Carvalho Chehab 
232464441979SMauro Carvalho Chehab 	/*
232564441979SMauro Carvalho Chehab 	 * in stream-end mode, the read pointer can overshoot the write pointer
232664441979SMauro Carvalho Chehab 	 * by up to 512 bytes
232764441979SMauro Carvalho Chehab 	 */
232864441979SMauro Carvalho Chehab 	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
232964441979SMauro Carvalho Chehab 		if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512)
233064441979SMauro Carvalho Chehab 			kfifo_init(&ctx->bitstream_fifo,
233164441979SMauro Carvalho Chehab 				ctx->bitstream.vaddr, ctx->bitstream.size);
233264441979SMauro Carvalho Chehab 	}
233364441979SMauro Carvalho Chehab 
233464441979SMauro Carvalho Chehab 	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
233564441979SMauro Carvalho Chehab 	src_fourcc = q_data_src->fourcc;
233664441979SMauro Carvalho Chehab 
233764441979SMauro Carvalho Chehab 	val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
233864441979SMauro Carvalho Chehab 	if (val != 1)
233964441979SMauro Carvalho Chehab 		pr_err("DEC_PIC_SUCCESS = %d\n", val);
234064441979SMauro Carvalho Chehab 
234164441979SMauro Carvalho Chehab 	success = val & 0x1;
234264441979SMauro Carvalho Chehab 	if (!success)
234364441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "decode failed\n");
234464441979SMauro Carvalho Chehab 
234564441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_H264) {
234664441979SMauro Carvalho Chehab 		if (val & (1 << 3))
234764441979SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
234864441979SMauro Carvalho Chehab 				 "insufficient PS buffer space (%d bytes)\n",
234964441979SMauro Carvalho Chehab 				 ctx->psbuf.size);
235064441979SMauro Carvalho Chehab 		if (val & (1 << 2))
235164441979SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev,
235264441979SMauro Carvalho Chehab 				 "insufficient slice buffer space (%d bytes)\n",
235364441979SMauro Carvalho Chehab 				 ctx->slicebuf.size);
235464441979SMauro Carvalho Chehab 	}
235564441979SMauro Carvalho Chehab 
235664441979SMauro Carvalho Chehab 	val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
235764441979SMauro Carvalho Chehab 	width = (val >> 16) & 0xffff;
235864441979SMauro Carvalho Chehab 	height = val & 0xffff;
235964441979SMauro Carvalho Chehab 
236064441979SMauro Carvalho Chehab 	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
236164441979SMauro Carvalho Chehab 
236264441979SMauro Carvalho Chehab 	/* frame crop information */
236364441979SMauro Carvalho Chehab 	if (src_fourcc == V4L2_PIX_FMT_H264) {
236464441979SMauro Carvalho Chehab 		u32 left_right;
236564441979SMauro Carvalho Chehab 		u32 top_bottom;
236664441979SMauro Carvalho Chehab 
236764441979SMauro Carvalho Chehab 		left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
236864441979SMauro Carvalho Chehab 		top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
236964441979SMauro Carvalho Chehab 
237064441979SMauro Carvalho Chehab 		if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
237164441979SMauro Carvalho Chehab 			/* Keep current crop information */
237264441979SMauro Carvalho Chehab 		} else {
237364441979SMauro Carvalho Chehab 			struct v4l2_rect *rect = &q_data_dst->rect;
237464441979SMauro Carvalho Chehab 
237564441979SMauro Carvalho Chehab 			rect->left = left_right >> 16 & 0xffff;
237664441979SMauro Carvalho Chehab 			rect->top = top_bottom >> 16 & 0xffff;
237764441979SMauro Carvalho Chehab 			rect->width = width - rect->left -
237864441979SMauro Carvalho Chehab 				      (left_right & 0xffff);
237964441979SMauro Carvalho Chehab 			rect->height = height - rect->top -
238064441979SMauro Carvalho Chehab 				       (top_bottom & 0xffff);
238164441979SMauro Carvalho Chehab 		}
238264441979SMauro Carvalho Chehab 	} else {
238364441979SMauro Carvalho Chehab 		/* no cropping */
238464441979SMauro Carvalho Chehab 	}
238564441979SMauro Carvalho Chehab 
238664441979SMauro Carvalho Chehab 	err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
238764441979SMauro Carvalho Chehab 	if (err_mb > 0) {
238864441979SMauro Carvalho Chehab 		if (__ratelimit(&dev->mb_err_rs))
238964441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb);
239064441979SMauro Carvalho Chehab 		v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl,
239164441979SMauro Carvalho Chehab 				 v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb);
239264441979SMauro Carvalho Chehab 	}
239364441979SMauro Carvalho Chehab 
239464441979SMauro Carvalho Chehab 	if (dev->devtype->product == CODA_HX4 ||
239564441979SMauro Carvalho Chehab 	    dev->devtype->product == CODA_7541) {
239664441979SMauro Carvalho Chehab 		val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
239764441979SMauro Carvalho Chehab 		if (val == 0) {
239864441979SMauro Carvalho Chehab 			/* not enough bitstream data */
239964441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "prescan failed: %d\n", val);
240064441979SMauro Carvalho Chehab 			ctx->hold = true;
240164441979SMauro Carvalho Chehab 			return;
240264441979SMauro Carvalho Chehab 		}
240364441979SMauro Carvalho Chehab 	}
240464441979SMauro Carvalho Chehab 
240564441979SMauro Carvalho Chehab 	/* Wait until the VDOA finished writing the previous display frame */
240664441979SMauro Carvalho Chehab 	if (ctx->use_vdoa &&
240764441979SMauro Carvalho Chehab 	    ctx->display_idx >= 0 &&
240864441979SMauro Carvalho Chehab 	    ctx->display_idx < ctx->num_internal_frames) {
240964441979SMauro Carvalho Chehab 		err_vdoa = vdoa_wait_for_completion(ctx->vdoa);
241064441979SMauro Carvalho Chehab 	}
241164441979SMauro Carvalho Chehab 
241264441979SMauro Carvalho Chehab 	ctx->frm_dis_flg = coda_read(dev,
241364441979SMauro Carvalho Chehab 				     CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
241464441979SMauro Carvalho Chehab 
241564441979SMauro Carvalho Chehab 	/* The previous display frame was copied out and can be overwritten */
241664441979SMauro Carvalho Chehab 	if (ctx->display_idx >= 0 &&
241764441979SMauro Carvalho Chehab 	    ctx->display_idx < ctx->num_internal_frames) {
241864441979SMauro Carvalho Chehab 		ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
241964441979SMauro Carvalho Chehab 		coda_write(dev, ctx->frm_dis_flg,
242064441979SMauro Carvalho Chehab 				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
242164441979SMauro Carvalho Chehab 	}
242264441979SMauro Carvalho Chehab 
242364441979SMauro Carvalho Chehab 	/*
242464441979SMauro Carvalho Chehab 	 * The index of the last decoded frame, not necessarily in
242564441979SMauro Carvalho Chehab 	 * display order, and the index of the next display frame.
242664441979SMauro Carvalho Chehab 	 * The latter could have been decoded in a previous run.
242764441979SMauro Carvalho Chehab 	 */
242864441979SMauro Carvalho Chehab 	decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
242964441979SMauro Carvalho Chehab 	display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
243064441979SMauro Carvalho Chehab 
243164441979SMauro Carvalho Chehab 	if (decoded_idx == -1) {
243264441979SMauro Carvalho Chehab 		/* no frame was decoded, but we might have a display frame */
243364441979SMauro Carvalho Chehab 		if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
243464441979SMauro Carvalho Chehab 			ctx->sequence_offset++;
243564441979SMauro Carvalho Chehab 		else if (ctx->display_idx < 0)
243664441979SMauro Carvalho Chehab 			ctx->hold = true;
243764441979SMauro Carvalho Chehab 	} else if (decoded_idx == -2) {
243864441979SMauro Carvalho Chehab 		if (ctx->display_idx >= 0 &&
243964441979SMauro Carvalho Chehab 		    ctx->display_idx < ctx->num_internal_frames)
244064441979SMauro Carvalho Chehab 			ctx->sequence_offset++;
244164441979SMauro Carvalho Chehab 		/* no frame was decoded, we still return remaining buffers */
244264441979SMauro Carvalho Chehab 	} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
244364441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
244464441979SMauro Carvalho Chehab 			 "decoded frame index out of range: %d\n", decoded_idx);
244564441979SMauro Carvalho Chehab 	} else {
244664441979SMauro Carvalho Chehab 		int sequence;
244764441979SMauro Carvalho Chehab 
244864441979SMauro Carvalho Chehab 		decoded_frame = &ctx->internal_frames[decoded_idx];
244964441979SMauro Carvalho Chehab 
245064441979SMauro Carvalho Chehab 		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM);
245164441979SMauro Carvalho Chehab 		if (ctx->sequence_offset == -1)
245264441979SMauro Carvalho Chehab 			ctx->sequence_offset = val;
245364441979SMauro Carvalho Chehab 
245464441979SMauro Carvalho Chehab 		sequence = val + ctx->first_frame_sequence
245564441979SMauro Carvalho Chehab 			       - ctx->sequence_offset;
245664441979SMauro Carvalho Chehab 		spin_lock(&ctx->buffer_meta_lock);
245764441979SMauro Carvalho Chehab 		if (!list_empty(&ctx->buffer_meta_list)) {
245864441979SMauro Carvalho Chehab 			meta = list_first_entry(&ctx->buffer_meta_list,
245964441979SMauro Carvalho Chehab 					      struct coda_buffer_meta, list);
246064441979SMauro Carvalho Chehab 			list_del(&meta->list);
246164441979SMauro Carvalho Chehab 			ctx->num_metas--;
246264441979SMauro Carvalho Chehab 			spin_unlock(&ctx->buffer_meta_lock);
246364441979SMauro Carvalho Chehab 			/*
246464441979SMauro Carvalho Chehab 			 * Clamp counters to 16 bits for comparison, as the HW
246564441979SMauro Carvalho Chehab 			 * counter rolls over at this point for h.264. This
246664441979SMauro Carvalho Chehab 			 * may be different for other formats, but using 16 bits
246764441979SMauro Carvalho Chehab 			 * should be enough to detect most errors and saves us
246864441979SMauro Carvalho Chehab 			 * from doing different things based on the format.
246964441979SMauro Carvalho Chehab 			 */
247064441979SMauro Carvalho Chehab 			if ((sequence & 0xffff) != (meta->sequence & 0xffff)) {
247164441979SMauro Carvalho Chehab 				v4l2_err(&dev->v4l2_dev,
247264441979SMauro Carvalho Chehab 					 "sequence number mismatch (%d(%d) != %d)\n",
247364441979SMauro Carvalho Chehab 					 sequence, ctx->sequence_offset,
247464441979SMauro Carvalho Chehab 					 meta->sequence);
247564441979SMauro Carvalho Chehab 			}
247664441979SMauro Carvalho Chehab 			decoded_frame->meta = *meta;
247764441979SMauro Carvalho Chehab 			kfree(meta);
247864441979SMauro Carvalho Chehab 		} else {
247964441979SMauro Carvalho Chehab 			spin_unlock(&ctx->buffer_meta_lock);
248064441979SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
248164441979SMauro Carvalho Chehab 			memset(&decoded_frame->meta, 0,
248264441979SMauro Carvalho Chehab 			       sizeof(struct coda_buffer_meta));
248364441979SMauro Carvalho Chehab 			decoded_frame->meta.sequence = sequence;
248464441979SMauro Carvalho Chehab 			decoded_frame->meta.last = false;
248564441979SMauro Carvalho Chehab 			ctx->sequence_offset++;
248664441979SMauro Carvalho Chehab 		}
248764441979SMauro Carvalho Chehab 
248864441979SMauro Carvalho Chehab 		trace_coda_dec_pic_done(ctx, &decoded_frame->meta);
248964441979SMauro Carvalho Chehab 
249064441979SMauro Carvalho Chehab 		val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
249164441979SMauro Carvalho Chehab 		decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME :
249264441979SMauro Carvalho Chehab 				      (val == 1) ? V4L2_BUF_FLAG_PFRAME :
249364441979SMauro Carvalho Chehab 						   V4L2_BUF_FLAG_BFRAME;
249464441979SMauro Carvalho Chehab 
249564441979SMauro Carvalho Chehab 		decoded_frame->error = err_mb;
249664441979SMauro Carvalho Chehab 	}
249764441979SMauro Carvalho Chehab 
249864441979SMauro Carvalho Chehab 	if (display_idx == -1) {
249964441979SMauro Carvalho Chehab 		/*
250064441979SMauro Carvalho Chehab 		 * no more frames to be decoded, but there could still
250164441979SMauro Carvalho Chehab 		 * be rotator output to dequeue
250264441979SMauro Carvalho Chehab 		 */
250364441979SMauro Carvalho Chehab 		ctx->hold = true;
250464441979SMauro Carvalho Chehab 	} else if (display_idx == -3) {
250564441979SMauro Carvalho Chehab 		/* possibly prescan failure */
250664441979SMauro Carvalho Chehab 	} else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
250764441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
250864441979SMauro Carvalho Chehab 			 "presentation frame index out of range: %d\n",
250964441979SMauro Carvalho Chehab 			 display_idx);
251064441979SMauro Carvalho Chehab 	}
251164441979SMauro Carvalho Chehab 
251264441979SMauro Carvalho Chehab 	/* If a frame was copied out, return it */
251364441979SMauro Carvalho Chehab 	if (ctx->display_idx >= 0 &&
251464441979SMauro Carvalho Chehab 	    ctx->display_idx < ctx->num_internal_frames) {
251564441979SMauro Carvalho Chehab 		struct coda_internal_frame *ready_frame;
251664441979SMauro Carvalho Chehab 
251764441979SMauro Carvalho Chehab 		ready_frame = &ctx->internal_frames[ctx->display_idx];
251864441979SMauro Carvalho Chehab 
251964441979SMauro Carvalho Chehab 		dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
252064441979SMauro Carvalho Chehab 		dst_buf->sequence = ctx->osequence++;
252164441979SMauro Carvalho Chehab 
252264441979SMauro Carvalho Chehab 		dst_buf->field = V4L2_FIELD_NONE;
252364441979SMauro Carvalho Chehab 		dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
252464441979SMauro Carvalho Chehab 					     V4L2_BUF_FLAG_PFRAME |
252564441979SMauro Carvalho Chehab 					     V4L2_BUF_FLAG_BFRAME);
252664441979SMauro Carvalho Chehab 		dst_buf->flags |= ready_frame->type;
252764441979SMauro Carvalho Chehab 		meta = &ready_frame->meta;
252864441979SMauro Carvalho Chehab 		if (meta->last && !coda_reorder_enable(ctx)) {
252964441979SMauro Carvalho Chehab 			/*
253064441979SMauro Carvalho Chehab 			 * If this was the last decoded frame, and reordering
253164441979SMauro Carvalho Chehab 			 * is disabled, this will be the last display frame.
253264441979SMauro Carvalho Chehab 			 */
253364441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "last meta, marking as last frame\n");
253464441979SMauro Carvalho Chehab 			dst_buf->flags |= V4L2_BUF_FLAG_LAST;
253564441979SMauro Carvalho Chehab 		} else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG &&
253664441979SMauro Carvalho Chehab 			   display_idx == -1) {
253764441979SMauro Carvalho Chehab 			/*
253864441979SMauro Carvalho Chehab 			 * If there is no designated presentation frame anymore,
253964441979SMauro Carvalho Chehab 			 * this frame has to be the last one.
254064441979SMauro Carvalho Chehab 			 */
254164441979SMauro Carvalho Chehab 			coda_dbg(1, ctx,
254264441979SMauro Carvalho Chehab 				 "no more frames to return, marking as last frame\n");
254364441979SMauro Carvalho Chehab 			dst_buf->flags |= V4L2_BUF_FLAG_LAST;
254464441979SMauro Carvalho Chehab 		}
254564441979SMauro Carvalho Chehab 		dst_buf->timecode = meta->timecode;
254664441979SMauro Carvalho Chehab 		dst_buf->vb2_buf.timestamp = meta->timestamp;
254764441979SMauro Carvalho Chehab 
254864441979SMauro Carvalho Chehab 		trace_coda_dec_rot_done(ctx, dst_buf, meta);
254964441979SMauro Carvalho Chehab 
255064441979SMauro Carvalho Chehab 		vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
255164441979SMauro Carvalho Chehab 				      q_data_dst->sizeimage);
255264441979SMauro Carvalho Chehab 
255364441979SMauro Carvalho Chehab 		if (ready_frame->error || err_vdoa)
255464441979SMauro Carvalho Chehab 			coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
255564441979SMauro Carvalho Chehab 		else
255664441979SMauro Carvalho Chehab 			coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
255764441979SMauro Carvalho Chehab 
255864441979SMauro Carvalho Chehab 		if (decoded_frame) {
255964441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n",
256064441979SMauro Carvalho Chehab 				 coda_frame_type_char(decoded_frame->type),
256164441979SMauro Carvalho Chehab 				 decoded_frame->meta.sequence,
256264441979SMauro Carvalho Chehab 				 coda_frame_type_char(dst_buf->flags),
256364441979SMauro Carvalho Chehab 				 ready_frame->meta.sequence,
256464441979SMauro Carvalho Chehab 				 dst_buf->sequence, ctx->qsequence,
256564441979SMauro Carvalho Chehab 				 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
256664441979SMauro Carvalho Chehab 				 " (last)" : "");
256764441979SMauro Carvalho Chehab 		} else {
256864441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n",
256964441979SMauro Carvalho Chehab 				 decoded_idx,
257064441979SMauro Carvalho Chehab 				 coda_frame_type_char(dst_buf->flags),
257164441979SMauro Carvalho Chehab 				 ready_frame->meta.sequence,
257264441979SMauro Carvalho Chehab 				 dst_buf->sequence, ctx->qsequence,
257364441979SMauro Carvalho Chehab 				 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
257464441979SMauro Carvalho Chehab 				 " (last)" : "");
257564441979SMauro Carvalho Chehab 		}
257664441979SMauro Carvalho Chehab 	} else {
257764441979SMauro Carvalho Chehab 		if (decoded_frame) {
257864441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n",
257964441979SMauro Carvalho Chehab 				 coda_frame_type_char(decoded_frame->type),
258064441979SMauro Carvalho Chehab 				 decoded_frame->meta.sequence,
258164441979SMauro Carvalho Chehab 				 ctx->display_idx);
258264441979SMauro Carvalho Chehab 		} else {
258364441979SMauro Carvalho Chehab 			coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n",
258464441979SMauro Carvalho Chehab 				 decoded_idx, ctx->display_idx);
258564441979SMauro Carvalho Chehab 		}
258664441979SMauro Carvalho Chehab 	}
258764441979SMauro Carvalho Chehab 
258864441979SMauro Carvalho Chehab 	/* The rotator will copy the current display frame next time */
258964441979SMauro Carvalho Chehab 	ctx->display_idx = display_idx;
259064441979SMauro Carvalho Chehab 
259164441979SMauro Carvalho Chehab 	/*
259264441979SMauro Carvalho Chehab 	 * The current decode run might have brought the bitstream fill level
259364441979SMauro Carvalho Chehab 	 * below the size where we can start the next decode run. As userspace
259464441979SMauro Carvalho Chehab 	 * might have filled the output queue completely and might thus be
259564441979SMauro Carvalho Chehab 	 * blocked, we can't rely on the next qbuf to trigger the bitstream
259664441979SMauro Carvalho Chehab 	 * refill. Check if we have data to refill the bitstream now.
259764441979SMauro Carvalho Chehab 	 */
259864441979SMauro Carvalho Chehab 	mutex_lock(&ctx->bitstream_mutex);
259964441979SMauro Carvalho Chehab 	coda_fill_bitstream(ctx, NULL);
260064441979SMauro Carvalho Chehab 	mutex_unlock(&ctx->bitstream_mutex);
260164441979SMauro Carvalho Chehab }
260264441979SMauro Carvalho Chehab 
coda_decode_timeout(struct coda_ctx * ctx)260364441979SMauro Carvalho Chehab static void coda_decode_timeout(struct coda_ctx *ctx)
260464441979SMauro Carvalho Chehab {
260564441979SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *dst_buf;
260664441979SMauro Carvalho Chehab 
260764441979SMauro Carvalho Chehab 	/*
260864441979SMauro Carvalho Chehab 	 * For now this only handles the case where we would deadlock with
260964441979SMauro Carvalho Chehab 	 * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS,
261064441979SMauro Carvalho Chehab 	 * but after a failed decode run we would hold the context and wait for
261164441979SMauro Carvalho Chehab 	 * userspace to queue more buffers.
261264441979SMauro Carvalho Chehab 	 */
261364441979SMauro Carvalho Chehab 	if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))
261464441979SMauro Carvalho Chehab 		return;
261564441979SMauro Carvalho Chehab 
261664441979SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
261764441979SMauro Carvalho Chehab 	dst_buf->sequence = ctx->qsequence - 1;
261864441979SMauro Carvalho Chehab 
261964441979SMauro Carvalho Chehab 	coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
262064441979SMauro Carvalho Chehab }
262164441979SMauro Carvalho Chehab 
262264441979SMauro Carvalho Chehab const struct coda_context_ops coda_bit_decode_ops = {
262364441979SMauro Carvalho Chehab 	.queue_init = coda_decoder_queue_init,
262464441979SMauro Carvalho Chehab 	.reqbufs = coda_decoder_reqbufs,
262564441979SMauro Carvalho Chehab 	.start_streaming = coda_start_decoding,
262664441979SMauro Carvalho Chehab 	.prepare_run = coda_prepare_decode,
262764441979SMauro Carvalho Chehab 	.finish_run = coda_finish_decode,
262864441979SMauro Carvalho Chehab 	.run_timeout = coda_decode_timeout,
262964441979SMauro Carvalho Chehab 	.seq_init_work = coda_dec_seq_init_work,
263064441979SMauro Carvalho Chehab 	.seq_end_work = coda_seq_end_work,
263164441979SMauro Carvalho Chehab 	.release = coda_bit_release,
263264441979SMauro Carvalho Chehab };
263364441979SMauro Carvalho Chehab 
coda_irq_handler(int irq,void * data)263464441979SMauro Carvalho Chehab irqreturn_t coda_irq_handler(int irq, void *data)
263564441979SMauro Carvalho Chehab {
263664441979SMauro Carvalho Chehab 	struct coda_dev *dev = data;
263764441979SMauro Carvalho Chehab 	struct coda_ctx *ctx;
263864441979SMauro Carvalho Chehab 
263964441979SMauro Carvalho Chehab 	/* read status register to attend the IRQ */
264064441979SMauro Carvalho Chehab 	coda_read(dev, CODA_REG_BIT_INT_STATUS);
264164441979SMauro Carvalho Chehab 	coda_write(dev, 0, CODA_REG_BIT_INT_REASON);
264264441979SMauro Carvalho Chehab 	coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
264364441979SMauro Carvalho Chehab 		      CODA_REG_BIT_INT_CLEAR);
264464441979SMauro Carvalho Chehab 
264564441979SMauro Carvalho Chehab 	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
264664441979SMauro Carvalho Chehab 	if (ctx == NULL) {
264764441979SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev,
264864441979SMauro Carvalho Chehab 			 "Instance released before the end of transaction\n");
264964441979SMauro Carvalho Chehab 		return IRQ_HANDLED;
265064441979SMauro Carvalho Chehab 	}
265164441979SMauro Carvalho Chehab 
265264441979SMauro Carvalho Chehab 	trace_coda_bit_done(ctx);
265364441979SMauro Carvalho Chehab 
265464441979SMauro Carvalho Chehab 	if (ctx->aborting) {
265564441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "task has been aborted\n");
265664441979SMauro Carvalho Chehab 	}
265764441979SMauro Carvalho Chehab 
265864441979SMauro Carvalho Chehab 	if (coda_isbusy(ctx->dev)) {
265964441979SMauro Carvalho Chehab 		coda_dbg(1, ctx, "coda is still busy!!!!\n");
266064441979SMauro Carvalho Chehab 		return IRQ_NONE;
266164441979SMauro Carvalho Chehab 	}
266264441979SMauro Carvalho Chehab 
266364441979SMauro Carvalho Chehab 	complete(&ctx->completion);
266464441979SMauro Carvalho Chehab 
266564441979SMauro Carvalho Chehab 	return IRQ_HANDLED;
266664441979SMauro Carvalho Chehab }
2667