• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/amlogic/amports/rmparser.c
3  *
4  * Copyright (C) 2015 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 
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/errno.h>
21 #include <linux/interrupt.h>
22 #include <linux/timer.h>
23 #include <linux/sched.h>
24 #include <linux/fs.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/platform_device.h>
27 #include <linux/amlogic/media/utils/amstream.h>
28 #include <linux/amlogic/media/frame_sync/ptsserv.h>
29 #include <linux/uaccess.h>
30 
31 #include <linux/amlogic/media/utils/vdec_reg.h>
32 #include "../amports/amports_priv.h"
33 #include "../amports/streambuf.h"
34 #include "../amports/streambuf_reg.h"
35 #include <linux/delay.h>
36 #include "rmparser.h"
37 
38 #define MANAGE_PTS
39 
40 static u32 fetch_done;
41 static u32 parse_halt;
42 
43 static DECLARE_WAIT_QUEUE_HEAD(rm_wq);
44 static const char rmparser_id[] = "rmparser-id";
45 
rm_parser_isr(int irq,void * dev_id)46 static irqreturn_t rm_parser_isr(int irq, void *dev_id)
47 {
48 	u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
49 
50 	if (int_status & PARSER_INTSTAT_FETCH_CMD) {
51 		WRITE_PARSER_REG(PARSER_INT_STATUS, PARSER_INTSTAT_FETCH_CMD);
52 		fetch_done = 1;
53 
54 		wake_up_interruptible(&rm_wq);
55 	}
56 
57 	return IRQ_HANDLED;
58 }
59 
rmparser_init(struct vdec_s * vdec)60 s32 rmparser_init(struct vdec_s *vdec)
61 {
62 	s32 r;
63 
64 	parse_halt = 0;
65 	if (fetchbuf == 0) {
66 		pr_info("%s: no fetchbuf\n", __func__);
67 		return -ENOMEM;
68 	}
69 
70 	WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
71 
72 /* for recorded file and local play, this can't change the input source*/
73 	/* TS data path */
74 /*
75 #ifndef CONFIG_AM_DVB
76 	WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0);
77 #else
78 	tsdemux_set_reset_flag();
79 #endif */
80 
81 	CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
82 	CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
83 	CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
84 
85 	CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
86 
87 	/* hook stream buffer with PARSER */
88 	WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
89 	WRITE_PARSER_REG(PARSER_VIDEO_END_PTR,
90 		vdec->input.start + vdec->input.size - 8);
91 
92 	CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
93 
94 	WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
95 				   READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
96 	WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
97 				   READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
98 	CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
99 
100 	WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
101 	CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
102 
103 	WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
104 	CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
105 
106 	WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
107 	WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
108 
109 	WRITE_PARSER_REG(PARSER_SEARCH_MASK, 0);
110 	WRITE_PARSER_REG(PARSER_CONTROL, (ES_SEARCH | ES_PARSER_START));
111 
112 #ifdef MANAGE_PTS
113 	if (pts_start(PTS_TYPE_VIDEO) < 0)
114 		goto Err_1;
115 
116 	if (pts_start(PTS_TYPE_AUDIO) < 0)
117 		goto Err_2;
118 #endif
119 	/*TODO irq */
120 
121 	/* enable interrupt */
122 
123 	r = vdec_request_irq(PARSER_IRQ, rm_parser_isr,
124 			"rmparser", (void *)rmparser_id);
125 
126 	if (r) {
127 		pr_info("RM parser irq register failed.\n");
128 		goto Err_3;
129 	}
130 
131 	WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
132 	WRITE_PARSER_REG(PARSER_INT_ENABLE,
133 			((PARSER_INT_ALL & (~PARSER_INTSTAT_FETCH_CMD)) <<
134 					PARSER_INT_AMRISC_EN_BIT)
135 			| (PARSER_INTSTAT_FETCH_CMD << PARSER_INT_HOST_EN_BIT));
136 
137 	return 0;
138 
139 Err_3:
140 	pts_stop(PTS_TYPE_AUDIO);
141 Err_2:
142 	pts_stop(PTS_TYPE_VIDEO);
143 Err_1:
144 	return -ENOENT;
145 }
146 EXPORT_SYMBOL(rmparser_init);
147 
rmparser_release(void)148 void rmparser_release(void)
149 {
150 	WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
151 	/*TODO irq */
152 
153 	vdec_free_irq(PARSER_IRQ, (void *)rmparser_id);
154 
155 #ifdef MANAGE_PTS
156 	pts_stop(PTS_TYPE_VIDEO);
157 	pts_stop(PTS_TYPE_AUDIO);
158 #endif
159 
160 }
161 EXPORT_SYMBOL(rmparser_release);
162 
buf_wp(u32 type)163 static inline u32 buf_wp(u32 type)
164 {
165 	return (type == BUF_TYPE_VIDEO) ? READ_VREG(VLD_MEM_VIFIFO_WP) :
166 		(type == BUF_TYPE_AUDIO) ?
167 		READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
168 		READ_PARSER_REG(PARSER_SUB_START_PTR);
169 }
170 
_rmparser_write(const char __user * buf,size_t count)171 static ssize_t _rmparser_write(const char __user *buf, size_t count)
172 {
173 	size_t r = count;
174 	const char __user *p = buf;
175 	u32 len;
176 	int ret;
177 	static int halt_droped_len;
178 	u32 vwp, awp;
179 	dma_addr_t dma_addr = 0;
180 
181 	if (r > 0) {
182 		len = min_t(size_t, r, FETCHBUF_SIZE);
183 
184 		if (copy_from_user(fetchbuf, p, len))
185 			return -EFAULT;
186 		dma_addr =
187 			dma_map_single(amports_get_dma_device(),
188 					fetchbuf, FETCHBUF_SIZE,
189 					DMA_TO_DEVICE);
190 		if (dma_mapping_error(amports_get_dma_device(), dma_addr))
191 			return -EFAULT;
192 
193 		fetch_done = 0;
194 
195 		wmb(); /* Ensure fetchbuf  contents visible */
196 		vwp = buf_wp(BUF_TYPE_VIDEO);
197 		awp = buf_wp(BUF_TYPE_AUDIO);
198 		WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
199 
200 		WRITE_PARSER_REG(PARSER_FETCH_CMD, (7 << FETCH_ENDIAN) | len);
201 		dma_unmap_single(amports_get_dma_device(), dma_addr,
202 						 FETCHBUF_SIZE, DMA_TO_DEVICE);
203 		ret =
204 			wait_event_interruptible_timeout(rm_wq, fetch_done != 0,
205 					HZ / 10);
206 		if (ret == 0) {
207 			WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
208 			parse_halt++;
209 			pr_info
210 			("write timeout,retry,halt_count=%d parse_control=%x\n",
211 			 parse_halt, READ_PARSER_REG(PARSER_CONTROL));
212 
213 			//vreal_set_fatal_flag(1);//DEBUG_TMP
214 
215 			if (parse_halt > 10) {
216 				WRITE_PARSER_REG(PARSER_CONTROL,
217 						(ES_SEARCH | ES_PARSER_START));
218 				pr_info("reset parse_control=%x\n",
219 					   READ_PARSER_REG(PARSER_CONTROL));
220 			}
221 			return -EAGAIN;
222 		} else if (ret < 0)
223 			return -ERESTARTSYS;
224 
225 		if (vwp == buf_wp(BUF_TYPE_VIDEO)
226 			&& awp == buf_wp(BUF_TYPE_AUDIO)) {
227 			struct stream_buf_s *v_buf_t =
228 				get_buf_by_type(BUF_TYPE_VIDEO);
229 			struct stream_buf_s *a_buf_t =
230 				get_buf_by_type(BUF_TYPE_AUDIO);
231 			int v_st_lv = stbuf_level(v_buf_t);
232 			int a_st_lv = stbuf_level(a_buf_t);
233 
234 			if ((parse_halt + 1) % 10 == 1) {
235 				pr_info("V&A WP not changed after write");
236 				pr_info(",video %x->%x", vwp,
237 						buf_wp(BUF_TYPE_VIDEO));
238 				pr_info(",Audio:%x-->%x,parse_halt=%d\n",
239 						awp, buf_wp(BUF_TYPE_AUDIO),
240 						parse_halt);
241 			}
242 			parse_halt++;
243 
244 /* wp not changed ,
245  *					  we think have bugs on parser now.
246  */
247 			if (parse_halt > 10 &&
248 					(v_st_lv < 1000 || a_st_lv < 100)) {
249 				/*reset while at  least one is underflow. */
250 				WRITE_PARSER_REG(PARSER_CONTROL,
251 						(ES_SEARCH | ES_PARSER_START));
252 				pr_info("reset parse_control=%x\n",
253 					   READ_PARSER_REG(PARSER_CONTROL));
254 			}
255 			if (parse_halt <= 10 ||
256 				halt_droped_len < 100 * 1024) {
257 				/*drops first 10 pkt ,
258 				 *  some times maybe no av data
259 				 */
260 				pr_info("drop this pkt=%d,len=%d\n", parse_halt,
261 					   len);
262 				p += len;
263 				r -= len;
264 				halt_droped_len += len;
265 			} else
266 				return -EAGAIN;
267 		} else {
268 			halt_droped_len = 0;
269 			parse_halt = 0;
270 			p += len;
271 			r -= len;
272 		}
273 	}
274 	return count - r;
275 }
276 
rmparser_write(struct file * file,struct stream_buf_s * vbuf,struct stream_buf_s * abuf,const char __user * buf,size_t count)277 ssize_t rmparser_write(struct file *file,
278 					   struct stream_buf_s *vbuf,
279 					   struct stream_buf_s *abuf,
280 					   const char __user *buf, size_t count)
281 {
282 	s32 r;
283 	struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
284 	struct stream_port_s *port = priv->port;
285 	size_t towrite = count;
286 
287 	if ((stbuf_space(vbuf) < count) || (stbuf_space(abuf) < count)) {
288 		if (file->f_flags & O_NONBLOCK) {
289 			towrite = min(stbuf_space(vbuf), stbuf_space(abuf));
290 			if (towrite < 1024)	/*? can write small? */
291 				return -EAGAIN;
292 		} else {
293 			if ((port->flag & PORT_FLAG_VID)
294 				&& (stbuf_space(vbuf) < count)) {
295 				r = stbuf_wait_space(vbuf, count);
296 				if (r < 0)
297 					return r;
298 			}
299 			if ((port->flag & PORT_FLAG_AID)
300 				&& (stbuf_space(abuf) < count)) {
301 				r = stbuf_wait_space(abuf, count);
302 				if (r < 0)
303 					return r;
304 			}
305 		}
306 	}
307 	towrite = min(towrite, count);
308 	return _rmparser_write(buf, towrite);
309 }
310 
rm_set_vasid(u32 vid,u32 aid)311 void rm_set_vasid(u32 vid, u32 aid)
312 {
313 	pr_info("rm_set_vasid aid %d, vid %d\n", aid, vid);
314 	WRITE_PARSER_REG(VAS_STREAM_ID, (aid << 8) | vid);
315 }
316 
rm_audio_reset(void)317 void rm_audio_reset(void)
318 {
319 	ulong flags;
320 	DEFINE_SPINLOCK(lock);
321 
322 	spin_lock_irqsave(&lock, flags);
323 
324 	WRITE_PARSER_REG(PARSER_AUDIO_WP,
325 				   READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
326 	WRITE_PARSER_REG(PARSER_AUDIO_RP,
327 				   READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
328 
329 	WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
330 				   READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
331 	WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
332 				   READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
333 	CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
334 
335 	WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
336 	CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
337 
338 	spin_unlock_irqrestore(&lock, flags);
339 }
340 EXPORT_SYMBOL(rm_audio_reset);
341