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