summaryrefslogtreecommitdiff
path: root/drivers/stream_input/parser/esparser.c (plain)
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
67static unsigned char *search_pattern;
68static dma_addr_t search_pattern_map;
69static u32 audio_real_wp;
70static u32 audio_buf_start;
71static u32 audio_buf_end;
72
73static const char esparser_id[] = "esparser-id";
74
75static DECLARE_WAIT_QUEUE_HEAD(wq);
76
77
78static u32 search_done;
79static u32 video_data_parsed;
80static u32 audio_data_parsed;
81static atomic_t esparser_use_count = ATOMIC_INIT(0);
82static DEFINE_MUTEX(esparser_mutex);
83
84static 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}
91static 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}
98static 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}
105static 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
114static 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
129static 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
156static 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
259static 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
320end_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
330s32 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
342s32 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
353s32 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
372s32 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
390s32 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
629Err_2:
630 pts_stop(pts_type);
631
632Err_1:
633 atomic_dec(&esparser_use_count);
634 buf->flag &= ~BUF_FLAG_PARSER;
635 mutex_unlock(&esparser_mutex);
636 return r;
637}
638EXPORT_SYMBOL(esparser_init);
639
640void 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
667void 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
698void 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}
744EXPORT_SYMBOL(esparser_release);
745
746ssize_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}
867EXPORT_SYMBOL(drm_write);
868
869/*
870 *flags:
871 *1:phy
872 *2:noblock
873 */
874ssize_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}
920ssize_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}
962EXPORT_SYMBOL(esparser_write);
963
964void 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