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