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
codec_h264_eos_sequence(u32 * len)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
codec_h264_can_recycle(struct amvdec_core * core)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
codec_h264_recycle(struct amvdec_core * core,u32 buf_idx)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
codec_h264_start(struct amvdec_session * sess)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
codec_h264_stop(struct amvdec_session * sess)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
codec_h264_load_extended_firmware(struct amvdec_session * sess,const u8 * data,u32 len)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
codec_h264_set_par(struct amvdec_session * sess)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
codec_h264_resume(struct amvdec_session * sess)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 */
codec_h264_src_change(struct amvdec_session * sess)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 */
get_offset_msb(struct amvdec_core * core,int frame_num)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
codec_h264_frames_ready(struct amvdec_session * sess,u32 status)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
codec_h264_threaded_isr(struct amvdec_session * sess)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
codec_h264_isr(struct amvdec_session * sess)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