]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/dma/MCD_dmaApi.c
socfpga: Move board/socfpga_cyclone5 to board/socfpga
[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 #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;
489                 MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
490                                      (char *)destAddr, MCD_taskTable,
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;
498                 MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
499                                     (char *)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((char *)srcAddr, srcIncr,
538                                                (char *)destAddr, destIncr,
539                                                (int)dmaSize, xferSizeIncr,
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;
549                         MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
550                                              (char *)destAddr, destIncr,
551                                              (int)dmaSize, xferSizeIncr,
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 }