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