Linux Audio

Check our new training course

Loading...
  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 <linux/fsl/bestcomm/bestcomm.h>
 25#include <linux/fsl/bestcomm/bestcomm_priv.h>
 26#include <linux/fsl/bestcomm/gen_bd.h>
 27
 28
 29/* ======================================================================== */
 30/* Task image/var/inc                                                       */
 31/* ======================================================================== */
 32
 33/* gen_bd tasks images */
 34extern u32 bcom_gen_bd_rx_task[];
 35extern u32 bcom_gen_bd_tx_task[];
 36
 37/* rx task vars that need to be set before enabling the task */
 38struct 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 */
 48struct 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 */
 56struct 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 */
 66struct 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 */
 76struct 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
 88struct bcom_task *
 89bcom_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}
115EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
116
117int
118bcom_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}
162EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
163
164void
165bcom_gen_bd_rx_release(struct bcom_task *tsk)
166{
167	/* Nothing special for the GenBD tasks */
168	bcom_task_free(tsk);
169}
170EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
171
172
173extern struct bcom_task *
174bcom_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}
199EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
200
201int
202bcom_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}
246EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
247
248void
249bcom_gen_bd_tx_release(struct bcom_task *tsk)
250{
251	/* Nothing special for the GenBD tasks */
252	bcom_task_free(tsk);
253}
254EXPORT_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 */
266static 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 */
319struct 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}
330EXPORT_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 */
340struct bcom_task *
341bcom_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}
348EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init);
349
350
351MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
352MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");
353MODULE_LICENSE("GPL v2");
354