162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Coda multi-standard codec IP - BIT processor functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Vista Silicon S.L.
662306a36Sopenharmony_ci *    Javier Martin, <javier.martin@vista-silicon.com>
762306a36Sopenharmony_ci *    Xavier Duret
862306a36Sopenharmony_ci * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/irqreturn.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/log2.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/ratelimit.h>
1762306a36Sopenharmony_ci#include <linux/reset.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/videodev2.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <media/v4l2-common.h>
2262306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
2362306a36Sopenharmony_ci#include <media/v4l2-fh.h>
2462306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h>
2562306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
2662306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
2762306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "coda.h"
3062306a36Sopenharmony_ci#include "imx-vdoa.h"
3162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
3262306a36Sopenharmony_ci#include "trace.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define CODA_PARA_BUF_SIZE	(10 * 1024)
3562306a36Sopenharmony_ci#define CODA7_PS_BUF_SIZE	0x28000
3662306a36Sopenharmony_ci#define CODA9_PS_SAVE_SIZE	(512 * 1024)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define CODA_DEFAULT_GAMMA	4096
3962306a36Sopenharmony_ci#define CODA9_DEFAULT_GAMMA	24576	/* 0.75 * 32768 */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic inline int coda_is_initialized(struct coda_dev *dev)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline unsigned long coda_isbusy(struct coda_dev *dev)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return coda_read(dev, CODA_REG_BIT_BUSY);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int coda_wait_timeout(struct coda_dev *dev)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	while (coda_isbusy(dev)) {
5862306a36Sopenharmony_ci		if (time_after(jiffies, timeout))
5962306a36Sopenharmony_ci			return -ETIMEDOUT;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void coda_command_async(struct coda_ctx *ctx, int cmd)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (dev->devtype->product == CODA_HX4 ||
6962306a36Sopenharmony_ci	    dev->devtype->product == CODA_7541 ||
7062306a36Sopenharmony_ci	    dev->devtype->product == CODA_960) {
7162306a36Sopenharmony_ci		/* Restore context related registers to CODA */
7262306a36Sopenharmony_ci		coda_write(dev, ctx->bit_stream_param,
7362306a36Sopenharmony_ci				CODA_REG_BIT_BIT_STREAM_PARAM);
7462306a36Sopenharmony_ci		coda_write(dev, ctx->frm_dis_flg,
7562306a36Sopenharmony_ci				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
7662306a36Sopenharmony_ci		coda_write(dev, ctx->frame_mem_ctrl,
7762306a36Sopenharmony_ci				CODA_REG_BIT_FRAME_MEM_CTRL);
7862306a36Sopenharmony_ci		coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
8262306a36Sopenharmony_ci		coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
8362306a36Sopenharmony_ci		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
8962306a36Sopenharmony_ci	coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
9062306a36Sopenharmony_ci	coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	trace_coda_bit_run(ctx, cmd);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int coda_command_sync(struct coda_ctx *ctx, int cmd)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
10062306a36Sopenharmony_ci	int ret;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	lockdep_assert_held(&dev->coda_mutex);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	coda_command_async(ctx, cmd);
10562306a36Sopenharmony_ci	ret = coda_wait_timeout(dev);
10662306a36Sopenharmony_ci	trace_coda_bit_done(ctx);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return ret;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciint coda_hw_reset(struct coda_ctx *ctx)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
11462306a36Sopenharmony_ci	unsigned long timeout;
11562306a36Sopenharmony_ci	unsigned int idx;
11662306a36Sopenharmony_ci	int ret;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	lockdep_assert_held(&dev->coda_mutex);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (!dev->rstc)
12162306a36Sopenharmony_ci		return -ENOENT;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
12662306a36Sopenharmony_ci		timeout = jiffies + msecs_to_jiffies(100);
12762306a36Sopenharmony_ci		coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
12862306a36Sopenharmony_ci		while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
12962306a36Sopenharmony_ci			if (time_after(jiffies, timeout))
13062306a36Sopenharmony_ci				return -ETIME;
13162306a36Sopenharmony_ci			cpu_relax();
13262306a36Sopenharmony_ci		}
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ret = reset_control_reset(dev->rstc);
13662306a36Sopenharmony_ci	if (ret < 0)
13762306a36Sopenharmony_ci		return ret;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
14062306a36Sopenharmony_ci		coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
14162306a36Sopenharmony_ci	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
14262306a36Sopenharmony_ci	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
14362306a36Sopenharmony_ci	ret = coda_wait_timeout(dev);
14462306a36Sopenharmony_ci	coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return ret;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
15262306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
15362306a36Sopenharmony_ci	u32 rd_ptr;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
15662306a36Sopenharmony_ci	kfifo->out = (kfifo->in & ~kfifo->mask) |
15762306a36Sopenharmony_ci		      (rd_ptr - ctx->bitstream.paddr);
15862306a36Sopenharmony_ci	if (kfifo->out > kfifo->in)
15962306a36Sopenharmony_ci		kfifo->out -= kfifo->mask + 1;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
16562306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
16662306a36Sopenharmony_ci	u32 rd_ptr, wr_ptr;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
16962306a36Sopenharmony_ci	coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
17062306a36Sopenharmony_ci	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
17162306a36Sopenharmony_ci	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
17762306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
17862306a36Sopenharmony_ci	u32 wr_ptr;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
18162306a36Sopenharmony_ci	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned char *buf;
18762306a36Sopenharmony_ci	u32 n;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (size < 6)
19062306a36Sopenharmony_ci		size = 6;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	buf = kmalloc(size, GFP_KERNEL);
19362306a36Sopenharmony_ci	if (!buf)
19462306a36Sopenharmony_ci		return -ENOMEM;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	coda_h264_filler_nal(size, buf);
19762306a36Sopenharmony_ci	n = kfifo_in(&ctx->bitstream_fifo, buf, size);
19862306a36Sopenharmony_ci	kfree(buf);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return (n < size) ? -ENOSPC : 0;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciint coda_bitstream_flush(struct coda_ctx *ctx)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int ret;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit)
20862306a36Sopenharmony_ci		return 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH);
21162306a36Sopenharmony_ci	if (ret < 0) {
21262306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n");
21362306a36Sopenharmony_ci		return ret;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr,
21762306a36Sopenharmony_ci		   ctx->bitstream.size);
21862306a36Sopenharmony_ci	coda_kfifo_sync_to_device_full(ctx);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return (n < size) ? -ENOSPC : 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic u32 coda_buffer_parse_headers(struct coda_ctx *ctx,
23162306a36Sopenharmony_ci				     struct vb2_v4l2_buffer *src_buf,
23262306a36Sopenharmony_ci				     u32 payload)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
23562306a36Sopenharmony_ci	u32 size = 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	switch (ctx->codec->src_fourcc) {
23862306a36Sopenharmony_ci	case V4L2_PIX_FMT_MPEG2:
23962306a36Sopenharmony_ci		size = coda_mpeg2_parse_headers(ctx, vaddr, payload);
24062306a36Sopenharmony_ci		break;
24162306a36Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
24262306a36Sopenharmony_ci		size = coda_mpeg4_parse_headers(ctx, vaddr, payload);
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci	default:
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return size;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic bool coda_bitstream_try_queue(struct coda_ctx *ctx,
25262306a36Sopenharmony_ci				     struct vb2_v4l2_buffer *src_buf)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
25562306a36Sopenharmony_ci	u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
25662306a36Sopenharmony_ci	int ret;
25762306a36Sopenharmony_ci	int i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (coda_get_bitstream_payload(ctx) + payload + 512 >=
26062306a36Sopenharmony_ci	    ctx->bitstream.size)
26162306a36Sopenharmony_ci		return false;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (!vaddr) {
26462306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
26562306a36Sopenharmony_ci		return true;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (ctx->qsequence == 0 && payload < 512) {
26962306a36Sopenharmony_ci		/*
27062306a36Sopenharmony_ci		 * Add padding after the first buffer, if it is too small to be
27162306a36Sopenharmony_ci		 * fetched by the CODA, by repeating the headers. Without
27262306a36Sopenharmony_ci		 * repeated headers, or the first frame already queued, decoder
27362306a36Sopenharmony_ci		 * sequence initialization fails with error code 0x2000 on i.MX6
27462306a36Sopenharmony_ci		 * or error code 0x1 on i.MX51.
27562306a36Sopenharmony_ci		 */
27662306a36Sopenharmony_ci		u32 header_size = coda_buffer_parse_headers(ctx, src_buf,
27762306a36Sopenharmony_ci							    payload);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		if (header_size) {
28062306a36Sopenharmony_ci			coda_dbg(1, ctx, "pad with %u-byte header\n",
28162306a36Sopenharmony_ci				 header_size);
28262306a36Sopenharmony_ci			for (i = payload; i < 512; i += header_size) {
28362306a36Sopenharmony_ci				ret = coda_bitstream_queue(ctx, vaddr,
28462306a36Sopenharmony_ci							   header_size);
28562306a36Sopenharmony_ci				if (ret < 0) {
28662306a36Sopenharmony_ci					v4l2_err(&ctx->dev->v4l2_dev,
28762306a36Sopenharmony_ci						 "bitstream buffer overflow\n");
28862306a36Sopenharmony_ci					return false;
28962306a36Sopenharmony_ci				}
29062306a36Sopenharmony_ci				if (ctx->dev->devtype->product == CODA_960)
29162306a36Sopenharmony_ci					break;
29262306a36Sopenharmony_ci			}
29362306a36Sopenharmony_ci		} else {
29462306a36Sopenharmony_ci			coda_dbg(1, ctx,
29562306a36Sopenharmony_ci				 "could not parse header, sequence initialization might fail\n");
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		/* Add padding before the first buffer, if it is too small */
29962306a36Sopenharmony_ci		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
30062306a36Sopenharmony_ci			coda_h264_bitstream_pad(ctx, 512 - payload);
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ret = coda_bitstream_queue(ctx, vaddr, payload);
30462306a36Sopenharmony_ci	if (ret < 0) {
30562306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
30662306a36Sopenharmony_ci		return false;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	src_buf->sequence = ctx->qsequence++;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Sync read pointer to device */
31262306a36Sopenharmony_ci	if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
31362306a36Sopenharmony_ci		coda_kfifo_sync_to_device_write(ctx);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Set the stream-end flag after the last buffer is queued */
31662306a36Sopenharmony_ci	if (src_buf->flags & V4L2_BUF_FLAG_LAST)
31762306a36Sopenharmony_ci		coda_bit_stream_end_flag(ctx);
31862306a36Sopenharmony_ci	ctx->hold = false;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return true;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_civoid coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_buf;
32662306a36Sopenharmony_ci	struct coda_buffer_meta *meta;
32762306a36Sopenharmony_ci	u32 start;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	lockdep_assert_held(&ctx->bitstream_mutex);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
33262306a36Sopenharmony_ci		return;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
33562306a36Sopenharmony_ci		/*
33662306a36Sopenharmony_ci		 * Only queue two JPEGs into the bitstream buffer to keep
33762306a36Sopenharmony_ci		 * latency low. We need at least one complete buffer and the
33862306a36Sopenharmony_ci		 * header of another buffer (for prescan) in the bitstream.
33962306a36Sopenharmony_ci		 */
34062306a36Sopenharmony_ci		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
34162306a36Sopenharmony_ci		    ctx->num_metas > 1)
34262306a36Sopenharmony_ci			break;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		if (ctx->num_internal_frames &&
34562306a36Sopenharmony_ci		    ctx->num_metas >= ctx->num_internal_frames) {
34662306a36Sopenharmony_ci			meta = list_first_entry(&ctx->buffer_meta_list,
34762306a36Sopenharmony_ci						struct coda_buffer_meta, list);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci			/*
35062306a36Sopenharmony_ci			 * If we managed to fill in at least a full reorder
35162306a36Sopenharmony_ci			 * window of buffers (num_internal_frames is a
35262306a36Sopenharmony_ci			 * conservative estimate for this) and the bitstream
35362306a36Sopenharmony_ci			 * prefetcher has at least 2 256 bytes periods beyond
35462306a36Sopenharmony_ci			 * the first buffer to fetch, we can safely stop queuing
35562306a36Sopenharmony_ci			 * in order to limit the decoder drain latency.
35662306a36Sopenharmony_ci			 */
35762306a36Sopenharmony_ci			if (coda_bitstream_can_fetch_past(ctx, meta->end))
35862306a36Sopenharmony_ci				break;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		/* Drop frames that do not start/end with a SOI/EOI markers */
36462306a36Sopenharmony_ci		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
36562306a36Sopenharmony_ci		    !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) {
36662306a36Sopenharmony_ci			v4l2_err(&ctx->dev->v4l2_dev,
36762306a36Sopenharmony_ci				 "dropping invalid JPEG frame %d\n",
36862306a36Sopenharmony_ci				 ctx->qsequence);
36962306a36Sopenharmony_ci			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
37062306a36Sopenharmony_ci			if (buffer_list) {
37162306a36Sopenharmony_ci				struct v4l2_m2m_buffer *m2m_buf;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci				m2m_buf = container_of(src_buf,
37462306a36Sopenharmony_ci						       struct v4l2_m2m_buffer,
37562306a36Sopenharmony_ci						       vb);
37662306a36Sopenharmony_ci				list_add_tail(&m2m_buf->list, buffer_list);
37762306a36Sopenharmony_ci			} else {
37862306a36Sopenharmony_ci				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
37962306a36Sopenharmony_ci			}
38062306a36Sopenharmony_ci			continue;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		/* Dump empty buffers */
38462306a36Sopenharmony_ci		if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) {
38562306a36Sopenharmony_ci			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
38662306a36Sopenharmony_ci			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
38762306a36Sopenharmony_ci			continue;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		/* Buffer start position */
39162306a36Sopenharmony_ci		start = ctx->bitstream_fifo.kfifo.in;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		if (coda_bitstream_try_queue(ctx, src_buf)) {
39462306a36Sopenharmony_ci			/*
39562306a36Sopenharmony_ci			 * Source buffer is queued in the bitstream ringbuffer;
39662306a36Sopenharmony_ci			 * queue the timestamp and mark source buffer as done
39762306a36Sopenharmony_ci			 */
39862306a36Sopenharmony_ci			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci			meta = kmalloc(sizeof(*meta), GFP_KERNEL);
40162306a36Sopenharmony_ci			if (meta) {
40262306a36Sopenharmony_ci				meta->sequence = src_buf->sequence;
40362306a36Sopenharmony_ci				meta->timecode = src_buf->timecode;
40462306a36Sopenharmony_ci				meta->timestamp = src_buf->vb2_buf.timestamp;
40562306a36Sopenharmony_ci				meta->start = start;
40662306a36Sopenharmony_ci				meta->end = ctx->bitstream_fifo.kfifo.in;
40762306a36Sopenharmony_ci				meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST;
40862306a36Sopenharmony_ci				if (meta->last)
40962306a36Sopenharmony_ci					coda_dbg(1, ctx, "marking last meta");
41062306a36Sopenharmony_ci				spin_lock(&ctx->buffer_meta_lock);
41162306a36Sopenharmony_ci				list_add_tail(&meta->list,
41262306a36Sopenharmony_ci					      &ctx->buffer_meta_list);
41362306a36Sopenharmony_ci				ctx->num_metas++;
41462306a36Sopenharmony_ci				spin_unlock(&ctx->buffer_meta_lock);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci				trace_coda_bit_queue(ctx, src_buf, meta);
41762306a36Sopenharmony_ci			}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci			if (buffer_list) {
42062306a36Sopenharmony_ci				struct v4l2_m2m_buffer *m2m_buf;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci				m2m_buf = container_of(src_buf,
42362306a36Sopenharmony_ci						       struct v4l2_m2m_buffer,
42462306a36Sopenharmony_ci						       vb);
42562306a36Sopenharmony_ci				list_add_tail(&m2m_buf->list, buffer_list);
42662306a36Sopenharmony_ci			} else {
42762306a36Sopenharmony_ci				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
42862306a36Sopenharmony_ci			}
42962306a36Sopenharmony_ci		} else {
43062306a36Sopenharmony_ci			break;
43162306a36Sopenharmony_ci		}
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_civoid coda_bit_stream_end_flag(struct coda_ctx *ctx)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* If this context is currently running, update the hardware flag */
44262306a36Sopenharmony_ci	if ((dev->devtype->product == CODA_960) &&
44362306a36Sopenharmony_ci	    coda_isbusy(dev) &&
44462306a36Sopenharmony_ci	    (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
44562306a36Sopenharmony_ci		coda_write(dev, ctx->bit_stream_param,
44662306a36Sopenharmony_ci			   CODA_REG_BIT_BIT_STREAM_PARAM);
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
45362306a36Sopenharmony_ci	u32 *p = ctx->parabuf.vaddr;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (dev->devtype->product == CODA_DX6)
45662306a36Sopenharmony_ci		p[index] = value;
45762306a36Sopenharmony_ci	else
45862306a36Sopenharmony_ci		p[index ^ 1] = value;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic inline int coda_alloc_context_buf(struct coda_ctx *ctx,
46262306a36Sopenharmony_ci					 struct coda_aux_buf *buf, size_t size,
46362306a36Sopenharmony_ci					 const char *name)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void coda_free_framebuffers(struct coda_ctx *ctx)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	int i;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
47462306a36Sopenharmony_ci		coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf);
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int coda_alloc_framebuffers(struct coda_ctx *ctx,
47862306a36Sopenharmony_ci				   struct coda_q_data *q_data, u32 fourcc)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
48162306a36Sopenharmony_ci	unsigned int ysize, ycbcr_size;
48262306a36Sopenharmony_ci	int ret;
48362306a36Sopenharmony_ci	int i;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
48662306a36Sopenharmony_ci	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 ||
48762306a36Sopenharmony_ci	    ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 ||
48862306a36Sopenharmony_ci	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4)
48962306a36Sopenharmony_ci		ysize = round_up(q_data->rect.width, 16) *
49062306a36Sopenharmony_ci			round_up(q_data->rect.height, 16);
49162306a36Sopenharmony_ci	else
49262306a36Sopenharmony_ci		ysize = round_up(q_data->rect.width, 8) * q_data->rect.height;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
49562306a36Sopenharmony_ci		ycbcr_size = round_up(ysize, 4096) + ysize / 2;
49662306a36Sopenharmony_ci	else
49762306a36Sopenharmony_ci		ycbcr_size = ysize + ysize / 2;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* Allocate frame buffers */
50062306a36Sopenharmony_ci	for (i = 0; i < ctx->num_internal_frames; i++) {
50162306a36Sopenharmony_ci		size_t size = ycbcr_size;
50262306a36Sopenharmony_ci		char *name;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		/* Add space for mvcol buffers */
50562306a36Sopenharmony_ci		if (dev->devtype->product != CODA_DX6 &&
50662306a36Sopenharmony_ci		    (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
50762306a36Sopenharmony_ci		     (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0)))
50862306a36Sopenharmony_ci			size += ysize / 4;
50962306a36Sopenharmony_ci		name = kasprintf(GFP_KERNEL, "fb%d", i);
51062306a36Sopenharmony_ci		if (!name) {
51162306a36Sopenharmony_ci			coda_free_framebuffers(ctx);
51262306a36Sopenharmony_ci			return -ENOMEM;
51362306a36Sopenharmony_ci		}
51462306a36Sopenharmony_ci		ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf,
51562306a36Sopenharmony_ci					     size, name);
51662306a36Sopenharmony_ci		kfree(name);
51762306a36Sopenharmony_ci		if (ret < 0) {
51862306a36Sopenharmony_ci			coda_free_framebuffers(ctx);
51962306a36Sopenharmony_ci			return ret;
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* Register frame buffers in the parameter buffer */
52462306a36Sopenharmony_ci	for (i = 0; i < ctx->num_internal_frames; i++) {
52562306a36Sopenharmony_ci		u32 y, cb, cr, mvcol;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		/* Start addresses of Y, Cb, Cr planes */
52862306a36Sopenharmony_ci		y = ctx->internal_frames[i].buf.paddr;
52962306a36Sopenharmony_ci		cb = y + ysize;
53062306a36Sopenharmony_ci		cr = y + ysize + ysize/4;
53162306a36Sopenharmony_ci		mvcol = y + ysize + ysize/4 + ysize/4;
53262306a36Sopenharmony_ci		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) {
53362306a36Sopenharmony_ci			cb = round_up(cb, 4096);
53462306a36Sopenharmony_ci			mvcol = cb + ysize/2;
53562306a36Sopenharmony_ci			cr = 0;
53662306a36Sopenharmony_ci			/* Packed 20-bit MSB of base addresses */
53762306a36Sopenharmony_ci			/* YYYYYCCC, CCyyyyyc, cccc.... */
53862306a36Sopenharmony_ci			y = (y & 0xfffff000) | cb >> 20;
53962306a36Sopenharmony_ci			cb = (cb & 0x000ff000) << 12;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci		coda_parabuf_write(ctx, i * 3 + 0, y);
54262306a36Sopenharmony_ci		coda_parabuf_write(ctx, i * 3 + 1, cb);
54362306a36Sopenharmony_ci		coda_parabuf_write(ctx, i * 3 + 2, cr);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		if (dev->devtype->product == CODA_DX6)
54662306a36Sopenharmony_ci			continue;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		/* mvcol buffer for h.264 and mpeg4 */
54962306a36Sopenharmony_ci		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
55062306a36Sopenharmony_ci			coda_parabuf_write(ctx, 96 + i, mvcol);
55162306a36Sopenharmony_ci		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0)
55262306a36Sopenharmony_ci			coda_parabuf_write(ctx, 97, mvcol);
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void coda_free_context_buffers(struct coda_ctx *ctx)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	coda_free_aux_buf(dev, &ctx->slicebuf);
56362306a36Sopenharmony_ci	coda_free_aux_buf(dev, &ctx->psbuf);
56462306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6)
56562306a36Sopenharmony_ci		coda_free_aux_buf(dev, &ctx->workbuf);
56662306a36Sopenharmony_ci	coda_free_aux_buf(dev, &ctx->parabuf);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int coda_alloc_context_buffers(struct coda_ctx *ctx,
57062306a36Sopenharmony_ci				      struct coda_q_data *q_data)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
57362306a36Sopenharmony_ci	size_t size;
57462306a36Sopenharmony_ci	int ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (!ctx->parabuf.vaddr) {
57762306a36Sopenharmony_ci		ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
57862306a36Sopenharmony_ci					     CODA_PARA_BUF_SIZE, "parabuf");
57962306a36Sopenharmony_ci		if (ret < 0)
58062306a36Sopenharmony_ci			return ret;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (dev->devtype->product == CODA_DX6)
58462306a36Sopenharmony_ci		return 0;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
58762306a36Sopenharmony_ci		/* worst case slice size */
58862306a36Sopenharmony_ci		size = (DIV_ROUND_UP(q_data->rect.width, 16) *
58962306a36Sopenharmony_ci			DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512;
59062306a36Sopenharmony_ci		ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
59162306a36Sopenharmony_ci					     "slicebuf");
59262306a36Sopenharmony_ci		if (ret < 0)
59362306a36Sopenharmony_ci			goto err;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 ||
59762306a36Sopenharmony_ci				  dev->devtype->product == CODA_7541)) {
59862306a36Sopenharmony_ci		ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
59962306a36Sopenharmony_ci					     CODA7_PS_BUF_SIZE, "psbuf");
60062306a36Sopenharmony_ci		if (ret < 0)
60162306a36Sopenharmony_ci			goto err;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (!ctx->workbuf.vaddr) {
60562306a36Sopenharmony_ci		size = dev->devtype->workbuf_size;
60662306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960 &&
60762306a36Sopenharmony_ci		    q_data->fourcc == V4L2_PIX_FMT_H264)
60862306a36Sopenharmony_ci			size += CODA9_PS_SAVE_SIZE;
60962306a36Sopenharmony_ci		ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size,
61062306a36Sopenharmony_ci					     "workbuf");
61162306a36Sopenharmony_ci		if (ret < 0)
61262306a36Sopenharmony_ci			goto err;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	return 0;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cierr:
61862306a36Sopenharmony_ci	coda_free_context_buffers(ctx);
61962306a36Sopenharmony_ci	return ret;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
62362306a36Sopenharmony_ci			      int header_code, u8 *header, int *size)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct vb2_buffer *vb = &buf->vb2_buf;
62662306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
62762306a36Sopenharmony_ci	struct coda_q_data *q_data_src;
62862306a36Sopenharmony_ci	struct v4l2_rect *r;
62962306a36Sopenharmony_ci	size_t bufsize;
63062306a36Sopenharmony_ci	int ret;
63162306a36Sopenharmony_ci	int i;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
63462306a36Sopenharmony_ci		memset(vb2_plane_vaddr(vb, 0), 0, 64);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0),
63762306a36Sopenharmony_ci		   CODA_CMD_ENC_HEADER_BB_START);
63862306a36Sopenharmony_ci	bufsize = vb2_plane_size(vb, 0);
63962306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
64062306a36Sopenharmony_ci		bufsize /= 1024;
64162306a36Sopenharmony_ci	coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
64262306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960 &&
64362306a36Sopenharmony_ci	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 &&
64462306a36Sopenharmony_ci	    header_code == CODA_HEADER_H264_SPS) {
64562306a36Sopenharmony_ci		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
64662306a36Sopenharmony_ci		r = &q_data_src->rect;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		if (r->width % 16 || r->height % 16) {
64962306a36Sopenharmony_ci			u32 crop_right = round_up(r->width, 16) -  r->width;
65062306a36Sopenharmony_ci			u32 crop_bottom = round_up(r->height, 16) - r->height;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci			coda_write(dev, crop_right,
65362306a36Sopenharmony_ci				   CODA9_CMD_ENC_HEADER_FRAME_CROP_H);
65462306a36Sopenharmony_ci			coda_write(dev, crop_bottom,
65562306a36Sopenharmony_ci				   CODA9_CMD_ENC_HEADER_FRAME_CROP_V);
65662306a36Sopenharmony_ci			header_code |= CODA9_HEADER_FRAME_CROP;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci	coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
66062306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
66162306a36Sopenharmony_ci	if (ret < 0) {
66262306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
66362306a36Sopenharmony_ci		return ret;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
66762306a36Sopenharmony_ci		for (i = 63; i > 0; i--)
66862306a36Sopenharmony_ci			if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0)
66962306a36Sopenharmony_ci				break;
67062306a36Sopenharmony_ci		*size = i + 1;
67162306a36Sopenharmony_ci	} else {
67262306a36Sopenharmony_ci		*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
67362306a36Sopenharmony_ci			coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci	memcpy(header, vb2_plane_vaddr(vb, 0), *size);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic u32 coda_slice_mode(struct coda_ctx *ctx)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	int size, unit;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	switch (ctx->params.slice_mode) {
68562306a36Sopenharmony_ci	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
68662306a36Sopenharmony_ci	default:
68762306a36Sopenharmony_ci		return 0;
68862306a36Sopenharmony_ci	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB:
68962306a36Sopenharmony_ci		size = ctx->params.slice_max_mb;
69062306a36Sopenharmony_ci		unit = 1;
69162306a36Sopenharmony_ci		break;
69262306a36Sopenharmony_ci	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES:
69362306a36Sopenharmony_ci		size = ctx->params.slice_max_bits;
69462306a36Sopenharmony_ci		unit = 0;
69562306a36Sopenharmony_ci		break;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) |
69962306a36Sopenharmony_ci	       ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) |
70062306a36Sopenharmony_ci	       ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET);
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic int coda_enc_param_change(struct coda_ctx *ctx)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
70662306a36Sopenharmony_ci	u32 change_enable = 0;
70762306a36Sopenharmony_ci	u32 success;
70862306a36Sopenharmony_ci	int ret;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (ctx->params.gop_size_changed) {
71162306a36Sopenharmony_ci		change_enable |= CODA_PARAM_CHANGE_RC_GOP;
71262306a36Sopenharmony_ci		coda_write(dev, ctx->params.gop_size,
71362306a36Sopenharmony_ci			   CODA_CMD_ENC_PARAM_RC_GOP);
71462306a36Sopenharmony_ci		ctx->gopcounter = ctx->params.gop_size - 1;
71562306a36Sopenharmony_ci		ctx->params.gop_size_changed = false;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci	if (ctx->params.h264_intra_qp_changed) {
71862306a36Sopenharmony_ci		coda_dbg(1, ctx, "parameter change: intra Qp %u\n",
71962306a36Sopenharmony_ci			 ctx->params.h264_intra_qp);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		if (ctx->params.bitrate) {
72262306a36Sopenharmony_ci			change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP;
72362306a36Sopenharmony_ci			coda_write(dev, ctx->params.h264_intra_qp,
72462306a36Sopenharmony_ci				   CODA_CMD_ENC_PARAM_RC_INTRA_QP);
72562306a36Sopenharmony_ci		}
72662306a36Sopenharmony_ci		ctx->params.h264_intra_qp_changed = false;
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci	if (ctx->params.bitrate_changed) {
72962306a36Sopenharmony_ci		coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n",
73062306a36Sopenharmony_ci			 ctx->params.bitrate);
73162306a36Sopenharmony_ci		change_enable |= CODA_PARAM_CHANGE_RC_BITRATE;
73262306a36Sopenharmony_ci		coda_write(dev, ctx->params.bitrate,
73362306a36Sopenharmony_ci			   CODA_CMD_ENC_PARAM_RC_BITRATE);
73462306a36Sopenharmony_ci		ctx->params.bitrate_changed = false;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci	if (ctx->params.framerate_changed) {
73762306a36Sopenharmony_ci		coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n",
73862306a36Sopenharmony_ci			 ctx->params.framerate & 0xffff,
73962306a36Sopenharmony_ci			 (ctx->params.framerate >> 16) + 1);
74062306a36Sopenharmony_ci		change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE;
74162306a36Sopenharmony_ci		coda_write(dev, ctx->params.framerate,
74262306a36Sopenharmony_ci			   CODA_CMD_ENC_PARAM_RC_FRAME_RATE);
74362306a36Sopenharmony_ci		ctx->params.framerate_changed = false;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	if (ctx->params.intra_refresh_changed) {
74662306a36Sopenharmony_ci		coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n",
74762306a36Sopenharmony_ci			 ctx->params.intra_refresh);
74862306a36Sopenharmony_ci		change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM;
74962306a36Sopenharmony_ci		coda_write(dev, ctx->params.intra_refresh,
75062306a36Sopenharmony_ci			   CODA_CMD_ENC_PARAM_INTRA_MB_NUM);
75162306a36Sopenharmony_ci		ctx->params.intra_refresh_changed = false;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci	if (ctx->params.slice_mode_changed) {
75462306a36Sopenharmony_ci		change_enable |= CODA_PARAM_CHANGE_SLICE_MODE;
75562306a36Sopenharmony_ci		coda_write(dev, coda_slice_mode(ctx),
75662306a36Sopenharmony_ci			   CODA_CMD_ENC_PARAM_SLICE_MODE);
75762306a36Sopenharmony_ci		ctx->params.slice_mode_changed = false;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (!change_enable)
76162306a36Sopenharmony_ci		return 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER);
76662306a36Sopenharmony_ci	if (ret < 0)
76762306a36Sopenharmony_ci		return ret;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS);
77062306a36Sopenharmony_ci	if (success != 1)
77162306a36Sopenharmony_ci		coda_dbg(1, ctx, "parameter change failed: %u\n", success);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return 0;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	phys_addr_t ret;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	size = round_up(size, 1024);
78162306a36Sopenharmony_ci	if (size > iram->remaining)
78262306a36Sopenharmony_ci		return 0;
78362306a36Sopenharmony_ci	iram->remaining -= size;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ret = iram->next_paddr;
78662306a36Sopenharmony_ci	iram->next_paddr += size;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return ret;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void coda_setup_iram(struct coda_ctx *ctx)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	struct coda_iram_info *iram_info = &ctx->iram_info;
79462306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
79562306a36Sopenharmony_ci	int w64, w128;
79662306a36Sopenharmony_ci	int mb_width;
79762306a36Sopenharmony_ci	int dbk_bits;
79862306a36Sopenharmony_ci	int bit_bits;
79962306a36Sopenharmony_ci	int ip_bits;
80062306a36Sopenharmony_ci	int me_bits;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	memset(iram_info, 0, sizeof(*iram_info));
80362306a36Sopenharmony_ci	iram_info->next_paddr = dev->iram.paddr;
80462306a36Sopenharmony_ci	iram_info->remaining = dev->iram.size;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (!dev->iram.vaddr)
80762306a36Sopenharmony_ci		return;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	switch (dev->devtype->product) {
81062306a36Sopenharmony_ci	case CODA_HX4:
81162306a36Sopenharmony_ci		dbk_bits = CODA7_USE_HOST_DBK_ENABLE;
81262306a36Sopenharmony_ci		bit_bits = CODA7_USE_HOST_BIT_ENABLE;
81362306a36Sopenharmony_ci		ip_bits = CODA7_USE_HOST_IP_ENABLE;
81462306a36Sopenharmony_ci		me_bits = CODA7_USE_HOST_ME_ENABLE;
81562306a36Sopenharmony_ci		break;
81662306a36Sopenharmony_ci	case CODA_7541:
81762306a36Sopenharmony_ci		dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
81862306a36Sopenharmony_ci		bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
81962306a36Sopenharmony_ci		ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
82062306a36Sopenharmony_ci		me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE;
82162306a36Sopenharmony_ci		break;
82262306a36Sopenharmony_ci	case CODA_960:
82362306a36Sopenharmony_ci		dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
82462306a36Sopenharmony_ci		bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
82562306a36Sopenharmony_ci		ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
82662306a36Sopenharmony_ci		me_bits = 0;
82762306a36Sopenharmony_ci		break;
82862306a36Sopenharmony_ci	default: /* CODA_DX6 */
82962306a36Sopenharmony_ci		return;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (ctx->inst_type == CODA_INST_ENCODER) {
83362306a36Sopenharmony_ci		struct coda_q_data *q_data_src;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
83662306a36Sopenharmony_ci		mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16);
83762306a36Sopenharmony_ci		w128 = mb_width * 128;
83862306a36Sopenharmony_ci		w64 = mb_width * 64;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		/* Prioritize in case IRAM is too small for everything */
84162306a36Sopenharmony_ci		if (dev->devtype->product == CODA_HX4 ||
84262306a36Sopenharmony_ci		    dev->devtype->product == CODA_7541) {
84362306a36Sopenharmony_ci			iram_info->search_ram_size = round_up(mb_width * 16 *
84462306a36Sopenharmony_ci							      36 + 2048, 1024);
84562306a36Sopenharmony_ci			iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
84662306a36Sopenharmony_ci						iram_info->search_ram_size);
84762306a36Sopenharmony_ci			if (!iram_info->search_ram_paddr) {
84862306a36Sopenharmony_ci				pr_err("IRAM is smaller than the search ram size\n");
84962306a36Sopenharmony_ci				goto out;
85062306a36Sopenharmony_ci			}
85162306a36Sopenharmony_ci			iram_info->axi_sram_use |= me_bits;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		/* Only H.264BP and H.263P3 are considered */
85562306a36Sopenharmony_ci		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
85662306a36Sopenharmony_ci		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
85762306a36Sopenharmony_ci		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
85862306a36Sopenharmony_ci			goto out;
85962306a36Sopenharmony_ci		iram_info->axi_sram_use |= dbk_bits;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
86262306a36Sopenharmony_ci		if (!iram_info->buf_bit_use)
86362306a36Sopenharmony_ci			goto out;
86462306a36Sopenharmony_ci		iram_info->axi_sram_use |= bit_bits;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
86762306a36Sopenharmony_ci		if (!iram_info->buf_ip_ac_dc_use)
86862306a36Sopenharmony_ci			goto out;
86962306a36Sopenharmony_ci		iram_info->axi_sram_use |= ip_bits;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		/* OVL and BTP disabled for encoder */
87262306a36Sopenharmony_ci	} else if (ctx->inst_type == CODA_INST_DECODER) {
87362306a36Sopenharmony_ci		struct coda_q_data *q_data_dst;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
87662306a36Sopenharmony_ci		mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
87762306a36Sopenharmony_ci		w128 = mb_width * 128;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
88062306a36Sopenharmony_ci		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
88162306a36Sopenharmony_ci		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
88262306a36Sopenharmony_ci			goto out;
88362306a36Sopenharmony_ci		iram_info->axi_sram_use |= dbk_bits;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
88662306a36Sopenharmony_ci		if (!iram_info->buf_bit_use)
88762306a36Sopenharmony_ci			goto out;
88862306a36Sopenharmony_ci		iram_info->axi_sram_use |= bit_bits;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
89162306a36Sopenharmony_ci		if (!iram_info->buf_ip_ac_dc_use)
89262306a36Sopenharmony_ci			goto out;
89362306a36Sopenharmony_ci		iram_info->axi_sram_use |= ip_bits;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		/* OVL and BTP unused as there is no VC1 support yet */
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ciout:
89962306a36Sopenharmony_ci	if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
90062306a36Sopenharmony_ci		coda_dbg(1, ctx, "IRAM smaller than needed\n");
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (dev->devtype->product == CODA_HX4 ||
90362306a36Sopenharmony_ci	    dev->devtype->product == CODA_7541) {
90462306a36Sopenharmony_ci		/* TODO - Enabling these causes picture errors on CODA7541 */
90562306a36Sopenharmony_ci		if (ctx->inst_type == CODA_INST_DECODER) {
90662306a36Sopenharmony_ci			/* fw 1.4.50 */
90762306a36Sopenharmony_ci			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
90862306a36Sopenharmony_ci						     CODA7_USE_IP_ENABLE);
90962306a36Sopenharmony_ci		} else {
91062306a36Sopenharmony_ci			/* fw 13.4.29 */
91162306a36Sopenharmony_ci			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
91262306a36Sopenharmony_ci						     CODA7_USE_HOST_DBK_ENABLE |
91362306a36Sopenharmony_ci						     CODA7_USE_IP_ENABLE |
91462306a36Sopenharmony_ci						     CODA7_USE_DBK_ENABLE);
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic u32 coda_supported_firmwares[] = {
92062306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
92162306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50),
92262306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
92362306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
92462306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9),
92562306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10),
92662306a36Sopenharmony_ci	CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1),
92762306a36Sopenharmony_ci};
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic bool coda_firmware_supported(u32 vernum)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	int i;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
93462306a36Sopenharmony_ci		if (vernum == coda_supported_firmwares[i])
93562306a36Sopenharmony_ci			return true;
93662306a36Sopenharmony_ci	return false;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ciint coda_check_firmware(struct coda_dev *dev)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	u16 product, major, minor, release;
94262306a36Sopenharmony_ci	u32 data;
94362306a36Sopenharmony_ci	int ret;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	ret = clk_prepare_enable(dev->clk_per);
94662306a36Sopenharmony_ci	if (ret)
94762306a36Sopenharmony_ci		goto err_clk_per;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	ret = clk_prepare_enable(dev->clk_ahb);
95062306a36Sopenharmony_ci	if (ret)
95162306a36Sopenharmony_ci		goto err_clk_ahb;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
95462306a36Sopenharmony_ci	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
95562306a36Sopenharmony_ci	coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
95662306a36Sopenharmony_ci	coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
95762306a36Sopenharmony_ci	coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
95862306a36Sopenharmony_ci	if (coda_wait_timeout(dev)) {
95962306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
96062306a36Sopenharmony_ci		ret = -EIO;
96162306a36Sopenharmony_ci		goto err_run_cmd;
96262306a36Sopenharmony_ci	}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
96562306a36Sopenharmony_ci		data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
96662306a36Sopenharmony_ci		v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
96762306a36Sopenharmony_ci			  data);
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/* Check we are compatible with the loaded firmware */
97162306a36Sopenharmony_ci	data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
97262306a36Sopenharmony_ci	product = CODA_FIRMWARE_PRODUCT(data);
97362306a36Sopenharmony_ci	major = CODA_FIRMWARE_MAJOR(data);
97462306a36Sopenharmony_ci	minor = CODA_FIRMWARE_MINOR(data);
97562306a36Sopenharmony_ci	release = CODA_FIRMWARE_RELEASE(data);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk_per);
97862306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk_ahb);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (product != dev->devtype->product) {
98162306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
98262306a36Sopenharmony_ci			 "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n",
98362306a36Sopenharmony_ci			 coda_product_name(dev->devtype->product),
98462306a36Sopenharmony_ci			 coda_product_name(product), major, minor, release);
98562306a36Sopenharmony_ci		return -EINVAL;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
98962306a36Sopenharmony_ci		  coda_product_name(product));
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	if (coda_firmware_supported(data)) {
99262306a36Sopenharmony_ci		v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
99362306a36Sopenharmony_ci			  major, minor, release);
99462306a36Sopenharmony_ci	} else {
99562306a36Sopenharmony_ci		v4l2_warn(&dev->v4l2_dev,
99662306a36Sopenharmony_ci			  "Unsupported firmware version: %u.%u.%u\n",
99762306a36Sopenharmony_ci			  major, minor, release);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cierr_run_cmd:
100362306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk_ahb);
100462306a36Sopenharmony_cierr_clk_ahb:
100562306a36Sopenharmony_ci	clk_disable_unprepare(dev->clk_per);
100662306a36Sopenharmony_cierr_clk_per:
100762306a36Sopenharmony_ci	return ret;
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cistatic void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	u32 cache_size, cache_config;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) {
101562306a36Sopenharmony_ci		/* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */
101662306a36Sopenharmony_ci		cache_size = 0x20262024;
101762306a36Sopenharmony_ci		cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET;
101862306a36Sopenharmony_ci	} else {
101962306a36Sopenharmony_ci		/* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */
102062306a36Sopenharmony_ci		cache_size = 0x02440243;
102162306a36Sopenharmony_ci		cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci	coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE);
102462306a36Sopenharmony_ci	if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) {
102562306a36Sopenharmony_ci		cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
102662306a36Sopenharmony_ci				16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET |
102762306a36Sopenharmony_ci				0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET;
102862306a36Sopenharmony_ci	} else {
102962306a36Sopenharmony_ci		cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
103062306a36Sopenharmony_ci				8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET |
103162306a36Sopenharmony_ci				8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci	coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci/*
103762306a36Sopenharmony_ci * Encoder context operations
103862306a36Sopenharmony_ci */
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic int coda_encoder_reqbufs(struct coda_ctx *ctx,
104162306a36Sopenharmony_ci				struct v4l2_requestbuffers *rb)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct coda_q_data *q_data_src;
104462306a36Sopenharmony_ci	int ret;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
104762306a36Sopenharmony_ci		return 0;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	if (rb->count) {
105062306a36Sopenharmony_ci		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
105162306a36Sopenharmony_ci		ret = coda_alloc_context_buffers(ctx, q_data_src);
105262306a36Sopenharmony_ci		if (ret < 0)
105362306a36Sopenharmony_ci			return ret;
105462306a36Sopenharmony_ci	} else {
105562306a36Sopenharmony_ci		coda_free_context_buffers(ctx);
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return 0;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic int coda_start_encoding(struct coda_ctx *ctx)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
106462306a36Sopenharmony_ci	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
106562306a36Sopenharmony_ci	struct coda_q_data *q_data_src, *q_data_dst;
106662306a36Sopenharmony_ci	u32 bitstream_buf, bitstream_size;
106762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *buf;
106862306a36Sopenharmony_ci	int gamma, ret, value;
106962306a36Sopenharmony_ci	u32 dst_fourcc;
107062306a36Sopenharmony_ci	int num_fb;
107162306a36Sopenharmony_ci	u32 stride;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
107462306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
107562306a36Sopenharmony_ci	dst_fourcc = q_data_dst->fourcc;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
107862306a36Sopenharmony_ci	bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0);
107962306a36Sopenharmony_ci	bitstream_size = q_data_dst->sizeimage;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (!coda_is_initialized(dev)) {
108262306a36Sopenharmony_ci		v4l2_err(v4l2_dev, "coda is not initialized.\n");
108362306a36Sopenharmony_ci		return -EFAULT;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
108762306a36Sopenharmony_ci		if (!ctx->params.jpeg_qmat_tab[0]) {
108862306a36Sopenharmony_ci			ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
108962306a36Sopenharmony_ci			if (!ctx->params.jpeg_qmat_tab[0])
109062306a36Sopenharmony_ci				return -ENOMEM;
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci		if (!ctx->params.jpeg_qmat_tab[1]) {
109362306a36Sopenharmony_ci			ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
109462306a36Sopenharmony_ci			if (!ctx->params.jpeg_qmat_tab[1])
109562306a36Sopenharmony_ci				return -ENOMEM;
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci		coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	mutex_lock(&dev->coda_mutex);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
110362306a36Sopenharmony_ci	coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
110462306a36Sopenharmony_ci	coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
110562306a36Sopenharmony_ci	switch (dev->devtype->product) {
110662306a36Sopenharmony_ci	case CODA_DX6:
110762306a36Sopenharmony_ci		coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
110862306a36Sopenharmony_ci			CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
110962306a36Sopenharmony_ci		break;
111062306a36Sopenharmony_ci	case CODA_960:
111162306a36Sopenharmony_ci		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
111262306a36Sopenharmony_ci		fallthrough;
111362306a36Sopenharmony_ci	case CODA_HX4:
111462306a36Sopenharmony_ci	case CODA_7541:
111562306a36Sopenharmony_ci		coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
111662306a36Sopenharmony_ci			CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
111762306a36Sopenharmony_ci		break;
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
112162306a36Sopenharmony_ci				 CODA9_FRAME_TILED2LINEAR);
112262306a36Sopenharmony_ci	if (q_data_src->fourcc == V4L2_PIX_FMT_NV12)
112362306a36Sopenharmony_ci		ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
112462306a36Sopenharmony_ci	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
112562306a36Sopenharmony_ci		ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR;
112662306a36Sopenharmony_ci	coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (dev->devtype->product == CODA_DX6) {
112962306a36Sopenharmony_ci		/* Configure the coda */
113062306a36Sopenharmony_ci		coda_write(dev, dev->iram.paddr,
113162306a36Sopenharmony_ci			   CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* Could set rotation here if needed */
113562306a36Sopenharmony_ci	value = 0;
113662306a36Sopenharmony_ci	switch (dev->devtype->product) {
113762306a36Sopenharmony_ci	case CODA_DX6:
113862306a36Sopenharmony_ci		value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK)
113962306a36Sopenharmony_ci			<< CODADX6_PICWIDTH_OFFSET;
114062306a36Sopenharmony_ci		value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK)
114162306a36Sopenharmony_ci			 << CODA_PICHEIGHT_OFFSET;
114262306a36Sopenharmony_ci		break;
114362306a36Sopenharmony_ci	case CODA_HX4:
114462306a36Sopenharmony_ci	case CODA_7541:
114562306a36Sopenharmony_ci		if (dst_fourcc == V4L2_PIX_FMT_H264) {
114662306a36Sopenharmony_ci			value = (round_up(q_data_src->rect.width, 16) &
114762306a36Sopenharmony_ci				 CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
114862306a36Sopenharmony_ci			value |= (round_up(q_data_src->rect.height, 16) &
114962306a36Sopenharmony_ci				 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
115062306a36Sopenharmony_ci			break;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci		fallthrough;
115362306a36Sopenharmony_ci	case CODA_960:
115462306a36Sopenharmony_ci		value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK)
115562306a36Sopenharmony_ci			<< CODA7_PICWIDTH_OFFSET;
115662306a36Sopenharmony_ci		value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK)
115762306a36Sopenharmony_ci			 << CODA_PICHEIGHT_OFFSET;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
116062306a36Sopenharmony_ci	if (dst_fourcc == V4L2_PIX_FMT_JPEG)
116162306a36Sopenharmony_ci		ctx->params.framerate = 0;
116262306a36Sopenharmony_ci	coda_write(dev, ctx->params.framerate,
116362306a36Sopenharmony_ci		   CODA_CMD_ENC_SEQ_SRC_F_RATE);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	ctx->params.codec_mode = ctx->codec->mode;
116662306a36Sopenharmony_ci	switch (dst_fourcc) {
116762306a36Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
116862306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960)
116962306a36Sopenharmony_ci			coda_write(dev, CODA9_STD_MPEG4,
117062306a36Sopenharmony_ci				   CODA_CMD_ENC_SEQ_COD_STD);
117162306a36Sopenharmony_ci		else
117262306a36Sopenharmony_ci			coda_write(dev, CODA_STD_MPEG4,
117362306a36Sopenharmony_ci				   CODA_CMD_ENC_SEQ_COD_STD);
117462306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	case V4L2_PIX_FMT_H264:
117762306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960)
117862306a36Sopenharmony_ci			coda_write(dev, CODA9_STD_H264,
117962306a36Sopenharmony_ci				   CODA_CMD_ENC_SEQ_COD_STD);
118062306a36Sopenharmony_ci		else
118162306a36Sopenharmony_ci			coda_write(dev, CODA_STD_H264,
118262306a36Sopenharmony_ci				   CODA_CMD_ENC_SEQ_COD_STD);
118362306a36Sopenharmony_ci		value = ((ctx->params.h264_disable_deblocking_filter_idc &
118462306a36Sopenharmony_ci			  CODA_264PARAM_DISABLEDEBLK_MASK) <<
118562306a36Sopenharmony_ci			 CODA_264PARAM_DISABLEDEBLK_OFFSET) |
118662306a36Sopenharmony_ci			((ctx->params.h264_slice_alpha_c0_offset_div2 &
118762306a36Sopenharmony_ci			  CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
118862306a36Sopenharmony_ci			 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
118962306a36Sopenharmony_ci			((ctx->params.h264_slice_beta_offset_div2 &
119062306a36Sopenharmony_ci			  CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
119162306a36Sopenharmony_ci			 CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) |
119262306a36Sopenharmony_ci			(ctx->params.h264_constrained_intra_pred_flag <<
119362306a36Sopenharmony_ci			 CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) |
119462306a36Sopenharmony_ci			(ctx->params.h264_chroma_qp_index_offset &
119562306a36Sopenharmony_ci			 CODA_264PARAM_CHROMAQPOFFSET_MASK);
119662306a36Sopenharmony_ci		coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	case V4L2_PIX_FMT_JPEG:
119962306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA);
120062306a36Sopenharmony_ci		coda_write(dev, ctx->params.jpeg_restart_interval,
120162306a36Sopenharmony_ci				CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL);
120262306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN);
120362306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE);
120462306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		coda_jpeg_write_tables(ctx);
120762306a36Sopenharmony_ci		break;
120862306a36Sopenharmony_ci	default:
120962306a36Sopenharmony_ci		v4l2_err(v4l2_dev,
121062306a36Sopenharmony_ci			 "dst format (0x%08x) invalid.\n", dst_fourcc);
121162306a36Sopenharmony_ci		ret = -EINVAL;
121262306a36Sopenharmony_ci		goto out;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/*
121662306a36Sopenharmony_ci	 * slice mode and GOP size registers are used for thumb size/offset
121762306a36Sopenharmony_ci	 * in JPEG mode
121862306a36Sopenharmony_ci	 */
121962306a36Sopenharmony_ci	if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
122062306a36Sopenharmony_ci		value = coda_slice_mode(ctx);
122162306a36Sopenharmony_ci		coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
122262306a36Sopenharmony_ci		value = ctx->params.gop_size;
122362306a36Sopenharmony_ci		coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (ctx->params.bitrate && (ctx->params.frame_rc_enable ||
122762306a36Sopenharmony_ci				    ctx->params.mb_rc_enable)) {
122862306a36Sopenharmony_ci		ctx->params.bitrate_changed = false;
122962306a36Sopenharmony_ci		ctx->params.h264_intra_qp_changed = false;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		/* Rate control enabled */
123262306a36Sopenharmony_ci		value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
123362306a36Sopenharmony_ci			<< CODA_RATECONTROL_BITRATE_OFFSET;
123462306a36Sopenharmony_ci		value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
123562306a36Sopenharmony_ci		value |= (ctx->params.vbv_delay &
123662306a36Sopenharmony_ci			  CODA_RATECONTROL_INITIALDELAY_MASK)
123762306a36Sopenharmony_ci			 << CODA_RATECONTROL_INITIALDELAY_OFFSET;
123862306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960)
123962306a36Sopenharmony_ci			value |= BIT(31); /* disable autoskip */
124062306a36Sopenharmony_ci	} else {
124162306a36Sopenharmony_ci		value = 0;
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
124662306a36Sopenharmony_ci	coda_write(dev, ctx->params.intra_refresh,
124762306a36Sopenharmony_ci		   CODA_CMD_ENC_SEQ_INTRA_REFRESH);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
125062306a36Sopenharmony_ci	coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	value = 0;
125462306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
125562306a36Sopenharmony_ci		gamma = CODA9_DEFAULT_GAMMA;
125662306a36Sopenharmony_ci	else
125762306a36Sopenharmony_ci		gamma = CODA_DEFAULT_GAMMA;
125862306a36Sopenharmony_ci	if (gamma > 0) {
125962306a36Sopenharmony_ci		coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
126062306a36Sopenharmony_ci			   CODA_CMD_ENC_SEQ_RC_GAMMA);
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
126462306a36Sopenharmony_ci		coda_write(dev,
126562306a36Sopenharmony_ci			   ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
126662306a36Sopenharmony_ci			   ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
126762306a36Sopenharmony_ci			   CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
127062306a36Sopenharmony_ci		if (ctx->params.h264_max_qp)
127162306a36Sopenharmony_ci			value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
127262306a36Sopenharmony_ci		if (CODA_DEFAULT_GAMMA > 0)
127362306a36Sopenharmony_ci			value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
127462306a36Sopenharmony_ci	} else {
127562306a36Sopenharmony_ci		if (CODA_DEFAULT_GAMMA > 0) {
127662306a36Sopenharmony_ci			if (dev->devtype->product == CODA_DX6)
127762306a36Sopenharmony_ci				value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
127862306a36Sopenharmony_ci			else
127962306a36Sopenharmony_ci				value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
128062306a36Sopenharmony_ci		}
128162306a36Sopenharmony_ci		if (ctx->params.h264_min_qp)
128262306a36Sopenharmony_ci			value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
128362306a36Sopenharmony_ci		if (ctx->params.h264_max_qp)
128462306a36Sopenharmony_ci			value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci	coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable)
128962306a36Sopenharmony_ci		value = 1;
129062306a36Sopenharmony_ci	else
129162306a36Sopenharmony_ci		value = 0;
129262306a36Sopenharmony_ci	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	coda_setup_iram(ctx);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (dst_fourcc == V4L2_PIX_FMT_H264) {
129762306a36Sopenharmony_ci		switch (dev->devtype->product) {
129862306a36Sopenharmony_ci		case CODA_DX6:
129962306a36Sopenharmony_ci			value = FMO_SLICE_SAVE_BUF_SIZE << 7;
130062306a36Sopenharmony_ci			coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
130162306a36Sopenharmony_ci			break;
130262306a36Sopenharmony_ci		case CODA_HX4:
130362306a36Sopenharmony_ci		case CODA_7541:
130462306a36Sopenharmony_ci			coda_write(dev, ctx->iram_info.search_ram_paddr,
130562306a36Sopenharmony_ci					CODA7_CMD_ENC_SEQ_SEARCH_BASE);
130662306a36Sopenharmony_ci			coda_write(dev, ctx->iram_info.search_ram_size,
130762306a36Sopenharmony_ci					CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
130862306a36Sopenharmony_ci			break;
130962306a36Sopenharmony_ci		case CODA_960:
131062306a36Sopenharmony_ci			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
131162306a36Sopenharmony_ci			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
131262306a36Sopenharmony_ci		}
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
131662306a36Sopenharmony_ci	if (ret < 0) {
131762306a36Sopenharmony_ci		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
131862306a36Sopenharmony_ci		goto out;
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
132262306a36Sopenharmony_ci		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
132362306a36Sopenharmony_ci		ret = -EFAULT;
132462306a36Sopenharmony_ci		goto out;
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci	ctx->initialized = 1;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
132962306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960)
133062306a36Sopenharmony_ci			ctx->num_internal_frames = 4;
133162306a36Sopenharmony_ci		else
133262306a36Sopenharmony_ci			ctx->num_internal_frames = 2;
133362306a36Sopenharmony_ci		ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
133462306a36Sopenharmony_ci		if (ret < 0) {
133562306a36Sopenharmony_ci			v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
133662306a36Sopenharmony_ci			goto out;
133762306a36Sopenharmony_ci		}
133862306a36Sopenharmony_ci		num_fb = 2;
133962306a36Sopenharmony_ci		stride = q_data_src->bytesperline;
134062306a36Sopenharmony_ci	} else {
134162306a36Sopenharmony_ci		ctx->num_internal_frames = 0;
134262306a36Sopenharmony_ci		num_fb = 0;
134362306a36Sopenharmony_ci		stride = 0;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci	coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM);
134662306a36Sopenharmony_ci	coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	if (dev->devtype->product == CODA_HX4 ||
134962306a36Sopenharmony_ci	    dev->devtype->product == CODA_7541) {
135062306a36Sopenharmony_ci		coda_write(dev, q_data_src->bytesperline,
135162306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6) {
135462306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_bit_use,
135562306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
135662306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
135762306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
135862306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
135962306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
136062306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
136162306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
136262306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_ovl_use,
136362306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
136462306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960) {
136562306a36Sopenharmony_ci			coda_write(dev, ctx->iram_info.buf_btp_use,
136662306a36Sopenharmony_ci					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci			coda9_set_frame_cache(ctx, q_data_src->fourcc);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci			/* FIXME */
137162306a36Sopenharmony_ci			coda_write(dev, ctx->internal_frames[2].buf.paddr,
137262306a36Sopenharmony_ci				   CODA9_CMD_SET_FRAME_SUBSAMP_A);
137362306a36Sopenharmony_ci			coda_write(dev, ctx->internal_frames[3].buf.paddr,
137462306a36Sopenharmony_ci				   CODA9_CMD_SET_FRAME_SUBSAMP_B);
137562306a36Sopenharmony_ci		}
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
137962306a36Sopenharmony_ci	if (ret < 0) {
138062306a36Sopenharmony_ci		v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
138162306a36Sopenharmony_ci		goto out;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n",
138562306a36Sopenharmony_ci		 q_data_src->rect.width, q_data_src->rect.height,
138662306a36Sopenharmony_ci		 (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc,
138762306a36Sopenharmony_ci		 ctx->params.framerate & 0xffff,
138862306a36Sopenharmony_ci		 (ctx->params.framerate >> 16) + 1);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	/* Save stream headers */
139162306a36Sopenharmony_ci	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
139262306a36Sopenharmony_ci	switch (dst_fourcc) {
139362306a36Sopenharmony_ci	case V4L2_PIX_FMT_H264:
139462306a36Sopenharmony_ci		/*
139562306a36Sopenharmony_ci		 * Get SPS in the first frame and copy it to an
139662306a36Sopenharmony_ci		 * intermediate buffer.
139762306a36Sopenharmony_ci		 */
139862306a36Sopenharmony_ci		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
139962306a36Sopenharmony_ci					 &ctx->vpu_header[0][0],
140062306a36Sopenharmony_ci					 &ctx->vpu_header_size[0]);
140162306a36Sopenharmony_ci		if (ret < 0)
140262306a36Sopenharmony_ci			goto out;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		/*
140562306a36Sopenharmony_ci		 * If visible width or height are not aligned to macroblock
140662306a36Sopenharmony_ci		 * size, the crop_right and crop_bottom SPS fields must be set
140762306a36Sopenharmony_ci		 * to the difference between visible and coded size.  This is
140862306a36Sopenharmony_ci		 * only supported by CODA960 firmware. All others do not allow
140962306a36Sopenharmony_ci		 * writing frame cropping parameters, so we have to manually
141062306a36Sopenharmony_ci		 * fix up the SPS RBSP (Sequence Parameter Set Raw Byte
141162306a36Sopenharmony_ci		 * Sequence Payload) ourselves.
141262306a36Sopenharmony_ci		 */
141362306a36Sopenharmony_ci		if (ctx->dev->devtype->product != CODA_960 &&
141462306a36Sopenharmony_ci		    ((q_data_src->rect.width % 16) ||
141562306a36Sopenharmony_ci		     (q_data_src->rect.height % 16))) {
141662306a36Sopenharmony_ci			ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width,
141762306a36Sopenharmony_ci						  q_data_src->rect.height,
141862306a36Sopenharmony_ci						  &ctx->vpu_header[0][0],
141962306a36Sopenharmony_ci						  &ctx->vpu_header_size[0],
142062306a36Sopenharmony_ci						  sizeof(ctx->vpu_header[0]));
142162306a36Sopenharmony_ci			if (ret < 0)
142262306a36Sopenharmony_ci				goto out;
142362306a36Sopenharmony_ci		}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci		/*
142662306a36Sopenharmony_ci		 * Get PPS in the first frame and copy it to an
142762306a36Sopenharmony_ci		 * intermediate buffer.
142862306a36Sopenharmony_ci		 */
142962306a36Sopenharmony_ci		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
143062306a36Sopenharmony_ci					 &ctx->vpu_header[1][0],
143162306a36Sopenharmony_ci					 &ctx->vpu_header_size[1]);
143262306a36Sopenharmony_ci		if (ret < 0)
143362306a36Sopenharmony_ci			goto out;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		/*
143662306a36Sopenharmony_ci		 * Length of H.264 headers is variable and thus it might not be
143762306a36Sopenharmony_ci		 * aligned for the coda to append the encoded frame. In that is
143862306a36Sopenharmony_ci		 * the case a filler NAL must be added to header 2.
143962306a36Sopenharmony_ci		 */
144062306a36Sopenharmony_ci		ctx->vpu_header_size[2] = coda_h264_padding(
144162306a36Sopenharmony_ci					(ctx->vpu_header_size[0] +
144262306a36Sopenharmony_ci					 ctx->vpu_header_size[1]),
144362306a36Sopenharmony_ci					 ctx->vpu_header[2]);
144462306a36Sopenharmony_ci		break;
144562306a36Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
144662306a36Sopenharmony_ci		/*
144762306a36Sopenharmony_ci		 * Get VOS in the first frame and copy it to an
144862306a36Sopenharmony_ci		 * intermediate buffer
144962306a36Sopenharmony_ci		 */
145062306a36Sopenharmony_ci		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
145162306a36Sopenharmony_ci					 &ctx->vpu_header[0][0],
145262306a36Sopenharmony_ci					 &ctx->vpu_header_size[0]);
145362306a36Sopenharmony_ci		if (ret < 0)
145462306a36Sopenharmony_ci			goto out;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
145762306a36Sopenharmony_ci					 &ctx->vpu_header[1][0],
145862306a36Sopenharmony_ci					 &ctx->vpu_header_size[1]);
145962306a36Sopenharmony_ci		if (ret < 0)
146062306a36Sopenharmony_ci			goto out;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
146362306a36Sopenharmony_ci					 &ctx->vpu_header[2][0],
146462306a36Sopenharmony_ci					 &ctx->vpu_header_size[2]);
146562306a36Sopenharmony_ci		if (ret < 0)
146662306a36Sopenharmony_ci			goto out;
146762306a36Sopenharmony_ci		break;
146862306a36Sopenharmony_ci	default:
146962306a36Sopenharmony_ci		/* No more formats need to save headers at the moment */
147062306a36Sopenharmony_ci		break;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ciout:
147462306a36Sopenharmony_ci	mutex_unlock(&dev->coda_mutex);
147562306a36Sopenharmony_ci	return ret;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic int coda_prepare_encode(struct coda_ctx *ctx)
147962306a36Sopenharmony_ci{
148062306a36Sopenharmony_ci	struct coda_q_data *q_data_src, *q_data_dst;
148162306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_buf, *dst_buf;
148262306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
148362306a36Sopenharmony_ci	int force_ipicture;
148462306a36Sopenharmony_ci	int quant_param = 0;
148562306a36Sopenharmony_ci	u32 pic_stream_buffer_addr, pic_stream_buffer_size;
148662306a36Sopenharmony_ci	u32 rot_mode = 0;
148762306a36Sopenharmony_ci	u32 dst_fourcc;
148862306a36Sopenharmony_ci	u32 reg;
148962306a36Sopenharmony_ci	int ret;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	ret = coda_enc_param_change(ctx);
149262306a36Sopenharmony_ci	if (ret < 0) {
149362306a36Sopenharmony_ci		v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n",
149462306a36Sopenharmony_ci			  ret);
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
149862306a36Sopenharmony_ci	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
149962306a36Sopenharmony_ci	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
150062306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
150162306a36Sopenharmony_ci	dst_fourcc = q_data_dst->fourcc;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	src_buf->sequence = ctx->osequence;
150462306a36Sopenharmony_ci	dst_buf->sequence = ctx->osequence;
150562306a36Sopenharmony_ci	ctx->osequence++;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	force_ipicture = ctx->params.force_ipicture;
150862306a36Sopenharmony_ci	if (force_ipicture)
150962306a36Sopenharmony_ci		ctx->params.force_ipicture = false;
151062306a36Sopenharmony_ci	else if (ctx->params.gop_size != 0 &&
151162306a36Sopenharmony_ci		 (src_buf->sequence % ctx->params.gop_size) == 0)
151262306a36Sopenharmony_ci		force_ipicture = 1;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/*
151562306a36Sopenharmony_ci	 * Workaround coda firmware BUG that only marks the first
151662306a36Sopenharmony_ci	 * frame as IDR. This is a problem for some decoders that can't
151762306a36Sopenharmony_ci	 * recover when a frame is lost.
151862306a36Sopenharmony_ci	 */
151962306a36Sopenharmony_ci	if (!force_ipicture) {
152062306a36Sopenharmony_ci		src_buf->flags |= V4L2_BUF_FLAG_PFRAME;
152162306a36Sopenharmony_ci		src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
152262306a36Sopenharmony_ci	} else {
152362306a36Sopenharmony_ci		src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
152462306a36Sopenharmony_ci		src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
152862306a36Sopenharmony_ci		coda_set_gdi_regs(ctx);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/*
153162306a36Sopenharmony_ci	 * Copy headers in front of the first frame and forced I frames for
153262306a36Sopenharmony_ci	 * H.264 only. In MPEG4 they are already copied by the CODA.
153362306a36Sopenharmony_ci	 */
153462306a36Sopenharmony_ci	if (src_buf->sequence == 0 || force_ipicture) {
153562306a36Sopenharmony_ci		pic_stream_buffer_addr =
153662306a36Sopenharmony_ci			vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) +
153762306a36Sopenharmony_ci			ctx->vpu_header_size[0] +
153862306a36Sopenharmony_ci			ctx->vpu_header_size[1] +
153962306a36Sopenharmony_ci			ctx->vpu_header_size[2];
154062306a36Sopenharmony_ci		pic_stream_buffer_size = q_data_dst->sizeimage -
154162306a36Sopenharmony_ci			ctx->vpu_header_size[0] -
154262306a36Sopenharmony_ci			ctx->vpu_header_size[1] -
154362306a36Sopenharmony_ci			ctx->vpu_header_size[2];
154462306a36Sopenharmony_ci		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0),
154562306a36Sopenharmony_ci		       &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
154662306a36Sopenharmony_ci		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0)
154762306a36Sopenharmony_ci			+ ctx->vpu_header_size[0], &ctx->vpu_header[1][0],
154862306a36Sopenharmony_ci			ctx->vpu_header_size[1]);
154962306a36Sopenharmony_ci		memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0)
155062306a36Sopenharmony_ci			+ ctx->vpu_header_size[0] + ctx->vpu_header_size[1],
155162306a36Sopenharmony_ci			&ctx->vpu_header[2][0], ctx->vpu_header_size[2]);
155262306a36Sopenharmony_ci	} else {
155362306a36Sopenharmony_ci		pic_stream_buffer_addr =
155462306a36Sopenharmony_ci			vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
155562306a36Sopenharmony_ci		pic_stream_buffer_size = q_data_dst->sizeimage;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (force_ipicture) {
155962306a36Sopenharmony_ci		switch (dst_fourcc) {
156062306a36Sopenharmony_ci		case V4L2_PIX_FMT_H264:
156162306a36Sopenharmony_ci			quant_param = ctx->params.h264_intra_qp;
156262306a36Sopenharmony_ci			break;
156362306a36Sopenharmony_ci		case V4L2_PIX_FMT_MPEG4:
156462306a36Sopenharmony_ci			quant_param = ctx->params.mpeg4_intra_qp;
156562306a36Sopenharmony_ci			break;
156662306a36Sopenharmony_ci		case V4L2_PIX_FMT_JPEG:
156762306a36Sopenharmony_ci			quant_param = 30;
156862306a36Sopenharmony_ci			break;
156962306a36Sopenharmony_ci		default:
157062306a36Sopenharmony_ci			v4l2_warn(&ctx->dev->v4l2_dev,
157162306a36Sopenharmony_ci				"cannot set intra qp, fmt not supported\n");
157262306a36Sopenharmony_ci			break;
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci	} else {
157562306a36Sopenharmony_ci		switch (dst_fourcc) {
157662306a36Sopenharmony_ci		case V4L2_PIX_FMT_H264:
157762306a36Sopenharmony_ci			quant_param = ctx->params.h264_inter_qp;
157862306a36Sopenharmony_ci			break;
157962306a36Sopenharmony_ci		case V4L2_PIX_FMT_MPEG4:
158062306a36Sopenharmony_ci			quant_param = ctx->params.mpeg4_inter_qp;
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci		default:
158362306a36Sopenharmony_ci			v4l2_warn(&ctx->dev->v4l2_dev,
158462306a36Sopenharmony_ci				"cannot set inter qp, fmt not supported\n");
158562306a36Sopenharmony_ci			break;
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/* submit */
159062306a36Sopenharmony_ci	if (ctx->params.rot_mode)
159162306a36Sopenharmony_ci		rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
159262306a36Sopenharmony_ci	coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
159362306a36Sopenharmony_ci	coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960) {
159662306a36Sopenharmony_ci		coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
159762306a36Sopenharmony_ci		coda_write(dev, q_data_src->bytesperline,
159862306a36Sopenharmony_ci			   CODA9_CMD_ENC_PIC_SRC_STRIDE);
159962306a36Sopenharmony_ci		coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y;
160262306a36Sopenharmony_ci	} else {
160362306a36Sopenharmony_ci		reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	coda_write_base(ctx, q_data_src, src_buf, reg);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	coda_write(dev, force_ipicture << 1 & 0x2,
160862306a36Sopenharmony_ci		   CODA_CMD_ENC_PIC_OPTION);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
161162306a36Sopenharmony_ci	coda_write(dev, pic_stream_buffer_size / 1024,
161262306a36Sopenharmony_ci		   CODA_CMD_ENC_PIC_BB_SIZE);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	if (!ctx->streamon_out) {
161562306a36Sopenharmony_ci		/* After streamoff on the output side, set stream end flag */
161662306a36Sopenharmony_ci		ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
161762306a36Sopenharmony_ci		coda_write(dev, ctx->bit_stream_param,
161862306a36Sopenharmony_ci			   CODA_REG_BIT_BIT_STREAM_PARAM);
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6)
162262306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.axi_sram_use,
162362306a36Sopenharmony_ci				CODA7_REG_BIT_AXI_SRAM_USE);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	trace_coda_enc_pic_run(ctx, src_buf);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	return 0;
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic char coda_frame_type_char(u32 flags)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
163562306a36Sopenharmony_ci	       (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' :
163662306a36Sopenharmony_ci	       (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?';
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistatic void coda_finish_encode(struct coda_ctx *ctx)
164062306a36Sopenharmony_ci{
164162306a36Sopenharmony_ci	struct vb2_v4l2_buffer *src_buf, *dst_buf;
164262306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
164362306a36Sopenharmony_ci	u32 wr_ptr, start_ptr;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	if (ctx->aborting)
164662306a36Sopenharmony_ci		return;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * Lock to make sure that an encoder stop command running in parallel
165062306a36Sopenharmony_ci	 * will either already have marked src_buf as last, or it will wake up
165162306a36Sopenharmony_ci	 * the capture queue after the buffers are returned.
165262306a36Sopenharmony_ci	 */
165362306a36Sopenharmony_ci	mutex_lock(&ctx->wakeup_mutex);
165462306a36Sopenharmony_ci	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
165562306a36Sopenharmony_ci	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	trace_coda_enc_pic_done(ctx, dst_buf);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/* Get results from the coda */
166062306a36Sopenharmony_ci	start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
166162306a36Sopenharmony_ci	wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/* Calculate bytesused field */
166462306a36Sopenharmony_ci	if (dst_buf->sequence == 0 ||
166562306a36Sopenharmony_ci	    src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) {
166662306a36Sopenharmony_ci		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
166762306a36Sopenharmony_ci					ctx->vpu_header_size[0] +
166862306a36Sopenharmony_ci					ctx->vpu_header_size[1] +
166962306a36Sopenharmony_ci					ctx->vpu_header_size[2]);
167062306a36Sopenharmony_ci	} else {
167162306a36Sopenharmony_ci		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr);
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
167762306a36Sopenharmony_ci	coda_read(dev, CODA_RET_ENC_PIC_FLAG);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
168062306a36Sopenharmony_ci			    V4L2_BUF_FLAG_PFRAME |
168162306a36Sopenharmony_ci			    V4L2_BUF_FLAG_LAST);
168262306a36Sopenharmony_ci	if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0)
168362306a36Sopenharmony_ci		dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
168462306a36Sopenharmony_ci	else
168562306a36Sopenharmony_ci		dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
168662306a36Sopenharmony_ci	dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
169362306a36Sopenharmony_ci	coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
169462306a36Sopenharmony_ci	mutex_unlock(&ctx->wakeup_mutex);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	ctx->gopcounter--;
169762306a36Sopenharmony_ci	if (ctx->gopcounter < 0)
169862306a36Sopenharmony_ci		ctx->gopcounter = ctx->params.gop_size - 1;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n",
170162306a36Sopenharmony_ci		 coda_frame_type_char(dst_buf->flags), dst_buf->sequence,
170262306a36Sopenharmony_ci		 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : "");
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistatic void coda_seq_end_work(struct work_struct *work)
170662306a36Sopenharmony_ci{
170762306a36Sopenharmony_ci	struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
170862306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	mutex_lock(&ctx->buffer_mutex);
171162306a36Sopenharmony_ci	mutex_lock(&dev->coda_mutex);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	if (ctx->initialized == 0)
171462306a36Sopenharmony_ci		goto out;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__);
171762306a36Sopenharmony_ci	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
171862306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
171962306a36Sopenharmony_ci			 "CODA_COMMAND_SEQ_END failed\n");
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	/*
172362306a36Sopenharmony_ci	 * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing
172462306a36Sopenharmony_ci	 * from the output stream after the h.264 decoder has run. Resetting the
172562306a36Sopenharmony_ci	 * hardware after the decoder has finished seems to help.
172662306a36Sopenharmony_ci	 */
172762306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
172862306a36Sopenharmony_ci		coda_hw_reset(ctx);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	kfifo_init(&ctx->bitstream_fifo,
173162306a36Sopenharmony_ci		ctx->bitstream.vaddr, ctx->bitstream.size);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	coda_free_framebuffers(ctx);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	ctx->initialized = 0;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ciout:
173862306a36Sopenharmony_ci	mutex_unlock(&dev->coda_mutex);
173962306a36Sopenharmony_ci	mutex_unlock(&ctx->buffer_mutex);
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_cistatic void coda_bit_release(struct coda_ctx *ctx)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	mutex_lock(&ctx->buffer_mutex);
174562306a36Sopenharmony_ci	coda_free_framebuffers(ctx);
174662306a36Sopenharmony_ci	coda_free_context_buffers(ctx);
174762306a36Sopenharmony_ci	coda_free_bitstream_buffer(ctx);
174862306a36Sopenharmony_ci	mutex_unlock(&ctx->buffer_mutex);
174962306a36Sopenharmony_ci}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ciconst struct coda_context_ops coda_bit_encode_ops = {
175262306a36Sopenharmony_ci	.queue_init = coda_encoder_queue_init,
175362306a36Sopenharmony_ci	.reqbufs = coda_encoder_reqbufs,
175462306a36Sopenharmony_ci	.start_streaming = coda_start_encoding,
175562306a36Sopenharmony_ci	.prepare_run = coda_prepare_encode,
175662306a36Sopenharmony_ci	.finish_run = coda_finish_encode,
175762306a36Sopenharmony_ci	.seq_end_work = coda_seq_end_work,
175862306a36Sopenharmony_ci	.release = coda_bit_release,
175962306a36Sopenharmony_ci};
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci/*
176262306a36Sopenharmony_ci * Decoder context operations
176362306a36Sopenharmony_ci */
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
176662306a36Sopenharmony_ci				       struct coda_q_data *q_data)
176762306a36Sopenharmony_ci{
176862306a36Sopenharmony_ci	if (ctx->bitstream.vaddr)
176962306a36Sopenharmony_ci		return 0;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
177262306a36Sopenharmony_ci	ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size,
177362306a36Sopenharmony_ci					    &ctx->bitstream.paddr, GFP_KERNEL);
177462306a36Sopenharmony_ci	if (!ctx->bitstream.vaddr) {
177562306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
177662306a36Sopenharmony_ci			 "failed to allocate bitstream ringbuffer");
177762306a36Sopenharmony_ci		return -ENOMEM;
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci	kfifo_init(&ctx->bitstream_fifo,
178062306a36Sopenharmony_ci		   ctx->bitstream.vaddr, ctx->bitstream.size);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	return 0;
178362306a36Sopenharmony_ci}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx)
178662306a36Sopenharmony_ci{
178762306a36Sopenharmony_ci	if (ctx->bitstream.vaddr == NULL)
178862306a36Sopenharmony_ci		return;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr,
179162306a36Sopenharmony_ci		    ctx->bitstream.paddr);
179262306a36Sopenharmony_ci	ctx->bitstream.vaddr = NULL;
179362306a36Sopenharmony_ci	kfifo_init(&ctx->bitstream_fifo, NULL, 0);
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_cistatic int coda_decoder_reqbufs(struct coda_ctx *ctx,
179762306a36Sopenharmony_ci				struct v4l2_requestbuffers *rb)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	struct coda_q_data *q_data_src;
180062306a36Sopenharmony_ci	int ret;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
180362306a36Sopenharmony_ci		return 0;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (rb->count) {
180662306a36Sopenharmony_ci		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
180762306a36Sopenharmony_ci		ret = coda_alloc_context_buffers(ctx, q_data_src);
180862306a36Sopenharmony_ci		if (ret < 0)
180962306a36Sopenharmony_ci			return ret;
181062306a36Sopenharmony_ci		ret = coda_alloc_bitstream_buffer(ctx, q_data_src);
181162306a36Sopenharmony_ci		if (ret < 0) {
181262306a36Sopenharmony_ci			coda_free_context_buffers(ctx);
181362306a36Sopenharmony_ci			return ret;
181462306a36Sopenharmony_ci		}
181562306a36Sopenharmony_ci	} else {
181662306a36Sopenharmony_ci		coda_free_bitstream_buffer(ctx);
181762306a36Sopenharmony_ci		coda_free_context_buffers(ctx);
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	return 0;
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic bool coda_reorder_enable(struct coda_ctx *ctx)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
182662306a36Sopenharmony_ci	int profile;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (dev->devtype->product != CODA_HX4 &&
182962306a36Sopenharmony_ci	    dev->devtype->product != CODA_7541 &&
183062306a36Sopenharmony_ci	    dev->devtype->product != CODA_960)
183162306a36Sopenharmony_ci		return false;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
183462306a36Sopenharmony_ci		return false;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264)
183762306a36Sopenharmony_ci		return true;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	profile = coda_h264_profile(ctx->params.h264_profile_idc);
184062306a36Sopenharmony_ci	if (profile < 0)
184162306a36Sopenharmony_ci		v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n",
184262306a36Sopenharmony_ci			  ctx->params.h264_profile_idc);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	/* Baseline profile does not support reordering */
184562306a36Sopenharmony_ci	return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic void coda_decoder_drop_used_metas(struct coda_ctx *ctx)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	struct coda_buffer_meta *meta, *tmp;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	/*
185362306a36Sopenharmony_ci	 * All metas that end at or before the RD pointer (fifo out),
185462306a36Sopenharmony_ci	 * are now consumed by the VPU and should be released.
185562306a36Sopenharmony_ci	 */
185662306a36Sopenharmony_ci	spin_lock(&ctx->buffer_meta_lock);
185762306a36Sopenharmony_ci	list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) {
185862306a36Sopenharmony_ci		if (ctx->bitstream_fifo.kfifo.out >= meta->end) {
185962306a36Sopenharmony_ci			coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n",
186062306a36Sopenharmony_ci				 meta->sequence, meta->start, meta->end);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci			list_del(&meta->list);
186362306a36Sopenharmony_ci			ctx->num_metas--;
186462306a36Sopenharmony_ci			ctx->first_frame_sequence++;
186562306a36Sopenharmony_ci			kfree(meta);
186662306a36Sopenharmony_ci		}
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci	spin_unlock(&ctx->buffer_meta_lock);
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic int __coda_decoder_seq_init(struct coda_ctx *ctx)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	struct coda_q_data *q_data_src, *q_data_dst;
187462306a36Sopenharmony_ci	u32 bitstream_buf, bitstream_size;
187562306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
187662306a36Sopenharmony_ci	int width, height;
187762306a36Sopenharmony_ci	u32 src_fourcc, dst_fourcc;
187862306a36Sopenharmony_ci	u32 val;
187962306a36Sopenharmony_ci	int ret;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	lockdep_assert_held(&dev->coda_mutex);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	coda_dbg(1, ctx, "Video Data Order Adapter: %s\n",
188462306a36Sopenharmony_ci		 ctx->use_vdoa ? "Enabled" : "Disabled");
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	/* Start decoding */
188762306a36Sopenharmony_ci	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
188862306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
188962306a36Sopenharmony_ci	bitstream_buf = ctx->bitstream.paddr;
189062306a36Sopenharmony_ci	bitstream_size = ctx->bitstream.size;
189162306a36Sopenharmony_ci	src_fourcc = q_data_src->fourcc;
189262306a36Sopenharmony_ci	dst_fourcc = q_data_dst->fourcc;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/* Update coda bitstream read and write pointers from kfifo */
189562306a36Sopenharmony_ci	coda_kfifo_sync_to_device_full(ctx);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
189862306a36Sopenharmony_ci				 CODA9_FRAME_TILED2LINEAR);
189962306a36Sopenharmony_ci	if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
190062306a36Sopenharmony_ci		ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
190162306a36Sopenharmony_ci	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
190262306a36Sopenharmony_ci		ctx->frame_mem_ctrl |= (0x3 << 9) |
190362306a36Sopenharmony_ci			((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
190462306a36Sopenharmony_ci	coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	ctx->display_idx = -1;
190762306a36Sopenharmony_ci	ctx->frm_dis_flg = 0;
190862306a36Sopenharmony_ci	coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
191162306a36Sopenharmony_ci	coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
191262306a36Sopenharmony_ci	val = 0;
191362306a36Sopenharmony_ci	if (coda_reorder_enable(ctx))
191462306a36Sopenharmony_ci		val |= CODA_REORDER_ENABLE;
191562306a36Sopenharmony_ci	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
191662306a36Sopenharmony_ci		val |= CODA_NO_INT_ENABLE;
191762306a36Sopenharmony_ci	coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	ctx->params.codec_mode = ctx->codec->mode;
192062306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960 &&
192162306a36Sopenharmony_ci	    src_fourcc == V4L2_PIX_FMT_MPEG4)
192262306a36Sopenharmony_ci		ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
192362306a36Sopenharmony_ci	else
192462306a36Sopenharmony_ci		ctx->params.codec_mode_aux = 0;
192562306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_MPEG4) {
192662306a36Sopenharmony_ci		coda_write(dev, CODA_MP4_CLASS_MPEG4,
192762306a36Sopenharmony_ci			   CODA_CMD_DEC_SEQ_MP4_ASP_CLASS);
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_H264) {
193062306a36Sopenharmony_ci		if (dev->devtype->product == CODA_HX4 ||
193162306a36Sopenharmony_ci		    dev->devtype->product == CODA_7541) {
193262306a36Sopenharmony_ci			coda_write(dev, ctx->psbuf.paddr,
193362306a36Sopenharmony_ci					CODA_CMD_DEC_SEQ_PS_BB_START);
193462306a36Sopenharmony_ci			coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
193562306a36Sopenharmony_ci					CODA_CMD_DEC_SEQ_PS_BB_SIZE);
193662306a36Sopenharmony_ci		}
193762306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960) {
193862306a36Sopenharmony_ci			coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
193962306a36Sopenharmony_ci			coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
194062306a36Sopenharmony_ci		}
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_JPEG)
194362306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN);
194462306a36Sopenharmony_ci	if (dev->devtype->product != CODA_960)
194562306a36Sopenharmony_ci		coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE;
194862306a36Sopenharmony_ci	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
194962306a36Sopenharmony_ci	ctx->bit_stream_param = 0;
195062306a36Sopenharmony_ci	if (ret) {
195162306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
195262306a36Sopenharmony_ci		return ret;
195362306a36Sopenharmony_ci	}
195462306a36Sopenharmony_ci	ctx->sequence_offset = ~0U;
195562306a36Sopenharmony_ci	ctx->initialized = 1;
195662306a36Sopenharmony_ci	ctx->first_frame_sequence = 0;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	/* Update kfifo out pointer from coda bitstream read pointer */
195962306a36Sopenharmony_ci	coda_kfifo_sync_from_device(ctx);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	/*
196262306a36Sopenharmony_ci	 * After updating the read pointer, we need to check if
196362306a36Sopenharmony_ci	 * any metas are consumed and should be released.
196462306a36Sopenharmony_ci	 */
196562306a36Sopenharmony_ci	coda_decoder_drop_used_metas(ctx);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
196862306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
196962306a36Sopenharmony_ci			"CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n",
197062306a36Sopenharmony_ci			coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
197162306a36Sopenharmony_ci		return -EAGAIN;
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
197562306a36Sopenharmony_ci	if (dev->devtype->product == CODA_DX6) {
197662306a36Sopenharmony_ci		width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
197762306a36Sopenharmony_ci		height = val & CODADX6_PICHEIGHT_MASK;
197862306a36Sopenharmony_ci	} else {
197962306a36Sopenharmony_ci		width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
198062306a36Sopenharmony_ci		height = val & CODA7_PICHEIGHT_MASK;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	if (width > q_data_dst->bytesperline || height > q_data_dst->height) {
198462306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
198562306a36Sopenharmony_ci			 width, height, q_data_dst->bytesperline,
198662306a36Sopenharmony_ci			 q_data_dst->height);
198762306a36Sopenharmony_ci		return -EINVAL;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	width = round_up(width, 16);
199162306a36Sopenharmony_ci	height = round_up(height, 16);
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
199662306a36Sopenharmony_ci	/*
199762306a36Sopenharmony_ci	 * If the VDOA is used, the decoder needs one additional frame,
199862306a36Sopenharmony_ci	 * because the frames are freed when the next frame is decoded.
199962306a36Sopenharmony_ci	 * Otherwise there are visible errors in the decoded frames (green
200062306a36Sopenharmony_ci	 * regions in displayed frames) and a broken order of frames (earlier
200162306a36Sopenharmony_ci	 * frames are sporadically displayed after later frames).
200262306a36Sopenharmony_ci	 */
200362306a36Sopenharmony_ci	if (ctx->use_vdoa)
200462306a36Sopenharmony_ci		ctx->num_internal_frames += 1;
200562306a36Sopenharmony_ci	if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
200662306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
200762306a36Sopenharmony_ci			 "not enough framebuffers to decode (%d < %d)\n",
200862306a36Sopenharmony_ci			 CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
200962306a36Sopenharmony_ci		return -EINVAL;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_H264) {
201362306a36Sopenharmony_ci		u32 left_right;
201462306a36Sopenharmony_ci		u32 top_bottom;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci		left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
201762306a36Sopenharmony_ci		top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci		q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
202062306a36Sopenharmony_ci		q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
202162306a36Sopenharmony_ci		q_data_dst->rect.width = width - q_data_dst->rect.left -
202262306a36Sopenharmony_ci					 (left_right & 0x3ff);
202362306a36Sopenharmony_ci		q_data_dst->rect.height = height - q_data_dst->rect.top -
202462306a36Sopenharmony_ci					  (top_bottom & 0x3ff);
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6) {
202862306a36Sopenharmony_ci		u8 profile, level;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci		val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT);
203162306a36Sopenharmony_ci		profile = val & 0xff;
203262306a36Sopenharmony_ci		level = (val >> 8) & 0x7f;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci		if (profile || level)
203562306a36Sopenharmony_ci			coda_update_profile_level_ctrls(ctx, profile, level);
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	return 0;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic void coda_dec_seq_init_work(struct work_struct *work)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	struct coda_ctx *ctx = container_of(work,
204462306a36Sopenharmony_ci					    struct coda_ctx, seq_init_work);
204562306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	mutex_lock(&ctx->buffer_mutex);
204862306a36Sopenharmony_ci	mutex_lock(&dev->coda_mutex);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	if (!ctx->initialized)
205162306a36Sopenharmony_ci		__coda_decoder_seq_init(ctx);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	mutex_unlock(&dev->coda_mutex);
205462306a36Sopenharmony_ci	mutex_unlock(&ctx->buffer_mutex);
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_cistatic int __coda_start_decoding(struct coda_ctx *ctx)
205862306a36Sopenharmony_ci{
205962306a36Sopenharmony_ci	struct coda_q_data *q_data_src, *q_data_dst;
206062306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
206162306a36Sopenharmony_ci	u32 src_fourcc, dst_fourcc;
206262306a36Sopenharmony_ci	int ret;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
206562306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
206662306a36Sopenharmony_ci	src_fourcc = q_data_src->fourcc;
206762306a36Sopenharmony_ci	dst_fourcc = q_data_dst->fourcc;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	if (!ctx->initialized) {
207062306a36Sopenharmony_ci		ret = __coda_decoder_seq_init(ctx);
207162306a36Sopenharmony_ci		if (ret < 0)
207262306a36Sopenharmony_ci			return ret;
207362306a36Sopenharmony_ci	} else {
207462306a36Sopenharmony_ci		ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
207562306a36Sopenharmony_ci					 CODA9_FRAME_TILED2LINEAR);
207662306a36Sopenharmony_ci		if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
207762306a36Sopenharmony_ci			ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
207862306a36Sopenharmony_ci		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
207962306a36Sopenharmony_ci			ctx->frame_mem_ctrl |= (0x3 << 9) |
208062306a36Sopenharmony_ci				((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
208162306a36Sopenharmony_ci	}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
208662306a36Sopenharmony_ci	if (ret < 0) {
208762306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
208862306a36Sopenharmony_ci		return ret;
208962306a36Sopenharmony_ci	}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	/* Tell the decoder how many frame buffers we allocated. */
209262306a36Sopenharmony_ci	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
209362306a36Sopenharmony_ci	coda_write(dev, round_up(q_data_dst->rect.width, 16),
209462306a36Sopenharmony_ci		   CODA_CMD_SET_FRAME_BUF_STRIDE);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6) {
209762306a36Sopenharmony_ci		/* Set secondary AXI IRAM */
209862306a36Sopenharmony_ci		coda_setup_iram(ctx);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_bit_use,
210162306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
210262306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
210362306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
210462306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
210562306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
210662306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
210762306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
210862306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.buf_ovl_use,
210962306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
211062306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960) {
211162306a36Sopenharmony_ci			coda_write(dev, ctx->iram_info.buf_btp_use,
211262306a36Sopenharmony_ci					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci			coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
211562306a36Sopenharmony_ci			coda9_set_frame_cache(ctx, dst_fourcc);
211662306a36Sopenharmony_ci		}
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_H264) {
212062306a36Sopenharmony_ci		coda_write(dev, ctx->slicebuf.paddr,
212162306a36Sopenharmony_ci				CODA_CMD_SET_FRAME_SLICE_BB_START);
212262306a36Sopenharmony_ci		coda_write(dev, ctx->slicebuf.size / 1024,
212362306a36Sopenharmony_ci				CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	if (dev->devtype->product == CODA_HX4 ||
212762306a36Sopenharmony_ci	    dev->devtype->product == CODA_7541) {
212862306a36Sopenharmony_ci		int max_mb_x = 1920 / 16;
212962306a36Sopenharmony_ci		int max_mb_y = 1088 / 16;
213062306a36Sopenharmony_ci		int max_mb_num = max_mb_x * max_mb_y;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
213362306a36Sopenharmony_ci				CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
213462306a36Sopenharmony_ci	} else if (dev->devtype->product == CODA_960) {
213562306a36Sopenharmony_ci		int max_mb_x = 1920 / 16;
213662306a36Sopenharmony_ci		int max_mb_y = 1088 / 16;
213762306a36Sopenharmony_ci		int max_mb_num = max_mb_x * max_mb_y;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
214062306a36Sopenharmony_ci				CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
214162306a36Sopenharmony_ci	}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
214462306a36Sopenharmony_ci		v4l2_err(&ctx->dev->v4l2_dev,
214562306a36Sopenharmony_ci			 "CODA_COMMAND_SET_FRAME_BUF timeout\n");
214662306a36Sopenharmony_ci		return -ETIMEDOUT;
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	return 0;
215062306a36Sopenharmony_ci}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_cistatic int coda_start_decoding(struct coda_ctx *ctx)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
215562306a36Sopenharmony_ci	int ret;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	mutex_lock(&dev->coda_mutex);
215862306a36Sopenharmony_ci	ret = __coda_start_decoding(ctx);
215962306a36Sopenharmony_ci	mutex_unlock(&dev->coda_mutex);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	return ret;
216262306a36Sopenharmony_ci}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_cistatic int coda_prepare_decode(struct coda_ctx *ctx)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	struct vb2_v4l2_buffer *dst_buf;
216762306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
216862306a36Sopenharmony_ci	struct coda_q_data *q_data_dst;
216962306a36Sopenharmony_ci	struct coda_buffer_meta *meta;
217062306a36Sopenharmony_ci	u32 rot_mode = 0;
217162306a36Sopenharmony_ci	u32 reg_addr, reg_stride;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
217462306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	/* Try to copy source buffer contents into the bitstream ringbuffer */
217762306a36Sopenharmony_ci	mutex_lock(&ctx->bitstream_mutex);
217862306a36Sopenharmony_ci	coda_fill_bitstream(ctx, NULL);
217962306a36Sopenharmony_ci	mutex_unlock(&ctx->bitstream_mutex);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	if (coda_get_bitstream_payload(ctx) < 512 &&
218262306a36Sopenharmony_ci	    (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
218362306a36Sopenharmony_ci		coda_dbg(1, ctx, "bitstream payload: %d, skipping\n",
218462306a36Sopenharmony_ci			 coda_get_bitstream_payload(ctx));
218562306a36Sopenharmony_ci		return -EAGAIN;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	/* Run coda_start_decoding (again) if not yet initialized */
218962306a36Sopenharmony_ci	if (!ctx->initialized) {
219062306a36Sopenharmony_ci		int ret = __coda_start_decoding(ctx);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci		if (ret < 0) {
219362306a36Sopenharmony_ci			v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
219462306a36Sopenharmony_ci			return -EAGAIN;
219562306a36Sopenharmony_ci		} else {
219662306a36Sopenharmony_ci			ctx->initialized = 1;
219762306a36Sopenharmony_ci		}
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	if (dev->devtype->product == CODA_960)
220162306a36Sopenharmony_ci		coda_set_gdi_regs(ctx);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	if (ctx->use_vdoa &&
220462306a36Sopenharmony_ci	    ctx->display_idx >= 0 &&
220562306a36Sopenharmony_ci	    ctx->display_idx < ctx->num_internal_frames) {
220662306a36Sopenharmony_ci		vdoa_device_run(ctx->vdoa,
220762306a36Sopenharmony_ci				vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0),
220862306a36Sopenharmony_ci				ctx->internal_frames[ctx->display_idx].buf.paddr);
220962306a36Sopenharmony_ci	} else {
221062306a36Sopenharmony_ci		if (dev->devtype->product == CODA_960) {
221162306a36Sopenharmony_ci			/*
221262306a36Sopenharmony_ci			 * It was previously assumed that the CODA960 has an
221362306a36Sopenharmony_ci			 * internal list of 64 buffer entries that contains
221462306a36Sopenharmony_ci			 * both the registered internal frame buffers as well
221562306a36Sopenharmony_ci			 * as the rotator buffer output, and that the ROT_INDEX
221662306a36Sopenharmony_ci			 * register must be set to a value between the last
221762306a36Sopenharmony_ci			 * internal frame buffers' index and 64.
221862306a36Sopenharmony_ci			 * At least on firmware version 3.1.1 it turns out that
221962306a36Sopenharmony_ci			 * setting ROT_INDEX to any value >= 32 causes CODA
222062306a36Sopenharmony_ci			 * hangups that it can not recover from with the SRC VPU
222162306a36Sopenharmony_ci			 * reset.
222262306a36Sopenharmony_ci			 * It does appear to work however, to just set it to a
222362306a36Sopenharmony_ci			 * fixed value in the [ctx->num_internal_frames, 31]
222462306a36Sopenharmony_ci			 * range, for example CODA_MAX_FRAMEBUFFERS.
222562306a36Sopenharmony_ci			 */
222662306a36Sopenharmony_ci			coda_write(dev, CODA_MAX_FRAMEBUFFERS,
222762306a36Sopenharmony_ci				   CODA9_CMD_DEC_PIC_ROT_INDEX);
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci			reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
223062306a36Sopenharmony_ci			reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE;
223162306a36Sopenharmony_ci		} else {
223262306a36Sopenharmony_ci			reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y;
223362306a36Sopenharmony_ci			reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE;
223462306a36Sopenharmony_ci		}
223562306a36Sopenharmony_ci		coda_write_base(ctx, q_data_dst, dst_buf, reg_addr);
223662306a36Sopenharmony_ci		coda_write(dev, q_data_dst->bytesperline, reg_stride);
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci		rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE);
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	switch (dev->devtype->product) {
224462306a36Sopenharmony_ci	case CODA_DX6:
224562306a36Sopenharmony_ci		/* TBD */
224662306a36Sopenharmony_ci	case CODA_HX4:
224762306a36Sopenharmony_ci	case CODA_7541:
224862306a36Sopenharmony_ci		coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
224962306a36Sopenharmony_ci		break;
225062306a36Sopenharmony_ci	case CODA_960:
225162306a36Sopenharmony_ci		/* 'hardcode to use interrupt disable mode'? */
225262306a36Sopenharmony_ci		coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION);
225362306a36Sopenharmony_ci		break;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
225962306a36Sopenharmony_ci	coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	if (dev->devtype->product != CODA_DX6)
226262306a36Sopenharmony_ci		coda_write(dev, ctx->iram_info.axi_sram_use,
226362306a36Sopenharmony_ci				CODA7_REG_BIT_AXI_SRAM_USE);
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	spin_lock(&ctx->buffer_meta_lock);
226662306a36Sopenharmony_ci	meta = list_first_entry_or_null(&ctx->buffer_meta_list,
226762306a36Sopenharmony_ci					struct coda_buffer_meta, list);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci		/* If this is the last buffer in the bitstream, add padding */
227262306a36Sopenharmony_ci		if (meta->end == ctx->bitstream_fifo.kfifo.in) {
227362306a36Sopenharmony_ci			static unsigned char buf[512];
227462306a36Sopenharmony_ci			unsigned int pad;
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci			/* Pad to multiple of 256 and then add 256 more */
227762306a36Sopenharmony_ci			pad = ((0 - meta->end) & 0xff) + 256;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci			memset(buf, 0xff, sizeof(buf));
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci			kfifo_in(&ctx->bitstream_fifo, buf, pad);
228262306a36Sopenharmony_ci		}
228362306a36Sopenharmony_ci	}
228462306a36Sopenharmony_ci	spin_unlock(&ctx->buffer_meta_lock);
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	coda_kfifo_sync_to_device_full(ctx);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	/* Clear decode success flag */
228962306a36Sopenharmony_ci	coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/* Clear error return value */
229262306a36Sopenharmony_ci	coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	trace_coda_dec_pic_run(ctx, meta);
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	return 0;
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_cistatic void coda_finish_decode(struct coda_ctx *ctx)
230262306a36Sopenharmony_ci{
230362306a36Sopenharmony_ci	struct coda_dev *dev = ctx->dev;
230462306a36Sopenharmony_ci	struct coda_q_data *q_data_src;
230562306a36Sopenharmony_ci	struct coda_q_data *q_data_dst;
230662306a36Sopenharmony_ci	struct vb2_v4l2_buffer *dst_buf;
230762306a36Sopenharmony_ci	struct coda_buffer_meta *meta;
230862306a36Sopenharmony_ci	int width, height;
230962306a36Sopenharmony_ci	int decoded_idx;
231062306a36Sopenharmony_ci	int display_idx;
231162306a36Sopenharmony_ci	struct coda_internal_frame *decoded_frame = NULL;
231262306a36Sopenharmony_ci	u32 src_fourcc;
231362306a36Sopenharmony_ci	int success;
231462306a36Sopenharmony_ci	u32 err_mb;
231562306a36Sopenharmony_ci	int err_vdoa = 0;
231662306a36Sopenharmony_ci	u32 val;
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	if (ctx->aborting)
231962306a36Sopenharmony_ci		return;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	/* Update kfifo out pointer from coda bitstream read pointer */
232262306a36Sopenharmony_ci	coda_kfifo_sync_from_device(ctx);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	/*
232562306a36Sopenharmony_ci	 * in stream-end mode, the read pointer can overshoot the write pointer
232662306a36Sopenharmony_ci	 * by up to 512 bytes
232762306a36Sopenharmony_ci	 */
232862306a36Sopenharmony_ci	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
232962306a36Sopenharmony_ci		if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512)
233062306a36Sopenharmony_ci			kfifo_init(&ctx->bitstream_fifo,
233162306a36Sopenharmony_ci				ctx->bitstream.vaddr, ctx->bitstream.size);
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
233562306a36Sopenharmony_ci	src_fourcc = q_data_src->fourcc;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
233862306a36Sopenharmony_ci	if (val != 1)
233962306a36Sopenharmony_ci		pr_err("DEC_PIC_SUCCESS = %d\n", val);
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	success = val & 0x1;
234262306a36Sopenharmony_ci	if (!success)
234362306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "decode failed\n");
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_H264) {
234662306a36Sopenharmony_ci		if (val & (1 << 3))
234762306a36Sopenharmony_ci			v4l2_err(&dev->v4l2_dev,
234862306a36Sopenharmony_ci				 "insufficient PS buffer space (%d bytes)\n",
234962306a36Sopenharmony_ci				 ctx->psbuf.size);
235062306a36Sopenharmony_ci		if (val & (1 << 2))
235162306a36Sopenharmony_ci			v4l2_err(&dev->v4l2_dev,
235262306a36Sopenharmony_ci				 "insufficient slice buffer space (%d bytes)\n",
235362306a36Sopenharmony_ci				 ctx->slicebuf.size);
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
235762306a36Sopenharmony_ci	width = (val >> 16) & 0xffff;
235862306a36Sopenharmony_ci	height = val & 0xffff;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	/* frame crop information */
236362306a36Sopenharmony_ci	if (src_fourcc == V4L2_PIX_FMT_H264) {
236462306a36Sopenharmony_ci		u32 left_right;
236562306a36Sopenharmony_ci		u32 top_bottom;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
236862306a36Sopenharmony_ci		top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci		if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
237162306a36Sopenharmony_ci			/* Keep current crop information */
237262306a36Sopenharmony_ci		} else {
237362306a36Sopenharmony_ci			struct v4l2_rect *rect = &q_data_dst->rect;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci			rect->left = left_right >> 16 & 0xffff;
237662306a36Sopenharmony_ci			rect->top = top_bottom >> 16 & 0xffff;
237762306a36Sopenharmony_ci			rect->width = width - rect->left -
237862306a36Sopenharmony_ci				      (left_right & 0xffff);
237962306a36Sopenharmony_ci			rect->height = height - rect->top -
238062306a36Sopenharmony_ci				       (top_bottom & 0xffff);
238162306a36Sopenharmony_ci		}
238262306a36Sopenharmony_ci	} else {
238362306a36Sopenharmony_ci		/* no cropping */
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
238762306a36Sopenharmony_ci	if (err_mb > 0) {
238862306a36Sopenharmony_ci		if (__ratelimit(&dev->mb_err_rs))
238962306a36Sopenharmony_ci			coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb);
239062306a36Sopenharmony_ci		v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl,
239162306a36Sopenharmony_ci				 v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb);
239262306a36Sopenharmony_ci	}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	if (dev->devtype->product == CODA_HX4 ||
239562306a36Sopenharmony_ci	    dev->devtype->product == CODA_7541) {
239662306a36Sopenharmony_ci		val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
239762306a36Sopenharmony_ci		if (val == 0) {
239862306a36Sopenharmony_ci			/* not enough bitstream data */
239962306a36Sopenharmony_ci			coda_dbg(1, ctx, "prescan failed: %d\n", val);
240062306a36Sopenharmony_ci			ctx->hold = true;
240162306a36Sopenharmony_ci			return;
240262306a36Sopenharmony_ci		}
240362306a36Sopenharmony_ci	}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* Wait until the VDOA finished writing the previous display frame */
240662306a36Sopenharmony_ci	if (ctx->use_vdoa &&
240762306a36Sopenharmony_ci	    ctx->display_idx >= 0 &&
240862306a36Sopenharmony_ci	    ctx->display_idx < ctx->num_internal_frames) {
240962306a36Sopenharmony_ci		err_vdoa = vdoa_wait_for_completion(ctx->vdoa);
241062306a36Sopenharmony_ci	}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	ctx->frm_dis_flg = coda_read(dev,
241362306a36Sopenharmony_ci				     CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	/* The previous display frame was copied out and can be overwritten */
241662306a36Sopenharmony_ci	if (ctx->display_idx >= 0 &&
241762306a36Sopenharmony_ci	    ctx->display_idx < ctx->num_internal_frames) {
241862306a36Sopenharmony_ci		ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
241962306a36Sopenharmony_ci		coda_write(dev, ctx->frm_dis_flg,
242062306a36Sopenharmony_ci				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
242162306a36Sopenharmony_ci	}
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	/*
242462306a36Sopenharmony_ci	 * The index of the last decoded frame, not necessarily in
242562306a36Sopenharmony_ci	 * display order, and the index of the next display frame.
242662306a36Sopenharmony_ci	 * The latter could have been decoded in a previous run.
242762306a36Sopenharmony_ci	 */
242862306a36Sopenharmony_ci	decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
242962306a36Sopenharmony_ci	display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (decoded_idx == -1) {
243262306a36Sopenharmony_ci		/* no frame was decoded, but we might have a display frame */
243362306a36Sopenharmony_ci		if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
243462306a36Sopenharmony_ci			ctx->sequence_offset++;
243562306a36Sopenharmony_ci		else if (ctx->display_idx < 0)
243662306a36Sopenharmony_ci			ctx->hold = true;
243762306a36Sopenharmony_ci	} else if (decoded_idx == -2) {
243862306a36Sopenharmony_ci		if (ctx->display_idx >= 0 &&
243962306a36Sopenharmony_ci		    ctx->display_idx < ctx->num_internal_frames)
244062306a36Sopenharmony_ci			ctx->sequence_offset++;
244162306a36Sopenharmony_ci		/* no frame was decoded, we still return remaining buffers */
244262306a36Sopenharmony_ci	} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
244362306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
244462306a36Sopenharmony_ci			 "decoded frame index out of range: %d\n", decoded_idx);
244562306a36Sopenharmony_ci	} else {
244662306a36Sopenharmony_ci		int sequence;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci		decoded_frame = &ctx->internal_frames[decoded_idx];
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM);
245162306a36Sopenharmony_ci		if (ctx->sequence_offset == -1)
245262306a36Sopenharmony_ci			ctx->sequence_offset = val;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci		sequence = val + ctx->first_frame_sequence
245562306a36Sopenharmony_ci			       - ctx->sequence_offset;
245662306a36Sopenharmony_ci		spin_lock(&ctx->buffer_meta_lock);
245762306a36Sopenharmony_ci		if (!list_empty(&ctx->buffer_meta_list)) {
245862306a36Sopenharmony_ci			meta = list_first_entry(&ctx->buffer_meta_list,
245962306a36Sopenharmony_ci					      struct coda_buffer_meta, list);
246062306a36Sopenharmony_ci			list_del(&meta->list);
246162306a36Sopenharmony_ci			ctx->num_metas--;
246262306a36Sopenharmony_ci			spin_unlock(&ctx->buffer_meta_lock);
246362306a36Sopenharmony_ci			/*
246462306a36Sopenharmony_ci			 * Clamp counters to 16 bits for comparison, as the HW
246562306a36Sopenharmony_ci			 * counter rolls over at this point for h.264. This
246662306a36Sopenharmony_ci			 * may be different for other formats, but using 16 bits
246762306a36Sopenharmony_ci			 * should be enough to detect most errors and saves us
246862306a36Sopenharmony_ci			 * from doing different things based on the format.
246962306a36Sopenharmony_ci			 */
247062306a36Sopenharmony_ci			if ((sequence & 0xffff) != (meta->sequence & 0xffff)) {
247162306a36Sopenharmony_ci				v4l2_err(&dev->v4l2_dev,
247262306a36Sopenharmony_ci					 "sequence number mismatch (%d(%d) != %d)\n",
247362306a36Sopenharmony_ci					 sequence, ctx->sequence_offset,
247462306a36Sopenharmony_ci					 meta->sequence);
247562306a36Sopenharmony_ci			}
247662306a36Sopenharmony_ci			decoded_frame->meta = *meta;
247762306a36Sopenharmony_ci			kfree(meta);
247862306a36Sopenharmony_ci		} else {
247962306a36Sopenharmony_ci			spin_unlock(&ctx->buffer_meta_lock);
248062306a36Sopenharmony_ci			v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
248162306a36Sopenharmony_ci			memset(&decoded_frame->meta, 0,
248262306a36Sopenharmony_ci			       sizeof(struct coda_buffer_meta));
248362306a36Sopenharmony_ci			decoded_frame->meta.sequence = sequence;
248462306a36Sopenharmony_ci			decoded_frame->meta.last = false;
248562306a36Sopenharmony_ci			ctx->sequence_offset++;
248662306a36Sopenharmony_ci		}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci		trace_coda_dec_pic_done(ctx, &decoded_frame->meta);
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
249162306a36Sopenharmony_ci		decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME :
249262306a36Sopenharmony_ci				      (val == 1) ? V4L2_BUF_FLAG_PFRAME :
249362306a36Sopenharmony_ci						   V4L2_BUF_FLAG_BFRAME;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci		decoded_frame->error = err_mb;
249662306a36Sopenharmony_ci	}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (display_idx == -1) {
249962306a36Sopenharmony_ci		/*
250062306a36Sopenharmony_ci		 * no more frames to be decoded, but there could still
250162306a36Sopenharmony_ci		 * be rotator output to dequeue
250262306a36Sopenharmony_ci		 */
250362306a36Sopenharmony_ci		ctx->hold = true;
250462306a36Sopenharmony_ci	} else if (display_idx == -3) {
250562306a36Sopenharmony_ci		/* possibly prescan failure */
250662306a36Sopenharmony_ci	} else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
250762306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
250862306a36Sopenharmony_ci			 "presentation frame index out of range: %d\n",
250962306a36Sopenharmony_ci			 display_idx);
251062306a36Sopenharmony_ci	}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	/* If a frame was copied out, return it */
251362306a36Sopenharmony_ci	if (ctx->display_idx >= 0 &&
251462306a36Sopenharmony_ci	    ctx->display_idx < ctx->num_internal_frames) {
251562306a36Sopenharmony_ci		struct coda_internal_frame *ready_frame;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci		ready_frame = &ctx->internal_frames[ctx->display_idx];
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci		dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
252062306a36Sopenharmony_ci		dst_buf->sequence = ctx->osequence++;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci		dst_buf->field = V4L2_FIELD_NONE;
252362306a36Sopenharmony_ci		dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
252462306a36Sopenharmony_ci					     V4L2_BUF_FLAG_PFRAME |
252562306a36Sopenharmony_ci					     V4L2_BUF_FLAG_BFRAME);
252662306a36Sopenharmony_ci		dst_buf->flags |= ready_frame->type;
252762306a36Sopenharmony_ci		meta = &ready_frame->meta;
252862306a36Sopenharmony_ci		if (meta->last && !coda_reorder_enable(ctx)) {
252962306a36Sopenharmony_ci			/*
253062306a36Sopenharmony_ci			 * If this was the last decoded frame, and reordering
253162306a36Sopenharmony_ci			 * is disabled, this will be the last display frame.
253262306a36Sopenharmony_ci			 */
253362306a36Sopenharmony_ci			coda_dbg(1, ctx, "last meta, marking as last frame\n");
253462306a36Sopenharmony_ci			dst_buf->flags |= V4L2_BUF_FLAG_LAST;
253562306a36Sopenharmony_ci		} else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG &&
253662306a36Sopenharmony_ci			   display_idx == -1) {
253762306a36Sopenharmony_ci			/*
253862306a36Sopenharmony_ci			 * If there is no designated presentation frame anymore,
253962306a36Sopenharmony_ci			 * this frame has to be the last one.
254062306a36Sopenharmony_ci			 */
254162306a36Sopenharmony_ci			coda_dbg(1, ctx,
254262306a36Sopenharmony_ci				 "no more frames to return, marking as last frame\n");
254362306a36Sopenharmony_ci			dst_buf->flags |= V4L2_BUF_FLAG_LAST;
254462306a36Sopenharmony_ci		}
254562306a36Sopenharmony_ci		dst_buf->timecode = meta->timecode;
254662306a36Sopenharmony_ci		dst_buf->vb2_buf.timestamp = meta->timestamp;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		trace_coda_dec_rot_done(ctx, dst_buf, meta);
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci		vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
255162306a36Sopenharmony_ci				      q_data_dst->sizeimage);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci		if (ready_frame->error || err_vdoa)
255462306a36Sopenharmony_ci			coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
255562306a36Sopenharmony_ci		else
255662306a36Sopenharmony_ci			coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		if (decoded_frame) {
255962306a36Sopenharmony_ci			coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n",
256062306a36Sopenharmony_ci				 coda_frame_type_char(decoded_frame->type),
256162306a36Sopenharmony_ci				 decoded_frame->meta.sequence,
256262306a36Sopenharmony_ci				 coda_frame_type_char(dst_buf->flags),
256362306a36Sopenharmony_ci				 ready_frame->meta.sequence,
256462306a36Sopenharmony_ci				 dst_buf->sequence, ctx->qsequence,
256562306a36Sopenharmony_ci				 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
256662306a36Sopenharmony_ci				 " (last)" : "");
256762306a36Sopenharmony_ci		} else {
256862306a36Sopenharmony_ci			coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n",
256962306a36Sopenharmony_ci				 decoded_idx,
257062306a36Sopenharmony_ci				 coda_frame_type_char(dst_buf->flags),
257162306a36Sopenharmony_ci				 ready_frame->meta.sequence,
257262306a36Sopenharmony_ci				 dst_buf->sequence, ctx->qsequence,
257362306a36Sopenharmony_ci				 (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
257462306a36Sopenharmony_ci				 " (last)" : "");
257562306a36Sopenharmony_ci		}
257662306a36Sopenharmony_ci	} else {
257762306a36Sopenharmony_ci		if (decoded_frame) {
257862306a36Sopenharmony_ci			coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n",
257962306a36Sopenharmony_ci				 coda_frame_type_char(decoded_frame->type),
258062306a36Sopenharmony_ci				 decoded_frame->meta.sequence,
258162306a36Sopenharmony_ci				 ctx->display_idx);
258262306a36Sopenharmony_ci		} else {
258362306a36Sopenharmony_ci			coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n",
258462306a36Sopenharmony_ci				 decoded_idx, ctx->display_idx);
258562306a36Sopenharmony_ci		}
258662306a36Sopenharmony_ci	}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	/* The rotator will copy the current display frame next time */
258962306a36Sopenharmony_ci	ctx->display_idx = display_idx;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	/*
259262306a36Sopenharmony_ci	 * The current decode run might have brought the bitstream fill level
259362306a36Sopenharmony_ci	 * below the size where we can start the next decode run. As userspace
259462306a36Sopenharmony_ci	 * might have filled the output queue completely and might thus be
259562306a36Sopenharmony_ci	 * blocked, we can't rely on the next qbuf to trigger the bitstream
259662306a36Sopenharmony_ci	 * refill. Check if we have data to refill the bitstream now.
259762306a36Sopenharmony_ci	 */
259862306a36Sopenharmony_ci	mutex_lock(&ctx->bitstream_mutex);
259962306a36Sopenharmony_ci	coda_fill_bitstream(ctx, NULL);
260062306a36Sopenharmony_ci	mutex_unlock(&ctx->bitstream_mutex);
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_cistatic void coda_decode_timeout(struct coda_ctx *ctx)
260462306a36Sopenharmony_ci{
260562306a36Sopenharmony_ci	struct vb2_v4l2_buffer *dst_buf;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	/*
260862306a36Sopenharmony_ci	 * For now this only handles the case where we would deadlock with
260962306a36Sopenharmony_ci	 * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS,
261062306a36Sopenharmony_ci	 * but after a failed decode run we would hold the context and wait for
261162306a36Sopenharmony_ci	 * userspace to queue more buffers.
261262306a36Sopenharmony_ci	 */
261362306a36Sopenharmony_ci	if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))
261462306a36Sopenharmony_ci		return;
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
261762306a36Sopenharmony_ci	dst_buf->sequence = ctx->qsequence - 1;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ciconst struct coda_context_ops coda_bit_decode_ops = {
262362306a36Sopenharmony_ci	.queue_init = coda_decoder_queue_init,
262462306a36Sopenharmony_ci	.reqbufs = coda_decoder_reqbufs,
262562306a36Sopenharmony_ci	.start_streaming = coda_start_decoding,
262662306a36Sopenharmony_ci	.prepare_run = coda_prepare_decode,
262762306a36Sopenharmony_ci	.finish_run = coda_finish_decode,
262862306a36Sopenharmony_ci	.run_timeout = coda_decode_timeout,
262962306a36Sopenharmony_ci	.seq_init_work = coda_dec_seq_init_work,
263062306a36Sopenharmony_ci	.seq_end_work = coda_seq_end_work,
263162306a36Sopenharmony_ci	.release = coda_bit_release,
263262306a36Sopenharmony_ci};
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ciirqreturn_t coda_irq_handler(int irq, void *data)
263562306a36Sopenharmony_ci{
263662306a36Sopenharmony_ci	struct coda_dev *dev = data;
263762306a36Sopenharmony_ci	struct coda_ctx *ctx;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	/* read status register to attend the IRQ */
264062306a36Sopenharmony_ci	coda_read(dev, CODA_REG_BIT_INT_STATUS);
264162306a36Sopenharmony_ci	coda_write(dev, 0, CODA_REG_BIT_INT_REASON);
264262306a36Sopenharmony_ci	coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
264362306a36Sopenharmony_ci		      CODA_REG_BIT_INT_CLEAR);
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
264662306a36Sopenharmony_ci	if (ctx == NULL) {
264762306a36Sopenharmony_ci		v4l2_err(&dev->v4l2_dev,
264862306a36Sopenharmony_ci			 "Instance released before the end of transaction\n");
264962306a36Sopenharmony_ci		return IRQ_HANDLED;
265062306a36Sopenharmony_ci	}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	trace_coda_bit_done(ctx);
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	if (ctx->aborting) {
265562306a36Sopenharmony_ci		coda_dbg(1, ctx, "task has been aborted\n");
265662306a36Sopenharmony_ci	}
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	if (coda_isbusy(ctx->dev)) {
265962306a36Sopenharmony_ci		coda_dbg(1, ctx, "coda is still busy!!!!\n");
266062306a36Sopenharmony_ci		return IRQ_NONE;
266162306a36Sopenharmony_ci	}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	complete(&ctx->completion);
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	return IRQ_HANDLED;
266662306a36Sopenharmony_ci}
2667