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