summaryrefslogtreecommitdiff
path: root/drivers/stream_input/parser/streambuf.c (plain)
blob: 256afb99a80a316cf1255b40cd8a478c919b054c
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 if (!buf->buf_start) {
281 r = _stbuf_alloc(buf, (vdec) ?
282 vdec->port_flag & PORT_FLAG_DRM : 0);
283 if (r < 0)
284 return r;
285 }
286 addr32 = buf->buf_start & 0xffffffff;
287 init_waitqueue_head(&buf->wq);
288
289 /*
290 * For multidec, do not touch HW stream buffers during port
291 * init and release.
292 */
293 if ((buf->type == BUF_TYPE_VIDEO) || (buf->type == BUF_TYPE_HEVC)) {
294 if (vdec) {
295 if (vdec_stream_based(vdec))
296 vdec_set_input_buffer(vdec, addr32,
297 buf->buf_size);
298 else
299 return vdec_set_input_buffer(vdec, addr32,
300 buf->buf_size);
301 }
302 }
303
304 buf->write_thread = 0;
305
306 if ((vdec && !vdec_single(vdec)) || (is_multi))
307 return 0;
308
309 if (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC) {
310 CLEAR_VREG_MASK(HEVC_STREAM_CONTROL, 1);
311 WRITE_VREG(HEVC_STREAM_START_ADDR, addr32);
312 WRITE_VREG(HEVC_STREAM_END_ADDR, addr32 + buf->buf_size);
313 WRITE_VREG(HEVC_STREAM_RD_PTR, addr32);
314 WRITE_VREG(HEVC_STREAM_WR_PTR, addr32);
315
316 return 0;
317 }
318
319 if (buf->type == BUF_TYPE_VIDEO) {
320 _WRITE_ST_REG(CONTROL, 0);
321 /* reset VLD before setting all pointers */
322 WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, 0);
323 /*TODO: only > m6*/
324#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
325 WRITE_VREG(DOS_SW_RESET0, (1 << 4));
326 WRITE_VREG(DOS_SW_RESET0, 0);
327#else
328 WRITE_RESET_REG(RESET0_REGISTER, RESET_VLD);
329#endif
330
331 dummy = READ_RESET_REG(RESET0_REGISTER);
332 WRITE_VREG(POWER_CTL_VLD, 1 << 4);
333 } else if (buf->type == BUF_TYPE_AUDIO) {
334 _WRITE_ST_REG(CONTROL, 0);
335
336 WRITE_AIU_REG(AIU_AIFIFO_GBIT, 0x80);
337 }
338
339 if (buf->type == BUF_TYPE_SUBTITLE) {
340 WRITE_PARSER_REG(PARSER_SUB_RP, addr32);
341 WRITE_PARSER_REG(PARSER_SUB_START_PTR, addr32);
342 WRITE_PARSER_REG(PARSER_SUB_END_PTR,
343 addr32 + buf->buf_size - 8);
344
345 return 0;
346 }
347
348 _WRITE_ST_REG(START_PTR, addr32);
349 _WRITE_ST_REG(CURR_PTR, addr32);
350 _WRITE_ST_REG(END_PTR, addr32 + buf->buf_size - 8);
351
352 _SET_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
353 _CLR_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
354
355 _WRITE_ST_REG(BUF_CTRL, MEM_BUFCTRL_MANUAL);
356 _WRITE_ST_REG(WP, addr32);
357
358 _SET_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
359 _CLR_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
360
361 _SET_ST_REG_MASK(CONTROL,
362 (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN |
363 MEM_CTRL_EMPTY_EN);
364 return 0;
365}
366EXPORT_SYMBOL(stbuf_init);
367
368void stbuf_vdec2_init(struct stream_buf_s *buf)
369{
370
371 _WRITE_VDEC2_ST_REG(CONTROL, 0);
372
373 _WRITE_VDEC2_ST_REG(START_PTR, _READ_ST_REG(START_PTR));
374 _WRITE_VDEC2_ST_REG(END_PTR, _READ_ST_REG(END_PTR));
375 _WRITE_VDEC2_ST_REG(CURR_PTR, _READ_ST_REG(CURR_PTR));
376
377 _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL | MEM_BUFCTRL_INIT);
378 _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL);
379
380 _WRITE_VDEC2_ST_REG(BUF_CTRL, MEM_BUFCTRL_INIT);
381 _WRITE_VDEC2_ST_REG(BUF_CTRL, 0);
382
383 _WRITE_VDEC2_ST_REG(CONTROL,
384 (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN
385 | MEM_CTRL_EMPTY_EN);
386}
387
388s32 stbuf_wait_space(struct stream_buf_s *stream_buf, size_t count)
389{
390 struct stream_buf_s *p = stream_buf;
391 long time_out = 200;
392
393 p->wcnt = count;
394
395 setup_timer(&p->timer, _stbuf_timer_func, (ulong) p);
396
397 mod_timer(&p->timer, jiffies + STBUF_WAIT_INTERVAL);
398
399 if (wait_event_interruptible_timeout
400 (p->wq, stbuf_space(p) >= count,
401 msecs_to_jiffies(time_out)) == 0) {
402 del_timer_sync(&p->timer);
403
404 return -EAGAIN;
405 }
406
407 del_timer_sync(&p->timer);
408
409 return 0;
410}
411
412void stbuf_release(struct stream_buf_s *buf, bool is_multi)
413{
414 int r;
415
416 buf->first_tstamp = INVALID_PTS;
417
418 r = stbuf_init(buf, NULL, is_multi);/* reinit buffer */
419 if (r < 0)
420 pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__);
421
422 if (buf->flag & BUF_FLAG_ALLOC && buf->buf_start) {
423 codec_mm_free_for_dma(MEM_NAME, buf->buf_start);
424 buf->flag &= ~BUF_FLAG_ALLOC;
425 buf->buf_start = 0;
426 buf->is_secure = false;
427 }
428 buf->flag &= ~BUF_FLAG_IN_USE;
429}
430EXPORT_SYMBOL(stbuf_release);
431
432u32 stbuf_sub_rp_get(void)
433{
434 return READ_PARSER_REG(PARSER_SUB_RP);
435}
436
437void stbuf_sub_rp_set(unsigned int sub_rp)
438{
439 WRITE_PARSER_REG(PARSER_SUB_RP, sub_rp);
440 return;
441}
442
443u32 stbuf_sub_wp_get(void)
444{
445 return READ_PARSER_REG(PARSER_SUB_WP);
446}
447
448u32 stbuf_sub_start_get(void)
449{
450 return READ_PARSER_REG(PARSER_SUB_START_PTR);
451}
452