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