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