1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Cedrus VPU driver
4  *
5  * Copyright (c) 2013 Jens Kuske <jenskuske@gmail.com>
6  * Copyright (c) 2018 Bootlin
7  */
8 
9 #include <linux/types.h>
10 
11 #include <media/videobuf2-dma-contig.h>
12 
13 #include "cedrus.h"
14 #include "cedrus_hw.h"
15 #include "cedrus_regs.h"
16 
17 enum cedrus_h264_sram_off {
18 	CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE	= 0x000,
19 	CEDRUS_SRAM_H264_FRAMEBUFFER_LIST	= 0x100,
20 	CEDRUS_SRAM_H264_REF_LIST_0		= 0x190,
21 	CEDRUS_SRAM_H264_REF_LIST_1		= 0x199,
22 	CEDRUS_SRAM_H264_SCALING_LIST_8x8_0	= 0x200,
23 	CEDRUS_SRAM_H264_SCALING_LIST_8x8_1	= 0x210,
24 	CEDRUS_SRAM_H264_SCALING_LIST_4x4	= 0x220,
25 };
26 
27 struct cedrus_h264_sram_ref_pic {
28 	__le32	top_field_order_cnt;
29 	__le32	bottom_field_order_cnt;
30 	__le32	frame_info;
31 	__le32	luma_ptr;
32 	__le32	chroma_ptr;
33 	__le32	mv_col_top_ptr;
34 	__le32	mv_col_bot_ptr;
35 	__le32	reserved;
36 } __packed;
37 
38 #define CEDRUS_H264_FRAME_NUM		18
39 
40 #define CEDRUS_NEIGHBOR_INFO_BUF_SIZE	(16 * SZ_1K)
41 #define CEDRUS_PIC_INFO_BUF_SIZE	(128 * SZ_1K)
42 
cedrus_h264_write_sram(struct cedrus_dev * dev,enum cedrus_h264_sram_off off,const void * data,size_t len)43 static void cedrus_h264_write_sram(struct cedrus_dev *dev,
44 				   enum cedrus_h264_sram_off off,
45 				   const void *data, size_t len)
46 {
47 	const u32 *buffer = data;
48 	size_t count = DIV_ROUND_UP(len, 4);
49 
50 	cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET, off << 2);
51 
52 	while (count--)
53 		cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, *buffer++);
54 }
55 
cedrus_h264_mv_col_buf_addr(struct cedrus_ctx * ctx,unsigned int position,unsigned int field)56 static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx,
57 					      unsigned int position,
58 					      unsigned int field)
59 {
60 	dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma;
61 
62 	/* Adjust for the position */
63 	addr += position * ctx->codec.h264.mv_col_buf_field_size * 2;
64 
65 	/* Adjust for the field */
66 	addr += field * ctx->codec.h264.mv_col_buf_field_size;
67 
68 	return addr;
69 }
70 
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)71 static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
72 				struct cedrus_buffer *buf,
73 				unsigned int top_field_order_cnt,
74 				unsigned int bottom_field_order_cnt,
75 				struct cedrus_h264_sram_ref_pic *pic)
76 {
77 	struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
78 	unsigned int position = buf->codec.h264.position;
79 
80 	pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
81 	pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
82 	pic->frame_info = cpu_to_le32(buf->codec.h264.pic_type << 8);
83 
84 	pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
85 	pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
86 	pic->mv_col_top_ptr =
87 		cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0));
88 	pic->mv_col_bot_ptr =
89 		cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1));
90 }
91 
cedrus_write_frame_list(struct cedrus_ctx * ctx,struct cedrus_run * run)92 static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
93 				    struct cedrus_run *run)
94 {
95 	struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM];
96 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
97 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
98 	const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
99 	struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
100 	struct cedrus_buffer *output_buf;
101 	struct cedrus_dev *dev = ctx->dev;
102 	unsigned long used_dpbs = 0;
103 	unsigned int position;
104 	unsigned int output = 0;
105 	unsigned int i;
106 
107 	memset(pic_list, 0, sizeof(pic_list));
108 
109 	for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) {
110 		const struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i];
111 		struct cedrus_buffer *cedrus_buf;
112 		int buf_idx;
113 
114 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
115 			continue;
116 
117 		buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0);
118 		if (buf_idx < 0)
119 			continue;
120 
121 		cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]);
122 		position = cedrus_buf->codec.h264.position;
123 		used_dpbs |= BIT(position);
124 
125 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
126 			continue;
127 
128 		cedrus_fill_ref_pic(ctx, cedrus_buf,
129 				    dpb->top_field_order_cnt,
130 				    dpb->bottom_field_order_cnt,
131 				    &pic_list[position]);
132 
133 		output = max(position, output);
134 	}
135 
136 	position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM,
137 				      output);
138 	if (position >= CEDRUS_H264_FRAME_NUM)
139 		position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM);
140 
141 	output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
142 	output_buf->codec.h264.position = position;
143 
144 	if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
145 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
146 	else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
147 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF;
148 	else
149 		output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FRAME;
150 
151 	cedrus_fill_ref_pic(ctx, output_buf,
152 			    decode->top_field_order_cnt,
153 			    decode->bottom_field_order_cnt,
154 			    &pic_list[position]);
155 
156 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_FRAMEBUFFER_LIST,
157 			       pic_list, sizeof(pic_list));
158 
159 	cedrus_write(dev, VE_H264_OUTPUT_FRAME_IDX, position);
160 }
161 
162 #define CEDRUS_MAX_REF_IDX	32
163 
_cedrus_write_ref_list(struct cedrus_ctx * ctx,struct cedrus_run * run,const u8 * ref_list,u8 num_ref,enum cedrus_h264_sram_off sram)164 static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
165 				   struct cedrus_run *run,
166 				   const u8 *ref_list, u8 num_ref,
167 				   enum cedrus_h264_sram_off sram)
168 {
169 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
170 	struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
171 	struct cedrus_dev *dev = ctx->dev;
172 	u8 sram_array[CEDRUS_MAX_REF_IDX];
173 	unsigned int i;
174 	size_t size;
175 
176 	memset(sram_array, 0, sizeof(sram_array));
177 
178 	for (i = 0; i < num_ref; i++) {
179 		const struct v4l2_h264_dpb_entry *dpb;
180 		const struct cedrus_buffer *cedrus_buf;
181 		const struct vb2_v4l2_buffer *ref_buf;
182 		unsigned int position;
183 		int buf_idx;
184 		u8 dpb_idx;
185 
186 		dpb_idx = ref_list[i];
187 		dpb = &decode->dpb[dpb_idx];
188 
189 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
190 			continue;
191 
192 		buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0);
193 		if (buf_idx < 0)
194 			continue;
195 
196 		ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]);
197 		cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf);
198 		position = cedrus_buf->codec.h264.position;
199 
200 		sram_array[i] |= position << 1;
201 		if (ref_buf->field == V4L2_FIELD_BOTTOM)
202 			sram_array[i] |= BIT(0);
203 	}
204 
205 	size = min_t(size_t, ALIGN(num_ref, 4), sizeof(sram_array));
206 	cedrus_h264_write_sram(dev, sram, &sram_array, size);
207 }
208 
cedrus_write_ref_list0(struct cedrus_ctx * ctx,struct cedrus_run * run)209 static void cedrus_write_ref_list0(struct cedrus_ctx *ctx,
210 				   struct cedrus_run *run)
211 {
212 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
213 
214 	_cedrus_write_ref_list(ctx, run,
215 			       slice->ref_pic_list0,
216 			       slice->num_ref_idx_l0_active_minus1 + 1,
217 			       CEDRUS_SRAM_H264_REF_LIST_0);
218 }
219 
cedrus_write_ref_list1(struct cedrus_ctx * ctx,struct cedrus_run * run)220 static void cedrus_write_ref_list1(struct cedrus_ctx *ctx,
221 				   struct cedrus_run *run)
222 {
223 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
224 
225 	_cedrus_write_ref_list(ctx, run,
226 			       slice->ref_pic_list1,
227 			       slice->num_ref_idx_l1_active_minus1 + 1,
228 			       CEDRUS_SRAM_H264_REF_LIST_1);
229 }
230 
cedrus_write_scaling_lists(struct cedrus_ctx * ctx,struct cedrus_run * run)231 static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
232 				       struct cedrus_run *run)
233 {
234 	const struct v4l2_ctrl_h264_scaling_matrix *scaling =
235 		run->h264.scaling_matrix;
236 	struct cedrus_dev *dev = ctx->dev;
237 
238 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0,
239 			       scaling->scaling_list_8x8[0],
240 			       sizeof(scaling->scaling_list_8x8[0]));
241 
242 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_1,
243 			       scaling->scaling_list_8x8[3],
244 			       sizeof(scaling->scaling_list_8x8[3]));
245 
246 	cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_4x4,
247 			       scaling->scaling_list_4x4,
248 			       sizeof(scaling->scaling_list_4x4));
249 }
250 
cedrus_write_pred_weight_table(struct cedrus_ctx * ctx,struct cedrus_run * run)251 static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx,
252 					   struct cedrus_run *run)
253 {
254 	const struct v4l2_ctrl_h264_slice_params *slice =
255 		run->h264.slice_params;
256 	const struct v4l2_h264_pred_weight_table *pred_weight =
257 		&slice->pred_weight_table;
258 	struct cedrus_dev *dev = ctx->dev;
259 	int i, j, k;
260 
261 	cedrus_write(dev, VE_H264_SHS_WP,
262 		     ((pred_weight->chroma_log2_weight_denom & 0x7) << 4) |
263 		     ((pred_weight->luma_log2_weight_denom & 0x7) << 0));
264 
265 	cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET,
266 		     CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE << 2);
267 
268 	for (i = 0; i < ARRAY_SIZE(pred_weight->weight_factors); i++) {
269 		const struct v4l2_h264_weight_factors *factors =
270 			&pred_weight->weight_factors[i];
271 
272 		for (j = 0; j < ARRAY_SIZE(factors->luma_weight); j++) {
273 			u32 val;
274 
275 			val = (((u32)factors->luma_offset[j] & 0x1ff) << 16) |
276 				(factors->luma_weight[j] & 0x1ff);
277 			cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
278 		}
279 
280 		for (j = 0; j < ARRAY_SIZE(factors->chroma_weight); j++) {
281 			for (k = 0; k < ARRAY_SIZE(factors->chroma_weight[0]); k++) {
282 				u32 val;
283 
284 				val = (((u32)factors->chroma_offset[j][k] & 0x1ff) << 16) |
285 					(factors->chroma_weight[j][k] & 0x1ff);
286 				cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
287 			}
288 		}
289 	}
290 }
291 
cedrus_set_params(struct cedrus_ctx * ctx,struct cedrus_run * run)292 static void cedrus_set_params(struct cedrus_ctx *ctx,
293 			      struct cedrus_run *run)
294 {
295 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
296 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
297 	const struct v4l2_ctrl_h264_pps *pps = run->h264.pps;
298 	const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
299 	struct vb2_buffer *src_buf = &run->src->vb2_buf;
300 	struct cedrus_dev *dev = ctx->dev;
301 	dma_addr_t src_buf_addr;
302 	u32 offset = slice->header_bit_size;
303 	u32 len = (slice->size * 8) - offset;
304 	u32 reg;
305 
306 	cedrus_write(dev, VE_H264_VLD_LEN, len);
307 	cedrus_write(dev, VE_H264_VLD_OFFSET, offset);
308 
309 	src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
310 	cedrus_write(dev, VE_H264_VLD_END,
311 		     src_buf_addr + vb2_get_plane_payload(src_buf, 0));
312 	cedrus_write(dev, VE_H264_VLD_ADDR,
313 		     VE_H264_VLD_ADDR_VAL(src_buf_addr) |
314 		     VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
315 		     VE_H264_VLD_ADDR_LAST);
316 
317 	/*
318 	 * FIXME: Since the bitstream parsing is done in software, and
319 	 * in userspace, this shouldn't be needed anymore. But it
320 	 * turns out that removing it breaks the decoding process,
321 	 * without any clear indication why.
322 	 */
323 	cedrus_write(dev, VE_H264_TRIGGER_TYPE,
324 		     VE_H264_TRIGGER_TYPE_INIT_SWDEC);
325 
326 	if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) &&
327 	     (slice->slice_type == V4L2_H264_SLICE_TYPE_P ||
328 	      slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) ||
329 	    (pps->weighted_bipred_idc == 1 &&
330 	     slice->slice_type == V4L2_H264_SLICE_TYPE_B))
331 		cedrus_write_pred_weight_table(ctx, run);
332 
333 	if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) ||
334 	    (slice->slice_type == V4L2_H264_SLICE_TYPE_SP) ||
335 	    (slice->slice_type == V4L2_H264_SLICE_TYPE_B))
336 		cedrus_write_ref_list0(ctx, run);
337 
338 	if (slice->slice_type == V4L2_H264_SLICE_TYPE_B)
339 		cedrus_write_ref_list1(ctx, run);
340 
341 	// picture parameters
342 	reg = 0;
343 	/*
344 	 * FIXME: the kernel headers are allowing the default value to
345 	 * be passed, but the libva doesn't give us that.
346 	 */
347 	reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 10;
348 	reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 5;
349 	reg |= (pps->weighted_bipred_idc & 0x3) << 2;
350 	if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)
351 		reg |= VE_H264_PPS_ENTROPY_CODING_MODE;
352 	if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED)
353 		reg |= VE_H264_PPS_WEIGHTED_PRED;
354 	if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)
355 		reg |= VE_H264_PPS_CONSTRAINED_INTRA_PRED;
356 	if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE)
357 		reg |= VE_H264_PPS_TRANSFORM_8X8_MODE;
358 	cedrus_write(dev, VE_H264_PPS, reg);
359 
360 	// sequence parameters
361 	reg = 0;
362 	reg |= (sps->chroma_format_idc & 0x7) << 19;
363 	reg |= (sps->pic_width_in_mbs_minus1 & 0xff) << 8;
364 	reg |= sps->pic_height_in_map_units_minus1 & 0xff;
365 	if (sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
366 		reg |= VE_H264_SPS_MBS_ONLY;
367 	if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
368 		reg |= VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD;
369 	if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)
370 		reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE;
371 	cedrus_write(dev, VE_H264_SPS, reg);
372 
373 	// slice parameters
374 	reg = 0;
375 	reg |= decode->nal_ref_idc ? BIT(12) : 0;
376 	reg |= (slice->slice_type & 0xf) << 8;
377 	reg |= slice->cabac_init_idc & 0x3;
378 	reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
379 	if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
380 		reg |= VE_H264_SHS_FIELD_PIC;
381 	if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
382 		reg |= VE_H264_SHS_BOTTOM_FIELD;
383 	if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED)
384 		reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED;
385 	cedrus_write(dev, VE_H264_SHS, reg);
386 
387 	reg = 0;
388 	reg |= VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD;
389 	reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 24;
390 	reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 16;
391 	reg |= (slice->disable_deblocking_filter_idc & 0x3) << 8;
392 	reg |= (slice->slice_alpha_c0_offset_div2 & 0xf) << 4;
393 	reg |= slice->slice_beta_offset_div2 & 0xf;
394 	cedrus_write(dev, VE_H264_SHS2, reg);
395 
396 	reg = 0;
397 	reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16;
398 	reg |= (pps->chroma_qp_index_offset & 0x3f) << 8;
399 	reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f;
400 	cedrus_write(dev, VE_H264_SHS_QP, reg);
401 
402 	// clear status flags
403 	cedrus_write(dev, VE_H264_STATUS, cedrus_read(dev, VE_H264_STATUS));
404 
405 	// enable int
406 	cedrus_write(dev, VE_H264_CTRL,
407 		     VE_H264_CTRL_SLICE_DECODE_INT |
408 		     VE_H264_CTRL_DECODE_ERR_INT |
409 		     VE_H264_CTRL_VLD_DATA_REQ_INT);
410 }
411 
412 static enum cedrus_irq_status
cedrus_h264_irq_status(struct cedrus_ctx * ctx)413 cedrus_h264_irq_status(struct cedrus_ctx *ctx)
414 {
415 	struct cedrus_dev *dev = ctx->dev;
416 	u32 reg = cedrus_read(dev, VE_H264_STATUS);
417 
418 	if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
419 		   VE_H264_STATUS_VLD_DATA_REQ_INT))
420 		return CEDRUS_IRQ_ERROR;
421 
422 	if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
423 		return CEDRUS_IRQ_OK;
424 
425 	return CEDRUS_IRQ_NONE;
426 }
427 
cedrus_h264_irq_clear(struct cedrus_ctx * ctx)428 static void cedrus_h264_irq_clear(struct cedrus_ctx *ctx)
429 {
430 	struct cedrus_dev *dev = ctx->dev;
431 
432 	cedrus_write(dev, VE_H264_STATUS,
433 		     VE_H264_STATUS_INT_MASK);
434 }
435 
cedrus_h264_irq_disable(struct cedrus_ctx * ctx)436 static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx)
437 {
438 	struct cedrus_dev *dev = ctx->dev;
439 	u32 reg = cedrus_read(dev, VE_H264_CTRL);
440 
441 	cedrus_write(dev, VE_H264_CTRL,
442 		     reg & ~VE_H264_CTRL_INT_MASK);
443 }
444 
cedrus_h264_setup(struct cedrus_ctx * ctx,struct cedrus_run * run)445 static void cedrus_h264_setup(struct cedrus_ctx *ctx,
446 			      struct cedrus_run *run)
447 {
448 	struct cedrus_dev *dev = ctx->dev;
449 
450 	cedrus_engine_enable(dev, CEDRUS_CODEC_H264);
451 
452 	cedrus_write(dev, VE_H264_SDROT_CTRL, 0);
453 	cedrus_write(dev, VE_H264_EXTRA_BUFFER1,
454 		     ctx->codec.h264.pic_info_buf_dma);
455 	cedrus_write(dev, VE_H264_EXTRA_BUFFER2,
456 		     ctx->codec.h264.neighbor_info_buf_dma);
457 
458 	cedrus_write_scaling_lists(ctx, run);
459 	cedrus_write_frame_list(ctx, run);
460 
461 	cedrus_set_params(ctx, run);
462 }
463 
cedrus_h264_start(struct cedrus_ctx * ctx)464 static int cedrus_h264_start(struct cedrus_ctx *ctx)
465 {
466 	struct cedrus_dev *dev = ctx->dev;
467 	unsigned int field_size;
468 	unsigned int mv_col_size;
469 	int ret;
470 
471 	/*
472 	 * FIXME: It seems that the H6 cedarX code is using a formula
473 	 * here based on the size of the frame, while all the older
474 	 * code is using a fixed size, so that might need to be
475 	 * changed at some point.
476 	 */
477 	ctx->codec.h264.pic_info_buf =
478 		dma_alloc_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
479 				   &ctx->codec.h264.pic_info_buf_dma,
480 				   GFP_KERNEL);
481 	if (!ctx->codec.h264.pic_info_buf)
482 		return -ENOMEM;
483 
484 	/*
485 	 * That buffer is supposed to be 16kiB in size, and be aligned
486 	 * on 16kiB as well. However, dma_alloc_coherent provides the
487 	 * guarantee that we'll have a CPU and DMA address aligned on
488 	 * the smallest page order that is greater to the requested
489 	 * size, so we don't have to overallocate.
490 	 */
491 	ctx->codec.h264.neighbor_info_buf =
492 		dma_alloc_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
493 				   &ctx->codec.h264.neighbor_info_buf_dma,
494 				   GFP_KERNEL);
495 	if (!ctx->codec.h264.neighbor_info_buf) {
496 		ret = -ENOMEM;
497 		goto err_pic_buf;
498 	}
499 
500 	field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
501 		DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
502 
503 	/*
504 	 * FIXME: This is actually conditional to
505 	 * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we
506 	 * might have to rework this if memory efficiency ever is
507 	 * something we need to work on.
508 	 */
509 	field_size = field_size * 2;
510 
511 	/*
512 	 * FIXME: This is actually conditional to
513 	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might
514 	 * have to rework this if memory efficiency ever is something
515 	 * we need to work on.
516 	 */
517 	field_size = field_size * 2;
518 	ctx->codec.h264.mv_col_buf_field_size = field_size;
519 
520 	mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM;
521 	ctx->codec.h264.mv_col_buf_size = mv_col_size;
522 	ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev,
523 							ctx->codec.h264.mv_col_buf_size,
524 							&ctx->codec.h264.mv_col_buf_dma,
525 							GFP_KERNEL);
526 	if (!ctx->codec.h264.mv_col_buf) {
527 		ret = -ENOMEM;
528 		goto err_neighbor_buf;
529 	}
530 
531 	return 0;
532 
533 err_neighbor_buf:
534 	dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
535 			  ctx->codec.h264.neighbor_info_buf,
536 			  ctx->codec.h264.neighbor_info_buf_dma);
537 
538 err_pic_buf:
539 	dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
540 			  ctx->codec.h264.pic_info_buf,
541 			  ctx->codec.h264.pic_info_buf_dma);
542 	return ret;
543 }
544 
cedrus_h264_stop(struct cedrus_ctx * ctx)545 static void cedrus_h264_stop(struct cedrus_ctx *ctx)
546 {
547 	struct cedrus_dev *dev = ctx->dev;
548 
549 	dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
550 			  ctx->codec.h264.mv_col_buf,
551 			  ctx->codec.h264.mv_col_buf_dma);
552 	dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
553 			  ctx->codec.h264.neighbor_info_buf,
554 			  ctx->codec.h264.neighbor_info_buf_dma);
555 	dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
556 			  ctx->codec.h264.pic_info_buf,
557 			  ctx->codec.h264.pic_info_buf_dma);
558 }
559 
cedrus_h264_trigger(struct cedrus_ctx * ctx)560 static void cedrus_h264_trigger(struct cedrus_ctx *ctx)
561 {
562 	struct cedrus_dev *dev = ctx->dev;
563 
564 	cedrus_write(dev, VE_H264_TRIGGER_TYPE,
565 		     VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE);
566 }
567 
568 struct cedrus_dec_ops cedrus_dec_ops_h264 = {
569 	.irq_clear	= cedrus_h264_irq_clear,
570 	.irq_disable	= cedrus_h264_irq_disable,
571 	.irq_status	= cedrus_h264_irq_status,
572 	.setup		= cedrus_h264_setup,
573 	.start		= cedrus_h264_start,
574 	.stop		= cedrus_h264_stop,
575 	.trigger	= cedrus_h264_trigger,
576 };
577