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