summaryrefslogtreecommitdiff
path: root/drivers/stream_input/parser/streambuf.c (plain)
blob: 10607705ea807c3b0ef2111657bd4add1c6c98f1
1/*
2 * drivers/amlogic/media/stream_input/parser/streambuf.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17#define DEBUG
18#include <linux/kernel.h>
19#include <linux/spinlock.h>
20#include <linux/timer.h>
21#include <linux/sched.h>
22#include <linux/fs.h>
23#include <linux/io.h>
24#include <linux/amlogic/media/frame_sync/ptsserv.h>
25#include <linux/amlogic/media/utils/vformat.h>
26#include <linux/amlogic/iomap.h>
27#include <asm/cacheflush.h>
28#include <linux/uaccess.h>
29#include <linux/vmalloc.h>
30/* #include <mach/am_regs.h> */
31
32#include <linux/amlogic/media/utils/vdec_reg.h>
33#include "../../frame_provider/decoder/utils/vdec.h"
34#include "streambuf_reg.h"
35#include "streambuf.h"
36#include <linux/amlogic/media/utils/amports_config.h>
37#include "../amports/amports_priv.h"
38#include <linux/dma-mapping.h>
39#include <linux/dma-contiguous.h>
40#include <linux/amlogic/media/codec_mm/codec_mm.h>
41
42#define STBUF_SIZE (64*1024)
43#define STBUF_WAIT_INTERVAL (HZ/100)
44#define MEM_NAME "streambuf"
45
46void *fetchbuf = 0;
47
48static s32 _stbuf_alloc(struct stream_buf_s *buf, bool is_secure)
49{
50 if (buf->buf_size == 0)
51 return -ENOBUFS;
52
53 while (buf->buf_start == 0) {
54 int flags = CODEC_MM_FLAGS_DMA;
55
56 buf->buf_page_num = PAGE_ALIGN(buf->buf_size) / PAGE_SIZE;
57 if (buf->type == BUF_TYPE_SUBTITLE)
58 flags = CODEC_MM_FLAGS_DMA_CPU;
59
60 /*
61 *if 4k,
62 *used cma first,for less mem fragments.
63 */
64 if (((buf->type == BUF_TYPE_HEVC) ||
65 (buf->type == BUF_TYPE_VIDEO)) &&
66 buf->for_4k)
67 flags |= CODEC_MM_FLAGS_CMA_FIRST;
68 if (buf->buf_size > 20 * 1024 * 1024)
69 flags |= CODEC_MM_FLAGS_CMA_FIRST;
70
71 if ((buf->type == BUF_TYPE_HEVC) ||
72 (buf->type == BUF_TYPE_VIDEO)) {
73 flags |= CODEC_MM_FLAGS_FOR_VDECODER;
74 } else if (buf->type == BUF_TYPE_AUDIO) {
75 flags |= CODEC_MM_FLAGS_FOR_ADECODER;
76 flags |= CODEC_MM_FLAGS_DMA_CPU;
77 }
78
79 if (is_secure)
80 flags |= CODEC_MM_FLAGS_TVP;
81
82 buf->buf_start = codec_mm_alloc_for_dma(MEM_NAME,
83 buf->buf_page_num, 4+PAGE_SHIFT, flags);
84 if (!buf->buf_start) {
85 int is_video = (buf->type == BUF_TYPE_HEVC) ||
86 (buf->type == BUF_TYPE_VIDEO);
87 if (is_video && buf->buf_size >= 9 * SZ_1M) {/*min 6M*/
88 int old_size = buf->buf_size;
89
90 buf->buf_size =
91 PAGE_ALIGN(buf->buf_size * 2/3);
92 pr_info("%s stbuf alloced size = %d failed try small %d size\n",
93 (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
94 (buf->type == BUF_TYPE_VIDEO) ? "Video" :
95 (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
96 "Subtitle", old_size, buf->buf_size);
97 continue;
98 }
99 pr_info("%s stbuf alloced size = %d failed\n",
100 (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
101 (buf->type == BUF_TYPE_VIDEO) ? "Video" :
102 (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
103 "Subtitle", buf->buf_size);
104 return -ENOMEM;
105 }
106
107 buf->is_secure = is_secure;
108
109 pr_debug("%s stbuf alloced at %p, secure = %d, size = %d\n",
110 (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
111 (buf->type == BUF_TYPE_VIDEO) ? "Video" :
112 (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
113 "Subtitle", (void *)buf->buf_start,
114 buf->is_secure,
115 buf->buf_size);
116 }
117 if (buf->buf_size < buf->canusebuf_size)
118 buf->canusebuf_size = buf->buf_size;
119 buf->flag |= BUF_FLAG_ALLOC;
120
121 return 0;
122}
123
124int stbuf_change_size(struct stream_buf_s *buf, int size, bool is_secure)
125{
126 unsigned long old_buf;
127 int old_size, old_pagenum;
128 int ret;
129
130 pr_info("buffersize=%d,%d,start=%p, secure=%d\n", size, buf->buf_size,
131 (void *)buf->buf_start, is_secure);
132
133 if (buf->buf_size == size && buf->buf_start != 0)
134 return 0;
135
136 old_buf = buf->buf_start;
137 old_size = buf->buf_size;
138 old_pagenum = buf->buf_page_num;
139 buf->buf_start = 0;
140 buf->buf_size = size;
141 ret = size;
142
143 if (size == 0 ||
144 _stbuf_alloc(buf, is_secure) == 0) {
145 /*
146 * size=0:We only free the old memory;
147 * alloc ok,changed to new buffer
148 */
149 if (old_buf != 0) {
150 codec_mm_free_for_dma(MEM_NAME, old_buf);
151 }
152
153 if (size == 0)
154 buf->is_secure = false;
155
156 pr_info("changed the (%d) buffer size from %d to %d\n",
157 buf->type, old_size, size);
158 return 0;
159 } else {
160 /* alloc failed */
161 buf->buf_start = old_buf;
162 buf->buf_size = old_size;
163 buf->buf_page_num = old_pagenum;
164 pr_info("changed the (%d) buffer size from %d to %d,failed\n",
165 buf->type, old_size, size);
166 }
167
168 return ret;
169}
170
171int stbuf_fetch_init(void)
172{
173 if (NULL != fetchbuf)
174 return 0;
175
176 fetchbuf = (void *)__get_free_pages(GFP_KERNEL,
177 get_order(FETCHBUF_SIZE));
178
179 if (!fetchbuf) {
180 pr_info("%s: Can not allocate fetch working buffer\n",
181 __func__);
182 return -ENOMEM;
183 }
184 return 0;
185}
186EXPORT_SYMBOL(stbuf_fetch_init);
187
188void stbuf_fetch_release(void)
189{
190 if (0 && fetchbuf) {
191 /* always don't free.for safe alloc/free*/
192 free_pages((unsigned long)fetchbuf, get_order(FETCHBUF_SIZE));
193 fetchbuf = 0;
194 }
195}
196
197static void _stbuf_timer_func(unsigned long arg)
198{
199 struct stream_buf_s *p = (struct stream_buf_s *)arg;
200
201 if (stbuf_space(p) < p->wcnt) {
202 p->timer.expires = jiffies + STBUF_WAIT_INTERVAL;
203
204 add_timer(&p->timer);
205 } else
206 wake_up_interruptible(&p->wq);
207
208}
209
210u32 stbuf_level(struct stream_buf_s *buf)
211{
212 if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
213 if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1) {
214 int level = READ_PARSER_REG(PARSER_VIDEO_WP) -
215 READ_PARSER_REG(PARSER_VIDEO_RP);
216 if (level < 0)
217 level += READ_PARSER_REG(PARSER_VIDEO_END_PTR) -
218 READ_PARSER_REG(PARSER_VIDEO_START_PTR) + 8;
219 return (u32)level;
220 } else
221 return (buf->type == BUF_TYPE_HEVC) ?
222 READ_VREG(HEVC_STREAM_LEVEL) :
223 _READ_ST_REG(LEVEL);
224 }
225
226 return _READ_ST_REG(LEVEL);
227}
228
229u32 stbuf_rp(struct stream_buf_s *buf)
230{
231 if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
232 if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1)
233 return READ_PARSER_REG(PARSER_VIDEO_RP);
234 else
235 return (buf->type == BUF_TYPE_HEVC) ?
236 READ_VREG(HEVC_STREAM_RD_PTR) :
237 _READ_ST_REG(RP);
238 }
239
240 return _READ_ST_REG(RP);
241}
242
243u32 stbuf_space(struct stream_buf_s *buf)
244{
245 /* reserved space for safe write,
246 * the parser fifo size is 1024byts, so reserve it
247 */
248 int size;
249
250 size = buf->canusebuf_size - stbuf_level(buf);
251
252 if (buf->canusebuf_size >= buf->buf_size / 2) {
253 /* old reversed value,tobe full, reversed only... */
254 size = size - 6 * 1024;
255 }
256
257 if ((buf->type == BUF_TYPE_VIDEO)
258 || (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC))
259 size -= READ_PARSER_REG(PARSER_VIDEO_HOLE);
260
261 return size > 0 ? size : 0;
262}
263
264u32 stbuf_size(struct stream_buf_s *buf)
265{
266 return buf->buf_size;
267}
268
269u32 stbuf_canusesize(struct stream_buf_s *buf)
270{
271 return buf->canusebuf_size;
272}
273
274s32 stbuf_init(struct stream_buf_s *buf, struct vdec_s *vdec, bool is_multi)
275{
276 s32 r;
277 u32 dummy;
278 u32 addr32;
279
280 VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
281
282 if (!buf->buf_start) {
283 r = _stbuf_alloc(buf, (vdec) ?
284 vdec->port_flag & PORT_FLAG_DRM : 0);
285 if (r < 0)
286 return r;
287 }
288 addr32 = buf->buf_start & 0xffffffff;
289 init_waitqueue_head(&buf->wq);
290
291 /*
292 * For multidec, do not touch HW stream buffers during port
293 * init and release.
294 */
295 if ((buf->type == BUF_TYPE_VIDEO) || (buf->type == BUF_TYPE_HEVC)) {
296 if (vdec) {
297 if (vdec_stream_based(vdec))
298 vdec_set_input_buffer(vdec, addr32,
299 buf->buf_size);
300 else
301 return vdec_set_input_buffer(vdec, addr32,
302 buf->buf_size);
303 }
304 }
305
306 buf->write_thread = 0;
307 if (((vdec && !vdec_single(vdec)) || (is_multi)) &&
308 (vdec_get_debug_flags() & 0x2) == 0)
309 return 0;
310 if (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC) {
311 CLEAR_VREG_MASK(HEVC_STREAM_CONTROL, 1);
312 WRITE_VREG(HEVC_STREAM_START_ADDR, addr32);
313 WRITE_VREG(HEVC_STREAM_END_ADDR, addr32 + buf->buf_size);
314 WRITE_VREG(HEVC_STREAM_RD_PTR, addr32);
315 WRITE_VREG(HEVC_STREAM_WR_PTR, addr32);
316
317 return 0;
318 }
319
320 if (buf->type == BUF_TYPE_VIDEO) {
321 VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
322
323 _WRITE_ST_REG(CONTROL, 0);
324 /* reset VLD before setting all pointers */
325 WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, 0);
326 /*TODO: only > m6*/
327#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
328 WRITE_VREG(DOS_SW_RESET0, (1 << 4));
329 WRITE_VREG(DOS_SW_RESET0, 0);
330#else
331 WRITE_RESET_REG(RESET0_REGISTER, RESET_VLD);
332#endif
333
334 dummy = READ_RESET_REG(RESET0_REGISTER);
335 WRITE_VREG(POWER_CTL_VLD, 1 << 4);
336 } else if (buf->type == BUF_TYPE_AUDIO) {
337 _WRITE_ST_REG(CONTROL, 0);
338
339 WRITE_AIU_REG(AIU_AIFIFO_GBIT, 0x80);
340 }
341
342 if (buf->type == BUF_TYPE_SUBTITLE) {
343 WRITE_PARSER_REG(PARSER_SUB_RP, addr32);
344 WRITE_PARSER_REG(PARSER_SUB_START_PTR, addr32);
345 WRITE_PARSER_REG(PARSER_SUB_END_PTR,
346 addr32 + buf->buf_size - 8);
347
348 return 0;
349 }
350
351 _WRITE_ST_REG(START_PTR, addr32);
352 _WRITE_ST_REG(CURR_PTR, addr32);
353 _WRITE_ST_REG(END_PTR, addr32 + buf->buf_size - 8);
354
355 _SET_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
356 _CLR_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
357
358 _WRITE_ST_REG(BUF_CTRL, MEM_BUFCTRL_MANUAL);
359 _WRITE_ST_REG(WP, addr32);
360
361 _SET_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
362 _CLR_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
363
364 _SET_ST_REG_MASK(CONTROL,
365 (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN |
366 MEM_CTRL_EMPTY_EN);
367 return 0;
368}
369EXPORT_SYMBOL(stbuf_init);
370
371void stbuf_vdec2_init(struct stream_buf_s *buf)
372{
373
374 _WRITE_VDEC2_ST_REG(CONTROL, 0);
375
376 _WRITE_VDEC2_ST_REG(START_PTR, _READ_ST_REG(START_PTR));
377 _WRITE_VDEC2_ST_REG(END_PTR, _READ_ST_REG(END_PTR));
378 _WRITE_VDEC2_ST_REG(CURR_PTR, _READ_ST_REG(CURR_PTR));
379
380 _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL | MEM_BUFCTRL_INIT);
381 _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL);
382
383 _WRITE_VDEC2_ST_REG(BUF_CTRL, MEM_BUFCTRL_INIT);
384 _WRITE_VDEC2_ST_REG(BUF_CTRL, 0);
385
386 _WRITE_VDEC2_ST_REG(CONTROL,
387 (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN
388 | MEM_CTRL_EMPTY_EN);
389}
390
391s32 stbuf_wait_space(struct stream_buf_s *stream_buf, size_t count)
392{
393 struct stream_buf_s *p = stream_buf;
394 long time_out = 200;
395
396 p->wcnt = count;
397
398 setup_timer(&p->timer, _stbuf_timer_func, (ulong) p);
399
400 mod_timer(&p->timer, jiffies + STBUF_WAIT_INTERVAL);
401
402 if (wait_event_interruptible_timeout
403 (p->wq, stbuf_space(p) >= count,
404 msecs_to_jiffies(time_out)) == 0) {
405 del_timer_sync(&p->timer);
406
407 return -EAGAIN;
408 }
409
410 del_timer_sync(&p->timer);
411
412 return 0;
413}
414
415void stbuf_release(struct stream_buf_s *buf, bool is_multi)
416{
417 int r;
418
419 buf->first_tstamp = INVALID_PTS;
420
421 r = stbuf_init(buf, NULL, is_multi);/* reinit buffer */
422 if (r < 0)
423 pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__);
424
425 if (buf->flag & BUF_FLAG_ALLOC && buf->buf_start) {
426 codec_mm_free_for_dma(MEM_NAME, buf->buf_start);
427 buf->flag &= ~BUF_FLAG_ALLOC;
428 buf->buf_start = 0;
429 buf->is_secure = false;
430 }
431 buf->flag &= ~BUF_FLAG_IN_USE;
432}
433EXPORT_SYMBOL(stbuf_release);
434
435u32 stbuf_sub_rp_get(void)
436{
437 return READ_PARSER_REG(PARSER_SUB_RP);
438}
439
440void stbuf_sub_rp_set(unsigned int sub_rp)
441{
442 WRITE_PARSER_REG(PARSER_SUB_RP, sub_rp);
443 return;
444}
445
446u32 stbuf_sub_wp_get(void)
447{
448 return READ_PARSER_REG(PARSER_SUB_WP);
449}
450
451u32 stbuf_sub_start_get(void)
452{
453 return READ_PARSER_REG(PARSER_SUB_START_PTR);
454}
455