16eb9b758SMaxime Ripard // SPDX-License-Identifier: GPL-2.0-or-later
26eb9b758SMaxime Ripard /*
36eb9b758SMaxime Ripard  * Cedrus VPU driver
46eb9b758SMaxime Ripard  *
56eb9b758SMaxime Ripard  * Copyright (c) 2013 Jens Kuske <jenskuske@gmail.com>
66eb9b758SMaxime Ripard  * Copyright (c) 2018 Bootlin
76eb9b758SMaxime Ripard  */
86eb9b758SMaxime Ripard 
961ad1233SJernej Skrabec #include <linux/delay.h>
106eb9b758SMaxime Ripard #include <linux/types.h>
116eb9b758SMaxime Ripard 
126eb9b758SMaxime Ripard #include <media/videobuf2-dma-contig.h>
136eb9b758SMaxime Ripard 
146eb9b758SMaxime Ripard #include "cedrus.h"
156eb9b758SMaxime Ripard #include "cedrus_hw.h"
166eb9b758SMaxime Ripard #include "cedrus_regs.h"
176eb9b758SMaxime Ripard 
186eb9b758SMaxime Ripard enum cedrus_h264_sram_off {
196eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE	= 0x000,
206eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_FRAMEBUFFER_LIST	= 0x100,
216eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_REF_LIST_0		= 0x190,
226eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_REF_LIST_1		= 0x199,
236eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_SCALING_LIST_8x8_0	= 0x200,
246eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_SCALING_LIST_8x8_1	= 0x210,
256eb9b758SMaxime Ripard 	CEDRUS_SRAM_H264_SCALING_LIST_4x4	= 0x220,
266eb9b758SMaxime Ripard };
276eb9b758SMaxime Ripard 
286eb9b758SMaxime Ripard struct cedrus_h264_sram_ref_pic {
296eb9b758SMaxime Ripard 	__le32	top_field_order_cnt;
306eb9b758SMaxime Ripard 	__le32	bottom_field_order_cnt;
316eb9b758SMaxime Ripard 	__le32	frame_info;
326eb9b758SMaxime Ripard 	__le32	luma_ptr;
336eb9b758SMaxime Ripard 	__le32	chroma_ptr;
346eb9b758SMaxime Ripard 	__le32	mv_col_top_ptr;
356eb9b758SMaxime Ripard 	__le32	mv_col_bot_ptr;
366eb9b758SMaxime Ripard 	__le32	reserved;
376eb9b758SMaxime Ripard } __packed;
386eb9b758SMaxime Ripard 
396eb9b758SMaxime Ripard #define CEDRUS_H264_FRAME_NUM		18
406eb9b758SMaxime Ripard 
41fecd363aSJernej Skrabec #define CEDRUS_NEIGHBOR_INFO_BUF_SIZE	(32 * SZ_1K)
4203e612e7SJernej Skrabec #define CEDRUS_MIN_PIC_INFO_BUF_SIZE       (130 * SZ_1K)
436eb9b758SMaxime Ripard 
cedrus_h264_write_sram(struct cedrus_dev * dev,enum cedrus_h264_sram_off off,const void * data,size_t len)446eb9b758SMaxime Ripard static void cedrus_h264_write_sram(struct cedrus_dev *dev,
456eb9b758SMaxime Ripard 				   enum cedrus_h264_sram_off off,
466eb9b758SMaxime Ripard 				   const void *data, size_t len)
476eb9b758SMaxime Ripard {
486eb9b758SMaxime Ripard 	const u32 *buffer = data;
496eb9b758SMaxime Ripard 	size_t count = DIV_ROUND_UP(len, 4);
506eb9b758SMaxime Ripard 
516eb9b758SMaxime Ripard 	cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET, off << 2);
526eb9b758SMaxime Ripard 
536eb9b758SMaxime Ripard 	while (count--)
546eb9b758SMaxime Ripard 		cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, *buffer++);
556eb9b758SMaxime Ripard }
566eb9b758SMaxime Ripard 
cedrus_h264_mv_col_buf_addr(struct cedrus_buffer * buf,unsigned int field)576eb9b758SMaxime Ripard static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_buffer *buf,
586eb9b758SMaxime Ripard 					      unsigned int field)
596eb9b758SMaxime Ripard {
606eb9b758SMaxime Ripard 	dma_addr_t addr = buf->codec.h264.mv_col_buf_dma;
616eb9b758SMaxime Ripard 
626eb9b758SMaxime Ripard 	/* Adjust for the field */
636eb9b758SMaxime Ripard 	addr += field * buf->codec.h264.mv_col_buf_size / 2;
646eb9b758SMaxime Ripard 
656eb9b758SMaxime Ripard 	return addr;
666eb9b758SMaxime Ripard }
676eb9b758SMaxime Ripard 
cedrus_fill_ref_pic(struct cedrus_ctx * ctx,struct cedrus_buffer * buf,unsigned int top_field_order_cnt,unsigned int bottom_field_order_cnt,struct cedrus_h264_sram_ref_pic * pic)686eb9b758SMaxime Ripard static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
696eb9b758SMaxime Ripard 				struct cedrus_buffer *buf,
706eb9b758SMaxime Ripard 				unsigned int top_field_order_cnt,
716eb9b758SMaxime Ripard 				unsigned int bottom_field_order_cnt,
726eb9b758SMaxime Ripard 				struct cedrus_h264_sram_ref_pic *pic)
736eb9b758SMaxime Ripard {
746eb9b758SMaxime Ripard 	struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
756eb9b758SMaxime Ripard 
766eb9b758SMaxime Ripard 	pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
776eb9b758SMaxime Ripard 	pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
786eb9b758SMaxime Ripard 	pic->frame_info = cpu_to_le32(buf->codec.h264.pic_type << 8);
796eb9b758SMaxime Ripard 
806eb9b758SMaxime Ripard 	pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
816eb9b758SMaxime Ripard 	pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
826eb9b758SMaxime Ripard 	pic->mv_col_top_ptr = cpu_to_le32(cedrus_h264_mv_col_buf_addr(buf, 0));
836eb9b758SMaxime Ripard 	pic->mv_col_bot_ptr = cpu_to_le32(cedrus_h264_mv_col_buf_addr(buf, 1));
846eb9b758SMaxime Ripard }
856eb9b758SMaxime Ripard 
cedrus_write_frame_list(struct cedrus_ctx * ctx,struct cedrus_run * run)866eb9b758SMaxime Ripard static int cedrus_write_frame_list(struct cedrus_ctx *ctx,
876eb9b758SMaxime Ripard 				   struct cedrus_run *run)
886eb9b758SMaxime Ripard {
896eb9b758SMaxime Ripard 	struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM];
906eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
916eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
926eb9b758SMaxime Ripard 	struct vb2_queue *cap_q;
936eb9b758SMaxime Ripard 	struct cedrus_buffer *output_buf;
946eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
956eb9b758SMaxime Ripard 	unsigned long used_dpbs = 0;
966eb9b758SMaxime Ripard 	unsigned int position;
976eb9b758SMaxime Ripard 	int output = -1;
986eb9b758SMaxime Ripard 	unsigned int i;
991fd50a2cSJernej Skrabec 
1006eb9b758SMaxime Ripard 	cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
1016eb9b758SMaxime Ripard 
1026eb9b758SMaxime Ripard 	memset(pic_list, 0, sizeof(pic_list));
1036eb9b758SMaxime Ripard 
10446e8893eSJernej Skrabec 	for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) {
1056eb9b758SMaxime Ripard 		const struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i];
1066eb9b758SMaxime Ripard 		struct cedrus_buffer *cedrus_buf;
1071fd50a2cSJernej Skrabec 		struct vb2_buffer *buf;
1081fd50a2cSJernej Skrabec 
1096eb9b758SMaxime Ripard 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
1106eb9b758SMaxime Ripard 			continue;
1116eb9b758SMaxime Ripard 
1126eb9b758SMaxime Ripard 		buf = vb2_find_buffer(cap_q, dpb->reference_ts);
1136eb9b758SMaxime Ripard 		if (!buf)
114e21cde40SEzequiel Garcia 			continue;
1156eb9b758SMaxime Ripard 
1166eb9b758SMaxime Ripard 		cedrus_buf = vb2_to_cedrus_buffer(buf);
1176eb9b758SMaxime Ripard 		position = cedrus_buf->codec.h264.position;
1186eb9b758SMaxime Ripard 		used_dpbs |= BIT(position);
119e21cde40SEzequiel Garcia 
120e21cde40SEzequiel Garcia 		if (run->dst->vb2_buf.timestamp == dpb->reference_ts) {
1216eb9b758SMaxime Ripard 			output = position;
1226eb9b758SMaxime Ripard 			continue;
123e21cde40SEzequiel Garcia 		}
1246eb9b758SMaxime Ripard 
1256eb9b758SMaxime Ripard 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
1266eb9b758SMaxime Ripard 			continue;
12746e8893eSJernej Skrabec 
12846e8893eSJernej Skrabec 		cedrus_fill_ref_pic(ctx, cedrus_buf,
12946e8893eSJernej Skrabec 				    dpb->top_field_order_cnt,
13046e8893eSJernej Skrabec 				    dpb->bottom_field_order_cnt,
13146e8893eSJernej Skrabec 				    &pic_list[position]);
1326eb9b758SMaxime Ripard 	}
1336eb9b758SMaxime Ripard 
1346eb9b758SMaxime Ripard 	if (output >= 0)
1356eb9b758SMaxime Ripard 		position = output;
1366eb9b758SMaxime Ripard 	else
1376eb9b758SMaxime Ripard 		position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM);
1386eb9b758SMaxime Ripard 
1396eb9b758SMaxime Ripard 	output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
1406eb9b758SMaxime Ripard 	output_buf->codec.h264.position = position;
14146e8893eSJernej Skrabec 
14246e8893eSJernej Skrabec 	if (!output_buf->codec.h264.mv_col_buf_size) {
14346e8893eSJernej Skrabec 		const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
1446eb9b758SMaxime Ripard 		unsigned int field_size;
1456eb9b758SMaxime Ripard 
1466eb9b758SMaxime Ripard 		field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
1476eb9b758SMaxime Ripard 			DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
1486eb9b758SMaxime Ripard 		if (!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE))
149d9358563SEzequiel Garcia 			field_size = field_size * 2;
1506eb9b758SMaxime Ripard 		if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
1516eb9b758SMaxime Ripard 			field_size = field_size * 2;
1526eb9b758SMaxime Ripard 
1536eb9b758SMaxime Ripard 		output_buf->codec.h264.mv_col_buf_size = field_size * 2;
1546eb9b758SMaxime Ripard 		/* Buffer is never accessed by CPU, so we can skip kernel mapping. */
1556eb9b758SMaxime Ripard 		output_buf->codec.h264.mv_col_buf =
1566eb9b758SMaxime Ripard 			dma_alloc_attrs(dev->dev,
1576eb9b758SMaxime Ripard 					output_buf->codec.h264.mv_col_buf_size,
1586eb9b758SMaxime Ripard 					&output_buf->codec.h264.mv_col_buf_dma,
1596eb9b758SMaxime Ripard 					GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
1606eb9b758SMaxime Ripard 
1616eb9b758SMaxime Ripard 		if (!output_buf->codec.h264.mv_col_buf) {
1626eb9b758SMaxime Ripard 			output_buf->codec.h264.mv_col_buf_size = 0;
1636eb9b758SMaxime Ripard 			return -ENOMEM;
1646eb9b758SMaxime Ripard 		}
1656eb9b758SMaxime Ripard 	}
1666eb9b758SMaxime Ripard 
1676eb9b758SMaxime Ripard 	if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
1686eb9b758SMaxime Ripard 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
1696eb9b758SMaxime Ripard 	else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
1706eb9b758SMaxime Ripard 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF;
171e000e1faSJernej Skrabec 	else
172e000e1faSJernej Skrabec 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FRAME;
1736eb9b758SMaxime Ripard 
1746eb9b758SMaxime Ripard 	cedrus_fill_ref_pic(ctx, output_buf,
1751fd50a2cSJernej Skrabec 			    decode->top_field_order_cnt,
1766eb9b758SMaxime Ripard 			    decode->bottom_field_order_cnt,
1776eb9b758SMaxime Ripard 			    &pic_list[position]);
1786eb9b758SMaxime Ripard 
1796eb9b758SMaxime Ripard 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_FRAMEBUFFER_LIST,
1806eb9b758SMaxime Ripard 			       pic_list, sizeof(pic_list));
1811fd50a2cSJernej Skrabec 
1821fd50a2cSJernej Skrabec 	cedrus_write(dev, VE_H264_OUTPUT_FRAME_IDX, position);
1836eb9b758SMaxime Ripard 
1846eb9b758SMaxime Ripard 	return 0;
1856eb9b758SMaxime Ripard }
1866eb9b758SMaxime Ripard 
1876eb9b758SMaxime Ripard #define CEDRUS_MAX_REF_IDX	32
1886eb9b758SMaxime Ripard 
_cedrus_write_ref_list(struct cedrus_ctx * ctx,struct cedrus_run * run,const struct v4l2_h264_reference * ref_list,u8 num_ref,enum cedrus_h264_sram_off sram)189e21cde40SEzequiel Garcia static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
1906eb9b758SMaxime Ripard 				   struct cedrus_run *run,
1916eb9b758SMaxime Ripard 				   const struct v4l2_h264_reference *ref_list,
192e000e1faSJernej Skrabec 				   u8 num_ref, enum cedrus_h264_sram_off sram)
1936eb9b758SMaxime Ripard {
1946eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
1956eb9b758SMaxime Ripard 	struct vb2_queue *cap_q;
1966eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
1976eb9b758SMaxime Ripard 	u8 sram_array[CEDRUS_MAX_REF_IDX];
198e21cde40SEzequiel Garcia 	unsigned int i;
199e21cde40SEzequiel Garcia 	size_t size;
2006eb9b758SMaxime Ripard 
2016eb9b758SMaxime Ripard 	cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
202e21cde40SEzequiel Garcia 
2036eb9b758SMaxime Ripard 	memset(sram_array, 0, sizeof(sram_array));
2046eb9b758SMaxime Ripard 
2056eb9b758SMaxime Ripard 	for (i = 0; i < num_ref; i++) {
20673bc0b0cSJernej Skrabec 		const struct v4l2_h264_dpb_entry *dpb;
2076eb9b758SMaxime Ripard 		const struct cedrus_buffer *cedrus_buf;
2086eb9b758SMaxime Ripard 		unsigned int position;
2096eb9b758SMaxime Ripard 		struct vb2_buffer *buf;
2106eb9b758SMaxime Ripard 		u8 dpb_idx;
2116eb9b758SMaxime Ripard 
2126eb9b758SMaxime Ripard 		dpb_idx = ref_list[i].index;
2136eb9b758SMaxime Ripard 		dpb = &decode->dpb[dpb_idx];
2146eb9b758SMaxime Ripard 
2156eb9b758SMaxime Ripard 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
2166eb9b758SMaxime Ripard 			continue;
2176eb9b758SMaxime Ripard 
2186eb9b758SMaxime Ripard 		buf = vb2_find_buffer(cap_q, dpb->reference_ts);
2196eb9b758SMaxime Ripard 		if (!buf)
2206eb9b758SMaxime Ripard 			continue;
2216eb9b758SMaxime Ripard 
2226eb9b758SMaxime Ripard 		cedrus_buf = vb2_to_cedrus_buffer(buf);
2236eb9b758SMaxime Ripard 		position = cedrus_buf->codec.h264.position;
2246eb9b758SMaxime Ripard 
2256eb9b758SMaxime Ripard 		sram_array[i] |= position << 1;
2266eb9b758SMaxime Ripard 		if (ref_list[i].fields == V4L2_H264_BOTTOM_FIELD_REF)
2276eb9b758SMaxime Ripard 			sram_array[i] |= BIT(0);
2286eb9b758SMaxime Ripard 	}
2296eb9b758SMaxime Ripard 
2306eb9b758SMaxime Ripard 	size = min_t(size_t, ALIGN(num_ref, 4), sizeof(sram_array));
2316eb9b758SMaxime Ripard 	cedrus_h264_write_sram(dev, sram, &sram_array, size);
2326eb9b758SMaxime Ripard }
2336eb9b758SMaxime Ripard 
cedrus_write_ref_list0(struct cedrus_ctx * ctx,struct cedrus_run * run)2346eb9b758SMaxime Ripard static void cedrus_write_ref_list0(struct cedrus_ctx *ctx,
2356eb9b758SMaxime Ripard 				   struct cedrus_run *run)
2366eb9b758SMaxime Ripard {
2376eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
2386eb9b758SMaxime Ripard 
2396eb9b758SMaxime Ripard 	_cedrus_write_ref_list(ctx, run,
2406eb9b758SMaxime Ripard 			       slice->ref_pic_list0,
241b3a23db0SEzequiel Garcia 			       slice->num_ref_idx_l0_active_minus1 + 1,
2426eb9b758SMaxime Ripard 			       CEDRUS_SRAM_H264_REF_LIST_0);
2436eb9b758SMaxime Ripard }
244b3a23db0SEzequiel Garcia 
cedrus_write_ref_list1(struct cedrus_ctx * ctx,struct cedrus_run * run)245b3a23db0SEzequiel Garcia static void cedrus_write_ref_list1(struct cedrus_ctx *ctx,
246b3a23db0SEzequiel Garcia 				   struct cedrus_run *run)
2476eb9b758SMaxime Ripard {
2486eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
2496eb9b758SMaxime Ripard 
2506eb9b758SMaxime Ripard 	_cedrus_write_ref_list(ctx, run,
2516eb9b758SMaxime Ripard 			       slice->ref_pic_list1,
252a6b8feaeSJonas Karlman 			       slice->num_ref_idx_l1_active_minus1 + 1,
253a6b8feaeSJonas Karlman 			       CEDRUS_SRAM_H264_REF_LIST_1);
2546eb9b758SMaxime Ripard }
2556eb9b758SMaxime Ripard 
cedrus_write_scaling_lists(struct cedrus_ctx * ctx,struct cedrus_run * run)2566eb9b758SMaxime Ripard static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
2576eb9b758SMaxime Ripard 				       struct cedrus_run *run)
2586eb9b758SMaxime Ripard {
2596eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_scaling_matrix *scaling =
2606eb9b758SMaxime Ripard 		run->h264.scaling_matrix;
2616eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_pps *pps = run->h264.pps;
2626eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
263eb44c6c9SEzequiel Garcia 
264eb44c6c9SEzequiel Garcia 	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
2656eb9b758SMaxime Ripard 		return;
2666eb9b758SMaxime Ripard 
2676eb9b758SMaxime Ripard 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0,
2686eb9b758SMaxime Ripard 			       scaling->scaling_list_8x8[0],
2696eb9b758SMaxime Ripard 			       sizeof(scaling->scaling_list_8x8[0]));
2706eb9b758SMaxime Ripard 
2716eb9b758SMaxime Ripard 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_1,
2726eb9b758SMaxime Ripard 			       scaling->scaling_list_8x8[1],
2736eb9b758SMaxime Ripard 			       sizeof(scaling->scaling_list_8x8[1]));
2746eb9b758SMaxime Ripard 
2756eb9b758SMaxime Ripard 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_4x4,
2766eb9b758SMaxime Ripard 			       scaling->scaling_list_4x4,
2776eb9b758SMaxime Ripard 			       sizeof(scaling->scaling_list_4x4));
2786eb9b758SMaxime Ripard }
2796eb9b758SMaxime Ripard 
cedrus_write_pred_weight_table(struct cedrus_ctx * ctx,struct cedrus_run * run)2806eb9b758SMaxime Ripard static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx,
2816eb9b758SMaxime Ripard 					   struct cedrus_run *run)
2826eb9b758SMaxime Ripard {
2836eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_pred_weights *pred_weight =
2846eb9b758SMaxime Ripard 		run->h264.pred_weights;
2856eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
2866eb9b758SMaxime Ripard 	int i, j, k;
2876eb9b758SMaxime Ripard 
2886eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SHS_WP,
2896eb9b758SMaxime Ripard 		     ((pred_weight->chroma_log2_weight_denom & 0x7) << 4) |
2906eb9b758SMaxime Ripard 		     ((pred_weight->luma_log2_weight_denom & 0x7) << 0));
2916eb9b758SMaxime Ripard 
2926eb9b758SMaxime Ripard 	cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET,
2936eb9b758SMaxime Ripard 		     CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE << 2);
2946eb9b758SMaxime Ripard 
2956eb9b758SMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(pred_weight->weight_factors); i++) {
2966eb9b758SMaxime Ripard 		const struct v4l2_h264_weight_factors *factors =
2976eb9b758SMaxime Ripard 			&pred_weight->weight_factors[i];
2986eb9b758SMaxime Ripard 
29961ad1233SJernej Skrabec 		for (j = 0; j < ARRAY_SIZE(factors->luma_weight); j++) {
30061ad1233SJernej Skrabec 			u32 val;
30161ad1233SJernej Skrabec 
30261ad1233SJernej Skrabec 			val = (((u32)factors->luma_offset[j] & 0x1ff) << 16) |
30361ad1233SJernej Skrabec 				(factors->luma_weight[j] & 0x1ff);
30461ad1233SJernej Skrabec 			cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
30561ad1233SJernej Skrabec 		}
30661ad1233SJernej Skrabec 
30761ad1233SJernej Skrabec 		for (j = 0; j < ARRAY_SIZE(factors->chroma_weight); j++) {
30861ad1233SJernej Skrabec 			for (k = 0; k < ARRAY_SIZE(factors->chroma_weight[0]); k++) {
30961ad1233SJernej Skrabec 				u32 val;
31061ad1233SJernej Skrabec 
31161ad1233SJernej Skrabec 				val = (((u32)factors->chroma_offset[j][k] & 0x1ff) << 16) |
31261ad1233SJernej Skrabec 					(factors->chroma_weight[j][k] & 0x1ff);
31361ad1233SJernej Skrabec 				cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
31461ad1233SJernej Skrabec 			}
31561ad1233SJernej Skrabec 		}
31661ad1233SJernej Skrabec 	}
31761ad1233SJernej Skrabec }
31861ad1233SJernej Skrabec 
31961ad1233SJernej Skrabec /*
32061ad1233SJernej Skrabec  * It turns out that using VE_H264_VLD_OFFSET to skip bits is not reliable. In
3216eb9b758SMaxime Ripard  * rare cases frame is not decoded correctly. However, setting offset to 0 and
3226eb9b758SMaxime Ripard  * skipping appropriate amount of bits with flush bits trigger always works.
3236eb9b758SMaxime Ripard  */
cedrus_skip_bits(struct cedrus_dev * dev,int num)3246eb9b758SMaxime Ripard static void cedrus_skip_bits(struct cedrus_dev *dev, int num)
3256eb9b758SMaxime Ripard {
3266eb9b758SMaxime Ripard 	int count = 0;
3276eb9b758SMaxime Ripard 
3286eb9b758SMaxime Ripard 	while (count < num) {
3296eb9b758SMaxime Ripard 		int tmp = min(num - count, 32);
3306eb9b758SMaxime Ripard 
331f6f0d58eSEzequiel Garcia 		cedrus_write(dev, VE_H264_TRIGGER_TYPE,
332eabf10e5SJernej Skrabec 			     VE_H264_TRIGGER_TYPE_FLUSH_BITS |
333eabf10e5SJernej Skrabec 			     VE_H264_TRIGGER_TYPE_N_BITS(tmp));
3346eb9b758SMaxime Ripard 		while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VLD_BUSY)
3356eb9b758SMaxime Ripard 			udelay(1);
336f6f0d58eSEzequiel Garcia 
33761ad1233SJernej Skrabec 		count += tmp;
3386eb9b758SMaxime Ripard 	}
3396eb9b758SMaxime Ripard }
340f6f0d58eSEzequiel Garcia 
cedrus_set_params(struct cedrus_ctx * ctx,struct cedrus_run * run)3416eb9b758SMaxime Ripard static void cedrus_set_params(struct cedrus_ctx *ctx,
3426eb9b758SMaxime Ripard 			      struct cedrus_run *run)
3436eb9b758SMaxime Ripard {
3446eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
3456eb9b758SMaxime Ripard 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
34603e612e7SJernej Skrabec 	const struct v4l2_ctrl_h264_pps *pps = run->h264.pps;
34703e612e7SJernej Skrabec 	const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
34803e612e7SJernej Skrabec 	struct vb2_buffer *src_buf = &run->src->vb2_buf;
34903e612e7SJernej Skrabec 	struct cedrus_dev *dev = ctx->dev;
35003e612e7SJernej Skrabec 	dma_addr_t src_buf_addr;
35103e612e7SJernej Skrabec 	size_t slice_bytes = vb2_get_plane_payload(src_buf, 0);
35203e612e7SJernej Skrabec 	unsigned int pic_width_in_mbs;
35303e612e7SJernej Skrabec 	bool mbaff_pic;
35403e612e7SJernej Skrabec 	u32 reg;
35503e612e7SJernej Skrabec 
35603e612e7SJernej Skrabec 	cedrus_write(dev, VE_H264_VLD_LEN, slice_bytes * 8);
35703e612e7SJernej Skrabec 	cedrus_write(dev, VE_H264_VLD_OFFSET, 0);
35803e612e7SJernej Skrabec 
35903e612e7SJernej Skrabec 	src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
3606eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_VLD_END, src_buf_addr + slice_bytes);
3616eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_VLD_ADDR,
3626eb9b758SMaxime Ripard 		     VE_H264_VLD_ADDR_VAL(src_buf_addr) |
3636eb9b758SMaxime Ripard 		     VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
3646eb9b758SMaxime Ripard 		     VE_H264_VLD_ADDR_LAST);
3656eb9b758SMaxime Ripard 
3666eb9b758SMaxime Ripard 	if (ctx->src_fmt.width > 2048) {
3676eb9b758SMaxime Ripard 		cedrus_write(dev, VE_BUF_CTRL,
3686eb9b758SMaxime Ripard 			     VE_BUF_CTRL_INTRAPRED_MIXED_RAM |
36961ad1233SJernej Skrabec 			     VE_BUF_CTRL_DBLK_MIXED_RAM);
37061ad1233SJernej Skrabec 		cedrus_write(dev, VE_DBLK_DRAM_BUF_ADDR,
371eb44c6c9SEzequiel Garcia 			     ctx->codec.h264.deblk_buf_dma);
3726eb9b758SMaxime Ripard 		cedrus_write(dev, VE_INTRAPRED_DRAM_BUF_ADDR,
3736eb9b758SMaxime Ripard 			     ctx->codec.h264.intra_pred_buf_dma);
3746eb9b758SMaxime Ripard 	} else {
3756eb9b758SMaxime Ripard 		cedrus_write(dev, VE_BUF_CTRL,
3766eb9b758SMaxime Ripard 			     VE_BUF_CTRL_INTRAPRED_INT_SRAM |
3776eb9b758SMaxime Ripard 			     VE_BUF_CTRL_DBLK_INT_SRAM);
3786eb9b758SMaxime Ripard 	}
3796eb9b758SMaxime Ripard 
3806eb9b758SMaxime Ripard 	/*
3816eb9b758SMaxime Ripard 	 * FIXME: Since the bitstream parsing is done in software, and
3826eb9b758SMaxime Ripard 	 * in userspace, this shouldn't be needed anymore. But it
3836eb9b758SMaxime Ripard 	 * turns out that removing it breaks the decoding process,
3846eb9b758SMaxime Ripard 	 * without any clear indication why.
3856eb9b758SMaxime Ripard 	 */
3866eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_TRIGGER_TYPE,
3876eb9b758SMaxime Ripard 		     VE_H264_TRIGGER_TYPE_INIT_SWDEC);
3886eb9b758SMaxime Ripard 
3896eb9b758SMaxime Ripard 	cedrus_skip_bits(dev, slice->header_bit_size);
3906eb9b758SMaxime Ripard 
3916eb9b758SMaxime Ripard 	if (V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice))
3926eb9b758SMaxime Ripard 		cedrus_write_pred_weight_table(ctx, run);
3936eb9b758SMaxime Ripard 
3946eb9b758SMaxime Ripard 	if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) ||
3956eb9b758SMaxime Ripard 	    (slice->slice_type == V4L2_H264_SLICE_TYPE_SP) ||
3966eb9b758SMaxime Ripard 	    (slice->slice_type == V4L2_H264_SLICE_TYPE_B))
3976eb9b758SMaxime Ripard 		cedrus_write_ref_list0(ctx, run);
3986eb9b758SMaxime Ripard 
3996eb9b758SMaxime Ripard 	if (slice->slice_type == V4L2_H264_SLICE_TYPE_B)
4006eb9b758SMaxime Ripard 		cedrus_write_ref_list1(ctx, run);
4016eb9b758SMaxime Ripard 
4026eb9b758SMaxime Ripard 	// picture parameters
4036eb9b758SMaxime Ripard 	reg = 0;
4046eb9b758SMaxime Ripard 	/*
4056eb9b758SMaxime Ripard 	 * FIXME: the kernel headers are allowing the default value to
4066eb9b758SMaxime Ripard 	 * be passed, but the libva doesn't give us that.
4076eb9b758SMaxime Ripard 	 */
4086eb9b758SMaxime Ripard 	reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 10;
4096eb9b758SMaxime Ripard 	reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 5;
4106eb9b758SMaxime Ripard 	reg |= (pps->weighted_bipred_idc & 0x3) << 2;
4116eb9b758SMaxime Ripard 	if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)
4126eb9b758SMaxime Ripard 		reg |= VE_H264_PPS_ENTROPY_CODING_MODE;
4136eb9b758SMaxime Ripard 	if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED)
414d9358563SEzequiel Garcia 		reg |= VE_H264_PPS_WEIGHTED_PRED;
415eabf10e5SJernej Skrabec 	if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)
416eabf10e5SJernej Skrabec 		reg |= VE_H264_PPS_CONSTRAINED_INTRA_PRED;
417eabf10e5SJernej Skrabec 	if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE)
4186eb9b758SMaxime Ripard 		reg |= VE_H264_PPS_TRANSFORM_8X8_MODE;
4196eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_PPS, reg);
420eabf10e5SJernej Skrabec 
421eabf10e5SJernej Skrabec 	// sequence parameters
422eabf10e5SJernej Skrabec 	reg = 0;
4236eb9b758SMaxime Ripard 	reg |= (sps->chroma_format_idc & 0x7) << 19;
4246eb9b758SMaxime Ripard 	reg |= (sps->pic_width_in_mbs_minus1 & 0xff) << 8;
4256eb9b758SMaxime Ripard 	reg |= sps->pic_height_in_map_units_minus1 & 0xff;
426eabf10e5SJernej Skrabec 	if (sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
4276eb9b758SMaxime Ripard 		reg |= VE_H264_SPS_MBS_ONLY;
428d9358563SEzequiel Garcia 	if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
4296eb9b758SMaxime Ripard 		reg |= VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD;
430d9358563SEzequiel Garcia 	if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)
4316eb9b758SMaxime Ripard 		reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE;
4326eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SPS, reg);
4336eb9b758SMaxime Ripard 
4346eb9b758SMaxime Ripard 	mbaff_pic = !(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) &&
4356eb9b758SMaxime Ripard 		    (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
4366eb9b758SMaxime Ripard 	pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
4376eb9b758SMaxime Ripard 
4386eb9b758SMaxime Ripard 	// slice parameters
4396eb9b758SMaxime Ripard 	reg = 0;
4406eb9b758SMaxime Ripard 	reg |= ((slice->first_mb_in_slice % pic_width_in_mbs) & 0xff) << 24;
4416eb9b758SMaxime Ripard 	reg |= (((slice->first_mb_in_slice / pic_width_in_mbs) *
4426eb9b758SMaxime Ripard 		 (mbaff_pic + 1)) & 0xff) << 16;
4436eb9b758SMaxime Ripard 	reg |= decode->nal_ref_idc ? BIT(12) : 0;
4446eb9b758SMaxime Ripard 	reg |= (slice->slice_type & 0xf) << 8;
4456eb9b758SMaxime Ripard 	reg |= slice->cabac_init_idc & 0x3;
4466eb9b758SMaxime Ripard 	if (ctx->fh.m2m_ctx->new_frame)
4476eb9b758SMaxime Ripard 		reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
4486eb9b758SMaxime Ripard 	if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
4499ac924b9SJernej Skrabec 		reg |= VE_H264_SHS_FIELD_PIC;
450b3a23db0SEzequiel Garcia 	if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
4516eb9b758SMaxime Ripard 		reg |= VE_H264_SHS_BOTTOM_FIELD;
4526eb9b758SMaxime Ripard 	if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED)
4536eb9b758SMaxime Ripard 		reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED;
4546eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SHS, reg);
4556eb9b758SMaxime Ripard 
4566eb9b758SMaxime Ripard 	reg = 0;
4576eb9b758SMaxime Ripard 	reg |= VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD;
4586eb9b758SMaxime Ripard 	reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 24;
4596eb9b758SMaxime Ripard 	reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 16;
4606eb9b758SMaxime Ripard 	reg |= (slice->disable_deblocking_filter_idc & 0x3) << 8;
4616eb9b758SMaxime Ripard 	reg |= (slice->slice_alpha_c0_offset_div2 & 0xf) << 4;
4626eb9b758SMaxime Ripard 	reg |= slice->slice_beta_offset_div2 & 0xf;
4636eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SHS2, reg);
4646eb9b758SMaxime Ripard 
4656eb9b758SMaxime Ripard 	reg = 0;
4666eb9b758SMaxime Ripard 	reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16;
4676eb9b758SMaxime Ripard 	reg |= (pps->chroma_qp_index_offset & 0x3f) << 8;
4686eb9b758SMaxime Ripard 	reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f;
4696eb9b758SMaxime Ripard 	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
4706eb9b758SMaxime Ripard 		reg |= VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT;
4716eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SHS_QP, reg);
4726eb9b758SMaxime Ripard 
4736eb9b758SMaxime Ripard 	// clear status flags
4746eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_STATUS, cedrus_read(dev, VE_H264_STATUS));
4756eb9b758SMaxime Ripard 
4766eb9b758SMaxime Ripard 	// enable int
4776eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_CTRL,
4786eb9b758SMaxime Ripard 		     VE_H264_CTRL_SLICE_DECODE_INT |
4796eb9b758SMaxime Ripard 		     VE_H264_CTRL_DECODE_ERR_INT |
4806eb9b758SMaxime Ripard 		     VE_H264_CTRL_VLD_DATA_REQ_INT);
4816eb9b758SMaxime Ripard }
4826eb9b758SMaxime Ripard 
4836eb9b758SMaxime Ripard static enum cedrus_irq_status
cedrus_h264_irq_status(struct cedrus_ctx * ctx)4846eb9b758SMaxime Ripard cedrus_h264_irq_status(struct cedrus_ctx *ctx)
4856eb9b758SMaxime Ripard {
4866eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
4876eb9b758SMaxime Ripard 	u32 reg = cedrus_read(dev, VE_H264_STATUS);
4886eb9b758SMaxime Ripard 
4896eb9b758SMaxime Ripard 	if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
4906eb9b758SMaxime Ripard 		   VE_H264_STATUS_VLD_DATA_REQ_INT))
4916eb9b758SMaxime Ripard 		return CEDRUS_IRQ_ERROR;
4926eb9b758SMaxime Ripard 
4936eb9b758SMaxime Ripard 	if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
4946eb9b758SMaxime Ripard 		return CEDRUS_IRQ_OK;
4956eb9b758SMaxime Ripard 
4964af46bccSJernej Skrabec 	return CEDRUS_IRQ_NONE;
4976eb9b758SMaxime Ripard }
4986eb9b758SMaxime Ripard 
cedrus_h264_irq_clear(struct cedrus_ctx * ctx)4996eb9b758SMaxime Ripard static void cedrus_h264_irq_clear(struct cedrus_ctx *ctx)
500*4fc81c58SJernej Skrabec {
5016eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
5026eb9b758SMaxime Ripard 
5036eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_STATUS,
5046eb9b758SMaxime Ripard 		     VE_H264_STATUS_INT_MASK);
5056eb9b758SMaxime Ripard }
5066eb9b758SMaxime Ripard 
cedrus_h264_irq_disable(struct cedrus_ctx * ctx)5076eb9b758SMaxime Ripard static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx)
5086eb9b758SMaxime Ripard {
5096eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
5106eb9b758SMaxime Ripard 	u32 reg = cedrus_read(dev, VE_H264_CTRL);
5116eb9b758SMaxime Ripard 
5124af46bccSJernej Skrabec 	cedrus_write(dev, VE_H264_CTRL,
5134af46bccSJernej Skrabec 		     reg & ~VE_H264_CTRL_INT_MASK);
5146eb9b758SMaxime Ripard }
5156eb9b758SMaxime Ripard 
cedrus_h264_setup(struct cedrus_ctx * ctx,struct cedrus_run * run)5166eb9b758SMaxime Ripard static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
5176eb9b758SMaxime Ripard {
5186eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
51903e612e7SJernej Skrabec 	int ret;
5206eb9b758SMaxime Ripard 
5216eb9b758SMaxime Ripard 	cedrus_engine_enable(ctx);
5226eb9b758SMaxime Ripard 
5236eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_SDROT_CTRL, 0);
5245db127a5SJernej Skrabec 	cedrus_write(dev, VE_H264_EXTRA_BUFFER1,
5255db127a5SJernej Skrabec 		     ctx->codec.h264.pic_info_buf_dma);
5265db127a5SJernej Skrabec 	cedrus_write(dev, VE_H264_EXTRA_BUFFER2,
5275db127a5SJernej Skrabec 		     ctx->codec.h264.neighbor_info_buf_dma);
5285db127a5SJernej Skrabec 
52903e612e7SJernej Skrabec 	cedrus_write_scaling_lists(ctx, run);
53003e612e7SJernej Skrabec 	ret = cedrus_write_frame_list(ctx, run);
53103e612e7SJernej Skrabec 	if (ret)
53203e612e7SJernej Skrabec 		return ret;
53303e612e7SJernej Skrabec 
53403e612e7SJernej Skrabec 	cedrus_set_params(ctx, run);
53503e612e7SJernej Skrabec 
5366eb9b758SMaxime Ripard 	return 0;
53703e612e7SJernej Skrabec }
53803e612e7SJernej Skrabec 
cedrus_h264_start(struct cedrus_ctx * ctx)5396eb9b758SMaxime Ripard static int cedrus_h264_start(struct cedrus_ctx *ctx)
54003e612e7SJernej Skrabec {
54103e612e7SJernej Skrabec 	struct cedrus_dev *dev = ctx->dev;
54203e612e7SJernej Skrabec 	unsigned int pic_info_size;
54303e612e7SJernej Skrabec 	int ret;
54403e612e7SJernej Skrabec 
54503e612e7SJernej Skrabec 	/*
5466eb9b758SMaxime Ripard 	 * NOTE: All buffers allocated here are only used by HW, so we
5475db127a5SJernej Skrabec 	 * can add DMA_ATTR_NO_KERNEL_MAPPING flag when allocating them.
5486eb9b758SMaxime Ripard 	 */
5495db127a5SJernej Skrabec 
5506eb9b758SMaxime Ripard 	/* Formula for picture buffer size is taken from CedarX source. */
5516eb9b758SMaxime Ripard 
5526eb9b758SMaxime Ripard 	if (ctx->src_fmt.width > 2048)
5536eb9b758SMaxime Ripard 		pic_info_size = CEDRUS_H264_FRAME_NUM * 0x4000;
5546eb9b758SMaxime Ripard 	else
5555db127a5SJernej Skrabec 		pic_info_size = CEDRUS_H264_FRAME_NUM * 0x1000;
5565db127a5SJernej Skrabec 
5575db127a5SJernej Skrabec 	/*
5585db127a5SJernej Skrabec 	 * FIXME: If V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is set,
5596eb9b758SMaxime Ripard 	 * there is no need to multiply by 2.
5606eb9b758SMaxime Ripard 	 */
5615db127a5SJernej Skrabec 	pic_info_size += ctx->src_fmt.height * 2 * 64;
5626eb9b758SMaxime Ripard 
5635db127a5SJernej Skrabec 	if (pic_info_size < CEDRUS_MIN_PIC_INFO_BUF_SIZE)
5646eb9b758SMaxime Ripard 		pic_info_size = CEDRUS_MIN_PIC_INFO_BUF_SIZE;
5656eb9b758SMaxime Ripard 
5666eb9b758SMaxime Ripard 	ctx->codec.h264.pic_info_buf_size = pic_info_size;
5676eb9b758SMaxime Ripard 	ctx->codec.h264.pic_info_buf =
5686eb9b758SMaxime Ripard 		dma_alloc_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size,
5696eb9b758SMaxime Ripard 				&ctx->codec.h264.pic_info_buf_dma,
5706eb9b758SMaxime Ripard 				GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
5716eb9b758SMaxime Ripard 	if (!ctx->codec.h264.pic_info_buf)
5726eb9b758SMaxime Ripard 		return -ENOMEM;
5736eb9b758SMaxime Ripard 
5746eb9b758SMaxime Ripard 	/*
5756eb9b758SMaxime Ripard 	 * That buffer is supposed to be 16kiB in size, and be aligned
5766eb9b758SMaxime Ripard 	 * on 16kiB as well. However, dma_alloc_attrs provides the
5776eb9b758SMaxime Ripard 	 * guarantee that we'll have a DMA address aligned on the
5786eb9b758SMaxime Ripard 	 * smallest page order that is greater to the requested size,
5796eb9b758SMaxime Ripard 	 * so we don't have to overallocate.
5806eb9b758SMaxime Ripard 	 */
5816eb9b758SMaxime Ripard 	ctx->codec.h264.neighbor_info_buf =
5826eb9b758SMaxime Ripard 		dma_alloc_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
5836eb9b758SMaxime Ripard 				&ctx->codec.h264.neighbor_info_buf_dma,
5846eb9b758SMaxime Ripard 				GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
5856eb9b758SMaxime Ripard 	if (!ctx->codec.h264.neighbor_info_buf) {
5866eb9b758SMaxime Ripard 		ret = -ENOMEM;
5876eb9b758SMaxime Ripard 		goto err_pic_buf;
5886eb9b758SMaxime Ripard 	}
5896eb9b758SMaxime Ripard 
5906eb9b758SMaxime Ripard 	if (ctx->src_fmt.width > 2048) {
5915db127a5SJernej Skrabec 		/*
5925db127a5SJernej Skrabec 		 * Formulas for deblock and intra prediction buffer sizes
5936eb9b758SMaxime Ripard 		 * are taken from CedarX source.
5946eb9b758SMaxime Ripard 		 */
5955db127a5SJernej Skrabec 
5966eb9b758SMaxime Ripard 		ctx->codec.h264.deblk_buf_size =
5976eb9b758SMaxime Ripard 			ALIGN(ctx->src_fmt.width, 32) * 12;
5986eb9b758SMaxime Ripard 		ctx->codec.h264.deblk_buf =
5996eb9b758SMaxime Ripard 			dma_alloc_attrs(dev->dev,
6006eb9b758SMaxime Ripard 					ctx->codec.h264.deblk_buf_size,
60103e612e7SJernej Skrabec 					&ctx->codec.h264.deblk_buf_dma,
60203e612e7SJernej Skrabec 					GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
60303e612e7SJernej Skrabec 		if (!ctx->codec.h264.deblk_buf) {
60403e612e7SJernej Skrabec 			ret = -ENOMEM;
60503e612e7SJernej Skrabec 			goto err_neighbor_buf;
60603e612e7SJernej Skrabec 		}
60703e612e7SJernej Skrabec 
60803e612e7SJernej Skrabec 		/*
60903e612e7SJernej Skrabec 		 * NOTE: Multiplying by two deviates from CedarX logic, but it
6105db127a5SJernej Skrabec 		 * is for some unknown reason needed for H264 4K decoding on H6.
61103e612e7SJernej Skrabec 		 */
61203e612e7SJernej Skrabec 		ctx->codec.h264.intra_pred_buf_size =
6135db127a5SJernej Skrabec 			ALIGN(ctx->src_fmt.width, 64) * 5 * 2;
61403e612e7SJernej Skrabec 		ctx->codec.h264.intra_pred_buf =
61503e612e7SJernej Skrabec 			dma_alloc_attrs(dev->dev,
61603e612e7SJernej Skrabec 					ctx->codec.h264.intra_pred_buf_size,
61703e612e7SJernej Skrabec 					&ctx->codec.h264.intra_pred_buf_dma,
61803e612e7SJernej Skrabec 					GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
619ea755701SJernej Skrabec 		if (!ctx->codec.h264.intra_pred_buf) {
620ea755701SJernej Skrabec 			ret = -ENOMEM;
621ea755701SJernej Skrabec 			goto err_deblk_buf;
622ea755701SJernej Skrabec 		}
62303e612e7SJernej Skrabec 	}
624ea755701SJernej Skrabec 
62503e612e7SJernej Skrabec 	return 0;
6265db127a5SJernej Skrabec 
62703e612e7SJernej Skrabec err_deblk_buf:
62803e612e7SJernej Skrabec 	dma_free_attrs(dev->dev, ctx->codec.h264.deblk_buf_size,
6295db127a5SJernej Skrabec 		       ctx->codec.h264.deblk_buf,
63003e612e7SJernej Skrabec 		       ctx->codec.h264.deblk_buf_dma,
63103e612e7SJernej Skrabec 		       DMA_ATTR_NO_KERNEL_MAPPING);
63203e612e7SJernej Skrabec 
63303e612e7SJernej Skrabec err_neighbor_buf:
63403e612e7SJernej Skrabec 	dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
63503e612e7SJernej Skrabec 		       ctx->codec.h264.neighbor_info_buf,
6366eb9b758SMaxime Ripard 		       ctx->codec.h264.neighbor_info_buf_dma,
6376eb9b758SMaxime Ripard 		       DMA_ATTR_NO_KERNEL_MAPPING);
63803e612e7SJernej Skrabec 
6395db127a5SJernej Skrabec err_pic_buf:
64003e612e7SJernej Skrabec 	dma_free_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size,
6415db127a5SJernej Skrabec 		       ctx->codec.h264.pic_info_buf,
6425db127a5SJernej Skrabec 		       ctx->codec.h264.pic_info_buf_dma,
64303e612e7SJernej Skrabec 		       DMA_ATTR_NO_KERNEL_MAPPING);
64403e612e7SJernej Skrabec 	return ret;
6455db127a5SJernej Skrabec }
64603e612e7SJernej Skrabec 
cedrus_h264_stop(struct cedrus_ctx * ctx)6475db127a5SJernej Skrabec static void cedrus_h264_stop(struct cedrus_ctx *ctx)
6485db127a5SJernej Skrabec {
64903e612e7SJernej Skrabec 	struct cedrus_dev *dev = ctx->dev;
6506eb9b758SMaxime Ripard 	struct cedrus_buffer *buf;
6515db127a5SJernej Skrabec 	struct vb2_queue *vq;
6526eb9b758SMaxime Ripard 	unsigned int i;
6535db127a5SJernej Skrabec 
6545db127a5SJernej Skrabec 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
6556eb9b758SMaxime Ripard 
6566eb9b758SMaxime Ripard 	for (i = 0; i < vq->num_buffers; i++) {
6575db127a5SJernej Skrabec 		buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i));
6586eb9b758SMaxime Ripard 
6595db127a5SJernej Skrabec 		if (buf->codec.h264.mv_col_buf_size > 0) {
6605db127a5SJernej Skrabec 			dma_free_attrs(dev->dev,
6616eb9b758SMaxime Ripard 				       buf->codec.h264.mv_col_buf_size,
6626eb9b758SMaxime Ripard 				       buf->codec.h264.mv_col_buf,
6636eb9b758SMaxime Ripard 				       buf->codec.h264.mv_col_buf_dma,
6646eb9b758SMaxime Ripard 				       DMA_ATTR_NO_KERNEL_MAPPING);
6656eb9b758SMaxime Ripard 
6666eb9b758SMaxime Ripard 			buf->codec.h264.mv_col_buf_size = 0;
6676eb9b758SMaxime Ripard 		}
6685db127a5SJernej Skrabec 	}
6696eb9b758SMaxime Ripard 
6705db127a5SJernej Skrabec 	dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
6715db127a5SJernej Skrabec 		       ctx->codec.h264.neighbor_info_buf,
6725db127a5SJernej Skrabec 		       ctx->codec.h264.neighbor_info_buf_dma,
6736eb9b758SMaxime Ripard 		       DMA_ATTR_NO_KERNEL_MAPPING);
6745db127a5SJernej Skrabec 	dma_free_attrs(dev->dev, ctx->codec.h264.pic_info_buf_size,
6755db127a5SJernej Skrabec 		       ctx->codec.h264.pic_info_buf,
6765db127a5SJernej Skrabec 		       ctx->codec.h264.pic_info_buf_dma,
6776eb9b758SMaxime Ripard 		       DMA_ATTR_NO_KERNEL_MAPPING);
6785db127a5SJernej Skrabec 	if (ctx->codec.h264.deblk_buf_size)
6795db127a5SJernej Skrabec 		dma_free_attrs(dev->dev, ctx->codec.h264.deblk_buf_size,
68003e612e7SJernej Skrabec 			       ctx->codec.h264.deblk_buf,
6815db127a5SJernej Skrabec 			       ctx->codec.h264.deblk_buf_dma,
68203e612e7SJernej Skrabec 			       DMA_ATTR_NO_KERNEL_MAPPING);
6835db127a5SJernej Skrabec 	if (ctx->codec.h264.intra_pred_buf_size)
6845db127a5SJernej Skrabec 		dma_free_attrs(dev->dev, ctx->codec.h264.intra_pred_buf_size,
68503e612e7SJernej Skrabec 			       ctx->codec.h264.intra_pred_buf,
6865db127a5SJernej Skrabec 			       ctx->codec.h264.intra_pred_buf_dma,
68703e612e7SJernej Skrabec 			       DMA_ATTR_NO_KERNEL_MAPPING);
6885db127a5SJernej Skrabec }
6895db127a5SJernej Skrabec 
cedrus_h264_trigger(struct cedrus_ctx * ctx)6906eb9b758SMaxime Ripard static void cedrus_h264_trigger(struct cedrus_ctx *ctx)
6916eb9b758SMaxime Ripard {
6926eb9b758SMaxime Ripard 	struct cedrus_dev *dev = ctx->dev;
6936eb9b758SMaxime Ripard 
6946eb9b758SMaxime Ripard 	cedrus_write(dev, VE_H264_TRIGGER_TYPE,
6956eb9b758SMaxime Ripard 		     VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE);
6966eb9b758SMaxime Ripard }
6976eb9b758SMaxime Ripard 
6986eb9b758SMaxime Ripard struct cedrus_dec_ops cedrus_dec_ops_h264 = {
6996eb9b758SMaxime Ripard 	.irq_clear	= cedrus_h264_irq_clear,
7006eb9b758SMaxime Ripard 	.irq_disable	= cedrus_h264_irq_disable,
7016eb9b758SMaxime Ripard 	.irq_status	= cedrus_h264_irq_status,
7026eb9b758SMaxime Ripard 	.setup		= cedrus_h264_setup,
7036eb9b758SMaxime Ripard 	.start		= cedrus_h264_start,
7046eb9b758SMaxime Ripard 	.stop		= cedrus_h264_stop,
7056eb9b758SMaxime Ripard 	.trigger	= cedrus_h264_trigger,
7066eb9b758SMaxime Ripard };
7076eb9b758SMaxime Ripard