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