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