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