blob: c37b473bc5479565042f64e2fc1f75f163de6889
1 | /* |
2 | * drivers/amlogic/media/frame_provider/decoder/utils/amvdec.c |
3 | * |
4 | * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | */ |
17 | #define DEBUG |
18 | #include <linux/kernel.h> |
19 | #include <linux/types.h> |
20 | #include <linux/errno.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/sched.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/dma-mapping.h> |
25 | #include <linux/amlogic/media/utils/vformat.h> |
26 | #include <linux/module.h> |
27 | #include <linux/delay.h> |
28 | #include <linux/vmalloc.h> |
29 | #include "vdec.h" |
30 | |
31 | #ifdef CONFIG_PM |
32 | #include <linux/pm.h> |
33 | #endif |
34 | |
35 | #ifdef CONFIG_WAKELOCK |
36 | #include <linux/wakelock.h> |
37 | #endif |
38 | #include "../../../stream_input/amports/amports_priv.h" |
39 | |
40 | /* #include <mach/am_regs.h> */ |
41 | /* #include <mach/power_gate.h> */ |
42 | #include <linux/amlogic/media/utils/vdec_reg.h> |
43 | #include "amvdec.h" |
44 | #include <linux/amlogic/media/utils/amports_config.h> |
45 | #include "firmware.h" |
46 | #include <linux/amlogic/tee.h> |
47 | #include "../../../common/chips/decoder_cpu_ver_info.h" |
48 | |
49 | #define MC_SIZE (4096 * 16) |
50 | |
51 | #ifdef CONFIG_WAKELOCK |
52 | static struct wake_lock amvdec_lock; |
53 | struct timer_list amvdevtimer; |
54 | #define WAKE_CHECK_INTERVAL (100*HZ/100) |
55 | #endif |
56 | #define AMVDEC_USE_STATIC_MEMORY |
57 | static void *mc_addr; |
58 | static dma_addr_t mc_addr_map; |
59 | |
60 | #ifdef CONFIG_WAKELOCK |
61 | static int video_running; |
62 | static int video_stated_changed = 1; |
63 | #endif |
64 | |
65 | static void amvdec_pg_enable(bool enable) |
66 | { |
67 | ulong timeout; |
68 | |
69 | if (enable) { |
70 | AMVDEC_CLK_GATE_ON(MDEC_CLK_PIC_DC); |
71 | AMVDEC_CLK_GATE_ON(MDEC_CLK_DBLK); |
72 | AMVDEC_CLK_GATE_ON(MC_CLK); |
73 | AMVDEC_CLK_GATE_ON(IQIDCT_CLK); |
74 | /* AMVDEC_CLK_GATE_ON(VLD_CLK); */ |
75 | AMVDEC_CLK_GATE_ON(AMRISC); |
76 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ |
77 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) |
78 | WRITE_VREG(GCLK_EN, 0x3ff); |
79 | /* #endif */ |
80 | CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); |
81 | } else { |
82 | |
83 | AMVDEC_CLK_GATE_OFF(AMRISC); |
84 | timeout = jiffies + HZ / 100; |
85 | |
86 | while (READ_VREG(MDEC_PIC_DC_STATUS) != 0) { |
87 | if (time_after(jiffies, timeout)) { |
88 | WRITE_VREG_BITS(MDEC_PIC_DC_CTRL, 1, 0, 1); |
89 | WRITE_VREG_BITS(MDEC_PIC_DC_CTRL, 0, 0, 1); |
90 | READ_VREG(MDEC_PIC_DC_STATUS); |
91 | READ_VREG(MDEC_PIC_DC_STATUS); |
92 | READ_VREG(MDEC_PIC_DC_STATUS); |
93 | break; |
94 | } |
95 | } |
96 | |
97 | AMVDEC_CLK_GATE_OFF(MDEC_CLK_PIC_DC); |
98 | timeout = jiffies + HZ / 100; |
99 | |
100 | while (READ_VREG(DBLK_STATUS) & 1) { |
101 | if (time_after(jiffies, timeout)) { |
102 | WRITE_VREG(DBLK_CTRL, 3); |
103 | WRITE_VREG(DBLK_CTRL, 0); |
104 | READ_VREG(DBLK_STATUS); |
105 | READ_VREG(DBLK_STATUS); |
106 | READ_VREG(DBLK_STATUS); |
107 | break; |
108 | } |
109 | } |
110 | AMVDEC_CLK_GATE_OFF(MDEC_CLK_DBLK); |
111 | timeout = jiffies + HZ / 100; |
112 | |
113 | while (READ_VREG(MC_STATUS0) & 1) { |
114 | if (time_after(jiffies, timeout)) { |
115 | SET_VREG_MASK(MC_CTRL1, 0x9); |
116 | CLEAR_VREG_MASK(MC_CTRL1, 0x9); |
117 | READ_VREG(MC_STATUS0); |
118 | READ_VREG(MC_STATUS0); |
119 | READ_VREG(MC_STATUS0); |
120 | break; |
121 | } |
122 | } |
123 | AMVDEC_CLK_GATE_OFF(MC_CLK); |
124 | timeout = jiffies + HZ / 100; |
125 | while (READ_VREG(DCAC_DMA_CTRL) & 0x8000) { |
126 | if (time_after(jiffies, timeout)) |
127 | break; |
128 | } |
129 | AMVDEC_CLK_GATE_OFF(IQIDCT_CLK); |
130 | /* AMVDEC_CLK_GATE_OFF(VLD_CLK); */ |
131 | } |
132 | } |
133 | |
134 | static void amvdec2_pg_enable(bool enable) |
135 | { |
136 | if (has_vdec2()) { |
137 | ulong timeout; |
138 | |
139 | if (!vdec_on(VDEC_2)) |
140 | return; |
141 | if (enable) { |
142 | /* WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); */ |
143 | } else { |
144 | timeout = jiffies + HZ / 10; |
145 | |
146 | while (READ_VREG(VDEC2_MDEC_PIC_DC_STATUS) != 0) { |
147 | if (time_after(jiffies, timeout)) { |
148 | WRITE_VREG_BITS(VDEC2_MDEC_PIC_DC_CTRL, |
149 | 1, 0, 1); |
150 | WRITE_VREG_BITS(VDEC2_MDEC_PIC_DC_CTRL, |
151 | 0, 0, 1); |
152 | READ_VREG(VDEC2_MDEC_PIC_DC_STATUS); |
153 | READ_VREG(VDEC2_MDEC_PIC_DC_STATUS); |
154 | READ_VREG(VDEC2_MDEC_PIC_DC_STATUS); |
155 | break; |
156 | } |
157 | } |
158 | |
159 | timeout = jiffies + HZ / 10; |
160 | |
161 | while (READ_VREG(VDEC2_DBLK_STATUS) & 1) { |
162 | if (time_after(jiffies, timeout)) { |
163 | WRITE_VREG(VDEC2_DBLK_CTRL, 3); |
164 | WRITE_VREG(VDEC2_DBLK_CTRL, 0); |
165 | READ_VREG(VDEC2_DBLK_STATUS); |
166 | READ_VREG(VDEC2_DBLK_STATUS); |
167 | READ_VREG(VDEC2_DBLK_STATUS); |
168 | break; |
169 | } |
170 | } |
171 | |
172 | timeout = jiffies + HZ / 10; |
173 | |
174 | while (READ_VREG(VDEC2_DCAC_DMA_CTRL) & 0x8000) { |
175 | if (time_after(jiffies, timeout)) |
176 | break; |
177 | } |
178 | } |
179 | } |
180 | } |
181 | |
182 | static void amhevc_pg_enable(bool enable) |
183 | { |
184 | if (has_hevc_vdec()) { |
185 | ulong timeout; |
186 | |
187 | if (!vdec_on(VDEC_HEVC)) |
188 | return; |
189 | if (enable) { |
190 | /* WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); */ |
191 | } else { |
192 | timeout = jiffies + HZ / 10; |
193 | |
194 | while (READ_VREG(HEVC_MDEC_PIC_DC_STATUS) != 0) { |
195 | if (time_after(jiffies, timeout)) { |
196 | WRITE_VREG_BITS(HEVC_MDEC_PIC_DC_CTRL, |
197 | 1, 0, 1); |
198 | WRITE_VREG_BITS(HEVC_MDEC_PIC_DC_CTRL, |
199 | 0, 0, 1); |
200 | READ_VREG(HEVC_MDEC_PIC_DC_STATUS); |
201 | READ_VREG(HEVC_MDEC_PIC_DC_STATUS); |
202 | READ_VREG(HEVC_MDEC_PIC_DC_STATUS); |
203 | break; |
204 | } |
205 | } |
206 | |
207 | timeout = jiffies + HZ / 10; |
208 | |
209 | while (READ_VREG(HEVC_DBLK_STATUS) & 1) { |
210 | if (time_after(jiffies, timeout)) { |
211 | WRITE_VREG(HEVC_DBLK_CTRL, 3); |
212 | WRITE_VREG(HEVC_DBLK_CTRL, 0); |
213 | READ_VREG(HEVC_DBLK_STATUS); |
214 | READ_VREG(HEVC_DBLK_STATUS); |
215 | READ_VREG(HEVC_DBLK_STATUS); |
216 | break; |
217 | } |
218 | } |
219 | |
220 | timeout = jiffies + HZ / 10; |
221 | |
222 | while (READ_VREG(HEVC_DCAC_DMA_CTRL) & 0x8000) { |
223 | if (time_after(jiffies, timeout)) |
224 | break; |
225 | } |
226 | } |
227 | } |
228 | } |
229 | |
230 | #ifdef CONFIG_WAKELOCK |
231 | int amvdec_wake_lock(void) |
232 | { |
233 | wake_lock(&amvdec_lock); |
234 | return 0; |
235 | } |
236 | |
237 | int amvdec_wake_unlock(void) |
238 | { |
239 | wake_unlock(&amvdec_lock); |
240 | return 0; |
241 | } |
242 | #else |
243 | #define amvdec_wake_lock() |
244 | #define amvdec_wake_unlock() |
245 | #endif |
246 | |
247 | static s32 am_vdec_loadmc_ex(struct vdec_s *vdec, |
248 | const char *name, char *def, s32(*load)(const u32 *)) |
249 | { |
250 | int err; |
251 | |
252 | if (!vdec->mc_loaded) { |
253 | if (!def) { |
254 | err = get_decoder_firmware_data(vdec->format, |
255 | name, (u8 *)(vdec->mc), |
256 | (4096 * 4 * 4)); |
257 | if (err <= 0) |
258 | return -1; |
259 | } else |
260 | memcpy((char *)vdec->mc, def, sizeof(vdec->mc)); |
261 | |
262 | vdec->mc_loaded = true; |
263 | } |
264 | |
265 | err = (*load)(vdec->mc); |
266 | if (err < 0) { |
267 | pr_err("loading firmware %s to vdec ram failed!\n", name); |
268 | return err; |
269 | } |
270 | |
271 | return err; |
272 | } |
273 | |
274 | static s32 am_vdec_loadmc_buf_ex(struct vdec_s *vdec, |
275 | char *buf, int size, s32(*load)(const u32 *)) |
276 | { |
277 | int err; |
278 | |
279 | if (!vdec->mc_loaded) { |
280 | memcpy((u8 *)(vdec->mc), buf, size); |
281 | vdec->mc_loaded = true; |
282 | } |
283 | |
284 | err = (*load)(vdec->mc); |
285 | if (err < 0) { |
286 | pr_err("loading firmware to vdec ram failed!\n"); |
287 | return err; |
288 | } |
289 | |
290 | return err; |
291 | } |
292 | |
293 | static s32 am_loadmc_ex(enum vformat_e type, |
294 | const char *name, char *def, s32(*load)(const u32 *)) |
295 | { |
296 | char *mc_addr = vmalloc(4096 * 16); |
297 | char *pmc_addr = def; |
298 | int err; |
299 | |
300 | if (!def && mc_addr) { |
301 | int loaded; |
302 | |
303 | loaded = get_decoder_firmware_data(type, |
304 | name, mc_addr, (4096 * 16)); |
305 | if (loaded > 0) |
306 | pmc_addr = mc_addr; |
307 | } |
308 | if (!pmc_addr) { |
309 | vfree(mc_addr); |
310 | return -1; |
311 | } |
312 | err = (*load)((u32 *) pmc_addr); |
313 | if (err < 0) { |
314 | pr_err("loading firmware %s to vdec ram failed!\n", name); |
315 | vfree(mc_addr); |
316 | return err; |
317 | } |
318 | vfree(mc_addr); |
319 | |
320 | return err; |
321 | } |
322 | |
323 | static s32 amvdec_loadmc(const u32 *p) |
324 | { |
325 | ulong timeout; |
326 | s32 ret = 0; |
327 | |
328 | #ifdef AMVDEC_USE_STATIC_MEMORY |
329 | if (mc_addr == NULL) { |
330 | #else |
331 | { |
332 | #endif |
333 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
334 | } |
335 | |
336 | if (!mc_addr) |
337 | return -ENOMEM; |
338 | |
339 | memcpy(mc_addr, p, MC_SIZE); |
340 | |
341 | mc_addr_map = dma_map_single(get_vdec_device(), |
342 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
343 | |
344 | WRITE_VREG(MPSR, 0); |
345 | WRITE_VREG(CPSR, 0); |
346 | |
347 | /* Read CBUS register for timing */ |
348 | timeout = READ_VREG(MPSR); |
349 | timeout = READ_VREG(MPSR); |
350 | |
351 | timeout = jiffies + HZ; |
352 | |
353 | WRITE_VREG(IMEM_DMA_ADR, mc_addr_map); |
354 | WRITE_VREG(IMEM_DMA_COUNT, 0x1000); |
355 | WRITE_VREG(IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
356 | |
357 | while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) { |
358 | if (time_before(jiffies, timeout)) |
359 | schedule(); |
360 | else { |
361 | pr_err("vdec load mc error\n"); |
362 | ret = -EBUSY; |
363 | break; |
364 | } |
365 | } |
366 | |
367 | dma_unmap_single(get_vdec_device(), |
368 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
369 | |
370 | #ifndef AMVDEC_USE_STATIC_MEMORY |
371 | kfree(mc_addr); |
372 | mc_addr = NULL; |
373 | #endif |
374 | |
375 | return ret; |
376 | } |
377 | |
378 | s32 optee_load_fw(enum vformat_e type, const char *fw_name) |
379 | { |
380 | s32 ret = -1; |
381 | unsigned int format = FIRMWARE_MAX; |
382 | unsigned int vdec = OPTEE_VDEC_LEGENCY; |
383 | char *name = __getname(); |
384 | bool is_swap = false; |
385 | |
386 | sprintf(name, "%s", fw_name ? fw_name : "null"); |
387 | |
388 | switch ((u32)type) { |
389 | case VFORMAT_VC1: |
390 | format = VIDEO_DEC_VC1; |
391 | break; |
392 | |
393 | case VFORMAT_AVS: |
394 | if (!strcmp(name, "avs_no_cabac")) |
395 | format = VIDEO_DEC_AVS_NOCABAC; |
396 | else if (!strcmp(name, "avs_multi")) |
397 | format = VIDEO_DEC_AVS_MULTI; |
398 | else |
399 | format = VIDEO_DEC_AVS; |
400 | break; |
401 | |
402 | case VFORMAT_MPEG12: |
403 | if (!strcmp(name, "mpeg12")) |
404 | format = VIDEO_DEC_MPEG12; |
405 | else if (!strcmp(name, "mmpeg12")) |
406 | format = VIDEO_DEC_MPEG12_MULTI; |
407 | break; |
408 | |
409 | case VFORMAT_MJPEG: |
410 | if (!strcmp(name, "mmjpeg")) |
411 | format = VIDEO_DEC_MJPEG_MULTI; |
412 | else |
413 | format = VIDEO_DEC_MJPEG; |
414 | break; |
415 | |
416 | case VFORMAT_VP9: |
417 | if (!strcmp(name, "vp9_mc")) |
418 | format = VIDEO_DEC_VP9; |
419 | else |
420 | format = VIDEO_DEC_VP9_MMU; |
421 | break; |
422 | |
423 | case VFORMAT_AVS2: |
424 | format = VIDEO_DEC_AVS2_MMU; |
425 | vdec = OPTEE_VDEC_HEVC; |
426 | break; |
427 | |
428 | case VFORMAT_AV1: |
429 | format = VIDEO_DEC_AV1_MMU; |
430 | vdec = OPTEE_VDEC_HEVC; |
431 | break; |
432 | |
433 | case VFORMAT_HEVC: |
434 | if (!strcmp(name, "h265_mmu")) |
435 | format = VIDEO_DEC_HEVC_MMU; |
436 | else if (!strcmp(name, "hevc_mmu_swap")) { |
437 | format = VIDEO_DEC_HEVC_MMU_SWAP; |
438 | vdec = OPTEE_VDEC_HEVC; |
439 | is_swap = true; |
440 | } else |
441 | format = VIDEO_DEC_HEVC; |
442 | break; |
443 | |
444 | case VFORMAT_REAL: |
445 | if (!strcmp(name, "vreal_mc_8")) |
446 | format = VIDEO_DEC_REAL_V8; |
447 | else if (!strcmp(name, "vreal_mc_9")) |
448 | format = VIDEO_DEC_REAL_V9; |
449 | break; |
450 | |
451 | case VFORMAT_MPEG4: |
452 | if (!strcmp(name, "mmpeg4_mc_5")) |
453 | format = VIDEO_DEC_MPEG4_5_MULTI; |
454 | else if ((!strcmp(name, "mh263_mc"))) |
455 | format = VIDEO_DEC_H263_MULTI; |
456 | else if (!strcmp(name, "vmpeg4_mc_5")) |
457 | format = VIDEO_DEC_MPEG4_5; |
458 | else if (!strcmp(name, "h263_mc")) |
459 | format = VIDEO_DEC_H263; |
460 | /*not support now*/ |
461 | else if (!strcmp(name, "vmpeg4_mc_311")) |
462 | format = VIDEO_DEC_MPEG4_3; |
463 | else if (!strcmp(name, "vmpeg4_mc_4")) |
464 | format = VIDEO_DEC_MPEG4_4; |
465 | break; |
466 | |
467 | case VFORMAT_H264_4K2K: |
468 | if (!strcmp(name, "single_core")) |
469 | format = VIDEO_DEC_H264_4k2K_SINGLE; |
470 | else |
471 | format = VIDEO_DEC_H264_4k2K; |
472 | break; |
473 | |
474 | case VFORMAT_H264MVC: |
475 | format = VIDEO_DEC_H264_MVC; |
476 | break; |
477 | |
478 | case VFORMAT_H264: |
479 | if (!strcmp(name, "mh264")) |
480 | format = VIDEO_DEC_H264_MULTI; |
481 | else if (!strcmp(name, "mh264_mmu")) { |
482 | format = VIDEO_DEC_H264_MULTI_MMU; |
483 | vdec = OPTEE_VDEC_HEVC; |
484 | } else |
485 | format = VIDEO_DEC_H264; |
486 | break; |
487 | |
488 | default: |
489 | pr_info("Unknow vdec format!\n"); |
490 | break; |
491 | } |
492 | |
493 | if (format < FIRMWARE_MAX) { |
494 | if (is_swap) |
495 | ret = tee_load_video_fw_swap(format, vdec, is_swap); |
496 | else |
497 | ret = tee_load_video_fw(format, vdec); |
498 | } |
499 | |
500 | __putname(name); |
501 | |
502 | return ret; |
503 | } |
504 | EXPORT_SYMBOL(optee_load_fw); |
505 | |
506 | s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def) |
507 | { |
508 | if (tee_enabled()) |
509 | return optee_load_fw(type, name); |
510 | else |
511 | return am_loadmc_ex(type, name, def, &amvdec_loadmc); |
512 | } |
513 | EXPORT_SYMBOL(amvdec_loadmc_ex); |
514 | |
515 | s32 amvdec_vdec_loadmc_ex(enum vformat_e type, const char *name, |
516 | struct vdec_s *vdec, char *def) |
517 | { |
518 | if (tee_enabled()) |
519 | return optee_load_fw(type, name); |
520 | else |
521 | return am_vdec_loadmc_ex(vdec, name, def, &amvdec_loadmc); |
522 | } |
523 | EXPORT_SYMBOL(amvdec_vdec_loadmc_ex); |
524 | |
525 | s32 amvdec_vdec_loadmc_buf_ex(enum vformat_e type, const char *name, |
526 | struct vdec_s *vdec, char *buf, int size) |
527 | { |
528 | if (tee_enabled()) |
529 | return optee_load_fw(type, name); |
530 | else |
531 | return am_vdec_loadmc_buf_ex(vdec, buf, size, &amvdec_loadmc); |
532 | } |
533 | EXPORT_SYMBOL(amvdec_vdec_loadmc_buf_ex); |
534 | |
535 | static s32 amvdec2_loadmc(const u32 *p) |
536 | { |
537 | if (has_vdec2()) { |
538 | ulong timeout; |
539 | s32 ret = 0; |
540 | |
541 | #ifdef AMVDEC_USE_STATIC_MEMORY |
542 | if (mc_addr == NULL) { |
543 | #else |
544 | { |
545 | #endif |
546 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
547 | } |
548 | |
549 | if (!mc_addr) |
550 | return -ENOMEM; |
551 | |
552 | memcpy(mc_addr, p, MC_SIZE); |
553 | |
554 | mc_addr_map = dma_map_single(get_vdec_device(), |
555 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
556 | |
557 | WRITE_VREG(VDEC2_MPSR, 0); |
558 | WRITE_VREG(VDEC2_CPSR, 0); |
559 | |
560 | /* Read CBUS register for timing */ |
561 | timeout = READ_VREG(VDEC2_MPSR); |
562 | timeout = READ_VREG(VDEC2_MPSR); |
563 | |
564 | timeout = jiffies + HZ; |
565 | |
566 | WRITE_VREG(VDEC2_IMEM_DMA_ADR, mc_addr_map); |
567 | WRITE_VREG(VDEC2_IMEM_DMA_COUNT, 0x1000); |
568 | WRITE_VREG(VDEC2_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
569 | |
570 | while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) { |
571 | if (time_before(jiffies, timeout)) |
572 | schedule(); |
573 | else { |
574 | pr_err("vdec2 load mc error\n"); |
575 | ret = -EBUSY; |
576 | break; |
577 | } |
578 | } |
579 | |
580 | dma_unmap_single(get_vdec_device(), |
581 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
582 | |
583 | #ifndef AMVDEC_USE_STATIC_MEMORY |
584 | kfree(mc_addr); |
585 | mc_addr = NULL; |
586 | #endif |
587 | |
588 | return ret; |
589 | } else |
590 | return 0; |
591 | } |
592 | |
593 | s32 amvdec2_loadmc_ex(enum vformat_e type, const char *name, char *def) |
594 | { |
595 | if (has_vdec2()) |
596 | return am_loadmc_ex(type, name, def, &amvdec2_loadmc); |
597 | else |
598 | return 0; |
599 | } |
600 | EXPORT_SYMBOL(amvdec2_loadmc_ex); |
601 | |
602 | s32 amhcodec_loadmc(const u32 *p) |
603 | { |
604 | #ifdef AMVDEC_USE_STATIC_MEMORY |
605 | if (mc_addr == NULL) { |
606 | #else |
607 | { |
608 | #endif |
609 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
610 | } |
611 | |
612 | if (!mc_addr) |
613 | return -ENOMEM; |
614 | |
615 | memcpy(mc_addr, p, MC_SIZE); |
616 | |
617 | mc_addr_map = dma_map_single(get_vdec_device(), |
618 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
619 | |
620 | WRITE_VREG(HCODEC_IMEM_DMA_ADR, mc_addr_map); |
621 | WRITE_VREG(HCODEC_IMEM_DMA_COUNT, 0x100); |
622 | WRITE_VREG(HCODEC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
623 | |
624 | while (READ_VREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) |
625 | udelay(1000); |
626 | |
627 | dma_unmap_single(get_vdec_device(), |
628 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
629 | |
630 | #ifndef AMVDEC_USE_STATIC_MEMORY |
631 | kfree(mc_addr); |
632 | #endif |
633 | |
634 | return 0; |
635 | } |
636 | EXPORT_SYMBOL(amhcodec_loadmc); |
637 | |
638 | s32 amhcodec_loadmc_ex(enum vformat_e type, const char *name, char *def) |
639 | { |
640 | return am_loadmc_ex(type, name, def, &amhcodec_loadmc); |
641 | } |
642 | EXPORT_SYMBOL(amhcodec_loadmc_ex); |
643 | |
644 | static s32 amhevc_loadmc(const u32 *p) |
645 | { |
646 | ulong timeout; |
647 | s32 ret = 0; |
648 | |
649 | if (has_hevc_vdec()) { |
650 | #ifdef AMVDEC_USE_STATIC_MEMORY |
651 | if (mc_addr == NULL) { |
652 | #else |
653 | { |
654 | #endif |
655 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
656 | } |
657 | |
658 | if (!mc_addr) |
659 | return -ENOMEM; |
660 | |
661 | memcpy(mc_addr, p, MC_SIZE); |
662 | |
663 | mc_addr_map = |
664 | dma_map_single(get_vdec_device(), |
665 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
666 | |
667 | WRITE_VREG(HEVC_MPSR, 0); |
668 | WRITE_VREG(HEVC_CPSR, 0); |
669 | |
670 | /* Read CBUS register for timing */ |
671 | timeout = READ_VREG(HEVC_MPSR); |
672 | timeout = READ_VREG(HEVC_MPSR); |
673 | |
674 | timeout = jiffies + HZ; |
675 | |
676 | WRITE_VREG(HEVC_IMEM_DMA_ADR, mc_addr_map); |
677 | WRITE_VREG(HEVC_IMEM_DMA_COUNT, 0x1000); |
678 | WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
679 | |
680 | while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) { |
681 | if (time_before(jiffies, timeout)) |
682 | schedule(); |
683 | else { |
684 | pr_err("vdec2 load mc error\n"); |
685 | ret = -EBUSY; |
686 | break; |
687 | } |
688 | } |
689 | |
690 | dma_unmap_single(get_vdec_device(), |
691 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
692 | |
693 | #ifndef AMVDEC_USE_STATIC_MEMORY |
694 | kfree(mc_addr); |
695 | mc_addr = NULL; |
696 | #endif |
697 | } |
698 | |
699 | return ret; |
700 | } |
701 | |
702 | s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def) |
703 | { |
704 | if (has_hevc_vdec()) |
705 | if (tee_enabled()) |
706 | return optee_load_fw(type, name); |
707 | else |
708 | return am_loadmc_ex(type, name, def, &amhevc_loadmc); |
709 | else |
710 | return -1; |
711 | } |
712 | EXPORT_SYMBOL(amhevc_loadmc_ex); |
713 | |
714 | s32 amhevc_vdec_loadmc_ex(enum vformat_e type, struct vdec_s *vdec, |
715 | const char *name, char *def) |
716 | { |
717 | if (has_hevc_vdec()) |
718 | if (tee_enabled()) |
719 | return optee_load_fw(type, name); |
720 | else |
721 | return am_vdec_loadmc_ex(vdec, name, def, &amhevc_loadmc); |
722 | else |
723 | return -1; |
724 | } |
725 | EXPORT_SYMBOL(amhevc_vdec_loadmc_ex); |
726 | |
727 | void amvdec_start(void) |
728 | { |
729 | #ifdef CONFIG_WAKELOCK |
730 | amvdec_wake_lock(); |
731 | #endif |
732 | |
733 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ |
734 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) { |
735 | READ_VREG(DOS_SW_RESET0); |
736 | READ_VREG(DOS_SW_RESET0); |
737 | READ_VREG(DOS_SW_RESET0); |
738 | |
739 | WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); |
740 | WRITE_VREG(DOS_SW_RESET0, 0); |
741 | |
742 | READ_VREG(DOS_SW_RESET0); |
743 | READ_VREG(DOS_SW_RESET0); |
744 | READ_VREG(DOS_SW_RESET0); |
745 | } else { |
746 | /* #else */ |
747 | /* additional cbus dummy register reading for timing control */ |
748 | READ_RESET_REG(RESET0_REGISTER); |
749 | READ_RESET_REG(RESET0_REGISTER); |
750 | READ_RESET_REG(RESET0_REGISTER); |
751 | READ_RESET_REG(RESET0_REGISTER); |
752 | |
753 | WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU); |
754 | |
755 | READ_RESET_REG(RESET0_REGISTER); |
756 | READ_RESET_REG(RESET0_REGISTER); |
757 | READ_RESET_REG(RESET0_REGISTER); |
758 | } |
759 | /* #endif */ |
760 | |
761 | WRITE_VREG(MPSR, 0x0001); |
762 | } |
763 | EXPORT_SYMBOL(amvdec_start); |
764 | |
765 | void amvdec2_start(void) |
766 | { |
767 | if (has_vdec2()) { |
768 | #ifdef CONFIG_WAKELOCK |
769 | amvdec_wake_lock(); |
770 | #endif |
771 | |
772 | READ_VREG(DOS_SW_RESET2); |
773 | READ_VREG(DOS_SW_RESET2); |
774 | READ_VREG(DOS_SW_RESET2); |
775 | |
776 | WRITE_VREG(DOS_SW_RESET2, (1 << 12) | (1 << 11)); |
777 | WRITE_VREG(DOS_SW_RESET2, 0); |
778 | |
779 | READ_VREG(DOS_SW_RESET2); |
780 | READ_VREG(DOS_SW_RESET2); |
781 | READ_VREG(DOS_SW_RESET2); |
782 | |
783 | WRITE_VREG(VDEC2_MPSR, 0x0001); |
784 | } |
785 | } |
786 | EXPORT_SYMBOL(amvdec2_start); |
787 | |
788 | void amhcodec_start(void) |
789 | { |
790 | WRITE_VREG(HCODEC_MPSR, 0x0001); |
791 | } |
792 | EXPORT_SYMBOL(amhcodec_start); |
793 | |
794 | void amhevc_start(void) |
795 | { |
796 | |
797 | if (has_hevc_vdec()) { |
798 | #ifdef CONFIG_WAKELOCK |
799 | amvdec_wake_lock(); |
800 | #endif |
801 | |
802 | READ_VREG(DOS_SW_RESET3); |
803 | READ_VREG(DOS_SW_RESET3); |
804 | READ_VREG(DOS_SW_RESET3); |
805 | |
806 | WRITE_VREG(DOS_SW_RESET3, (1 << 12) | (1 << 11)); |
807 | WRITE_VREG(DOS_SW_RESET3, 0); |
808 | |
809 | READ_VREG(DOS_SW_RESET3); |
810 | READ_VREG(DOS_SW_RESET3); |
811 | READ_VREG(DOS_SW_RESET3); |
812 | |
813 | WRITE_VREG(HEVC_MPSR, 0x0001); |
814 | } |
815 | } |
816 | EXPORT_SYMBOL(amhevc_start); |
817 | |
818 | void amvdec_stop(void) |
819 | { |
820 | ulong timeout = jiffies + HZ/10; |
821 | |
822 | WRITE_VREG(MPSR, 0); |
823 | WRITE_VREG(CPSR, 0); |
824 | |
825 | while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) { |
826 | if (time_after(jiffies, timeout)) |
827 | break; |
828 | } |
829 | |
830 | timeout = jiffies + HZ/10; |
831 | while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) { |
832 | if (time_after(jiffies, timeout)) |
833 | break; |
834 | } |
835 | |
836 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ |
837 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) { |
838 | READ_VREG(DOS_SW_RESET0); |
839 | READ_VREG(DOS_SW_RESET0); |
840 | READ_VREG(DOS_SW_RESET0); |
841 | |
842 | WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); |
843 | WRITE_VREG(DOS_SW_RESET0, 0); |
844 | |
845 | READ_VREG(DOS_SW_RESET0); |
846 | READ_VREG(DOS_SW_RESET0); |
847 | READ_VREG(DOS_SW_RESET0); |
848 | } else { |
849 | /* #else */ |
850 | WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU); |
851 | |
852 | /* additional cbus dummy register reading for timing control */ |
853 | READ_RESET_REG(RESET0_REGISTER); |
854 | READ_RESET_REG(RESET0_REGISTER); |
855 | READ_RESET_REG(RESET0_REGISTER); |
856 | READ_RESET_REG(RESET0_REGISTER); |
857 | } |
858 | /* #endif */ |
859 | |
860 | #ifdef CONFIG_WAKELOCK |
861 | amvdec_wake_unlock(); |
862 | #endif |
863 | } |
864 | EXPORT_SYMBOL(amvdec_stop); |
865 | |
866 | void amvdec2_stop(void) |
867 | { |
868 | if (has_vdec2()) { |
869 | ulong timeout = jiffies + HZ/10; |
870 | |
871 | WRITE_VREG(VDEC2_MPSR, 0); |
872 | WRITE_VREG(VDEC2_CPSR, 0); |
873 | |
874 | while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) { |
875 | if (time_after(jiffies, timeout)) |
876 | break; |
877 | } |
878 | |
879 | READ_VREG(DOS_SW_RESET2); |
880 | READ_VREG(DOS_SW_RESET2); |
881 | READ_VREG(DOS_SW_RESET2); |
882 | |
883 | #ifdef CONFIG_WAKELOCK |
884 | amvdec_wake_unlock(); |
885 | #endif |
886 | } |
887 | } |
888 | EXPORT_SYMBOL(amvdec2_stop); |
889 | |
890 | void amhcodec_stop(void) |
891 | { |
892 | WRITE_VREG(HCODEC_MPSR, 0); |
893 | } |
894 | EXPORT_SYMBOL(amhcodec_stop); |
895 | |
896 | void amhevc_stop(void) |
897 | { |
898 | if (has_hevc_vdec()) { |
899 | ulong timeout = jiffies + HZ/10; |
900 | |
901 | WRITE_VREG(HEVC_MPSR, 0); |
902 | WRITE_VREG(HEVC_CPSR, 0); |
903 | |
904 | while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) { |
905 | if (time_after(jiffies, timeout)) |
906 | break; |
907 | } |
908 | |
909 | timeout = jiffies + HZ/10; |
910 | while (READ_VREG(HEVC_LMEM_DMA_CTRL) & 0x8000) { |
911 | if (time_after(jiffies, timeout)) |
912 | break; |
913 | } |
914 | |
915 | READ_VREG(DOS_SW_RESET3); |
916 | READ_VREG(DOS_SW_RESET3); |
917 | READ_VREG(DOS_SW_RESET3); |
918 | |
919 | #ifdef CONFIG_WAKELOCK |
920 | amvdec_wake_unlock(); |
921 | #endif |
922 | } |
923 | } |
924 | EXPORT_SYMBOL(amhevc_stop); |
925 | |
926 | void amvdec_enable(void) |
927 | { |
928 | amvdec_pg_enable(true); |
929 | } |
930 | EXPORT_SYMBOL(amvdec_enable); |
931 | |
932 | void amvdec_disable(void) |
933 | { |
934 | amvdec_pg_enable(false); |
935 | } |
936 | EXPORT_SYMBOL(amvdec_disable); |
937 | |
938 | void amvdec2_enable(void) |
939 | { |
940 | if (has_vdec2()) |
941 | amvdec2_pg_enable(true); |
942 | } |
943 | EXPORT_SYMBOL(amvdec2_enable); |
944 | |
945 | void amvdec2_disable(void) |
946 | { |
947 | if (has_vdec2()) |
948 | amvdec2_pg_enable(false); |
949 | } |
950 | EXPORT_SYMBOL(amvdec2_disable); |
951 | |
952 | void amhevc_enable(void) |
953 | { |
954 | if (has_hevc_vdec()) |
955 | amhevc_pg_enable(true); |
956 | } |
957 | EXPORT_SYMBOL(amhevc_enable); |
958 | |
959 | void amhevc_disable(void) |
960 | { |
961 | if (has_hevc_vdec()) |
962 | amhevc_pg_enable(false); |
963 | } |
964 | EXPORT_SYMBOL(amhevc_disable); |
965 | |
966 | #ifdef CONFIG_PM |
967 | int amvdec_suspend(struct platform_device *dev, pm_message_t event) |
968 | { |
969 | amvdec_pg_enable(false); |
970 | |
971 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ |
972 | if (has_vdec2()) |
973 | amvdec2_pg_enable(false); |
974 | /* #endif */ |
975 | |
976 | if (has_hevc_vdec()) |
977 | amhevc_pg_enable(false); |
978 | /*vdec_set_suspend_clk(1, 0);*//*DEBUG_TMP*/ |
979 | return 0; |
980 | } |
981 | EXPORT_SYMBOL(amvdec_suspend); |
982 | |
983 | int amvdec_resume(struct platform_device *dev) |
984 | { |
985 | amvdec_pg_enable(true); |
986 | |
987 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ |
988 | if (has_vdec2()) |
989 | amvdec2_pg_enable(true); |
990 | /* #endif */ |
991 | |
992 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
993 | if (has_hevc_vdec()) |
994 | amhevc_pg_enable(true); |
995 | /* #endif */ |
996 | /*vdec_set_suspend_clk(0, 0);*//*DEBUG_TMP*/ |
997 | return 0; |
998 | } |
999 | EXPORT_SYMBOL(amvdec_resume); |
1000 | |
1001 | int amhevc_suspend(struct platform_device *dev, pm_message_t event) |
1002 | { |
1003 | if (has_hevc_vdec()) { |
1004 | amhevc_pg_enable(false); |
1005 | /*vdec_set_suspend_clk(1, 1);*//*DEBUG_TMP*/ |
1006 | } |
1007 | return 0; |
1008 | } |
1009 | EXPORT_SYMBOL(amhevc_suspend); |
1010 | |
1011 | int amhevc_resume(struct platform_device *dev) |
1012 | { |
1013 | if (has_hevc_vdec()) { |
1014 | amhevc_pg_enable(true); |
1015 | /*vdec_set_suspend_clk(0, 1);*//*DEBUG_TMP*/ |
1016 | } |
1017 | return 0; |
1018 | } |
1019 | EXPORT_SYMBOL(amhevc_resume); |
1020 | |
1021 | |
1022 | #endif |
1023 | |
1024 | #ifdef CONFIG_WAKELOCK |
1025 | |
1026 | static int vdec_is_paused(void) |
1027 | { |
1028 | static unsigned long old_wp = -1, old_rp = -1, old_level = -1; |
1029 | unsigned long wp, rp, level; |
1030 | static int paused_time; |
1031 | |
1032 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
1033 | if (has_hevc_vdec()) { |
1034 | if ((vdec_on(VDEC_HEVC)) |
1035 | && (READ_VREG(HEVC_STREAM_CONTROL) & 1)) { |
1036 | wp = READ_VREG(HEVC_STREAM_WR_PTR); |
1037 | rp = READ_VREG(HEVC_STREAM_RD_PTR); |
1038 | level = READ_VREG(HEVC_STREAM_LEVEL); |
1039 | } else { |
1040 | wp = READ_VREG(VLD_MEM_VIFIFO_WP); |
1041 | rp = READ_VREG(VLD_MEM_VIFIFO_RP); |
1042 | level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); |
1043 | } |
1044 | } else |
1045 | /* #endif */ |
1046 | { |
1047 | wp = READ_VREG(VLD_MEM_VIFIFO_WP); |
1048 | rp = READ_VREG(VLD_MEM_VIFIFO_RP); |
1049 | level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); |
1050 | } |
1051 | /*have data,but output buffer is full */ |
1052 | if ((rp == old_rp && level > 1024) || |
1053 | (rp == old_rp && wp == old_wp && level == old_level)) { |
1054 | /*no write && not read */ |
1055 | paused_time++; |
1056 | } else { |
1057 | paused_time = 0; |
1058 | } |
1059 | old_wp = wp; old_rp = rp; old_level = level; |
1060 | if (paused_time > 10) |
1061 | return 1; |
1062 | return 0; |
1063 | } |
1064 | |
1065 | int amvdev_pause(void) |
1066 | { |
1067 | video_running = 0; |
1068 | video_stated_changed = 1; |
1069 | return 0; |
1070 | } |
1071 | EXPORT_SYMBOL(amvdev_pause); |
1072 | |
1073 | int amvdev_resume(void) |
1074 | { |
1075 | video_running = 1; |
1076 | video_stated_changed = 1; |
1077 | return 0; |
1078 | } |
1079 | EXPORT_SYMBOL(amvdev_resume); |
1080 | |
1081 | static void vdec_paused_check_timer(unsigned long arg) |
1082 | { |
1083 | if (video_stated_changed) { |
1084 | if (!video_running) { |
1085 | if (vdec_is_paused()) { |
1086 | pr_info("vdec paused and release wakelock now\n"); |
1087 | amvdec_wake_unlock(); |
1088 | video_stated_changed = 0; |
1089 | } |
1090 | } else { |
1091 | amvdec_wake_lock(); |
1092 | video_stated_changed = 0; |
1093 | } |
1094 | } |
1095 | mod_timer(&amvdevtimer, jiffies + WAKE_CHECK_INTERVAL); |
1096 | } |
1097 | #else |
1098 | int amvdev_pause(void) |
1099 | { |
1100 | return 0; |
1101 | } |
1102 | |
1103 | int amvdev_resume(void) |
1104 | { |
1105 | return 0; |
1106 | } |
1107 | #endif |
1108 | |
1109 | int amvdec_init(void) |
1110 | { |
1111 | #ifdef CONFIG_WAKELOCK |
1112 | /* |
1113 | *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock"); |
1114 | *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8 |
1115 | */ |
1116 | wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND, |
1117 | "amvdec_lock"); |
1118 | |
1119 | init_timer(&amvdevtimer); |
1120 | |
1121 | amvdevtimer.data = (ulong) &amvdevtimer; |
1122 | amvdevtimer.function = vdec_paused_check_timer; |
1123 | #endif |
1124 | return 0; |
1125 | } |
1126 | EXPORT_SYMBOL(amvdec_init); |
1127 | |
1128 | void amvdec_exit(void) |
1129 | { |
1130 | #ifdef CONFIG_WAKELOCK |
1131 | del_timer_sync(&amvdevtimer); |
1132 | #endif |
1133 | } |
1134 | EXPORT_SYMBOL(amvdec_exit); |
1135 | |
1136 | #if 0 |
1137 | int __init amvdec_init(void) |
1138 | { |
1139 | #ifdef CONFIG_WAKELOCK |
1140 | /* |
1141 | *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock"); |
1142 | *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8 |
1143 | */ |
1144 | wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND, |
1145 | "amvdec_lock"); |
1146 | |
1147 | init_timer(&amvdevtimer); |
1148 | |
1149 | amvdevtimer.data = (ulong) &amvdevtimer; |
1150 | amvdevtimer.function = vdec_paused_check_timer; |
1151 | #endif |
1152 | return 0; |
1153 | } |
1154 | |
1155 | static void __exit amvdec_exit(void) |
1156 | { |
1157 | #ifdef CONFIG_WAKELOCK |
1158 | del_timer_sync(&amvdevtimer); |
1159 | #endif |
1160 | } |
1161 | |
1162 | module_init(amvdec_init); |
1163 | module_exit(amvdec_exit); |
1164 | #endif |
1165 | |
1166 | MODULE_DESCRIPTION("Amlogic Video Decoder Utility Driver"); |
1167 | MODULE_LICENSE("GPL"); |
1168 | MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>"); |
1169 |