blob: bf8955e36fbbdbe25e6d05adc9cc695aa271ea59
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_HEVC: |
429 | if (!strcmp(name, "h265_mmu")) |
430 | format = VIDEO_DEC_HEVC_MMU; |
431 | else if (!strcmp(name, "hevc_mmu_swap")) { |
432 | format = VIDEO_DEC_HEVC_MMU_SWAP; |
433 | vdec = OPTEE_VDEC_HEVC; |
434 | is_swap = true; |
435 | } else |
436 | format = VIDEO_DEC_HEVC; |
437 | break; |
438 | |
439 | case VFORMAT_REAL: |
440 | if (!strcmp(name, "vreal_mc_8")) |
441 | format = VIDEO_DEC_REAL_V8; |
442 | else if (!strcmp(name, "vreal_mc_9")) |
443 | format = VIDEO_DEC_REAL_V9; |
444 | break; |
445 | |
446 | case VFORMAT_MPEG4: |
447 | if (!strcmp(name, "mmpeg4_mc_5")) |
448 | format = VIDEO_DEC_MPEG4_5_MULTI; |
449 | else if ((!strcmp(name, "mh263_mc"))) |
450 | format = VIDEO_DEC_H263_MULTI; |
451 | else if (!strcmp(name, "vmpeg4_mc_5")) |
452 | format = VIDEO_DEC_MPEG4_5; |
453 | else if (!strcmp(name, "h263_mc")) |
454 | format = VIDEO_DEC_H263; |
455 | /*not support now*/ |
456 | else if (!strcmp(name, "vmpeg4_mc_311")) |
457 | format = VIDEO_DEC_MPEG4_3; |
458 | else if (!strcmp(name, "vmpeg4_mc_4")) |
459 | format = VIDEO_DEC_MPEG4_4; |
460 | break; |
461 | |
462 | case VFORMAT_H264_4K2K: |
463 | if (!strcmp(name, "single_core")) |
464 | format = VIDEO_DEC_H264_4k2K_SINGLE; |
465 | else |
466 | format = VIDEO_DEC_H264_4k2K; |
467 | break; |
468 | |
469 | case VFORMAT_H264MVC: |
470 | format = VIDEO_DEC_H264_MVC; |
471 | break; |
472 | |
473 | case VFORMAT_H264: |
474 | if (!strcmp(name, "mh264")) |
475 | format = VIDEO_DEC_H264_MULTI; |
476 | else if (!strcmp(name, "mh264_mmu")) { |
477 | format = VIDEO_DEC_H264_MULTI_MMU; |
478 | vdec = OPTEE_VDEC_HEVC; |
479 | } else |
480 | format = VIDEO_DEC_H264; |
481 | break; |
482 | |
483 | default: |
484 | pr_info("Unknow vdec format!\n"); |
485 | break; |
486 | } |
487 | |
488 | if (format < FIRMWARE_MAX) { |
489 | if (is_swap) |
490 | ret = tee_load_video_fw_swap(format, vdec, is_swap); |
491 | else |
492 | ret = tee_load_video_fw(format, vdec); |
493 | } |
494 | |
495 | __putname(name); |
496 | |
497 | return ret; |
498 | } |
499 | EXPORT_SYMBOL(optee_load_fw); |
500 | |
501 | s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def) |
502 | { |
503 | if (tee_enabled()) |
504 | return optee_load_fw(type, name); |
505 | else |
506 | return am_loadmc_ex(type, name, def, &amvdec_loadmc); |
507 | } |
508 | EXPORT_SYMBOL(amvdec_loadmc_ex); |
509 | |
510 | s32 amvdec_vdec_loadmc_ex(enum vformat_e type, const char *name, |
511 | struct vdec_s *vdec, char *def) |
512 | { |
513 | if (tee_enabled()) |
514 | return optee_load_fw(type, name); |
515 | else |
516 | return am_vdec_loadmc_ex(vdec, name, def, &amvdec_loadmc); |
517 | } |
518 | EXPORT_SYMBOL(amvdec_vdec_loadmc_ex); |
519 | |
520 | s32 amvdec_vdec_loadmc_buf_ex(enum vformat_e type, const char *name, |
521 | struct vdec_s *vdec, char *buf, int size) |
522 | { |
523 | if (tee_enabled()) |
524 | return optee_load_fw(type, name); |
525 | else |
526 | return am_vdec_loadmc_buf_ex(vdec, buf, size, &amvdec_loadmc); |
527 | } |
528 | EXPORT_SYMBOL(amvdec_vdec_loadmc_buf_ex); |
529 | |
530 | static s32 amvdec2_loadmc(const u32 *p) |
531 | { |
532 | if (has_vdec2()) { |
533 | ulong timeout; |
534 | s32 ret = 0; |
535 | |
536 | #ifdef AMVDEC_USE_STATIC_MEMORY |
537 | if (mc_addr == NULL) { |
538 | #else |
539 | { |
540 | #endif |
541 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
542 | } |
543 | |
544 | if (!mc_addr) |
545 | return -ENOMEM; |
546 | |
547 | memcpy(mc_addr, p, MC_SIZE); |
548 | |
549 | mc_addr_map = dma_map_single(get_vdec_device(), |
550 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
551 | |
552 | WRITE_VREG(VDEC2_MPSR, 0); |
553 | WRITE_VREG(VDEC2_CPSR, 0); |
554 | |
555 | /* Read CBUS register for timing */ |
556 | timeout = READ_VREG(VDEC2_MPSR); |
557 | timeout = READ_VREG(VDEC2_MPSR); |
558 | |
559 | timeout = jiffies + HZ; |
560 | |
561 | WRITE_VREG(VDEC2_IMEM_DMA_ADR, mc_addr_map); |
562 | WRITE_VREG(VDEC2_IMEM_DMA_COUNT, 0x1000); |
563 | WRITE_VREG(VDEC2_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
564 | |
565 | while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) { |
566 | if (time_before(jiffies, timeout)) |
567 | schedule(); |
568 | else { |
569 | pr_err("vdec2 load mc error\n"); |
570 | ret = -EBUSY; |
571 | break; |
572 | } |
573 | } |
574 | |
575 | dma_unmap_single(get_vdec_device(), |
576 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
577 | |
578 | #ifndef AMVDEC_USE_STATIC_MEMORY |
579 | kfree(mc_addr); |
580 | mc_addr = NULL; |
581 | #endif |
582 | |
583 | return ret; |
584 | } else |
585 | return 0; |
586 | } |
587 | |
588 | s32 amvdec2_loadmc_ex(enum vformat_e type, const char *name, char *def) |
589 | { |
590 | if (has_vdec2()) |
591 | return am_loadmc_ex(type, name, def, &amvdec2_loadmc); |
592 | else |
593 | return 0; |
594 | } |
595 | EXPORT_SYMBOL(amvdec2_loadmc_ex); |
596 | |
597 | s32 amhcodec_loadmc(const u32 *p) |
598 | { |
599 | #ifdef AMVDEC_USE_STATIC_MEMORY |
600 | if (mc_addr == NULL) { |
601 | #else |
602 | { |
603 | #endif |
604 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
605 | } |
606 | |
607 | if (!mc_addr) |
608 | return -ENOMEM; |
609 | |
610 | memcpy(mc_addr, p, MC_SIZE); |
611 | |
612 | mc_addr_map = dma_map_single(get_vdec_device(), |
613 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
614 | |
615 | WRITE_VREG(HCODEC_IMEM_DMA_ADR, mc_addr_map); |
616 | WRITE_VREG(HCODEC_IMEM_DMA_COUNT, 0x100); |
617 | WRITE_VREG(HCODEC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
618 | |
619 | while (READ_VREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) |
620 | udelay(1000); |
621 | |
622 | dma_unmap_single(get_vdec_device(), |
623 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
624 | |
625 | #ifndef AMVDEC_USE_STATIC_MEMORY |
626 | kfree(mc_addr); |
627 | #endif |
628 | |
629 | return 0; |
630 | } |
631 | EXPORT_SYMBOL(amhcodec_loadmc); |
632 | |
633 | s32 amhcodec_loadmc_ex(enum vformat_e type, const char *name, char *def) |
634 | { |
635 | return am_loadmc_ex(type, name, def, &amhcodec_loadmc); |
636 | } |
637 | EXPORT_SYMBOL(amhcodec_loadmc_ex); |
638 | |
639 | static s32 amhevc_loadmc(const u32 *p) |
640 | { |
641 | ulong timeout; |
642 | s32 ret = 0; |
643 | |
644 | if (has_hevc_vdec()) { |
645 | #ifdef AMVDEC_USE_STATIC_MEMORY |
646 | if (mc_addr == NULL) { |
647 | #else |
648 | { |
649 | #endif |
650 | mc_addr = kmalloc(MC_SIZE, GFP_KERNEL); |
651 | } |
652 | |
653 | if (!mc_addr) |
654 | return -ENOMEM; |
655 | |
656 | memcpy(mc_addr, p, MC_SIZE); |
657 | |
658 | mc_addr_map = |
659 | dma_map_single(get_vdec_device(), |
660 | mc_addr, MC_SIZE, DMA_TO_DEVICE); |
661 | |
662 | WRITE_VREG(HEVC_MPSR, 0); |
663 | WRITE_VREG(HEVC_CPSR, 0); |
664 | |
665 | /* Read CBUS register for timing */ |
666 | timeout = READ_VREG(HEVC_MPSR); |
667 | timeout = READ_VREG(HEVC_MPSR); |
668 | |
669 | timeout = jiffies + HZ; |
670 | |
671 | WRITE_VREG(HEVC_IMEM_DMA_ADR, mc_addr_map); |
672 | WRITE_VREG(HEVC_IMEM_DMA_COUNT, 0x1000); |
673 | WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); |
674 | |
675 | while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) { |
676 | if (time_before(jiffies, timeout)) |
677 | schedule(); |
678 | else { |
679 | pr_err("vdec2 load mc error\n"); |
680 | ret = -EBUSY; |
681 | break; |
682 | } |
683 | } |
684 | |
685 | dma_unmap_single(get_vdec_device(), |
686 | mc_addr_map, MC_SIZE, DMA_TO_DEVICE); |
687 | |
688 | #ifndef AMVDEC_USE_STATIC_MEMORY |
689 | kfree(mc_addr); |
690 | mc_addr = NULL; |
691 | #endif |
692 | } |
693 | |
694 | return ret; |
695 | } |
696 | |
697 | s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def) |
698 | { |
699 | if (has_hevc_vdec()) |
700 | if (tee_enabled()) |
701 | return optee_load_fw(type, name); |
702 | else |
703 | return am_loadmc_ex(type, name, def, &amhevc_loadmc); |
704 | else |
705 | return -1; |
706 | } |
707 | EXPORT_SYMBOL(amhevc_loadmc_ex); |
708 | |
709 | s32 amhevc_vdec_loadmc_ex(enum vformat_e type, struct vdec_s *vdec, |
710 | const char *name, char *def) |
711 | { |
712 | if (has_hevc_vdec()) |
713 | if (tee_enabled()) |
714 | return optee_load_fw(type, name); |
715 | else |
716 | return am_vdec_loadmc_ex(vdec, name, def, &amhevc_loadmc); |
717 | else |
718 | return -1; |
719 | } |
720 | EXPORT_SYMBOL(amhevc_vdec_loadmc_ex); |
721 | |
722 | void amvdec_start(void) |
723 | { |
724 | #ifdef CONFIG_WAKELOCK |
725 | amvdec_wake_lock(); |
726 | #endif |
727 | |
728 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ |
729 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) { |
730 | READ_VREG(DOS_SW_RESET0); |
731 | READ_VREG(DOS_SW_RESET0); |
732 | READ_VREG(DOS_SW_RESET0); |
733 | |
734 | WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); |
735 | WRITE_VREG(DOS_SW_RESET0, 0); |
736 | |
737 | READ_VREG(DOS_SW_RESET0); |
738 | READ_VREG(DOS_SW_RESET0); |
739 | READ_VREG(DOS_SW_RESET0); |
740 | } else { |
741 | /* #else */ |
742 | /* additional cbus dummy register reading for timing control */ |
743 | READ_RESET_REG(RESET0_REGISTER); |
744 | READ_RESET_REG(RESET0_REGISTER); |
745 | READ_RESET_REG(RESET0_REGISTER); |
746 | READ_RESET_REG(RESET0_REGISTER); |
747 | |
748 | WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU); |
749 | |
750 | READ_RESET_REG(RESET0_REGISTER); |
751 | READ_RESET_REG(RESET0_REGISTER); |
752 | READ_RESET_REG(RESET0_REGISTER); |
753 | } |
754 | /* #endif */ |
755 | |
756 | WRITE_VREG(MPSR, 0x0001); |
757 | } |
758 | EXPORT_SYMBOL(amvdec_start); |
759 | |
760 | void amvdec2_start(void) |
761 | { |
762 | if (has_vdec2()) { |
763 | #ifdef CONFIG_WAKELOCK |
764 | amvdec_wake_lock(); |
765 | #endif |
766 | |
767 | READ_VREG(DOS_SW_RESET2); |
768 | READ_VREG(DOS_SW_RESET2); |
769 | READ_VREG(DOS_SW_RESET2); |
770 | |
771 | WRITE_VREG(DOS_SW_RESET2, (1 << 12) | (1 << 11)); |
772 | WRITE_VREG(DOS_SW_RESET2, 0); |
773 | |
774 | READ_VREG(DOS_SW_RESET2); |
775 | READ_VREG(DOS_SW_RESET2); |
776 | READ_VREG(DOS_SW_RESET2); |
777 | |
778 | WRITE_VREG(VDEC2_MPSR, 0x0001); |
779 | } |
780 | } |
781 | EXPORT_SYMBOL(amvdec2_start); |
782 | |
783 | void amhcodec_start(void) |
784 | { |
785 | WRITE_VREG(HCODEC_MPSR, 0x0001); |
786 | } |
787 | EXPORT_SYMBOL(amhcodec_start); |
788 | |
789 | void amhevc_start(void) |
790 | { |
791 | |
792 | if (has_hevc_vdec()) { |
793 | #ifdef CONFIG_WAKELOCK |
794 | amvdec_wake_lock(); |
795 | #endif |
796 | |
797 | READ_VREG(DOS_SW_RESET3); |
798 | READ_VREG(DOS_SW_RESET3); |
799 | READ_VREG(DOS_SW_RESET3); |
800 | |
801 | WRITE_VREG(DOS_SW_RESET3, (1 << 12) | (1 << 11)); |
802 | WRITE_VREG(DOS_SW_RESET3, 0); |
803 | |
804 | READ_VREG(DOS_SW_RESET3); |
805 | READ_VREG(DOS_SW_RESET3); |
806 | READ_VREG(DOS_SW_RESET3); |
807 | |
808 | WRITE_VREG(HEVC_MPSR, 0x0001); |
809 | } |
810 | } |
811 | EXPORT_SYMBOL(amhevc_start); |
812 | |
813 | void amvdec_stop(void) |
814 | { |
815 | ulong timeout = jiffies + HZ/10; |
816 | |
817 | WRITE_VREG(MPSR, 0); |
818 | WRITE_VREG(CPSR, 0); |
819 | |
820 | while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) { |
821 | if (time_after(jiffies, timeout)) |
822 | break; |
823 | } |
824 | |
825 | timeout = jiffies + HZ/10; |
826 | while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) { |
827 | if (time_after(jiffies, timeout)) |
828 | break; |
829 | } |
830 | |
831 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ |
832 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) { |
833 | READ_VREG(DOS_SW_RESET0); |
834 | READ_VREG(DOS_SW_RESET0); |
835 | READ_VREG(DOS_SW_RESET0); |
836 | |
837 | WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); |
838 | WRITE_VREG(DOS_SW_RESET0, 0); |
839 | |
840 | READ_VREG(DOS_SW_RESET0); |
841 | READ_VREG(DOS_SW_RESET0); |
842 | READ_VREG(DOS_SW_RESET0); |
843 | } else { |
844 | /* #else */ |
845 | WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU); |
846 | |
847 | /* additional cbus dummy register reading for timing control */ |
848 | READ_RESET_REG(RESET0_REGISTER); |
849 | READ_RESET_REG(RESET0_REGISTER); |
850 | READ_RESET_REG(RESET0_REGISTER); |
851 | READ_RESET_REG(RESET0_REGISTER); |
852 | } |
853 | /* #endif */ |
854 | |
855 | #ifdef CONFIG_WAKELOCK |
856 | amvdec_wake_unlock(); |
857 | #endif |
858 | } |
859 | EXPORT_SYMBOL(amvdec_stop); |
860 | |
861 | void amvdec2_stop(void) |
862 | { |
863 | if (has_vdec2()) { |
864 | ulong timeout = jiffies + HZ/10; |
865 | |
866 | WRITE_VREG(VDEC2_MPSR, 0); |
867 | WRITE_VREG(VDEC2_CPSR, 0); |
868 | |
869 | while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) { |
870 | if (time_after(jiffies, timeout)) |
871 | break; |
872 | } |
873 | |
874 | READ_VREG(DOS_SW_RESET2); |
875 | READ_VREG(DOS_SW_RESET2); |
876 | READ_VREG(DOS_SW_RESET2); |
877 | |
878 | #ifdef CONFIG_WAKELOCK |
879 | amvdec_wake_unlock(); |
880 | #endif |
881 | } |
882 | } |
883 | EXPORT_SYMBOL(amvdec2_stop); |
884 | |
885 | void amhcodec_stop(void) |
886 | { |
887 | WRITE_VREG(HCODEC_MPSR, 0); |
888 | } |
889 | EXPORT_SYMBOL(amhcodec_stop); |
890 | |
891 | void amhevc_stop(void) |
892 | { |
893 | if (has_hevc_vdec()) { |
894 | ulong timeout = jiffies + HZ/10; |
895 | |
896 | WRITE_VREG(HEVC_MPSR, 0); |
897 | WRITE_VREG(HEVC_CPSR, 0); |
898 | |
899 | while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) { |
900 | if (time_after(jiffies, timeout)) |
901 | break; |
902 | } |
903 | |
904 | timeout = jiffies + HZ/10; |
905 | while (READ_VREG(HEVC_LMEM_DMA_CTRL) & 0x8000) { |
906 | if (time_after(jiffies, timeout)) |
907 | break; |
908 | } |
909 | |
910 | READ_VREG(DOS_SW_RESET3); |
911 | READ_VREG(DOS_SW_RESET3); |
912 | READ_VREG(DOS_SW_RESET3); |
913 | |
914 | #ifdef CONFIG_WAKELOCK |
915 | amvdec_wake_unlock(); |
916 | #endif |
917 | } |
918 | } |
919 | EXPORT_SYMBOL(amhevc_stop); |
920 | |
921 | void amvdec_enable(void) |
922 | { |
923 | amvdec_pg_enable(true); |
924 | } |
925 | EXPORT_SYMBOL(amvdec_enable); |
926 | |
927 | void amvdec_disable(void) |
928 | { |
929 | amvdec_pg_enable(false); |
930 | } |
931 | EXPORT_SYMBOL(amvdec_disable); |
932 | |
933 | void amvdec2_enable(void) |
934 | { |
935 | if (has_vdec2()) |
936 | amvdec2_pg_enable(true); |
937 | } |
938 | EXPORT_SYMBOL(amvdec2_enable); |
939 | |
940 | void amvdec2_disable(void) |
941 | { |
942 | if (has_vdec2()) |
943 | amvdec2_pg_enable(false); |
944 | } |
945 | EXPORT_SYMBOL(amvdec2_disable); |
946 | |
947 | void amhevc_enable(void) |
948 | { |
949 | if (has_hevc_vdec()) |
950 | amhevc_pg_enable(true); |
951 | } |
952 | EXPORT_SYMBOL(amhevc_enable); |
953 | |
954 | void amhevc_disable(void) |
955 | { |
956 | if (has_hevc_vdec()) |
957 | amhevc_pg_enable(false); |
958 | } |
959 | EXPORT_SYMBOL(amhevc_disable); |
960 | |
961 | #ifdef CONFIG_PM |
962 | int amvdec_suspend(struct platform_device *dev, pm_message_t event) |
963 | { |
964 | amvdec_pg_enable(false); |
965 | |
966 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ |
967 | if (has_vdec2()) |
968 | amvdec2_pg_enable(false); |
969 | /* #endif */ |
970 | |
971 | if (has_hevc_vdec()) |
972 | amhevc_pg_enable(false); |
973 | /*vdec_set_suspend_clk(1, 0);*//*DEBUG_TMP*/ |
974 | return 0; |
975 | } |
976 | EXPORT_SYMBOL(amvdec_suspend); |
977 | |
978 | int amvdec_resume(struct platform_device *dev) |
979 | { |
980 | amvdec_pg_enable(true); |
981 | |
982 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ |
983 | if (has_vdec2()) |
984 | amvdec2_pg_enable(true); |
985 | /* #endif */ |
986 | |
987 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
988 | if (has_hevc_vdec()) |
989 | amhevc_pg_enable(true); |
990 | /* #endif */ |
991 | /*vdec_set_suspend_clk(0, 0);*//*DEBUG_TMP*/ |
992 | return 0; |
993 | } |
994 | EXPORT_SYMBOL(amvdec_resume); |
995 | |
996 | int amhevc_suspend(struct platform_device *dev, pm_message_t event) |
997 | { |
998 | if (has_hevc_vdec()) { |
999 | amhevc_pg_enable(false); |
1000 | /*vdec_set_suspend_clk(1, 1);*//*DEBUG_TMP*/ |
1001 | } |
1002 | return 0; |
1003 | } |
1004 | EXPORT_SYMBOL(amhevc_suspend); |
1005 | |
1006 | int amhevc_resume(struct platform_device *dev) |
1007 | { |
1008 | if (has_hevc_vdec()) { |
1009 | amhevc_pg_enable(true); |
1010 | /*vdec_set_suspend_clk(0, 1);*//*DEBUG_TMP*/ |
1011 | } |
1012 | return 0; |
1013 | } |
1014 | EXPORT_SYMBOL(amhevc_resume); |
1015 | |
1016 | |
1017 | #endif |
1018 | |
1019 | #ifdef CONFIG_WAKELOCK |
1020 | |
1021 | static int vdec_is_paused(void) |
1022 | { |
1023 | static unsigned long old_wp = -1, old_rp = -1, old_level = -1; |
1024 | unsigned long wp, rp, level; |
1025 | static int paused_time; |
1026 | |
1027 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
1028 | if (has_hevc_vdec()) { |
1029 | if ((vdec_on(VDEC_HEVC)) |
1030 | && (READ_VREG(HEVC_STREAM_CONTROL) & 1)) { |
1031 | wp = READ_VREG(HEVC_STREAM_WR_PTR); |
1032 | rp = READ_VREG(HEVC_STREAM_RD_PTR); |
1033 | level = READ_VREG(HEVC_STREAM_LEVEL); |
1034 | } else { |
1035 | wp = READ_VREG(VLD_MEM_VIFIFO_WP); |
1036 | rp = READ_VREG(VLD_MEM_VIFIFO_RP); |
1037 | level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); |
1038 | } |
1039 | } else |
1040 | /* #endif */ |
1041 | { |
1042 | wp = READ_VREG(VLD_MEM_VIFIFO_WP); |
1043 | rp = READ_VREG(VLD_MEM_VIFIFO_RP); |
1044 | level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); |
1045 | } |
1046 | /*have data,but output buffer is full */ |
1047 | if ((rp == old_rp && level > 1024) || |
1048 | (rp == old_rp && wp == old_wp && level == old_level)) { |
1049 | /*no write && not read */ |
1050 | paused_time++; |
1051 | } else { |
1052 | paused_time = 0; |
1053 | } |
1054 | old_wp = wp; old_rp = rp; old_level = level; |
1055 | if (paused_time > 10) |
1056 | return 1; |
1057 | return 0; |
1058 | } |
1059 | |
1060 | int amvdev_pause(void) |
1061 | { |
1062 | video_running = 0; |
1063 | video_stated_changed = 1; |
1064 | return 0; |
1065 | } |
1066 | EXPORT_SYMBOL(amvdev_pause); |
1067 | |
1068 | int amvdev_resume(void) |
1069 | { |
1070 | video_running = 1; |
1071 | video_stated_changed = 1; |
1072 | return 0; |
1073 | } |
1074 | EXPORT_SYMBOL(amvdev_resume); |
1075 | |
1076 | static void vdec_paused_check_timer(unsigned long arg) |
1077 | { |
1078 | if (video_stated_changed) { |
1079 | if (!video_running) { |
1080 | if (vdec_is_paused()) { |
1081 | pr_info("vdec paused and release wakelock now\n"); |
1082 | amvdec_wake_unlock(); |
1083 | video_stated_changed = 0; |
1084 | } |
1085 | } else { |
1086 | amvdec_wake_lock(); |
1087 | video_stated_changed = 0; |
1088 | } |
1089 | } |
1090 | mod_timer(&amvdevtimer, jiffies + WAKE_CHECK_INTERVAL); |
1091 | } |
1092 | #else |
1093 | int amvdev_pause(void) |
1094 | { |
1095 | return 0; |
1096 | } |
1097 | |
1098 | int amvdev_resume(void) |
1099 | { |
1100 | return 0; |
1101 | } |
1102 | #endif |
1103 | |
1104 | int amvdec_init(void) |
1105 | { |
1106 | #ifdef CONFIG_WAKELOCK |
1107 | /* |
1108 | *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock"); |
1109 | *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8 |
1110 | */ |
1111 | wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND, |
1112 | "amvdec_lock"); |
1113 | |
1114 | init_timer(&amvdevtimer); |
1115 | |
1116 | amvdevtimer.data = (ulong) &amvdevtimer; |
1117 | amvdevtimer.function = vdec_paused_check_timer; |
1118 | #endif |
1119 | return 0; |
1120 | } |
1121 | EXPORT_SYMBOL(amvdec_init); |
1122 | |
1123 | void amvdec_exit(void) |
1124 | { |
1125 | #ifdef CONFIG_WAKELOCK |
1126 | del_timer_sync(&amvdevtimer); |
1127 | #endif |
1128 | } |
1129 | EXPORT_SYMBOL(amvdec_exit); |
1130 | |
1131 | #if 0 |
1132 | int __init amvdec_init(void) |
1133 | { |
1134 | #ifdef CONFIG_WAKELOCK |
1135 | /* |
1136 | *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock"); |
1137 | *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8 |
1138 | */ |
1139 | wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND, |
1140 | "amvdec_lock"); |
1141 | |
1142 | init_timer(&amvdevtimer); |
1143 | |
1144 | amvdevtimer.data = (ulong) &amvdevtimer; |
1145 | amvdevtimer.function = vdec_paused_check_timer; |
1146 | #endif |
1147 | return 0; |
1148 | } |
1149 | |
1150 | static void __exit amvdec_exit(void) |
1151 | { |
1152 | #ifdef CONFIG_WAKELOCK |
1153 | del_timer_sync(&amvdevtimer); |
1154 | #endif |
1155 | } |
1156 | |
1157 | module_init(amvdec_init); |
1158 | module_exit(amvdec_exit); |
1159 | #endif |
1160 | |
1161 | MODULE_DESCRIPTION("Amlogic Video Decoder Utility Driver"); |
1162 | MODULE_LICENSE("GPL"); |
1163 | MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>"); |
1164 |