xref: /linux/drivers/staging/media/meson/vdec/codec_h264.c (revision e5a52fd2b8cdb700b3c07b030e050a49ef3156b9)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 BayLibre, SAS
4  * Author: Maxime Jourdan <mjourdan@baylibre.com>
5  */
6 
7 #include <media/v4l2-mem2mem.h>
8 #include <media/videobuf2-dma-contig.h>
9 
10 #include "vdec_helpers.h"
11 #include "dos_regs.h"
12 #include "codec_h264.h"
13 
14 #define SIZE_EXT_FW	(20 * SZ_1K)
15 #define SIZE_WORKSPACE	0x1ee000
16 #define SIZE_SEI	(8 * SZ_1K)
17 
18 /*
19  * Offset added by the firmware which must be substracted
20  * from the workspace phyaddr
21  */
22 #define WORKSPACE_BUF_OFFSET	0x1000000
23 
24 /* ISR status */
25 #define CMD_MASK		GENMASK(7, 0)
26 #define CMD_SRC_CHANGE		1
27 #define CMD_FRAMES_READY	2
28 #define CMD_FATAL_ERROR		6
29 #define CMD_BAD_WIDTH		7
30 #define CMD_BAD_HEIGHT		8
31 
32 #define SEI_DATA_READY	BIT(15)
33 
34 /* Picture type */
35 #define PIC_TOP_BOT	5
36 #define PIC_BOT_TOP	6
37 
38 /* Size of Motion Vector per macroblock */
39 #define MB_MV_SIZE	96
40 
41 /* Frame status data */
42 #define PIC_STRUCT_BIT	5
43 #define PIC_STRUCT_MASK	GENMASK(2, 0)
44 #define BUF_IDX_MASK	GENMASK(4, 0)
45 #define ERROR_FLAG	BIT(9)
46 #define OFFSET_BIT	16
47 #define OFFSET_MASK	GENMASK(15, 0)
48 
49 /* Bitstream parsed data */
50 #define MB_TOTAL_BIT	8
51 #define MB_TOTAL_MASK	GENMASK(15, 0)
52 #define MB_WIDTH_MASK	GENMASK(7, 0)
53 #define MAX_REF_BIT	24
54 #define MAX_REF_MASK	GENMASK(6, 0)
55 #define AR_IDC_BIT	16
56 #define AR_IDC_MASK	GENMASK(7, 0)
57 #define AR_PRESENT_FLAG	BIT(0)
58 #define AR_EXTEND	0xff
59 
60 /*
61  * Buffer to send to the ESPARSER to signal End Of Stream for H.264.
62  * This is a 16x16 encoded picture that will trigger drain firmware-side.
63  * There is no known alternative.
64  */
65 static const u8 eos_sequence[SZ_4K] = {
66 	0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd,
67 	0xe6, 0xd9, 0x48, 0xb7,	0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef,
68 	0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63,	0x6f, 0x72, 0x65, 0x20,
69 	0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37,
70 	0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34,
71 	0x2f, 0x4d, 0x50, 0x45,	0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20,
72 	0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20,	0x43, 0x6f, 0x70, 0x79,
73 	0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30,
74 	0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
75 	0x77, 0x77, 0x77, 0x2e,	0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e,
76 	0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36,	0x34, 0x2e, 0x68, 0x74,
77 	0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
78 	0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65,
79 	0x66, 0x3d, 0x31, 0x20,	0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d,
80 	0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e,	0x61, 0x6c, 0x79, 0x73,
81 	0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20,
82 	0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65,
83 	0x3d, 0x36, 0x20, 0x70,	0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e,
84 	0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69,	0x78, 0x65, 0x64, 0x5f,
85 	0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e,
86 	0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61,
87 	0x5f, 0x6d, 0x65, 0x3d,	0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
88 	0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64,	0x63, 0x74, 0x3d, 0x30,
89 	0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a,
90 	0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68,
91 	0x72, 0x6f, 0x6d, 0x61,	0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73,
92 	0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68,	0x72, 0x65, 0x61, 0x64,
93 	0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63,
94 	0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66,
95 	0x66, 0x3d, 0x30, 0x20,	0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d,
96 	0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74,	0x3d, 0x32, 0x35, 0x30,
97 	0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d,
98 	0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d,
99 	0x34, 0x30, 0x20, 0x72,	0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69,
100 	0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30,	0x20, 0x72, 0x61, 0x74,
101 	0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f,
102 	0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69,
103 	0x6e, 0x3d, 0x31, 0x30,	0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35,
104 	0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70,	0x3d, 0x34, 0x20, 0x69,
105 	0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
106 	0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
107 	0x00, 0x00, 0x00, 0x01,	0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20,
108 	0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06,	0x51, 0xe2, 0x44, 0xd4,
109 	0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01,
110 	0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6,
111 	0x57, 0xae, 0x49, 0x30,	0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4,
112 	0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb,	0xd6, 0xbe, 0x5c, 0xd7,
113 	0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09,
114 	0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66,
115 	0xba, 0x9b, 0x82, 0x29,	0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b,
116 	0x00, 0x00, 0x01, 0x0ff,
117 };
118 
119 static const u8 *codec_h264_eos_sequence(u32 *len)
120 {
121 	*len = ARRAY_SIZE(eos_sequence);
122 	return eos_sequence;
123 }
124 
125 struct codec_h264 {
126 	/* H.264 decoder requires an extended firmware */
127 	void      *ext_fw_vaddr;
128 	dma_addr_t ext_fw_paddr;
129 
130 	/* Buffer for the H.264 Workspace */
131 	void      *workspace_vaddr;
132 	dma_addr_t workspace_paddr;
133 
134 	/* Buffer for the H.264 references MV */
135 	void      *ref_vaddr;
136 	dma_addr_t ref_paddr;
137 	u32	   ref_size;
138 
139 	/* Buffer for parsed SEI data */
140 	void      *sei_vaddr;
141 	dma_addr_t sei_paddr;
142 
143 	u32 mb_width;
144 	u32 mb_height;
145 	u32 max_refs;
146 };
147 
148 static int codec_h264_can_recycle(struct amvdec_core *core)
149 {
150 	return !amvdec_read_dos(core, AV_SCRATCH_7) ||
151 	       !amvdec_read_dos(core, AV_SCRATCH_8);
152 }
153 
154 static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx)
155 {
156 	/*
157 	 * Tell the firmware it can recycle this buffer.
158 	 * AV_SCRATCH_8 serves the same purpose.
159 	 */
160 	if (!amvdec_read_dos(core, AV_SCRATCH_7))
161 		amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1);
162 	else
163 		amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1);
164 }
165 
166 static int codec_h264_start(struct amvdec_session *sess)
167 {
168 	u32 workspace_offset;
169 	struct amvdec_core *core = sess->core;
170 	struct codec_h264 *h264 = sess->priv;
171 
172 	/* Allocate some memory for the H.264 decoder's state */
173 	h264->workspace_vaddr =
174 		dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
175 				   &h264->workspace_paddr, GFP_KERNEL);
176 	if (!h264->workspace_vaddr)
177 		return -ENOMEM;
178 
179 	/* Allocate some memory for the H.264 SEI dump */
180 	h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI,
181 					     &h264->sei_paddr, GFP_KERNEL);
182 	if (!h264->sei_vaddr)
183 		return -ENOMEM;
184 
185 	amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6));
186 
187 	workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET;
188 	amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset);
189 	amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr);
190 	amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr -
191 					     workspace_offset);
192 
193 	/* Enable "error correction" */
194 	amvdec_write_dos(core, AV_SCRATCH_F,
195 			 (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) |
196 			 BIT(4) | BIT(7));
197 
198 	amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
199 
200 	return 0;
201 }
202 
203 static int codec_h264_stop(struct amvdec_session *sess)
204 {
205 	struct codec_h264 *h264 = sess->priv;
206 	struct amvdec_core *core = sess->core;
207 
208 	if (h264->ext_fw_vaddr)
209 		dma_free_coherent(core->dev, SIZE_EXT_FW,
210 				  h264->ext_fw_vaddr, h264->ext_fw_paddr);
211 
212 	if (h264->workspace_vaddr)
213 		dma_free_coherent(core->dev, SIZE_WORKSPACE,
214 				  h264->workspace_vaddr, h264->workspace_paddr);
215 
216 	if (h264->ref_vaddr)
217 		dma_free_coherent(core->dev, h264->ref_size,
218 				  h264->ref_vaddr, h264->ref_paddr);
219 
220 	if (h264->sei_vaddr)
221 		dma_free_coherent(core->dev, SIZE_SEI,
222 				  h264->sei_vaddr, h264->sei_paddr);
223 
224 	return 0;
225 }
226 
227 static int codec_h264_load_extended_firmware(struct amvdec_session *sess,
228 					     const u8 *data, u32 len)
229 {
230 	struct codec_h264 *h264;
231 	struct amvdec_core *core = sess->core;
232 
233 	if (len < SIZE_EXT_FW)
234 		return -EINVAL;
235 
236 	h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
237 	if (!h264)
238 		return -ENOMEM;
239 
240 	h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
241 						&h264->ext_fw_paddr,
242 						GFP_KERNEL);
243 	if (!h264->ext_fw_vaddr) {
244 		kfree(h264);
245 		return -ENOMEM;
246 	}
247 
248 	memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
249 	sess->priv = h264;
250 
251 	return 0;
252 }
253 
254 static const struct v4l2_fract par_table[] = {
255 	{ 1, 1 },   { 1, 1 },    { 12, 11 }, { 10, 11 },
256 	{ 16, 11 }, { 40, 33 },  { 24, 11 }, { 20, 11 },
257 	{ 32, 11 }, { 80, 33 },  { 18, 11 }, { 15, 11 },
258 	{ 64, 33 }, { 160, 99 }, { 4, 3 },   { 3, 2 },
259 	{ 2, 1 }
260 };
261 
262 static void codec_h264_set_par(struct amvdec_session *sess)
263 {
264 	struct amvdec_core *core = sess->core;
265 	u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2);
266 	u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK;
267 
268 	if (!(seq_info & AR_PRESENT_FLAG))
269 		return;
270 
271 	if (ar_idc == AR_EXTEND) {
272 		u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3);
273 
274 		sess->pixelaspect.numerator = ar_info & 0xffff;
275 		sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff;
276 		return;
277 	}
278 
279 	if (ar_idc >= ARRAY_SIZE(par_table))
280 		return;
281 
282 	sess->pixelaspect = par_table[ar_idc];
283 }
284 
285 static void codec_h264_resume(struct amvdec_session *sess)
286 {
287 	struct amvdec_core *core = sess->core;
288 	struct codec_h264 *h264 = sess->priv;
289 	u32 mb_width, mb_height, mb_total;
290 
291 	amvdec_set_canvases(sess,
292 			    (u32[]){ ANC0_CANVAS_ADDR, 0 },
293 			    (u32[]){ 24, 0 });
294 
295 	dev_dbg(core->dev, "max_refs = %u; actual_dpb_size = %u\n",
296 		h264->max_refs, sess->num_dst_bufs);
297 
298 	/* Align to a multiple of 4 macroblocks */
299 	mb_width = ALIGN(h264->mb_width, 4);
300 	mb_height = ALIGN(h264->mb_height, 4);
301 	mb_total = mb_width * mb_height;
302 
303 	h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs;
304 	h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size,
305 					     &h264->ref_paddr, GFP_KERNEL);
306 	if (!h264->ref_vaddr) {
307 		amvdec_abort(sess);
308 		return;
309 	}
310 
311 	/* Address to store the references' MVs */
312 	amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr);
313 	/* End of ref MV */
314 	amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size);
315 
316 	amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) |
317 					     (sess->num_dst_bufs << 16) |
318 					     ((h264->max_refs - 1) << 8));
319 }
320 
321 /*
322  * Configure the H.264 decoder when the parser detected a parameter set change
323  */
324 static void codec_h264_src_change(struct amvdec_session *sess)
325 {
326 	struct amvdec_core *core = sess->core;
327 	struct codec_h264 *h264 = sess->priv;
328 	u32 parsed_info, mb_total;
329 	u32 crop_infor, crop_bottom, crop_right;
330 	u32 frame_width, frame_height;
331 
332 	sess->keyframe_found = 1;
333 
334 	parsed_info = amvdec_read_dos(core, AV_SCRATCH_1);
335 
336 	/* Total number of 16x16 macroblocks */
337 	mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK;
338 	/* Number of macroblocks per line */
339 	h264->mb_width = parsed_info & MB_WIDTH_MASK;
340 	/* Number of macroblock lines */
341 	h264->mb_height = mb_total / h264->mb_width;
342 
343 	h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1;
344 
345 	crop_infor = amvdec_read_dos(core, AV_SCRATCH_6);
346 	crop_bottom = (crop_infor & 0xff);
347 	crop_right = (crop_infor >> 16) & 0xff;
348 
349 	frame_width = h264->mb_width * 16 - crop_right;
350 	frame_height = h264->mb_height * 16 - crop_bottom;
351 
352 	dev_dbg(core->dev, "frame: %ux%u; crop: %u %u\n",
353 		frame_width, frame_height, crop_right, crop_bottom);
354 
355 	codec_h264_set_par(sess);
356 	amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5);
357 }
358 
359 /*
360  * The bitstream offset is split in half in 2 different registers.
361  * Fetch its MSB here, which location depends on the frame number.
362  */
363 static u32 get_offset_msb(struct amvdec_core *core, int frame_num)
364 {
365 	int take_msb = frame_num % 2;
366 	int reg_offset = (frame_num / 2) * 4;
367 	u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset);
368 
369 	if (take_msb)
370 		return offset_msb & 0xffff0000;
371 
372 	return (offset_msb & 0x0000ffff) << 16;
373 }
374 
375 static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
376 {
377 	struct amvdec_core *core = sess->core;
378 	int error_count;
379 	int num_frames;
380 	int i;
381 
382 	error_count = amvdec_read_dos(core, AV_SCRATCH_D);
383 	num_frames = (status >> 8) & 0xff;
384 	if (error_count) {
385 		dev_warn(core->dev,
386 			 "decoder error(s) happened, count %d\n", error_count);
387 		amvdec_write_dos(core, AV_SCRATCH_D, 0);
388 	}
389 
390 	for (i = 0; i < num_frames; i++) {
391 		u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4);
392 		u32 buffer_index = frame_status & BUF_IDX_MASK;
393 		u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) &
394 				 PIC_STRUCT_MASK;
395 		u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK;
396 		u32 field = V4L2_FIELD_NONE;
397 
398 		/*
399 		 * A buffer decode error means it was decoded,
400 		 * but part of the picture will have artifacts.
401 		 * Typical reason is a temporarily corrupted bitstream
402 		 */
403 		if (frame_status & ERROR_FLAG)
404 			dev_dbg(core->dev, "Buffer %d decode error\n",
405 				buffer_index);
406 
407 		if (pic_struct == PIC_TOP_BOT)
408 			field = V4L2_FIELD_INTERLACED_TB;
409 		else if (pic_struct == PIC_BOT_TOP)
410 			field = V4L2_FIELD_INTERLACED_BT;
411 
412 		offset |= get_offset_msb(core, i);
413 		amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
414 	}
415 }
416 
417 static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess)
418 {
419 	struct amvdec_core *core = sess->core;
420 	u32 status;
421 	u32 size;
422 	u8 cmd;
423 
424 	status = amvdec_read_dos(core, AV_SCRATCH_0);
425 	cmd = status & CMD_MASK;
426 
427 	switch (cmd) {
428 	case CMD_SRC_CHANGE:
429 		codec_h264_src_change(sess);
430 		break;
431 	case CMD_FRAMES_READY:
432 		codec_h264_frames_ready(sess, status);
433 		break;
434 	case CMD_FATAL_ERROR:
435 		dev_err(core->dev, "H.264 decoder fatal error\n");
436 		goto abort;
437 	case CMD_BAD_WIDTH:
438 		size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
439 		dev_err(core->dev, "Unsupported video width: %u\n", size);
440 		goto abort;
441 	case CMD_BAD_HEIGHT:
442 		size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
443 		dev_err(core->dev, "Unsupported video height: %u\n", size);
444 		goto abort;
445 	case 0: /* Unused but not worth printing for */
446 	case 9:
447 		break;
448 	default:
449 		dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd);
450 		break;
451 	}
452 
453 	if (cmd && cmd != CMD_SRC_CHANGE)
454 		amvdec_write_dos(core, AV_SCRATCH_0, 0);
455 
456 	/* Decoder has some SEI data for us ; ignore */
457 	if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY)
458 		amvdec_write_dos(core, AV_SCRATCH_J, 0);
459 
460 	return IRQ_HANDLED;
461 abort:
462 	amvdec_abort(sess);
463 	return IRQ_HANDLED;
464 }
465 
466 static irqreturn_t codec_h264_isr(struct amvdec_session *sess)
467 {
468 	struct amvdec_core *core = sess->core;
469 
470 	amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
471 
472 	return IRQ_WAKE_THREAD;
473 }
474 
475 struct amvdec_codec_ops codec_h264_ops = {
476 	.start = codec_h264_start,
477 	.stop = codec_h264_stop,
478 	.load_extended_firmware = codec_h264_load_extended_firmware,
479 	.isr = codec_h264_isr,
480 	.threaded_isr = codec_h264_threaded_isr,
481 	.can_recycle = codec_h264_can_recycle,
482 	.recycle = codec_h264_recycle,
483 	.eos_sequence = codec_h264_eos_sequence,
484 	.resume = codec_h264_resume,
485 };
486