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