• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
_stbuf_alloc(struct stream_buf_s * buf,bool is_secure)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 
118 	buf->canusebuf_size = buf->buf_size;
119 	buf->flag |= BUF_FLAG_ALLOC;
120 
121 	return 0;
122 }
123 
stbuf_change_size(struct stream_buf_s * buf,int size,bool is_secure)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 
stbuf_fetch_init(void)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 
stbuf_fetch_release(void)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 
_stbuf_timer_func(unsigned long arg)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 
stbuf_level(struct stream_buf_s * buf)210 u32 stbuf_level(struct stream_buf_s *buf)
211 {
212 	if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
213 		if (buf->no_parser) {
214 			int level = buf->buf_wp - buf->buf_rp;
215 			if (level < 0)
216 				level += buf->buf_size;
217 			return level;
218 		} else {
219 			if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1) {
220 				int level = READ_PARSER_REG(PARSER_VIDEO_WP) -
221 					READ_PARSER_REG(PARSER_VIDEO_RP);
222 				if (level < 0)
223 					level += READ_PARSER_REG(PARSER_VIDEO_END_PTR) -
224 					READ_PARSER_REG(PARSER_VIDEO_START_PTR) + 8;
225 				return (u32)level;
226 			} else
227 				return (buf->type == BUF_TYPE_HEVC) ?
228 					READ_VREG(HEVC_STREAM_LEVEL) :
229 					_READ_ST_REG(LEVEL);
230 		}
231 	}
232 
233 	return _READ_ST_REG(LEVEL);
234 }
235 
stbuf_rp(struct stream_buf_s * buf)236 u32 stbuf_rp(struct stream_buf_s *buf)
237 {
238 	if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
239 		if (buf->no_parser)
240 			return buf->buf_rp;
241 		else {
242 			if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1)
243 				return READ_PARSER_REG(PARSER_VIDEO_RP);
244 			else
245 				return (buf->type == BUF_TYPE_HEVC) ?
246 					READ_VREG(HEVC_STREAM_RD_PTR) :
247 					_READ_ST_REG(RP);
248 		}
249 	}
250 
251 	return _READ_ST_REG(RP);
252 }
253 
stbuf_space(struct stream_buf_s * buf)254 u32 stbuf_space(struct stream_buf_s *buf)
255 {
256 	/* reserved space for safe write,
257 	 *   the parser fifo size is 1024byts, so reserve it
258 	 */
259 	int size;
260 
261 	size = buf->canusebuf_size - stbuf_level(buf);
262 
263 	if (buf->canusebuf_size >= buf->buf_size / 2) {
264 		/* old reversed value,tobe full, reversed only... */
265 		size = size - 6 * 1024;
266 	}
267 
268 	if ((buf->type == BUF_TYPE_VIDEO)
269 		|| (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC))
270 		size -= READ_PARSER_REG(PARSER_VIDEO_HOLE);
271 
272 	return size > 0 ? size : 0;
273 }
274 
stbuf_size(struct stream_buf_s * buf)275 u32 stbuf_size(struct stream_buf_s *buf)
276 {
277 	return buf->buf_size;
278 }
279 
stbuf_canusesize(struct stream_buf_s * buf)280 u32 stbuf_canusesize(struct stream_buf_s *buf)
281 {
282 	return buf->canusebuf_size;
283 }
284 
stbuf_init(struct stream_buf_s * buf,struct vdec_s * vdec)285 s32 stbuf_init(struct stream_buf_s *buf, struct vdec_s *vdec)
286 {
287 	s32 r;
288 	u32 dummy;
289 	u32 addr32;
290 
291 	VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
292 
293 	if (!buf->buf_start) {
294 		r = _stbuf_alloc(buf, (vdec) ?
295 			vdec->port_flag & PORT_FLAG_DRM : 0);
296 		if (r < 0)
297 			return r;
298 	}
299 	addr32 = buf->buf_start & 0xffffffff;
300 	init_waitqueue_head(&buf->wq);
301 
302 	/*
303 	 * For multidec, do not touch HW stream buffers during port
304 	 * init and release.
305 	 */
306 	if ((buf->type == BUF_TYPE_VIDEO) || (buf->type == BUF_TYPE_HEVC)) {
307 		if (vdec) {
308 			if (vdec_stream_based(vdec))
309 				vdec_set_input_buffer(vdec, addr32,
310 						buf->buf_size);
311 			else
312 				return vdec_set_input_buffer(vdec, addr32,
313 						buf->buf_size);
314 		}
315 	}
316 
317 	buf->write_thread = 0;
318 	if (((vdec && !vdec_single(vdec)) || (buf->is_multi_inst)) &&
319 		(vdec_get_debug_flags() & 0x2) == 0)
320 		return 0;
321 	if (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC) {
322 		CLEAR_VREG_MASK(HEVC_STREAM_CONTROL, 1);
323 		WRITE_VREG(HEVC_STREAM_START_ADDR, addr32);
324 		WRITE_VREG(HEVC_STREAM_END_ADDR, addr32 + buf->buf_size);
325 		WRITE_VREG(HEVC_STREAM_RD_PTR, addr32);
326 		WRITE_VREG(HEVC_STREAM_WR_PTR, addr32);
327 
328 		return 0;
329 	}
330 
331 	if (buf->type == BUF_TYPE_VIDEO) {
332 		VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
333 
334 		_WRITE_ST_REG(CONTROL, 0);
335 		/* reset VLD before setting all pointers */
336 		WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, 0);
337 		/*TODO: only > m6*/
338 #if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
339 		WRITE_VREG(DOS_SW_RESET0, (1 << 4));
340 		WRITE_VREG(DOS_SW_RESET0, 0);
341 #else
342 		WRITE_RESET_REG(RESET0_REGISTER, RESET_VLD);
343 #endif
344 
345 		dummy = READ_RESET_REG(RESET0_REGISTER);
346 		WRITE_VREG(POWER_CTL_VLD, 1 << 4);
347 	} else if (buf->type == BUF_TYPE_AUDIO) {
348 		_WRITE_ST_REG(CONTROL, 0);
349 
350 		WRITE_AIU_REG(AIU_AIFIFO_GBIT, 0x80);
351 	}
352 
353 	if (buf->type == BUF_TYPE_SUBTITLE) {
354 		WRITE_PARSER_REG(PARSER_SUB_RP, addr32);
355 		WRITE_PARSER_REG(PARSER_SUB_START_PTR, addr32);
356 		WRITE_PARSER_REG(PARSER_SUB_END_PTR,
357 					   addr32 + buf->buf_size - 8);
358 
359 		return 0;
360 	}
361 
362 	_WRITE_ST_REG(START_PTR, addr32);
363 	_WRITE_ST_REG(CURR_PTR, addr32);
364 	_WRITE_ST_REG(END_PTR, addr32 + buf->buf_size - 8);
365 
366 	_SET_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
367 	_CLR_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
368 
369 	_WRITE_ST_REG(BUF_CTRL, MEM_BUFCTRL_MANUAL);
370 	_WRITE_ST_REG(WP, addr32);
371 
372 	_SET_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
373 	_CLR_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
374 
375 	_SET_ST_REG_MASK(CONTROL,
376 			(0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN |
377 			MEM_CTRL_EMPTY_EN);
378 
379 	if (buf->no_parser)
380 		_SET_ST_REG_MASK(CONTROL, 7 << 3);
381 
382 	return 0;
383 }
384 EXPORT_SYMBOL(stbuf_init);
385 
stbuf_vdec2_init(struct stream_buf_s * buf)386 void stbuf_vdec2_init(struct stream_buf_s *buf)
387 {
388 
389 	_WRITE_VDEC2_ST_REG(CONTROL, 0);
390 
391 	_WRITE_VDEC2_ST_REG(START_PTR, _READ_ST_REG(START_PTR));
392 	_WRITE_VDEC2_ST_REG(END_PTR, _READ_ST_REG(END_PTR));
393 	_WRITE_VDEC2_ST_REG(CURR_PTR, _READ_ST_REG(CURR_PTR));
394 
395 	_WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL | MEM_BUFCTRL_INIT);
396 	_WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL);
397 
398 	_WRITE_VDEC2_ST_REG(BUF_CTRL, MEM_BUFCTRL_INIT);
399 	_WRITE_VDEC2_ST_REG(BUF_CTRL, 0);
400 
401 	_WRITE_VDEC2_ST_REG(CONTROL,
402 			(0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN
403 			| MEM_CTRL_EMPTY_EN);
404 }
405 
stbuf_wait_space(struct stream_buf_s * stream_buf,size_t count)406 s32 stbuf_wait_space(struct stream_buf_s *stream_buf, size_t count)
407 {
408 	struct stream_buf_s *p = stream_buf;
409 	long time_out = 200;
410 
411 	p->wcnt = count;
412 
413 	setup_timer(&p->timer, _stbuf_timer_func, (ulong) p);
414 
415 	mod_timer(&p->timer, jiffies + STBUF_WAIT_INTERVAL);
416 
417 	if (wait_event_interruptible_timeout
418 		(p->wq, stbuf_space(p) >= count,
419 		 msecs_to_jiffies(time_out)) == 0) {
420 		del_timer_sync(&p->timer);
421 
422 		return -EAGAIN;
423 	}
424 
425 	del_timer_sync(&p->timer);
426 
427 	return 0;
428 }
429 
stbuf_release(struct stream_buf_s * buf)430 void stbuf_release(struct stream_buf_s *buf)
431 {
432 	int r;
433 
434 	buf->first_tstamp = INVALID_PTS;
435 
436 	r = stbuf_init(buf, NULL);/* reinit buffer */
437 	if (r < 0)
438 		pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__);
439 
440 	if (buf->flag & BUF_FLAG_ALLOC && buf->buf_start) {
441 		codec_mm_free_for_dma(MEM_NAME, buf->buf_start);
442 		buf->flag &= ~BUF_FLAG_ALLOC;
443 		buf->buf_start = 0;
444 		buf->is_secure = false;
445 	}
446 	buf->flag &= ~BUF_FLAG_IN_USE;
447 }
448 EXPORT_SYMBOL(stbuf_release);
449 
stbuf_sub_rp_get(void)450 u32 stbuf_sub_rp_get(void)
451 {
452 	return READ_PARSER_REG(PARSER_SUB_RP);
453 }
454 
stbuf_sub_rp_set(unsigned int sub_rp)455 void stbuf_sub_rp_set(unsigned int sub_rp)
456 {
457 	WRITE_PARSER_REG(PARSER_SUB_RP, sub_rp);
458 	return;
459 }
460 
stbuf_sub_wp_get(void)461 u32 stbuf_sub_wp_get(void)
462 {
463 	return READ_PARSER_REG(PARSER_SUB_WP);
464 }
465 
stbuf_sub_start_get(void)466 u32 stbuf_sub_start_get(void)
467 {
468 	return READ_PARSER_REG(PARSER_SUB_START_PTR);
469 }
470 
parser_get_wp(struct stream_buf_s * vb)471 u32 parser_get_wp(struct stream_buf_s *vb)
472 {
473 	return READ_PARSER_REG(PARSER_VIDEO_WP);
474 }
475 EXPORT_SYMBOL(parser_get_wp);
476 
parser_set_wp(struct stream_buf_s * vb,u32 val)477 void parser_set_wp(struct stream_buf_s *vb, u32 val)
478 {
479 	WRITE_PARSER_REG(PARSER_VIDEO_WP, val);
480 }
481 EXPORT_SYMBOL(parser_set_wp);
482 
parser_get_rp(struct stream_buf_s * vb)483 u32 parser_get_rp(struct stream_buf_s *vb)
484 {
485 	return READ_PARSER_REG(PARSER_VIDEO_RP);
486 }
487 EXPORT_SYMBOL(parser_get_rp);
488 
parser_set_rp(struct stream_buf_s * vb,u32 val)489 void parser_set_rp(struct stream_buf_s *vb, u32 val)
490 {
491 	WRITE_PARSER_REG(PARSER_VIDEO_RP, val);
492 }
493 EXPORT_SYMBOL(parser_set_rp);
494 
495