• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/amlogic/media/stream_input/parser/stream_bufffer_interface.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/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/uaccess.h>
29 #include <linux/atomic.h>
30 #include <linux/delay.h>
31 #include <linux/amlogic/media/codec_mm/codec_mm.h>
32 #include <linux/amlogic/media/frame_sync/ptsserv.h>
33 #include "../../frame_provider/decoder/utils/vdec.h"
34 #include "stream_buffer_base.h"
35 #include "amports_priv.h"
36 #include "thread_rw.h"
37 
38 #define MEM_NAME "stbuf"
39 #define MAP_RANGE (SZ_1M)
40 
41 static void stream_buffer_release(struct stream_buf_s *stbuf);
42 
type_to_str(int t)43 static const char *type_to_str(int t)
44 {
45 	switch (t) {
46 	case BUF_TYPE_VIDEO:
47 		return "VIDEO";
48 	case BUF_TYPE_AUDIO:
49 		return "AUDIO";
50 	case BUF_TYPE_SUBTITLE:
51 		return "SUB";
52 	case BUF_TYPE_USERDATA:
53 		return "USER";
54 	case BUF_TYPE_HEVC:
55 		return "HEVC";
56 	default:
57 		return "ERR";
58 	}
59 }
60 
type_to_pts(int t)61 static int type_to_pts(int t)
62 {
63 	switch (t) {
64 	case BUF_TYPE_VIDEO:
65 		return PTS_TYPE_VIDEO;
66 	case BUF_TYPE_HEVC:
67 		return PTS_TYPE_HEVC;
68 	default:
69 		return PTS_TYPE_MAX;
70 	}
71 }
72 
stream_buffer_init(struct stream_buf_s * stbuf,struct vdec_s * vdec)73 static int stream_buffer_init(struct stream_buf_s *stbuf, struct vdec_s *vdec)
74 {
75 	int ret = 0;
76 	u32 flags = CODEC_MM_FLAGS_DMA;
77 	bool is_secure = 0;
78 	u32 addr = 0;
79 	int pages = 0;
80 	u32 size;
81 
82 	if (stbuf->buf_start)
83 		return 0;
84 
85 	snprintf(stbuf->name, sizeof(stbuf->name),
86 		"%s-%d", MEM_NAME, vdec->id);
87 
88 	if (stbuf->ext_buf_addr) {
89 		addr	= stbuf->ext_buf_addr;
90 		size	= stbuf->buf_size;
91 	} else {
92 		flags |= CODEC_MM_FLAGS_FOR_VDECODER;
93 		if (vdec->port_flag & PORT_FLAG_DRM) {
94 			flags |= CODEC_MM_FLAGS_TVP;
95 			is_secure = true;
96 		}
97 
98 		size = PAGE_ALIGN(stbuf->buf_size);
99 		pages = (size >> PAGE_SHIFT);
100 		addr = codec_mm_alloc_for_dma(stbuf->name,
101 				pages, PAGE_SHIFT + 4, flags);
102 		if (!addr) {
103 			ret = -ENOMEM;
104 			goto err;
105 		}
106 
107 		ret = vdec_set_input_buffer(vdec, addr, size);
108 		if (ret) {
109 			pr_err("[%d]: set input buffer err.\n", stbuf->id);
110 			goto err;
111 		}
112 	}
113 
114 	atomic_set(&stbuf->payload, 0);
115 	init_waitqueue_head(&stbuf->wq);
116 
117 	stbuf->buf_start	= addr;
118 	stbuf->buf_wp		= addr;
119 	stbuf->buf_rp		= addr;
120 	stbuf->buf_size		= size;
121 	stbuf->is_secure	= is_secure;
122 	stbuf->no_parser	= true;
123 	stbuf->buf_page_num	= pages;
124 	stbuf->canusebuf_size	= size;
125 
126 	/* init pts server. */
127 	ret = pts_start(type_to_pts(stbuf->type));
128 	if (ret < 0) {
129 		pr_err("[%d]: pts server failed\n", stbuf->id);
130 		//goto err;//fixme
131 	}
132 
133 	/* init thread write. */
134 	if (!(vdec_get_debug_flags() & 1) &&
135 		!codec_mm_video_tvp_enabled()) {
136 		int block_size = PAGE_SIZE << 4;
137 		int buf_num = (2 * SZ_1M) / (PAGE_SIZE << 4);
138 
139 		stbuf->write_thread =
140 			threadrw_alloc(buf_num, block_size,
141 				       stream_buffer_write_ex, 0);
142 	}
143 
144 	stbuf->flag |= BUF_FLAG_ALLOC;
145 	stbuf->flag |= BUF_FLAG_IN_USE;
146 
147 	pr_info("[%d]: [%s-%s] addr: %lx, size: %x, thrRW: %d, extbuf: %d, secure: %d\n",
148 		stbuf->id, type_to_str(stbuf->type), stbuf->name,
149 		stbuf->buf_start, stbuf->buf_size,
150 		!!stbuf->write_thread,
151 		!!stbuf->ext_buf_addr,
152 		stbuf->is_secure);
153 
154 	return 0;
155 err:
156 	stream_buffer_release(stbuf);
157 
158 	return ret;
159 }
160 
stream_buffer_release(struct stream_buf_s * stbuf)161 static void stream_buffer_release(struct stream_buf_s *stbuf)
162 {
163 	if (stbuf->write_thread)
164 		threadrw_release(stbuf);
165 
166 	pts_stop(type_to_pts(stbuf->type));
167 
168 	if (stbuf->flag & BUF_FLAG_ALLOC && stbuf->buf_start) {
169 		if (!stbuf->ext_buf_addr)
170 			codec_mm_free_for_dma(MEM_NAME, stbuf->buf_start);
171 
172 		stbuf->flag		&= ~BUF_FLAG_ALLOC;
173 		stbuf->ext_buf_addr	= 0;
174 		stbuf->buf_start	= 0;
175 		stbuf->is_secure	= false;
176 	}
177 	stbuf->flag &= ~BUF_FLAG_IN_USE;
178 }
179 
get_free_space(struct stream_buf_s * stbuf)180 static int get_free_space(struct stream_buf_s *stbuf)
181 {
182 	u32 len = stbuf->buf_size;
183 	int idle = 0;
184 
185 	if (!atomic_read(&stbuf->payload) && (stbuf->buf_rp == stbuf->buf_wp))
186 		idle = len;
187 	else if (stbuf->buf_wp > stbuf->buf_rp)
188 		idle = len - (stbuf->buf_wp - stbuf->buf_rp);
189 	else if (stbuf->buf_wp < stbuf->buf_rp)
190 		idle = stbuf->buf_rp - stbuf->buf_wp;
191 
192 	/*pr_info("[%d]: wp: %x, rp: %x, payload: %d, free space: %d\n",
193 		stbuf->id, stbuf->buf_wp, stbuf->buf_rp,
194 		atomic_read(&stbuf->payload), idle);*/
195 
196 	return idle;
197 }
198 
aml_copy_from_user(void * to,const void * from,ulong n)199 static int aml_copy_from_user(void *to, const void *from, ulong n)
200 {
201 	int ret =0;
202 
203 	if (likely(access_ok(VERIFY_READ, from, n)))
204 		ret = copy_from_user(to, from, n);
205 	else
206 		memcpy(to, from, n);
207 
208 	return ret;
209 }
210 
stream_buffer_copy(struct stream_buf_s * stbuf,const u8 * buf,u32 size)211 static int stream_buffer_copy(struct stream_buf_s *stbuf, const u8 *buf, u32 size)
212 {
213 	int ret = 0;
214 	void *src = NULL, *dst = NULL;
215 	int i, len;
216 
217 	for (i = 0; i < size; i += MAP_RANGE) {
218 		len = ((size - i) > MAP_RANGE) ? MAP_RANGE : size - i;
219 		src = stbuf->is_phybuf ?
220 			codec_mm_vmap((ulong) buf + i, len) :
221 			(void *) buf;
222 		dst = codec_mm_vmap(stbuf->buf_wp + i, len);
223 		if (!src || !dst) {
224 			ret = -EFAULT;
225 			pr_err("[%d]: %s, src or dst is invalid.\n",
226 				stbuf->id,  __func__);
227 			goto err;
228 		}
229 
230 		if (aml_copy_from_user(dst, src, len)) {
231 			ret = -EAGAIN;
232 			goto err;
233 		}
234 
235 		codec_mm_dma_flush(dst, len, DMA_TO_DEVICE);
236 		codec_mm_unmap_phyaddr(dst);
237 
238 		if (stbuf->is_phybuf)
239 			codec_mm_unmap_phyaddr(src);
240 	}
241 
242 	return 0;
243 err:
244 	if (stbuf->is_phybuf && src)
245 		codec_mm_unmap_phyaddr(src);
246 	if (dst)
247 		codec_mm_unmap_phyaddr(dst);
248 	return ret;
249 }
250 
rb_push_data(struct stream_buf_s * stbuf,const u8 * in,u32 size)251 static int rb_push_data(struct stream_buf_s *stbuf, const u8 *in, u32 size)
252 {
253 	int ret, len;
254 	u32 wp = stbuf->buf_wp;
255 	u32 sp = (stbuf->buf_wp + size);
256 	u32 ep = (stbuf->buf_start + stbuf->buf_size);
257 
258 	len = sp > ep ? ep - wp : size;
259 
260 	if (!stbuf->ext_buf_addr) {
261 		ret = stream_buffer_copy(stbuf, in, len);
262 		if (ret)
263 			return ret;
264 	}
265 
266 	stbuf->ops->set_wp(stbuf, (wp + len >= ep) ?
267 		stbuf->buf_start : (wp + len));
268 
269 	if (stbuf->buf_wp == stbuf->buf_rp) {
270 		pr_debug("[%d]: stream buffer is full, payload: %d\n",
271 			stbuf->id, atomic_read(&stbuf->payload));
272 	}
273 
274 	return len;
275 }
276 
stream_buffer_write_inner(struct stream_buf_s * stbuf,const u8 * in,u32 size)277 static int stream_buffer_write_inner(struct stream_buf_s *stbuf,
278 				     const u8 *in, u32 size)
279 {
280 	if (in == NULL || size > stbuf->buf_size) {
281 		pr_err("[%d]: params are not valid.\n", stbuf->id);
282 		return -1;
283 	}
284 
285 	if (get_free_space(stbuf) < size)
286 		return -EAGAIN;
287 
288 	return rb_push_data(stbuf, in, size);
289 }
290 
stream_buffer_get_wp(struct stream_buf_s * stbuf)291 static u32 stream_buffer_get_wp(struct stream_buf_s *stbuf)
292 {
293 	return stbuf->buf_wp;
294 }
295 
stream_buffer_set_wp(struct stream_buf_s * stbuf,u32 val)296 static void stream_buffer_set_wp(struct stream_buf_s *stbuf, u32 val)
297 {
298 	int len = (val >= stbuf->buf_wp) ? (val - stbuf->buf_wp) :
299 		((stbuf->buf_start + stbuf->buf_size) - stbuf->buf_wp);
300 
301 	stbuf->buf_wp = val;
302 	atomic_add(len, &stbuf->payload);
303 }
304 
stream_buffer_get_rp(struct stream_buf_s * stbuf)305 static u32 stream_buffer_get_rp(struct stream_buf_s *stbuf)
306 {
307 	return stbuf->buf_rp;
308 }
309 
stream_buffer_set_rp(struct stream_buf_s * stbuf,u32 val)310 static void stream_buffer_set_rp(struct stream_buf_s *stbuf, u32 val)
311 {
312 	int len = (val >= stbuf->buf_rp) ? (val - stbuf->buf_rp) :
313 		((stbuf->buf_start + stbuf->buf_size) - stbuf->buf_rp);
314 
315 	stbuf->buf_rp = val;
316 	atomic_sub(len, &stbuf->payload);
317 }
318 
319 static struct stream_buf_ops stream_buffer_ops = {
320 	.init	= stream_buffer_init,
321 	.release = stream_buffer_release,
322 	.write	= stream_buffer_write_inner,
323 	.get_wp	= stream_buffer_get_wp,
324 	.set_wp	= stream_buffer_set_wp,
325 	.get_rp	= stream_buffer_get_rp,
326 	.set_rp	= stream_buffer_set_rp,
327 };
328 
get_stbuf_ops(void)329 struct stream_buf_ops *get_stbuf_ops(void)
330 {
331 	return &stream_buffer_ops;
332 }
333 EXPORT_SYMBOL(get_stbuf_ops);
334 
335