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