blob: f81ba0cc08ad7ce3faf24136643e702bedcccecd
1 | /* |
2 | * drivers/amlogic/media/stream_input/parser/esparser.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/interrupt.h> |
22 | #include <linux/wait.h> |
23 | #include <linux/sched.h> |
24 | #include <linux/fs.h> |
25 | #include <linux/mutex.h> |
26 | #include <linux/slab.h> |
27 | #include <linux/dma-mapping.h> |
28 | #include <linux/amlogic/media/frame_sync/ptsserv.h> |
29 | |
30 | #include <linux/uaccess.h> |
31 | #include <linux/atomic.h> |
32 | |
33 | /* #include <mach/am_regs.h> */ |
34 | #include <linux/delay.h> |
35 | |
36 | #include "../../frame_provider/decoder/utils/vdec.h" |
37 | #include <linux/amlogic/media/utils/vdec_reg.h> |
38 | #include "streambuf_reg.h" |
39 | #include "streambuf.h" |
40 | #include "esparser.h" |
41 | #include "../amports/amports_priv.h" |
42 | #include "thread_rw.h" |
43 | |
44 | #include <linux/amlogic/media/codec_mm/codec_mm.h> |
45 | |
46 | |
47 | |
48 | #define SAVE_SCR 0 |
49 | |
50 | #define ES_START_CODE_PATTERN 0x00000100 |
51 | #define ES_START_CODE_MASK 0xffffff00 |
52 | #define SEARCH_PATTERN_LEN 512 |
53 | #define ES_PARSER_POP READ_PARSER_REG(PFIFO_DATA) |
54 | |
55 | #define PARSER_WRITE (ES_WRITE | ES_PARSER_START) |
56 | #define PARSER_VIDEO (ES_TYPE_VIDEO) |
57 | #define PARSER_AUDIO (ES_TYPE_AUDIO) |
58 | #define PARSER_SUBPIC (ES_TYPE_SUBTITLE) |
59 | #define PARSER_PASSTHROUGH (ES_PASSTHROUGH | ES_PARSER_START) |
60 | #define PARSER_AUTOSEARCH (ES_SEARCH | ES_PARSER_START) |
61 | #define PARSER_DISCARD (ES_DISCARD | ES_PARSER_START) |
62 | #define PARSER_BUSY (ES_PARSER_BUSY) |
63 | |
64 | #define MAX_DRM_PACKAGE_SIZE 0x500000 |
65 | |
66 | |
67 | static unsigned char *search_pattern; |
68 | static dma_addr_t search_pattern_map; |
69 | static u32 audio_real_wp; |
70 | static u32 audio_buf_start; |
71 | static u32 audio_buf_end; |
72 | |
73 | static const char esparser_id[] = "esparser-id"; |
74 | |
75 | static DECLARE_WAIT_QUEUE_HEAD(wq); |
76 | |
77 | |
78 | static u32 search_done; |
79 | static u32 video_data_parsed; |
80 | static u32 audio_data_parsed; |
81 | static atomic_t esparser_use_count = ATOMIC_INIT(0); |
82 | static DEFINE_MUTEX(esparser_mutex); |
83 | |
84 | static inline u32 get_buf_wp(u32 type) |
85 | { |
86 | if (type == BUF_TYPE_AUDIO) |
87 | return audio_real_wp; |
88 | else |
89 | return 0; |
90 | } |
91 | static inline u32 get_buf_start(u32 type) |
92 | { |
93 | if (type == BUF_TYPE_AUDIO) |
94 | return audio_buf_start; |
95 | else |
96 | return 0; |
97 | } |
98 | static inline u32 get_buf_end(u32 type) |
99 | { |
100 | if (type == BUF_TYPE_AUDIO) |
101 | return audio_buf_end; |
102 | else |
103 | return 0; |
104 | } |
105 | static void set_buf_wp(u32 type, u32 wp) |
106 | { |
107 | if (type == BUF_TYPE_AUDIO) { |
108 | audio_real_wp = wp; |
109 | WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP, wp/* & 0xffffff00*/); |
110 | } |
111 | return; |
112 | } |
113 | |
114 | static irqreturn_t esparser_isr(int irq, void *dev_id) |
115 | { |
116 | u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS); |
117 | |
118 | WRITE_PARSER_REG(PARSER_INT_STATUS, int_status); |
119 | |
120 | if (int_status & PARSER_INTSTAT_SC_FOUND) { |
121 | WRITE_PARSER_REG(PFIFO_RD_PTR, 0); |
122 | WRITE_PARSER_REG(PFIFO_WR_PTR, 0); |
123 | search_done = 1; |
124 | wake_up_interruptible(&wq); |
125 | } |
126 | return IRQ_HANDLED; |
127 | } |
128 | |
129 | static inline u32 buf_wp(u32 type) |
130 | { |
131 | u32 wp; |
132 | |
133 | if ((READ_PARSER_REG(PARSER_ES_CONTROL) & ES_VID_MAN_RD_PTR) == 0) { |
134 | wp = |
135 | #if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
136 | (type == BUF_TYPE_HEVC) ? READ_VREG(HEVC_STREAM_WR_PTR) : |
137 | #endif |
138 | (type == BUF_TYPE_VIDEO) ? READ_VREG(VLD_MEM_VIFIFO_WP) : |
139 | (type == BUF_TYPE_AUDIO) ? |
140 | READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) : |
141 | READ_PARSER_REG(PARSER_SUB_START_PTR); |
142 | } else { |
143 | wp = |
144 | #if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
145 | (type == BUF_TYPE_HEVC) ? READ_PARSER_REG(PARSER_VIDEO_WP) : |
146 | #endif |
147 | (type == BUF_TYPE_VIDEO) ? READ_PARSER_REG(PARSER_VIDEO_WP) : |
148 | (type == BUF_TYPE_AUDIO) ? |
149 | READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) : |
150 | READ_PARSER_REG(PARSER_SUB_START_PTR); |
151 | } |
152 | |
153 | return wp; |
154 | } |
155 | |
156 | static ssize_t _esparser_write(const char __user *buf, |
157 | size_t count, struct stream_buf_s *stbuf, int isphybuf) |
158 | { |
159 | size_t r = count; |
160 | const char __user *p = buf; |
161 | |
162 | u32 len = 0; |
163 | u32 parser_type; |
164 | int ret; |
165 | u32 wp; |
166 | dma_addr_t dma_addr = 0; |
167 | u32 type = stbuf->type; |
168 | |
169 | VDEC_PRINT_FUN_LINENO(__func__, __LINE__); |
170 | if (type == BUF_TYPE_HEVC) |
171 | parser_type = PARSER_VIDEO; |
172 | else if (type == BUF_TYPE_VIDEO) |
173 | parser_type = PARSER_VIDEO; |
174 | else if (type == BUF_TYPE_AUDIO) |
175 | parser_type = PARSER_AUDIO; |
176 | else |
177 | parser_type = PARSER_SUBPIC; |
178 | |
179 | wp = buf_wp(type); |
180 | |
181 | if (r > 0) { |
182 | if (isphybuf) |
183 | len = count; |
184 | else { |
185 | len = min_t(size_t, r, (size_t) FETCHBUF_SIZE); |
186 | |
187 | if (copy_from_user(fetchbuf, p, len)) |
188 | return -EFAULT; |
189 | dma_addr = dma_map_single( |
190 | amports_get_dma_device(), fetchbuf, |
191 | FETCHBUF_SIZE, DMA_TO_DEVICE); |
192 | if (dma_mapping_error(amports_get_dma_device(), |
193 | (dma_addr_t) dma_addr)) |
194 | return -EFAULT; |
195 | |
196 | } |
197 | |
198 | /* wmb(); don't need */ |
199 | /* reset the Write and read pointer to zero again */ |
200 | WRITE_PARSER_REG(PFIFO_RD_PTR, 0); |
201 | WRITE_PARSER_REG(PFIFO_WR_PTR, 0); |
202 | |
203 | WRITE_PARSER_REG_BITS(PARSER_CONTROL, len, ES_PACK_SIZE_BIT, |
204 | ES_PACK_SIZE_WID); |
205 | WRITE_PARSER_REG_BITS(PARSER_CONTROL, |
206 | parser_type | PARSER_WRITE | |
207 | PARSER_AUTOSEARCH, ES_CTRL_BIT, |
208 | ES_CTRL_WID); |
209 | |
210 | if (isphybuf) { |
211 | u32 buf_32 = (unsigned long)buf & 0xffffffff; |
212 | WRITE_PARSER_REG(PARSER_FETCH_ADDR, buf_32); |
213 | } else { |
214 | WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr); |
215 | dma_unmap_single(amports_get_dma_device(), dma_addr, |
216 | FETCHBUF_SIZE, DMA_TO_DEVICE); |
217 | } |
218 | |
219 | search_done = 0; |
220 | if (!(isphybuf & TYPE_PATTERN)) { |
221 | WRITE_PARSER_REG(PARSER_FETCH_CMD, |
222 | (7 << FETCH_ENDIAN) | len); |
223 | WRITE_PARSER_REG(PARSER_FETCH_ADDR, search_pattern_map); |
224 | WRITE_PARSER_REG(PARSER_FETCH_CMD, |
225 | (7 << FETCH_ENDIAN) | SEARCH_PATTERN_LEN); |
226 | } else { |
227 | WRITE_PARSER_REG(PARSER_FETCH_CMD, |
228 | (7 << FETCH_ENDIAN) | (len + 512)); |
229 | } |
230 | ret = wait_event_interruptible_timeout(wq, search_done != 0, |
231 | HZ / 5); |
232 | if (ret == 0) { |
233 | WRITE_PARSER_REG(PARSER_FETCH_CMD, 0); |
234 | |
235 | if (wp == buf_wp(type)) { |
236 | /*no data fetched */ |
237 | return -EAGAIN; |
238 | } else { |
239 | pr_info("W Timeout, but fetch ok,"); |
240 | pr_info("type %d len=%d,wpdiff=%d, isphy %x\n", |
241 | type, len, wp - buf_wp(type), isphybuf); |
242 | } |
243 | } else if (ret < 0) |
244 | return -ERESTARTSYS; |
245 | } |
246 | |
247 | if ((type == BUF_TYPE_VIDEO) |
248 | || (has_hevc_vdec() && (type == BUF_TYPE_HEVC))) |
249 | video_data_parsed += len; |
250 | else if (type == BUF_TYPE_AUDIO) |
251 | audio_data_parsed += len; |
252 | |
253 | threadrw_update_buffer_level(stbuf, len); |
254 | VDEC_PRINT_FUN_LINENO(__func__, __LINE__); |
255 | |
256 | return len; |
257 | } |
258 | |
259 | static ssize_t _esparser_write_s(const char __user *buf, |
260 | size_t count, struct stream_buf_s *stbuf) |
261 | { |
262 | size_t r = count; |
263 | const char __user *p = buf; |
264 | u32 len = 0; |
265 | int ret; |
266 | u32 wp, buf_start, buf_end; |
267 | u32 type = stbuf->type; |
268 | void *vaddr = NULL; |
269 | |
270 | if (type != BUF_TYPE_AUDIO) |
271 | BUG(); |
272 | wp = get_buf_wp(type); |
273 | buf_end = get_buf_end(type) + 8; |
274 | buf_start = get_buf_start(type); |
275 | /*pr_info("write wp 0x%x, count %d, start 0x%x, end 0x%x\n", |
276 | * wp, (u32)count, buf_start, buf_end);*/ |
277 | if (wp + count > buf_end) { |
278 | if (wp == buf_end) { |
279 | wp = buf_start; |
280 | set_buf_wp(type, wp); |
281 | return -EAGAIN; |
282 | } |
283 | vaddr = codec_mm_phys_to_virt(wp); |
284 | ret = copy_from_user(vaddr, p, buf_end - wp); |
285 | if (ret > 0) { |
286 | len += buf_end - wp - ret; |
287 | codec_mm_dma_flush(vaddr, len, DMA_TO_DEVICE); |
288 | wp += len; |
289 | pr_info("copy from user not finished\n"); |
290 | set_buf_wp(type, wp); |
291 | goto end_write; |
292 | } else if (ret == 0) { |
293 | len += buf_end - wp; |
294 | codec_mm_dma_flush(vaddr, len, DMA_TO_DEVICE); |
295 | wp = buf_start; |
296 | r = count - len; |
297 | set_buf_wp(type, wp); |
298 | } else { |
299 | pr_info("copy from user failed 1\n"); |
300 | pr_info("w wp 0x%x, count %d, start 0x%x end 0x%x\n", |
301 | wp, (u32)count, buf_start, buf_end); |
302 | return -EAGAIN; |
303 | } |
304 | } |
305 | |
306 | vaddr = codec_mm_phys_to_virt(wp); |
307 | ret = copy_from_user(vaddr, p + len, r); |
308 | if (ret >= 0) { |
309 | len += r - ret; |
310 | codec_mm_dma_flush(vaddr, r - ret, DMA_TO_DEVICE); |
311 | if (ret > 0) |
312 | pr_info("copy from user not finished 2\n"); |
313 | wp += r - ret; |
314 | set_buf_wp(type, wp); |
315 | } else { |
316 | pr_info("copy from user failed 2\n"); |
317 | return -EAGAIN; |
318 | } |
319 | |
320 | end_write: |
321 | if (type == BUF_TYPE_AUDIO) |
322 | { |
323 | audio_data_parsed += len; |
324 | threadrw_update_buffer_level(stbuf, len); |
325 | } |
326 | |
327 | return len; |
328 | } |
329 | |
330 | s32 es_vpts_checkin_us64(struct stream_buf_s *buf, u64 us64) |
331 | { |
332 | u32 passed; |
333 | |
334 | if (buf->write_thread) |
335 | passed = threadrw_dataoffset(buf); |
336 | else |
337 | passed = video_data_parsed; |
338 | return pts_checkin_offset_us64(PTS_TYPE_VIDEO, passed, us64); |
339 | |
340 | } |
341 | |
342 | s32 es_apts_checkin_us64(struct stream_buf_s *buf, u64 us64) |
343 | { |
344 | u32 passed; |
345 | |
346 | if (buf->write_thread) |
347 | passed = threadrw_dataoffset(buf); |
348 | else |
349 | passed = audio_data_parsed; |
350 | return pts_checkin_offset_us64(PTS_TYPE_AUDIO, passed, us64); |
351 | } |
352 | |
353 | s32 es_vpts_checkin(struct stream_buf_s *buf, u32 pts) |
354 | { |
355 | #if 0 |
356 | if (buf->first_tstamp == INVALID_PTS) { |
357 | buf->flag |= BUF_FLAG_FIRST_TSTAMP; |
358 | buf->first_tstamp = pts; |
359 | return 0; |
360 | } |
361 | #endif |
362 | u32 passed = 0; |
363 | |
364 | mutex_lock(&esparser_mutex); |
365 | passed = video_data_parsed + threadrw_buffer_level(buf); |
366 | mutex_unlock(&esparser_mutex); |
367 | |
368 | return pts_checkin_offset(PTS_TYPE_VIDEO, passed, pts); |
369 | |
370 | } |
371 | |
372 | s32 es_apts_checkin(struct stream_buf_s *buf, u32 pts) |
373 | { |
374 | #if 0 |
375 | if (buf->first_tstamp == INVALID_PTS) { |
376 | buf->flag |= BUF_FLAG_FIRST_TSTAMP; |
377 | buf->first_tstamp = pts; |
378 | |
379 | return 0; |
380 | } |
381 | #endif |
382 | u32 passed = 0; |
383 | mutex_lock(&esparser_mutex); |
384 | passed = audio_data_parsed + threadrw_buffer_level(buf); |
385 | mutex_unlock(&esparser_mutex); |
386 | |
387 | return pts_checkin_offset(PTS_TYPE_AUDIO, passed, pts); |
388 | } |
389 | |
390 | s32 esparser_init(struct stream_buf_s *buf, struct vdec_s *vdec) |
391 | { |
392 | s32 r = 0; |
393 | u32 pts_type; |
394 | u32 parser_sub_start_ptr; |
395 | u32 parser_sub_end_ptr; |
396 | u32 parser_sub_rp; |
397 | bool first_use = false; |
398 | /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ |
399 | VDEC_PRINT_FUN_LINENO(__func__, __LINE__); |
400 | |
401 | if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC)) |
402 | pts_type = PTS_TYPE_HEVC; |
403 | else |
404 | /* #endif */ |
405 | if (buf->type == BUF_TYPE_VIDEO) |
406 | pts_type = PTS_TYPE_VIDEO; |
407 | else if (buf->type == BUF_TYPE_AUDIO) |
408 | pts_type = PTS_TYPE_AUDIO; |
409 | else if (buf->type == BUF_TYPE_SUBTITLE) |
410 | pts_type = PTS_TYPE_MAX; |
411 | else |
412 | return -EINVAL; |
413 | mutex_lock(&esparser_mutex); |
414 | parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR); |
415 | parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR); |
416 | parser_sub_rp = READ_PARSER_REG(PARSER_SUB_RP); |
417 | |
418 | buf->flag |= BUF_FLAG_PARSER; |
419 | |
420 | if (atomic_add_return(1, &esparser_use_count) == 1) { |
421 | first_use = true; |
422 | |
423 | if (fetchbuf == 0) { |
424 | pr_info("%s: no fetchbuf\n", __func__); |
425 | r = -ENOMEM; |
426 | goto Err_1; |
427 | } |
428 | |
429 | if (search_pattern == NULL) { |
430 | search_pattern = kcalloc(1, |
431 | SEARCH_PATTERN_LEN, |
432 | GFP_KERNEL); |
433 | |
434 | if (search_pattern == NULL) { |
435 | pr_err("%s: no search_pattern\n", __func__); |
436 | r = -ENOMEM; |
437 | goto Err_1; |
438 | } |
439 | |
440 | /* build a fake start code to get parser interrupt */ |
441 | search_pattern[0] = 0x00; |
442 | search_pattern[1] = 0x00; |
443 | search_pattern[2] = 0x01; |
444 | search_pattern[3] = 0xff; |
445 | |
446 | search_pattern_map = dma_map_single( |
447 | amports_get_dma_device(), |
448 | search_pattern, |
449 | SEARCH_PATTERN_LEN, |
450 | DMA_TO_DEVICE); |
451 | } |
452 | |
453 | /* reset PARSER with first esparser_init() call */ |
454 | WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER); |
455 | /* for recorded file and local play, this can't change the input source*/ |
456 | /* TS data path */ |
457 | /* |
458 | #ifndef CONFIG_AM_DVB |
459 | WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0); |
460 | #else |
461 | tsdemux_set_reset_flag(); |
462 | #endif */ |
463 | |
464 | CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE); |
465 | CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE); |
466 | CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE); |
467 | |
468 | CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE)); |
469 | |
470 | WRITE_PARSER_REG(PARSER_CONFIG, |
471 | (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | |
472 | (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | |
473 | (16 << PS_CFG_MAX_FETCH_CYCLE_BIT)); |
474 | |
475 | WRITE_PARSER_REG(PFIFO_RD_PTR, 0); |
476 | WRITE_PARSER_REG(PFIFO_WR_PTR, 0); |
477 | |
478 | WRITE_PARSER_REG(PARSER_SEARCH_PATTERN, ES_START_CODE_PATTERN); |
479 | WRITE_PARSER_REG(PARSER_SEARCH_MASK, ES_START_CODE_MASK); |
480 | |
481 | WRITE_PARSER_REG(PARSER_CONFIG, |
482 | (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | |
483 | (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | |
484 | PS_CFG_STARTCODE_WID_24 | |
485 | PS_CFG_PFIFO_ACCESS_WID_8 | |
486 | /* single byte pop */ |
487 | (16 << PS_CFG_MAX_FETCH_CYCLE_BIT)); |
488 | |
489 | WRITE_PARSER_REG(PARSER_CONTROL, PARSER_AUTOSEARCH); |
490 | |
491 | } |
492 | |
493 | /* hook stream buffer with PARSER */ |
494 | if (has_hevc_vdec() && (pts_type == PTS_TYPE_HEVC)) { |
495 | WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start); |
496 | WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, vdec->input.start |
497 | + vdec->input.size - 8); |
498 | |
499 | if (vdec_single(vdec)) { |
500 | CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, |
501 | ES_VID_MAN_RD_PTR); |
502 | |
503 | /* set vififo_vbuf_rp_sel=>hevc */ |
504 | WRITE_VREG(DOS_GEN_CTRL0, 3 << 1); |
505 | |
506 | /* set use_parser_vbuf_wp */ |
507 | SET_VREG_MASK(HEVC_STREAM_CONTROL, |
508 | (1 << 3) | (0 << 4)); |
509 | /* set stream_fetch_enable */ |
510 | SET_VREG_MASK(HEVC_STREAM_CONTROL, 1); |
511 | |
512 | /* set stream_buffer_hole with 256 bytes */ |
513 | SET_VREG_MASK(HEVC_STREAM_FIFO_CTL, (1 << 29)); |
514 | } else { |
515 | SET_PARSER_REG_MASK(PARSER_ES_CONTROL, |
516 | ES_VID_MAN_RD_PTR); |
517 | WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start); |
518 | WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start); |
519 | } |
520 | video_data_parsed = 0; |
521 | } else if (pts_type == PTS_TYPE_VIDEO) { |
522 | WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, |
523 | vdec->input.start); |
524 | WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, |
525 | vdec->input.start + vdec->input.size - 8); |
526 | if (vdec_single(vdec) || (vdec_get_debug_flags() & 0x2)) { |
527 | if (vdec_get_debug_flags() & 0x2) |
528 | pr_info("%s %d\n", __func__, __LINE__); |
529 | CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, |
530 | ES_VID_MAN_RD_PTR); |
531 | |
532 | WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT); |
533 | CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL, |
534 | MEM_BUFCTRL_INIT); |
535 | |
536 | if (has_hevc_vdec()) { |
537 | /* set vififo_vbuf_rp_sel=>vdec */ |
538 | WRITE_VREG(DOS_GEN_CTRL0, 0); |
539 | } |
540 | } else { |
541 | SET_PARSER_REG_MASK(PARSER_ES_CONTROL, |
542 | ES_VID_MAN_RD_PTR); |
543 | WRITE_PARSER_REG(PARSER_VIDEO_WP, |
544 | vdec->input.start); |
545 | WRITE_PARSER_REG(PARSER_VIDEO_RP, |
546 | vdec->input.start); |
547 | } |
548 | video_data_parsed = 0; |
549 | } else if (pts_type == PTS_TYPE_AUDIO) { |
550 | /* set wp as buffer start */ |
551 | SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, |
552 | MEM_BUFCTRL_MANUAL); |
553 | WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP, |
554 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
555 | WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3); |
556 | SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, |
557 | MEM_BUFCTRL_INIT); |
558 | CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, |
559 | MEM_BUFCTRL_INIT); |
560 | WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP, |
561 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
562 | audio_data_parsed = 0; |
563 | audio_buf_start = |
564 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR); |
565 | audio_real_wp = audio_buf_start; |
566 | audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR); |
567 | } else if (buf->type == BUF_TYPE_SUBTITLE) { |
568 | WRITE_PARSER_REG(PARSER_SUB_START_PTR, |
569 | parser_sub_start_ptr); |
570 | WRITE_PARSER_REG(PARSER_SUB_END_PTR, |
571 | parser_sub_end_ptr); |
572 | WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_rp); |
573 | SET_PARSER_REG_MASK(PARSER_ES_CONTROL, |
574 | (7 << ES_SUB_WR_ENDIAN_BIT) | |
575 | ES_SUB_MAN_RD_PTR); |
576 | } |
577 | |
578 | if (pts_type < PTS_TYPE_MAX) { |
579 | r = pts_start(pts_type); |
580 | |
581 | if (r < 0) { |
582 | pr_info("esparser_init: pts_start failed\n"); |
583 | goto Err_1; |
584 | } |
585 | } |
586 | #if 0 |
587 | if (buf->flag & BUF_FLAG_FIRST_TSTAMP) { |
588 | if (buf->type == BUF_TYPE_VIDEO) |
589 | es_vpts_checkin(buf, buf->first_tstamp); |
590 | else if (buf->type == BUF_TYPE_AUDIO) |
591 | es_apts_checkin(buf, buf->first_tstamp); |
592 | |
593 | buf->flag &= ~BUF_FLAG_FIRST_TSTAMP; |
594 | } |
595 | #endif |
596 | |
597 | if (first_use) { |
598 | /*TODO irq */ |
599 | r = vdec_request_irq(PARSER_IRQ, esparser_isr, |
600 | "parser", (void *)esparser_id); |
601 | |
602 | if (r) { |
603 | pr_info("esparser_init: irq register failed.\n"); |
604 | goto Err_2; |
605 | } |
606 | VDEC_PRINT_FUN_LINENO(__func__, __LINE__); |
607 | |
608 | WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff); |
609 | WRITE_PARSER_REG(PARSER_INT_ENABLE, |
610 | PARSER_INTSTAT_SC_FOUND << |
611 | PARSER_INT_HOST_EN_BIT); |
612 | } |
613 | mutex_unlock(&esparser_mutex); |
614 | if (!(vdec_get_debug_flags() & 1) && |
615 | !codec_mm_video_tvp_enabled()) { |
616 | int block_size = (buf->type == BUF_TYPE_AUDIO) ? |
617 | PAGE_SIZE : PAGE_SIZE << 4; |
618 | int buf_num = (buf->type == BUF_TYPE_AUDIO) ? |
619 | 20 : (2 * SZ_1M)/(PAGE_SIZE << 4); |
620 | if (!(buf->type == BUF_TYPE_SUBTITLE)) |
621 | buf->write_thread = threadrw_alloc(buf_num, |
622 | block_size, |
623 | esparser_write_ex, |
624 | (buf->type == BUF_TYPE_AUDIO) ? 1 : 0); |
625 | /*manul mode for audio*/ |
626 | } |
627 | return 0; |
628 | |
629 | Err_2: |
630 | pts_stop(pts_type); |
631 | |
632 | Err_1: |
633 | atomic_dec(&esparser_use_count); |
634 | buf->flag &= ~BUF_FLAG_PARSER; |
635 | mutex_unlock(&esparser_mutex); |
636 | return r; |
637 | } |
638 | EXPORT_SYMBOL(esparser_init); |
639 | |
640 | void esparser_audio_reset_s(struct stream_buf_s *buf) |
641 | { |
642 | ulong flags; |
643 | DEFINE_SPINLOCK(lock); |
644 | |
645 | spin_lock_irqsave(&lock, flags); |
646 | |
647 | SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL); |
648 | WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP, |
649 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
650 | WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3); |
651 | SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT); |
652 | CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT); |
653 | WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP, |
654 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
655 | |
656 | buf->flag |= BUF_FLAG_PARSER; |
657 | |
658 | audio_data_parsed = 0; |
659 | audio_real_wp = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR); |
660 | audio_buf_start = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR); |
661 | audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR); |
662 | spin_unlock_irqrestore(&lock, flags); |
663 | |
664 | return; |
665 | } |
666 | |
667 | void esparser_audio_reset(struct stream_buf_s *buf) |
668 | { |
669 | ulong flags; |
670 | DEFINE_SPINLOCK(lock); |
671 | |
672 | spin_lock_irqsave(&lock, flags); |
673 | |
674 | WRITE_PARSER_REG(PARSER_AUDIO_WP, |
675 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
676 | WRITE_PARSER_REG(PARSER_AUDIO_RP, |
677 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
678 | |
679 | WRITE_PARSER_REG(PARSER_AUDIO_START_PTR, |
680 | READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR)); |
681 | WRITE_PARSER_REG(PARSER_AUDIO_END_PTR, |
682 | READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR)); |
683 | CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR); |
684 | |
685 | WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT); |
686 | CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT); |
687 | |
688 | buf->flag |= BUF_FLAG_PARSER; |
689 | |
690 | audio_data_parsed = 0; |
691 | audio_real_wp = 0; |
692 | audio_buf_start = 0; |
693 | audio_buf_end = 0; |
694 | spin_unlock_irqrestore(&lock, flags); |
695 | |
696 | } |
697 | |
698 | void esparser_release(struct stream_buf_s *buf) |
699 | { |
700 | u32 pts_type; |
701 | |
702 | /* check if esparser_init() is ever called */ |
703 | if ((buf->flag & BUF_FLAG_PARSER) == 0) |
704 | return; |
705 | |
706 | if (atomic_read(&esparser_use_count) == 0) { |
707 | pr_info |
708 | ("[%s:%d]###warning, esparser has been released already\n", |
709 | __func__, __LINE__); |
710 | return; |
711 | } |
712 | if (buf->write_thread) |
713 | threadrw_release(buf); |
714 | if (atomic_dec_and_test(&esparser_use_count)) { |
715 | WRITE_PARSER_REG(PARSER_INT_ENABLE, 0); |
716 | /*TODO irq */ |
717 | |
718 | vdec_free_irq(PARSER_IRQ, (void *)esparser_id); |
719 | |
720 | if (search_pattern) { |
721 | dma_unmap_single(amports_get_dma_device(), |
722 | search_pattern_map, |
723 | SEARCH_PATTERN_LEN, DMA_TO_DEVICE); |
724 | kfree(search_pattern); |
725 | search_pattern = NULL; |
726 | } |
727 | } |
728 | |
729 | if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC)) |
730 | pts_type = PTS_TYPE_VIDEO; |
731 | else if (buf->type == BUF_TYPE_VIDEO) |
732 | pts_type = PTS_TYPE_VIDEO; |
733 | else if (buf->type == BUF_TYPE_AUDIO) |
734 | pts_type = PTS_TYPE_AUDIO; |
735 | else if (buf->type == BUF_TYPE_SUBTITLE) { |
736 | buf->flag &= ~BUF_FLAG_PARSER; |
737 | return; |
738 | } else |
739 | return; |
740 | |
741 | buf->flag &= ~BUF_FLAG_PARSER; |
742 | pts_stop(pts_type); |
743 | } |
744 | EXPORT_SYMBOL(esparser_release); |
745 | |
746 | ssize_t drm_write(struct file *file, struct stream_buf_s *stbuf, |
747 | const char __user *buf, size_t count) |
748 | { |
749 | s32 r; |
750 | u32 len; |
751 | u32 realcount, totalcount; |
752 | u32 havewritebytes = 0; |
753 | u32 leftcount = 0; |
754 | |
755 | struct drm_info tmpmm; |
756 | struct drm_info *drm = &tmpmm; |
757 | u32 res = 0; |
758 | int isphybuf = 0; |
759 | unsigned long realbuf; |
760 | |
761 | if (buf == NULL || count == 0) |
762 | return -EINVAL; |
763 | if (stbuf->write_thread) { |
764 | r = threadrw_flush_buffers(stbuf); |
765 | if (r < 0) |
766 | pr_info("Warning. drm flush threadrw failed[%d]\n", r); |
767 | } |
768 | res = copy_from_user(drm, buf, sizeof(struct drm_info)); |
769 | if (res) { |
770 | pr_info("drm kmalloc failed res[%d]\n", res); |
771 | return -EFAULT; |
772 | } |
773 | |
774 | if ((drm->drm_flag & TYPE_DRMINFO) && (drm->drm_hasesdata == 0)) { |
775 | if (drm->drm_pktsize > MAX_DRM_PACKAGE_SIZE) { |
776 | pr_err("drm package size is error, size is %u\n", drm->drm_pktsize); |
777 | return -EINVAL; |
778 | } |
779 | /* buf only has drminfo not have esdata; */ |
780 | realbuf = drm->drm_phy; |
781 | realcount = drm->drm_pktsize; |
782 | isphybuf = drm->drm_flag; |
783 | /* DRM_PRNT("drm_get_rawdata |
784 | *onlydrminfo drm->drm_hasesdata[0x%x] |
785 | * stbuf->type %d buf[0x%x]\n", |
786 | *drm->drm_hasesdata,stbuf->type,buf); |
787 | */ |
788 | } else if (drm->drm_hasesdata == 1) { /* buf is drminfo+es; */ |
789 | if (drm->drm_pktsize > MAX_DRM_PACKAGE_SIZE) { |
790 | pr_err("drm package size is error, size is %u\n", drm->drm_pktsize); |
791 | return -EINVAL; |
792 | } |
793 | realcount = drm->drm_pktsize; |
794 | realbuf = (unsigned long)buf + sizeof(struct drm_info); |
795 | isphybuf = 0; |
796 | /* DRM_PRNT("drm_get_rawdata |
797 | * drminfo+es drm->drm_hasesdata[0x%x] |
798 | * stbuf->type %d\n",drm->drm_hasesdata,stbuf->type); |
799 | */ |
800 | } else { /* buf is hwhead; */ |
801 | realcount = count; |
802 | isphybuf = 0; |
803 | realbuf = (unsigned long)buf; |
804 | /* DRM_PRNT("drm_get_rawdata |
805 | * drm->drm_hasesdata[0x%x] |
806 | * len[%d] count[%d] realcout[%d]\n", |
807 | * drm->drm_hasesdata,len,count,realcount); |
808 | */ |
809 | } |
810 | |
811 | len = realcount; |
812 | count = realcount; |
813 | totalcount = realcount; |
814 | |
815 | while (len > 0) { |
816 | if (stbuf->type != BUF_TYPE_SUBTITLE |
817 | && stbuf_space(stbuf) < count) { |
818 | /*should not write partial data in drm mode*/ |
819 | r = stbuf_wait_space(stbuf, count); |
820 | if (r < 0) |
821 | return r; |
822 | if (stbuf_space(stbuf) < count) |
823 | return -EAGAIN; |
824 | } |
825 | len = min_t(u32, len, count); |
826 | |
827 | mutex_lock(&esparser_mutex); |
828 | |
829 | if (stbuf->type != BUF_TYPE_AUDIO) |
830 | r = _esparser_write((const char __user *)realbuf, len, |
831 | stbuf, isphybuf); |
832 | else |
833 | r = _esparser_write_s((const char __user *)realbuf, len, |
834 | stbuf); |
835 | if (r < 0) { |
836 | pr_info("drm_write _esparser_write failed [%d]\n", r); |
837 | mutex_unlock(&esparser_mutex); |
838 | return r; |
839 | } |
840 | havewritebytes += r; |
841 | leftcount = totalcount - havewritebytes; |
842 | if (havewritebytes == totalcount) { |
843 | |
844 | mutex_unlock(&esparser_mutex); |
845 | break; /* write ok; */ |
846 | } else if ((len > 0) && (havewritebytes < totalcount)) { |
847 | DRM_PRNT |
848 | ("d writebytes[%d] want[%d] total[%d] real[%d]\n", |
849 | havewritebytes, len, totalcount, realcount); |
850 | len = len - r; /* write again; */ |
851 | realbuf = realbuf + r; |
852 | } else { |
853 | pr_info |
854 | ("e writebytes[%d] want[%d] total[%d] real[%d]\n", |
855 | havewritebytes, len, totalcount, realcount); |
856 | } |
857 | mutex_unlock(&esparser_mutex); |
858 | } |
859 | |
860 | if ((drm->drm_flag & TYPE_DRMINFO) && (drm->drm_hasesdata == 0)) { |
861 | havewritebytes = sizeof(struct drm_info); |
862 | } else if (drm->drm_hasesdata == 1) { |
863 | havewritebytes += sizeof(struct drm_info); |
864 | } |
865 | return havewritebytes; |
866 | } |
867 | EXPORT_SYMBOL(drm_write); |
868 | |
869 | /* |
870 | *flags: |
871 | *1:phy |
872 | *2:noblock |
873 | */ |
874 | ssize_t esparser_write_ex(struct file *file, |
875 | struct stream_buf_s *stbuf, |
876 | const char __user *buf, size_t count, |
877 | int flags) |
878 | { |
879 | |
880 | s32 r; |
881 | u32 len = count; |
882 | |
883 | if (buf == NULL || count == 0) |
884 | return -EINVAL; |
885 | |
886 | /*subtitle have no level to check, */ |
887 | if (stbuf->type != BUF_TYPE_SUBTITLE && stbuf_space(stbuf) < count) { |
888 | if ((flags & 2) || ((file != NULL) && |
889 | (file->f_flags & O_NONBLOCK))) { |
890 | len = stbuf_space(stbuf); |
891 | |
892 | if (len < 256) /* <1k.do eagain, */ |
893 | return -EAGAIN; |
894 | } else { |
895 | len = min(stbuf_canusesize(stbuf) / 8, len); |
896 | |
897 | if (stbuf_space(stbuf) < len) { |
898 | r = stbuf_wait_space(stbuf, len); |
899 | if (r < 0) |
900 | return r; |
901 | } |
902 | } |
903 | } |
904 | |
905 | stbuf->last_write_jiffies64 = jiffies_64; |
906 | |
907 | len = min_t(u32, len, count); |
908 | |
909 | mutex_lock(&esparser_mutex); |
910 | |
911 | if (stbuf->type == BUF_TYPE_AUDIO) |
912 | r = _esparser_write_s(buf, len, stbuf); |
913 | else |
914 | r = _esparser_write(buf, len, stbuf, flags & 1); |
915 | |
916 | mutex_unlock(&esparser_mutex); |
917 | |
918 | return r; |
919 | } |
920 | ssize_t esparser_write(struct file *file, |
921 | struct stream_buf_s *stbuf, |
922 | const char __user *buf, size_t count) |
923 | { |
924 | if (stbuf->write_thread) { |
925 | ssize_t ret; |
926 | |
927 | ret = threadrw_write(file, stbuf, buf, count); |
928 | if (ret == -EAGAIN) { |
929 | u32 a, b; |
930 | int vdelay, adelay; |
931 | |
932 | if ((stbuf->type != BUF_TYPE_VIDEO) && |
933 | (stbuf->type != BUF_TYPE_HEVC)) |
934 | return ret; |
935 | if (stbuf->buf_size > (SZ_1M * 30) || |
936 | (threadrw_buffer_size(stbuf) > SZ_1M * 10) || |
937 | !threadrw_support_more_buffers(stbuf)) |
938 | return ret; |
939 | /*only chang buffer for video.*/ |
940 | vdelay = calculation_stream_delayed_ms( |
941 | PTS_TYPE_VIDEO, &a, &b); |
942 | adelay = calculation_stream_delayed_ms( |
943 | PTS_TYPE_AUDIO, &a, &b); |
944 | if ((vdelay > 100 && vdelay < 2000) && /*vdelay valid.*/ |
945 | ((vdelay < 500) ||/*video delay is short!*/ |
946 | (adelay > 0 && adelay < 1000))/*audio is low.*/ |
947 | ) { |
948 | /*on buffer fulled. |
949 | *if delay is less than 100ms we think errors, |
950 | *And we add more buffer on delay < 2s. |
951 | */ |
952 | int new_size = 2 * 1024 * 1024; |
953 | |
954 | threadrw_alloc_more_buffer_size( |
955 | stbuf, new_size); |
956 | } |
957 | } |
958 | return ret; |
959 | } |
960 | return esparser_write_ex(file, stbuf, buf, count, 0); |
961 | } |
962 | EXPORT_SYMBOL(esparser_write); |
963 | |
964 | void esparser_sub_reset(void) |
965 | { |
966 | ulong flags; |
967 | DEFINE_SPINLOCK(lock); |
968 | u32 parser_sub_start_ptr; |
969 | u32 parser_sub_end_ptr; |
970 | |
971 | spin_lock_irqsave(&lock, flags); |
972 | |
973 | parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR); |
974 | parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR); |
975 | |
976 | WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr); |
977 | WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr); |
978 | WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr); |
979 | WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr); |
980 | SET_PARSER_REG_MASK(PARSER_ES_CONTROL, |
981 | (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR); |
982 | |
983 | spin_unlock_irqrestore(&lock, flags); |
984 | } |
985 |