1 /*
2  * Driver for MPC52xx processor BestComm General Buffer Descriptor
3  *
4  * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
5  * Copyright (C) 2006 AppSpec Computer Technologies Corp.
6  *                    Jeff Gibbons <jeff.gibbons@appspec.com>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published
10  * by the Free Software Foundation.
11  *
12  */
13 
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/types.h>
18 #include <asm/errno.h>
19 #include <asm/io.h>
20 
21 #include <asm/mpc52xx.h>
22 #include <asm/mpc52xx_psc.h>
23 
24 #include "bestcomm.h"
25 #include "bestcomm_priv.h"
26 #include "gen_bd.h"
27 
28 
29 /* ======================================================================== */
30 /* Task image/var/inc                                                       */
31 /* ======================================================================== */
32 
33 /* gen_bd tasks images */
34 extern u32 bcom_gen_bd_rx_task[];
35 extern u32 bcom_gen_bd_tx_task[];
36 
37 /* rx task vars that need to be set before enabling the task */
38 struct bcom_gen_bd_rx_var {
39 	u32 enable;		/* (u16*) address of task's control register */
40 	u32 fifo;		/* (u32*) address of gen_bd's fifo */
41 	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
42 	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
43 	u32 bd_start;		/* (struct bcom_bd*) current bd */
44 	u32 buffer_size;	/* size of receive buffer */
45 };
46 
47 /* rx task incs that need to be set before enabling the task */
48 struct bcom_gen_bd_rx_inc {
49 	u16 pad0;
50 	s16 incr_bytes;
51 	u16 pad1;
52 	s16 incr_dst;
53 };
54 
55 /* tx task vars that need to be set before enabling the task */
56 struct bcom_gen_bd_tx_var {
57 	u32 fifo;		/* (u32*) address of gen_bd's fifo */
58 	u32 enable;		/* (u16*) address of task's control register */
59 	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
60 	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
61 	u32 bd_start;		/* (struct bcom_bd*) current bd */
62 	u32 buffer_size;	/* set by uCode for each packet */
63 };
64 
65 /* tx task incs that need to be set before enabling the task */
66 struct bcom_gen_bd_tx_inc {
67 	u16 pad0;
68 	s16 incr_bytes;
69 	u16 pad1;
70 	s16 incr_src;
71 	u16 pad2;
72 	s16 incr_src_ma;
73 };
74 
75 /* private structure */
76 struct bcom_gen_bd_priv {
77 	phys_addr_t	fifo;
78 	int		initiator;
79 	int		ipr;
80 	int		maxbufsize;
81 };
82 
83 
84 /* ======================================================================== */
85 /* Task support code                                                        */
86 /* ======================================================================== */
87 
88 struct bcom_task *
bcom_gen_bd_rx_init(int queue_len,phys_addr_t fifo,int initiator,int ipr,int maxbufsize)89 bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
90 			int initiator, int ipr, int maxbufsize)
91 {
92 	struct bcom_task *tsk;
93 	struct bcom_gen_bd_priv *priv;
94 
95 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
96 			sizeof(struct bcom_gen_bd_priv));
97 	if (!tsk)
98 		return NULL;
99 
100 	tsk->flags = BCOM_FLAGS_NONE;
101 
102 	priv = tsk->priv;
103 	priv->fifo	= fifo;
104 	priv->initiator	= initiator;
105 	priv->ipr	= ipr;
106 	priv->maxbufsize = maxbufsize;
107 
108 	if (bcom_gen_bd_rx_reset(tsk)) {
109 		bcom_task_free(tsk);
110 		return NULL;
111 	}
112 
113 	return tsk;
114 }
115 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
116 
117 int
bcom_gen_bd_rx_reset(struct bcom_task * tsk)118 bcom_gen_bd_rx_reset(struct bcom_task *tsk)
119 {
120 	struct bcom_gen_bd_priv *priv = tsk->priv;
121 	struct bcom_gen_bd_rx_var *var;
122 	struct bcom_gen_bd_rx_inc *inc;
123 
124 	/* Shutdown the task */
125 	bcom_disable_task(tsk->tasknum);
126 
127 	/* Reset the microcode */
128 	var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);
129 	inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);
130 
131 	if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))
132 		return -1;
133 
134 	var->enable	= bcom_eng->regs_base +
135 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
136 	var->fifo	= (u32) priv->fifo;
137 	var->bd_base	= tsk->bd_pa;
138 	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
139 	var->bd_start	= tsk->bd_pa;
140 	var->buffer_size = priv->maxbufsize;
141 
142 	inc->incr_bytes	= -(s16)sizeof(u32);
143 	inc->incr_dst	= sizeof(u32);
144 
145 	/* Reset the BDs */
146 	tsk->index = 0;
147 	tsk->outdex = 0;
148 
149 	memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
150 
151 	/* Configure some stuff */
152 	bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
153 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
154 
155 	out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
156 	bcom_set_initiator(tsk->tasknum, priv->initiator);
157 
158 	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
159 
160 	return 0;
161 }
162 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
163 
164 void
bcom_gen_bd_rx_release(struct bcom_task * tsk)165 bcom_gen_bd_rx_release(struct bcom_task *tsk)
166 {
167 	/* Nothing special for the GenBD tasks */
168 	bcom_task_free(tsk);
169 }
170 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
171 
172 
173 extern struct bcom_task *
bcom_gen_bd_tx_init(int queue_len,phys_addr_t fifo,int initiator,int ipr)174 bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
175 			int initiator, int ipr)
176 {
177 	struct bcom_task *tsk;
178 	struct bcom_gen_bd_priv *priv;
179 
180 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
181 			sizeof(struct bcom_gen_bd_priv));
182 	if (!tsk)
183 		return NULL;
184 
185 	tsk->flags = BCOM_FLAGS_NONE;
186 
187 	priv = tsk->priv;
188 	priv->fifo	= fifo;
189 	priv->initiator	= initiator;
190 	priv->ipr	= ipr;
191 
192 	if (bcom_gen_bd_tx_reset(tsk)) {
193 		bcom_task_free(tsk);
194 		return NULL;
195 	}
196 
197 	return tsk;
198 }
199 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
200 
201 int
bcom_gen_bd_tx_reset(struct bcom_task * tsk)202 bcom_gen_bd_tx_reset(struct bcom_task *tsk)
203 {
204 	struct bcom_gen_bd_priv *priv = tsk->priv;
205 	struct bcom_gen_bd_tx_var *var;
206 	struct bcom_gen_bd_tx_inc *inc;
207 
208 	/* Shutdown the task */
209 	bcom_disable_task(tsk->tasknum);
210 
211 	/* Reset the microcode */
212 	var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);
213 	inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);
214 
215 	if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))
216 		return -1;
217 
218 	var->enable	= bcom_eng->regs_base +
219 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
220 	var->fifo	= (u32) priv->fifo;
221 	var->bd_base	= tsk->bd_pa;
222 	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
223 	var->bd_start	= tsk->bd_pa;
224 
225 	inc->incr_bytes	= -(s16)sizeof(u32);
226 	inc->incr_src	= sizeof(u32);
227 	inc->incr_src_ma = sizeof(u8);
228 
229 	/* Reset the BDs */
230 	tsk->index = 0;
231 	tsk->outdex = 0;
232 
233 	memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
234 
235 	/* Configure some stuff */
236 	bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
237 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
238 
239 	out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
240 	bcom_set_initiator(tsk->tasknum, priv->initiator);
241 
242 	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
243 
244 	return 0;
245 }
246 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
247 
248 void
bcom_gen_bd_tx_release(struct bcom_task * tsk)249 bcom_gen_bd_tx_release(struct bcom_task *tsk)
250 {
251 	/* Nothing special for the GenBD tasks */
252 	bcom_task_free(tsk);
253 }
254 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
255 
256 /* ---------------------------------------------------------------------
257  * PSC support code
258  */
259 
260 /**
261  * bcom_psc_parameters - Bestcomm initialization value table for PSC devices
262  *
263  * This structure is only used internally.  It is a lookup table for PSC
264  * specific parameters to bestcomm tasks.
265  */
266 static struct bcom_psc_params {
267 	int rx_initiator;
268 	int rx_ipr;
269 	int tx_initiator;
270 	int tx_ipr;
271 } bcom_psc_params[] = {
272 	[0] = {
273 		.rx_initiator = BCOM_INITIATOR_PSC1_RX,
274 		.rx_ipr = BCOM_IPR_PSC1_RX,
275 		.tx_initiator = BCOM_INITIATOR_PSC1_TX,
276 		.tx_ipr = BCOM_IPR_PSC1_TX,
277 	},
278 	[1] = {
279 		.rx_initiator = BCOM_INITIATOR_PSC2_RX,
280 		.rx_ipr = BCOM_IPR_PSC2_RX,
281 		.tx_initiator = BCOM_INITIATOR_PSC2_TX,
282 		.tx_ipr = BCOM_IPR_PSC2_TX,
283 	},
284 	[2] = {
285 		.rx_initiator = BCOM_INITIATOR_PSC3_RX,
286 		.rx_ipr = BCOM_IPR_PSC3_RX,
287 		.tx_initiator = BCOM_INITIATOR_PSC3_TX,
288 		.tx_ipr = BCOM_IPR_PSC3_TX,
289 	},
290 	[3] = {
291 		.rx_initiator = BCOM_INITIATOR_PSC4_RX,
292 		.rx_ipr = BCOM_IPR_PSC4_RX,
293 		.tx_initiator = BCOM_INITIATOR_PSC4_TX,
294 		.tx_ipr = BCOM_IPR_PSC4_TX,
295 	},
296 	[4] = {
297 		.rx_initiator = BCOM_INITIATOR_PSC5_RX,
298 		.rx_ipr = BCOM_IPR_PSC5_RX,
299 		.tx_initiator = BCOM_INITIATOR_PSC5_TX,
300 		.tx_ipr = BCOM_IPR_PSC5_TX,
301 	},
302 	[5] = {
303 		.rx_initiator = BCOM_INITIATOR_PSC6_RX,
304 		.rx_ipr = BCOM_IPR_PSC6_RX,
305 		.tx_initiator = BCOM_INITIATOR_PSC6_TX,
306 		.tx_ipr = BCOM_IPR_PSC6_TX,
307 	},
308 };
309 
310 /**
311  * bcom_psc_gen_bd_rx_init - Allocate a receive bcom_task for a PSC port
312  * @psc_num:	Number of the PSC to allocate a task for
313  * @queue_len:	number of buffer descriptors to allocate for the task
314  * @fifo:	physical address of FIFO register
315  * @maxbufsize:	Maximum receive data size in bytes.
316  *
317  * Allocate a bestcomm task structure for receiving data from a PSC.
318  */
bcom_psc_gen_bd_rx_init(unsigned psc_num,int queue_len,phys_addr_t fifo,int maxbufsize)319 struct bcom_task * bcom_psc_gen_bd_rx_init(unsigned psc_num, int queue_len,
320 					   phys_addr_t fifo, int maxbufsize)
321 {
322 	if (psc_num >= MPC52xx_PSC_MAXNUM)
323 		return NULL;
324 
325 	return bcom_gen_bd_rx_init(queue_len, fifo,
326 				   bcom_psc_params[psc_num].rx_initiator,
327 				   bcom_psc_params[psc_num].rx_ipr,
328 				   maxbufsize);
329 }
330 EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_rx_init);
331 
332 /**
333  * bcom_psc_gen_bd_tx_init - Allocate a transmit bcom_task for a PSC port
334  * @psc_num:	Number of the PSC to allocate a task for
335  * @queue_len:	number of buffer descriptors to allocate for the task
336  * @fifo:	physical address of FIFO register
337  *
338  * Allocate a bestcomm task structure for transmitting data to a PSC.
339  */
340 struct bcom_task *
bcom_psc_gen_bd_tx_init(unsigned psc_num,int queue_len,phys_addr_t fifo)341 bcom_psc_gen_bd_tx_init(unsigned psc_num, int queue_len, phys_addr_t fifo)
342 {
343 	struct psc;
344 	return bcom_gen_bd_tx_init(queue_len, fifo,
345 				   bcom_psc_params[psc_num].tx_initiator,
346 				   bcom_psc_params[psc_num].tx_ipr);
347 }
348 EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init);
349 
350 
351 MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
352 MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");
353 MODULE_LICENSE("GPL v2");
354 
355