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