xref: /openbmc/u-boot/drivers/dma/MCD_dmaApi.c (revision 7c1058fa)
1 /*
2  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 /*Main C file for multi-channel DMA API. */
8 
9 #include <common.h>
10 
11 #include <MCD_dma.h>
12 #include <MCD_tasksInit.h>
13 #include <MCD_progCheck.h>
14 
15 /********************************************************************/
16 /* This is an API-internal pointer to the DMA's registers */
17 dmaRegs *MCD_dmaBar;
18 
19 /*
20  * These are the real and model task tables as generated by the
21  * build process
22  */
23 extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
24 extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
25 
26 /*
27  * However, this (usually) gets relocated to on-chip SRAM, at which
28  * point we access them as these tables
29  */
30 volatile TaskTableEntry *MCD_taskTable;
31 TaskTableEntry *MCD_modelTaskTable;
32 
33 /*
34  * MCD_chStatus[] is an array of status indicators for remembering
35  * whether a DMA has ever been attempted on each channel, pausing
36  * status, etc.
37  */
38 static int MCD_chStatus[NCHANNELS] = {
39 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
40 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
41 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
42 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
43 };
44 
45 /* Prototypes for local functions */
46 static void MCD_memcpy(int *dest, int *src, u32 size);
47 static void MCD_resmActions(int channel);
48 
49 /*
50  * Buffer descriptors used for storage of progress info for single Dmas
51  * Also used as storage for the DMA for CRCs for single DMAs
52  * Otherwise, the DMA does not parse these buffer descriptors
53  */
54 #ifdef MCD_INCLUDE_EU
55 extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
56 #else
57 MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
58 #endif
59 MCD_bufDesc *MCD_relocBuffDesc;
60 
61 /* Defines for the debug control register's functions */
62 #define DBG_CTL_COMP1_TASK	(0x00002000)
63 #define DBG_CTL_ENABLE		(DBG_CTL_AUTO_ARM	| \
64 				 DBG_CTL_BREAK		| \
65 				 DBG_CTL_INT_BREAK	| \
66 				 DBG_CTL_COMP1_TASK)
67 #define DBG_CTL_DISABLE		(DBG_CTL_AUTO_ARM	| \
68 				 DBG_CTL_INT_BREAK	| \
69 				 DBG_CTL_COMP1_TASK)
70 #define DBG_KILL_ALL_STAT	(0xFFFFFFFF)
71 
72 /* Offset to context save area where progress info is stored */
73 #define CSAVE_OFFSET		10
74 
75 /* Defines for Byte Swapping */
76 #define MCD_BYTE_SWAP_KILLER	0xFFF8888F
77 #define MCD_NO_BYTE_SWAP_ATALL	0x00040000
78 
79 /* Execution Unit Identifiers */
80 #define MAC			0	/* legacy - not used */
81 #define LUAC			1	/* legacy - not used */
82 #define CRC			2	/* legacy - not used */
83 #define LURC			3	/* Logic Unit with CRC */
84 
85 /* Task Identifiers */
86 #define TASK_CHAINNOEU		0
87 #define TASK_SINGLENOEU		1
88 #ifdef MCD_INCLUDE_EU
89 #define TASK_CHAINEU		2
90 #define TASK_SINGLEEU		3
91 #define TASK_FECRX		4
92 #define TASK_FECTX		5
93 #else
94 #define TASK_CHAINEU		0
95 #define TASK_SINGLEEU		1
96 #define TASK_FECRX		2
97 #define TASK_FECTX		3
98 #endif
99 
100 /*
101  * Structure to remember which variant is on which channel
102  * TBD- need this?
103  */
104 typedef struct MCD_remVariants_struct MCD_remVariant;
105 struct MCD_remVariants_struct {
106 	int remDestRsdIncr[NCHANNELS];	/* -1,0,1 */
107 	int remSrcRsdIncr[NCHANNELS];	/* -1,0,1 */
108 	s16 remDestIncr[NCHANNELS];	/* DestIncr */
109 	s16 remSrcIncr[NCHANNELS];	/* srcIncr */
110 	u32 remXferSize[NCHANNELS];	/* xferSize */
111 };
112 
113 /* Structure to remember the startDma parameters for each channel */
114 MCD_remVariant MCD_remVariants;
115 /********************************************************************/
116 /* Function: MCD_initDma
117  * Purpose:  Initializes the DMA API by setting up a pointer to the DMA
118  *           registers, relocating and creating the appropriate task
119  *           structures, and setting up some global settings
120  * Arguments:
121  *  dmaBarAddr    - pointer to the multichannel DMA registers
122  *  taskTableDest - location to move DMA task code and structs to
123  *  flags         - operational parameters
124  * Return Value:
125  *  MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
126  *  MCD_OK otherwise
127  */
128 extern u32 MCD_funcDescTab0[];
129 
130 int MCD_initDma(dmaRegs * dmaBarAddr, void *taskTableDest, u32 flags)
131 {
132 	int i;
133 	TaskTableEntry *entryPtr;
134 
135 	/* setup the local pointer to register set */
136 	MCD_dmaBar = dmaBarAddr;
137 
138 	/* do we need to move/create a task table */
139 	if ((flags & MCD_RELOC_TASKS) != 0) {
140 		int fixedSize;
141 		u32 *fixedPtr;
142 		/*int *tablePtr = taskTableDest;TBD */
143 		int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
144 		int taskDescTabsOffset;
145 		int taskTableSize, varTabsSize, funcDescTabsSize,
146 		    contextSavesSize;
147 		int taskDescTabSize;
148 
149 		int i;
150 
151 		/* check if physical address is aligned on 512 byte boundary */
152 		if (((u32) taskTableDest & 0x000001ff) != 0)
153 			return (MCD_TABLE_UNALIGNED);
154 
155 		/* set up local pointer to task Table */
156 		MCD_taskTable = taskTableDest;
157 
158 		/*
159 		 * Create a task table:
160 		 * - compute aligned base offsets for variable tables and
161 		 *   function descriptor tables, then
162 		 * - loop through the task table and setup the pointers
163 		 * - copy over model task table with the the actual task
164 		 *   descriptor tables
165 		 */
166 
167 		taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
168 		/* align variable tables to size */
169 		varTabsOffset = taskTableSize + (u32) taskTableDest;
170 		if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
171 			varTabsOffset =
172 			    (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
173 		/* align function descriptor tables */
174 		varTabsSize = NCHANNELS * VAR_TAB_SIZE;
175 		funcDescTabsOffset = varTabsOffset + varTabsSize;
176 
177 		if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
178 			funcDescTabsOffset =
179 			    (funcDescTabsOffset +
180 			     FUNCDESC_TAB_SIZE) & (~FUNCDESC_TAB_SIZE);
181 
182 		funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
183 		contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
184 		contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
185 		fixedSize =
186 		    taskTableSize + varTabsSize + funcDescTabsSize +
187 		    contextSavesSize;
188 
189 		/* zero the thing out */
190 		fixedPtr = (u32 *) taskTableDest;
191 		for (i = 0; i < (fixedSize / 4); i++)
192 			fixedPtr[i] = 0;
193 
194 		entryPtr = (TaskTableEntry *) MCD_taskTable;
195 		/* set up fixed pointers */
196 		for (i = 0; i < NCHANNELS; i++) {
197 			/* update ptr to local value */
198 			entryPtr[i].varTab = (u32) varTabsOffset;
199 			entryPtr[i].FDTandFlags =
200 			    (u32) funcDescTabsOffset | MCD_TT_FLAGS_DEF;
201 			entryPtr[i].contextSaveSpace = (u32) contextSavesOffset;
202 			varTabsOffset += VAR_TAB_SIZE;
203 #ifdef MCD_INCLUDE_EU
204 			/* if not there is only one, just point to the
205 			   same one */
206 			funcDescTabsOffset += FUNCDESC_TAB_SIZE;
207 #endif
208 			contextSavesOffset += CONTEXT_SAVE_SIZE;
209 		}
210 		/* copy over the function descriptor table */
211 		for (i = 0; i < FUNCDESC_TAB_NUM; i++) {
212 			MCD_memcpy((void *)(entryPtr[i].
213 					    FDTandFlags & ~MCD_TT_FLAGS_MASK),
214 				   (void *)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
215 		}
216 
217 		/* copy model task table to where the context saves stuff
218 		   leaves off */
219 		MCD_modelTaskTable = (TaskTableEntry *) contextSavesOffset;
220 
221 		MCD_memcpy((void *)MCD_modelTaskTable,
222 			   (void *)MCD_modelTaskTableSrc,
223 			   NUMOFVARIANTS * sizeof(TaskTableEntry));
224 
225 		/* point to local version of model task table */
226 		entryPtr = MCD_modelTaskTable;
227 		taskDescTabsOffset = (u32) MCD_modelTaskTable +
228 		    (NUMOFVARIANTS * sizeof(TaskTableEntry));
229 
230 		/* copy actual task code and update TDT ptrs in local
231 		   model task table */
232 		for (i = 0; i < NUMOFVARIANTS; i++) {
233 			taskDescTabSize =
234 			    entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
235 			MCD_memcpy((void *)taskDescTabsOffset,
236 				   (void *)entryPtr[i].TDTstart,
237 				   taskDescTabSize);
238 			entryPtr[i].TDTstart = (u32) taskDescTabsOffset;
239 			taskDescTabsOffset += taskDescTabSize;
240 			entryPtr[i].TDTend = (u32) taskDescTabsOffset - 4;
241 		}
242 #ifdef MCD_INCLUDE_EU
243 		/* Tack single DMA BDs onto end of code so API controls
244 		   where they are since DMA might write to them */
245 		MCD_relocBuffDesc =
246 		    (MCD_bufDesc *) (entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
247 #else
248 		/* DMA does not touch them so they can be wherever and we
249 		   don't need to waste SRAM on them */
250 		MCD_relocBuffDesc = MCD_singleBufDescs;
251 #endif
252 	} else {
253 		/* point the would-be relocated task tables and the
254 		   buffer descriptors to the ones the linker generated */
255 
256 		if (((u32) MCD_realTaskTableSrc & 0x000001ff) != 0)
257 			return (MCD_TABLE_UNALIGNED);
258 
259 		/* need to add code to make sure that every thing else is
260 		   aligned properly TBD. this is problematic if we init
261 		   more than once or after running tasks, need to add
262 		   variable to see if we have aleady init'd */
263 		entryPtr = MCD_realTaskTableSrc;
264 		for (i = 0; i < NCHANNELS; i++) {
265 			if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
266 			    ((entryPtr[i].
267 			      FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
268 				return (MCD_TABLE_UNALIGNED);
269 		}
270 
271 		MCD_taskTable = MCD_realTaskTableSrc;
272 		MCD_modelTaskTable = MCD_modelTaskTableSrc;
273 		MCD_relocBuffDesc = MCD_singleBufDescs;
274 	}
275 
276 	/* Make all channels as totally inactive, and remember them as such: */
277 
278 	MCD_dmaBar->taskbar = (u32) MCD_taskTable;
279 	for (i = 0; i < NCHANNELS; i++) {
280 		MCD_dmaBar->taskControl[i] = 0x0;
281 		MCD_chStatus[i] = MCD_NO_DMA;
282 	}
283 
284 	/* Set up pausing mechanism to inactive state: */
285 	/* no particular values yet for either comparator registers */
286 	MCD_dmaBar->debugComp1 = 0;
287 	MCD_dmaBar->debugComp2 = 0;
288 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
289 	MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
290 
291 	/* enable or disable commbus prefetch, really need an ifdef or
292 	   something to keep from trying to set this in the 8220 */
293 	if ((flags & MCD_COMM_PREFETCH_EN) != 0)
294 		MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
295 	else
296 		MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
297 
298 	return (MCD_OK);
299 }
300 
301 /*********************** End of MCD_initDma() ***********************/
302 
303 /********************************************************************/
304 /* Function:   MCD_dmaStatus
305  * Purpose:    Returns the status of the DMA on the requested channel
306  * Arguments:  channel - channel number
307  * Returns:    Predefined status indicators
308  */
309 int MCD_dmaStatus(int channel)
310 {
311 	u16 tcrValue;
312 
313 	if ((channel < 0) || (channel >= NCHANNELS))
314 		return (MCD_CHANNEL_INVALID);
315 
316 	tcrValue = MCD_dmaBar->taskControl[channel];
317 	if ((tcrValue & TASK_CTL_EN) == 0) {	/* nothing running */
318 		/* if last reported with task enabled */
319 		if (MCD_chStatus[channel] == MCD_RUNNING
320 		    || MCD_chStatus[channel] == MCD_IDLE)
321 			MCD_chStatus[channel] = MCD_DONE;
322 	} else {		/* something is running */
323 
324 		/* There are three possibilities: paused, running or idle. */
325 		if (MCD_chStatus[channel] == MCD_RUNNING
326 		    || MCD_chStatus[channel] == MCD_IDLE) {
327 			MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
328 			/* This register is selected to know which initiator is
329 			   actually asserted. */
330 			if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
331 				MCD_chStatus[channel] = MCD_RUNNING;
332 			else
333 				MCD_chStatus[channel] = MCD_IDLE;
334 			/* do not change the status if it is already paused. */
335 		}
336 	}
337 	return MCD_chStatus[channel];
338 }
339 
340 /******************** End of MCD_dmaStatus() ************************/
341 
342 /********************************************************************/
343 /* Function:    MCD_startDma
344  * Ppurpose:    Starts a particular kind of DMA
345  * Arguments:
346  * srcAddr	- the channel on which to run the DMA
347  * srcIncr	- the address to move data from, or buffer-descriptor address
348  * destAddr	- the amount to increment the source address per transfer
349  * destIncr	- the address to move data to
350  * dmaSize	- the amount to increment the destination address per transfer
351  * xferSize	- the number bytes in of each data movement (1, 2, or 4)
352  * initiator	- what device initiates the DMA
353  * priority	- priority of the DMA
354  * flags	- flags describing the DMA
355  * funcDesc	- description of byte swapping, bit swapping, and CRC actions
356  * srcAddrVirt	- virtual buffer descriptor address TBD
357  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
358  */
359 
360 int MCD_startDma(int channel, s8 * srcAddr, s16 srcIncr, s8 * destAddr,
361 		 s16 destIncr, u32 dmaSize, u32 xferSize, u32 initiator,
362 		 int priority, u32 flags, u32 funcDesc
363 #ifdef MCD_NEED_ADDR_TRANS
364 		 s8 * srcAddrVirt
365 #endif
366     )
367 {
368 	int srcRsdIncr, destRsdIncr;
369 	int *cSave;
370 	short xferSizeIncr;
371 	int tcrCount = 0;
372 #ifdef MCD_INCLUDE_EU
373 	u32 *realFuncArray;
374 #endif
375 
376 	if ((channel < 0) || (channel >= NCHANNELS))
377 		return (MCD_CHANNEL_INVALID);
378 
379 	/* tbd - need to determine the proper response to a bad funcDesc when
380 	   not including EU functions, for now, assign a benign funcDesc, but
381 	   maybe should return an error */
382 #ifndef MCD_INCLUDE_EU
383 	funcDesc = MCD_FUNC_NOEU1;
384 #endif
385 
386 #ifdef MCD_DEBUG
387 	printf("startDma:Setting up params\n");
388 #endif
389 	/* Set us up for task-wise priority.  We don't technically need to do
390 	   this on every start, but since the register involved is in the same
391 	   longword as other registers that users are in control of, setting
392 	   it more than once is probably preferable.  That since the
393 	   documentation doesn't seem to be completely consistent about the
394 	   nature of the PTD control register. */
395 	MCD_dmaBar->ptdControl |= (u16) 0x8000;
396 
397 	/* Not sure what we need to keep here rtm TBD */
398 #if 1
399 	/* Calculate additional parameters to the regular DMA calls. */
400 	srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
401 	destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
402 
403 	xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
404 
405 	/* Remember for each channel which variant is running. */
406 	MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
407 	MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
408 	MCD_remVariants.remDestIncr[channel] = destIncr;
409 	MCD_remVariants.remSrcIncr[channel] = srcIncr;
410 	MCD_remVariants.remXferSize[channel] = xferSize;
411 #endif
412 
413 	cSave =
414 	    (int *)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET +
415 	    CURRBD;
416 
417 #ifdef MCD_INCLUDE_EU
418 	/* may move this to EU specific calls */
419 	realFuncArray =
420 	    (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
421 	/* Modify the LURC's normal and byte-residue-loop functions according
422 	   to parameter. */
423 	realFuncArray[(LURC * 16)] = xferSize == 4 ?
424 	    funcDesc : xferSize == 2 ?
425 	    funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
426 	realFuncArray[(LURC * 16 + 1)] =
427 	    (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
428 #endif
429 	/* Write the initiator field in the TCR, and also set the
430 	   initiator-hold bit. Note that,due to a hardware quirk, this could
431 	   collide with an MDE access to the initiator-register file, so we
432 	   have to verify that the write reads back correctly. */
433 
434 	MCD_dmaBar->taskControl[channel] =
435 	    (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
436 
437 	while (((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
438 		((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM))
439 	       && (tcrCount < 1000)) {
440 		tcrCount++;
441 		/*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020; */
442 		MCD_dmaBar->taskControl[channel] =
443 		    (initiator << 8) | TASK_CTL_HIPRITSKEN |
444 		    TASK_CTL_HLDINITNUM;
445 	}
446 
447 	MCD_dmaBar->priority[channel] = (u8) priority & PRIORITY_PRI_MASK;
448 	/* should be albe to handle this stuff with only one write to ts reg
449 	   - tbd */
450 	if (channel < 8 && channel >= 0) {
451 		MCD_dmaBar->taskSize0 &= ~(0xf << (7 - channel) * 4);
452 		MCD_dmaBar->taskSize0 |=
453 		    (xferSize & 3) << (((7 - channel) * 4) + 2);
454 		MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel) * 4);
455 	} else {
456 		MCD_dmaBar->taskSize1 &= ~(0xf << (15 - channel) * 4);
457 		MCD_dmaBar->taskSize1 |=
458 		    (xferSize & 3) << (((15 - channel) * 4) + 2);
459 		MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel) * 4);
460 	}
461 
462 	/* setup task table flags/options which mostly control the line
463 	   buffers */
464 	MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
465 	MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
466 
467 	if (flags & MCD_FECTX_DMA) {
468 		/* TDTStart and TDTEnd */
469 		MCD_taskTable[channel].TDTstart =
470 		    MCD_modelTaskTable[TASK_FECTX].TDTstart;
471 		MCD_taskTable[channel].TDTend =
472 		    MCD_modelTaskTable[TASK_FECTX].TDTend;
473 		MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
474 				     (char *)destAddr, MCD_taskTable,
475 				     channel);
476 	} else if (flags & MCD_FECRX_DMA) {
477 		/* TDTStart and TDTEnd */
478 		MCD_taskTable[channel].TDTstart =
479 		    MCD_modelTaskTable[TASK_FECRX].TDTstart;
480 		MCD_taskTable[channel].TDTend =
481 		    MCD_modelTaskTable[TASK_FECRX].TDTend;
482 		MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
483 				    (char *)destAddr, MCD_taskTable,
484 				    channel);
485 	} else if (flags & MCD_SINGLE_DMA) {
486 		/* this buffer descriptor is used for storing off initial
487 		   parameters for later progress query calculation and for the
488 		   DMA to write the resulting checksum. The DMA does not use
489 		   this to determine how to operate, that info is passed with
490 		   the init routine */
491 		MCD_relocBuffDesc[channel].srcAddr = srcAddr;
492 		MCD_relocBuffDesc[channel].destAddr = destAddr;
493 
494 		/* definitely not its final value */
495 		MCD_relocBuffDesc[channel].lastDestAddr = destAddr;
496 
497 		MCD_relocBuffDesc[channel].dmaSize = dmaSize;
498 		MCD_relocBuffDesc[channel].flags = 0;	/* not used */
499 		MCD_relocBuffDesc[channel].csumResult = 0;	/* not used */
500 		MCD_relocBuffDesc[channel].next = 0;	/* not used */
501 
502 		/* Initialize the progress-querying stuff to show no
503 		   progress: */
504 		((volatile int *)MCD_taskTable[channel].
505 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
506 		((volatile int *)MCD_taskTable[channel].
507 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
508 		((volatile int *)MCD_taskTable[channel].
509 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
510 		((volatile int *)MCD_taskTable[channel].
511 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
512 (u32) & (MCD_relocBuffDesc[channel]);
513 		/* tbd - need to keep the user from trying to call the EU
514 		   routine when MCD_INCLUDE_EU is not defined */
515 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
516 			/* TDTStart and TDTEnd */
517 			MCD_taskTable[channel].TDTstart =
518 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
519 			MCD_taskTable[channel].TDTend =
520 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
521 			MCD_startDmaSingleNoEu((char *)srcAddr, srcIncr,
522 					       (char *)destAddr, destIncr,
523 					       (int)dmaSize, xferSizeIncr,
524 					       flags, (int *)
525 					       &(MCD_relocBuffDesc[channel]),
526 					       cSave, MCD_taskTable, channel);
527 		} else {
528 			/* TDTStart and TDTEnd */
529 			MCD_taskTable[channel].TDTstart =
530 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
531 			MCD_taskTable[channel].TDTend =
532 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
533 			MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
534 					     (char *)destAddr, destIncr,
535 					     (int)dmaSize, xferSizeIncr,
536 					     flags, (int *)
537 					     &(MCD_relocBuffDesc[channel]),
538 					     cSave, MCD_taskTable, channel);
539 		}
540 	} else {		/* chained DMAS */
541 		/* Initialize the progress-querying stuff to show no
542 		   progress: */
543 #if 1
544 		/* (!defined(MCD_NEED_ADDR_TRANS)) */
545 		((volatile int *)MCD_taskTable[channel].
546 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
547 		    = (int)((MCD_bufDesc *) srcAddr)->srcAddr;
548 		((volatile int *)MCD_taskTable[channel].
549 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
550 		    = (int)((MCD_bufDesc *) srcAddr)->destAddr;
551 #else
552 		/* if using address translation, need the virtual addr of the
553 		   first buffdesc */
554 		((volatile int *)MCD_taskTable[channel].
555 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
556 		    = (int)((MCD_bufDesc *) srcAddrVirt)->srcAddr;
557 		((volatile int *)MCD_taskTable[channel].
558 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
559 		    = (int)((MCD_bufDesc *) srcAddrVirt)->destAddr;
560 #endif
561 		((volatile int *)MCD_taskTable[channel].
562 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
563 		((volatile int *)MCD_taskTable[channel].
564 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
565 
566 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
567 			/*TDTStart and TDTEnd */
568 			MCD_taskTable[channel].TDTstart =
569 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
570 			MCD_taskTable[channel].TDTend =
571 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
572 			MCD_startDmaChainNoEu((int *)srcAddr, srcIncr,
573 					      destIncr, xferSize,
574 					      xferSizeIncr, cSave,
575 					      MCD_taskTable, channel);
576 		} else {
577 			/*TDTStart and TDTEnd */
578 			MCD_taskTable[channel].TDTstart =
579 			    MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
580 			MCD_taskTable[channel].TDTend =
581 			    MCD_modelTaskTable[TASK_CHAINEU].TDTend;
582 			MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr,
583 					    xferSize, xferSizeIncr, cSave,
584 					    MCD_taskTable, channel);
585 		}
586 	}
587 	MCD_chStatus[channel] = MCD_IDLE;
588 	return (MCD_OK);
589 }
590 
591 /************************ End of MCD_startDma() *********************/
592 
593 /********************************************************************/
594 /* Function:    MCD_XferProgrQuery
595  * Purpose:     Returns progress of DMA on requested channel
596  * Arguments:   channel - channel to retrieve progress for
597  *              progRep - pointer to user supplied MCD_XferProg struct
598  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
599  *
600  * Notes:
601  *  MCD_XferProgrQuery() upon completing or after aborting a DMA, or
602  *  while the DMA is in progress, this function returns the first
603  *  DMA-destination address not (or not yet) used in the DMA. When
604  *  encountering a non-ready buffer descriptor, the information for
605  *  the last completed descriptor is returned.
606  *
607  *  MCD_XferProgQuery() has to avoid the possibility of getting
608  *  partially-updated information in the event that we should happen
609  *  to query DMA progress just as the DMA is updating it. It does that
610  *  by taking advantage of the fact context is not saved frequently for
611  *  the most part. We therefore read it at least twice until we get the
612  *  same information twice in a row.
613  *
614  *  Because a small, but not insignificant, amount of time is required
615  *  to write out the progress-query information, especially upon
616  *  completion of the DMA, it would be wise to guarantee some time lag
617  *  between successive readings of the progress-query information.
618  */
619 
620 /* How many iterations of the loop below to execute to stabilize values */
621 #define STABTIME 0
622 
623 int MCD_XferProgrQuery(int channel, MCD_XferProg * progRep)
624 {
625 	MCD_XferProg prevRep;
626 	int again;		/* true if we are to try again to ge
627 				   consistent results */
628 	int i;			/* used as a time-waste counter */
629 	int destDiffBytes;	/* Total no of bytes that we think actually
630 				   got xfered. */
631 	int numIterations;	/* number of iterations */
632 	int bytesNotXfered;	/* bytes that did not get xfered. */
633 	s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
634 	int subModVal, addModVal;	/* Mode values to added and subtracted
635 					   from the final destAddr */
636 
637 	if ((channel < 0) || (channel >= NCHANNELS))
638 		return (MCD_CHANNEL_INVALID);
639 
640 	/* Read a trial value for the progress-reporting values */
641 	prevRep.lastSrcAddr =
642 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
643 		    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
644 	prevRep.lastDestAddr =
645 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
646 		    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
647 	prevRep.dmaSize =
648 	    ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT +
649 								      CSAVE_OFFSET];
650 	prevRep.currBufDesc =
651 	    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
652 			     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
653 	/* Repeatedly reread those values until they match previous values: */
654 	do {
655 		/* Waste a little bit of time to ensure stability: */
656 		for (i = 0; i < STABTIME; i++) {
657 			/* make sure this loop does something so that it
658 			   doesn't get optimized out */
659 			i += i >> 2;
660 		}
661 		/* Check them again: */
662 		progRep->lastSrcAddr =
663 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
664 			    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
665 		progRep->lastDestAddr =
666 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
667 			    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
668 		progRep->dmaSize =
669 		    ((volatile int *)MCD_taskTable[channel].
670 		     contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
671 		progRep->currBufDesc =
672 		    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
673 				     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
674 		/* See if they match: */
675 		if (prevRep.lastSrcAddr != progRep->lastSrcAddr
676 		    || prevRep.lastDestAddr != progRep->lastDestAddr
677 		    || prevRep.dmaSize != progRep->dmaSize
678 		    || prevRep.currBufDesc != progRep->currBufDesc) {
679 			/* If they don't match, remember previous values and
680 			   try again: */
681 			prevRep.lastSrcAddr = progRep->lastSrcAddr;
682 			prevRep.lastDestAddr = progRep->lastDestAddr;
683 			prevRep.dmaSize = progRep->dmaSize;
684 			prevRep.currBufDesc = progRep->currBufDesc;
685 			again = MCD_TRUE;
686 		} else
687 			again = MCD_FALSE;
688 	} while (again == MCD_TRUE);
689 
690 	/* Update the dCount, srcAddr and destAddr */
691 	/* To calculate dmaCount, we consider destination address. C
692 	   overs M1,P1,Z for destination */
693 	switch (MCD_remVariants.remDestRsdIncr[channel]) {
694 	case MINUS1:
695 		subModVal =
696 		    ((int)progRep->
697 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
698 				      1);
699 		addModVal =
700 		    ((int)progRep->currBufDesc->
701 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
702 		LWAlignedInitDestAddr =
703 		    (progRep->currBufDesc->destAddr) - addModVal;
704 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
705 		destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
706 		bytesNotXfered =
707 		    (destDiffBytes / MCD_remVariants.remDestIncr[channel]) *
708 		    (MCD_remVariants.remDestIncr[channel]
709 		     + MCD_remVariants.remXferSize[channel]);
710 		progRep->dmaSize =
711 		    destDiffBytes - bytesNotXfered + addModVal - subModVal;
712 		break;
713 	case ZERO:
714 		progRep->lastDestAddr = progRep->currBufDesc->destAddr;
715 		break;
716 	case PLUS1:
717 		/* This value has to be subtracted from the final
718 		   calculated dCount. */
719 		subModVal =
720 		    ((int)progRep->currBufDesc->
721 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
722 		/* These bytes are already in lastDestAddr. */
723 		addModVal =
724 		    ((int)progRep->
725 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
726 				      1);
727 		LWAlignedInitDestAddr =
728 		    (progRep->currBufDesc->destAddr) - subModVal;
729 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
730 		destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
731 		numIterations =
732 		    (LWAlignedCurrDestAddr -
733 		     LWAlignedInitDestAddr) /
734 		    MCD_remVariants.remDestIncr[channel];
735 		bytesNotXfered =
736 		    numIterations * (MCD_remVariants.remDestIncr[channel]
737 				     - MCD_remVariants.remXferSize[channel]);
738 		progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
739 		break;
740 	default:
741 		break;
742 	}
743 
744 	/* This covers M1,P1,Z for source */
745 	switch (MCD_remVariants.remSrcRsdIncr[channel]) {
746 	case MINUS1:
747 		progRep->lastSrcAddr =
748 		    progRep->currBufDesc->srcAddr +
749 		    (MCD_remVariants.remSrcIncr[channel] *
750 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
751 		break;
752 	case ZERO:
753 		progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
754 		break;
755 	case PLUS1:
756 		progRep->lastSrcAddr =
757 		    progRep->currBufDesc->srcAddr +
758 		    (MCD_remVariants.remSrcIncr[channel] *
759 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
760 		break;
761 	default:
762 		break;
763 	}
764 
765 	return (MCD_OK);
766 }
767 
768 /******************* End of MCD_XferProgrQuery() ********************/
769 
770 /********************************************************************/
771 /* MCD_resmActions() does the majority of the actions of a DMA resume.
772  * It is called from MCD_killDma() and MCD_resumeDma().  It has to be
773  * a separate function because the kill function has to negate the task
774  * enable before resuming it, but the resume function has to do nothing
775  * if there is no DMA on that channel (i.e., if the enable bit is 0).
776  */
777 static void MCD_resmActions(int channel)
778 {
779 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
780 	MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
781 	/* This register is selected to know which initiator is
782 	   actually asserted. */
783 	MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
784 
785 	if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
786 		MCD_chStatus[channel] = MCD_RUNNING;
787 	else
788 		MCD_chStatus[channel] = MCD_IDLE;
789 }
790 
791 /********************* End of MCD_resmActions() *********************/
792 
793 /********************************************************************/
794 /* Function:    MCD_killDma
795  * Purpose:     Halt the DMA on the requested channel, without any
796  *              intention of resuming the DMA.
797  * Arguments:   channel - requested channel
798  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
799  *
800  * Notes:
801  *  A DMA may be killed from any state, including paused state, and it
802  *  always goes to the MCD_HALTED state even if it is killed while in
803  *  the MCD_NO_DMA or MCD_IDLE states.
804  */
805 int MCD_killDma(int channel)
806 {
807 	/* MCD_XferProg progRep; */
808 
809 	if ((channel < 0) || (channel >= NCHANNELS))
810 		return (MCD_CHANNEL_INVALID);
811 
812 	MCD_dmaBar->taskControl[channel] = 0x0;
813 	MCD_resumeDma(channel);
814 	/*
815 	 * This must be after the write to the TCR so that the task doesn't
816 	 * start up again momentarily, and before the status assignment so
817 	 * as to override whatever MCD_resumeDma() may do to the channel
818 	 * status.
819 	 */
820 	MCD_chStatus[channel] = MCD_HALTED;
821 
822 	/*
823 	 * Update the current buffer descriptor's lastDestAddr field
824 	 *
825 	 * MCD_XferProgrQuery (channel, &progRep);
826 	 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
827 	 */
828 	return (MCD_OK);
829 }
830 
831 /************************ End of MCD_killDma() **********************/
832 
833 /********************************************************************/
834 /* Function:    MCD_continDma
835  * Purpose:     Continue a DMA which as stopped due to encountering an
836  *              unready buffer descriptor.
837  * Arguments:   channel - channel to continue the DMA on
838  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
839  *
840  * Notes:
841  *  This routine does not check to see if there is a task which can
842  *  be continued. Also this routine should not be used with single DMAs.
843  */
844 int MCD_continDma(int channel)
845 {
846 	if ((channel < 0) || (channel >= NCHANNELS))
847 		return (MCD_CHANNEL_INVALID);
848 
849 	MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
850 	MCD_chStatus[channel] = MCD_RUNNING;
851 
852 	return (MCD_OK);
853 }
854 
855 /********************** End of MCD_continDma() **********************/
856 
857 /*********************************************************************
858  * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
859  * to freeze a task and resume it.  We freeze a task by breakpointing
860  * on the stated task.  That is, not any specific place in the task,
861  * but any time that task executes.  In particular, when that task
862  * executes, we want to freeze that task and only that task.
863  *
864  * The bits of the debug control register influence interrupts vs.
865  * breakpoints as follows:
866  * - Bits 14 and 0 enable or disable debug functions.  If enabled, you
867  *   will get the interrupt but you may or may not get a breakpoint.
868  * - Bits 2 and 1 decide whether you also get a breakpoint in addition
869  *   to an interrupt.
870  *
871  * The debug unit can do these actions in response to either internally
872  * detected breakpoint conditions from the comparators, or in response
873  * to the external breakpoint pin, or both.
874  * - Bits 14 and 1 perform the above-described functions for
875  *   internally-generated conditions, i.e., the debug comparators.
876  * - Bits 0 and 2 perform the above-described functions for external
877  *   conditions, i.e., the breakpoint external pin.
878  *
879  * Note that, although you "always" get the interrupt when you turn
880  * the debug functions, the interrupt can nevertheless, if desired, be
881  * masked by the corresponding bit in the PTD's IMR. Note also that
882  * this means that bits 14 and 0 must enable debug functions before
883  * bits 1 and 2, respectively, have any effect.
884  *
885  * NOTE: It's extremely important to not pause more than one DMA channel
886  *  at a time.
887  ********************************************************************/
888 
889 /********************************************************************/
890 /* Function:    MCD_pauseDma
891  * Purpose:     Pauses the DMA on a given channel (if any DMA is running
892  *              on that channel).
893  * Arguments:   channel
894  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
895  */
896 int MCD_pauseDma(int channel)
897 {
898 	/* MCD_XferProg progRep; */
899 
900 	if ((channel < 0) || (channel >= NCHANNELS))
901 		return (MCD_CHANNEL_INVALID);
902 
903 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) {
904 		MCD_dmaBar->debugComp1 = channel;
905 		MCD_dmaBar->debugControl =
906 		    DBG_CTL_ENABLE | (1 << (channel + 16));
907 		MCD_chStatus[channel] = MCD_PAUSED;
908 
909 		/*
910 		 * Update the current buffer descriptor's lastDestAddr field
911 		 *
912 		 * MCD_XferProgrQuery (channel, &progRep);
913 		 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
914 		 */
915 	}
916 	return (MCD_OK);
917 }
918 
919 /************************* End of MCD_pauseDma() ********************/
920 
921 /********************************************************************/
922 /* Function:    MCD_resumeDma
923  * Purpose:     Resumes the DMA on a given channel (if any DMA is
924  *              running on that channel).
925  * Arguments:   channel - channel on which to resume DMA
926  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
927  */
928 int MCD_resumeDma(int channel)
929 {
930 	if ((channel < 0) || (channel >= NCHANNELS))
931 		return (MCD_CHANNEL_INVALID);
932 
933 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
934 		MCD_resmActions(channel);
935 
936 	return (MCD_OK);
937 }
938 
939 /************************ End of MCD_resumeDma() ********************/
940 
941 /********************************************************************/
942 /* Function:    MCD_csumQuery
943  * Purpose:     Provide the checksum after performing a non-chained DMA
944  * Arguments:   channel - channel to report on
945  *              csum - pointer to where to write the checksum/CRC
946  * Returns:     MCD_ERROR if the channel is invalid, else MCD_OK
947  *
948  * Notes:
949  *
950  */
951 int MCD_csumQuery(int channel, u32 * csum)
952 {
953 #ifdef MCD_INCLUDE_EU
954 	if ((channel < 0) || (channel >= NCHANNELS))
955 		return (MCD_CHANNEL_INVALID);
956 
957 	*csum = MCD_relocBuffDesc[channel].csumResult;
958 	return (MCD_OK);
959 #else
960 	return (MCD_ERROR);
961 #endif
962 }
963 
964 /*********************** End of MCD_resumeDma() *********************/
965 
966 /********************************************************************/
967 /* Function:    MCD_getCodeSize
968  * Purpose:     Provide the size requirements of the microcoded tasks
969  * Returns:     Size in bytes
970  */
971 int MCD_getCodeSize(void)
972 {
973 #ifdef MCD_INCLUDE_EU
974 	return (0x2b5c);
975 #else
976 	return (0x173c);
977 #endif
978 }
979 
980 /********************** End of MCD_getCodeSize() ********************/
981 
982 /********************************************************************/
983 /* Function:    MCD_getVersion
984  * Purpose:     Provide the version string and number
985  * Arguments:   longVersion - user supplied pointer to a pointer to a char
986  *                    which points to the version string
987  * Returns:     Version number and version string (by reference)
988  */
989 char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
990 #define MCD_REV_MAJOR   0x00
991 #define MCD_REV_MINOR   0x03
992 
993 int MCD_getVersion(char **longVersion)
994 {
995 	*longVersion = MCD_versionString;
996 	return ((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
997 }
998 
999 /********************** End of MCD_getVersion() *********************/
1000 
1001 /********************************************************************/
1002 /* Private version of memcpy()
1003  * Note that everything this is used for is longword-aligned.
1004  */
1005 static void MCD_memcpy(int *dest, int *src, u32 size)
1006 {
1007 	u32 i;
1008 
1009 	for (i = 0; i < size; i += sizeof(int), dest++, src++)
1010 		*dest = *src;
1011 }
1012