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 | |
46 | void *fetchbuf = 0; |
47 | |
48 | static 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 | |
124 | int 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 | |
171 | int 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 | } |
186 | EXPORT_SYMBOL(stbuf_fetch_init); |
187 | |
188 | void 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 | |
197 | static 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 | |
210 | u32 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 | |
229 | u32 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 | |
243 | u32 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 | |
264 | u32 stbuf_size(struct stream_buf_s *buf) |
265 | { |
266 | return buf->buf_size; |
267 | } |
268 | |
269 | u32 stbuf_canusesize(struct stream_buf_s *buf) |
270 | { |
271 | return buf->canusebuf_size; |
272 | } |
273 | |
274 | s32 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 | } |
366 | EXPORT_SYMBOL(stbuf_init); |
367 | |
368 | void 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 | |
388 | s32 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 | |
412 | void 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 | } |
430 | EXPORT_SYMBOL(stbuf_release); |
431 | |
432 | u32 stbuf_sub_rp_get(void) |
433 | { |
434 | return READ_PARSER_REG(PARSER_SUB_RP); |
435 | } |
436 | |
437 | void stbuf_sub_rp_set(unsigned int sub_rp) |
438 | { |
439 | WRITE_PARSER_REG(PARSER_SUB_RP, sub_rp); |
440 | return; |
441 | } |
442 | |
443 | u32 stbuf_sub_wp_get(void) |
444 | { |
445 | return READ_PARSER_REG(PARSER_SUB_WP); |
446 | } |
447 | |
448 | u32 stbuf_sub_start_get(void) |
449 | { |
450 | return READ_PARSER_REG(PARSER_SUB_START_PTR); |
451 | } |
452 |