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