2 * drivers/dma/MCD_dmaApi.c
4 * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Kurt Mahan <kmahan@freescale.com>
6 * Shrek Wu b16972@freescale.com
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 #include "MCD_tasksInit.h"
26 #include "MCD_progCheck.h"
28 /********************************************************************/
30 * This is an API-internal pointer to the DMA's registers
35 * These are the real and model task tables as generated by the
38 extern TaskTableEntry MCD_realTaskTableSrc
[NCHANNELS
];
39 extern TaskTableEntry MCD_modelTaskTableSrc
[NUMOFVARIANTS
];
42 * However, this (usually) gets relocated to on-chip SRAM, at which
43 * point we access them as these tables
45 volatile TaskTableEntry
*MCD_taskTable
;
46 TaskTableEntry
*MCD_modelTaskTable
;
50 * MCD_chStatus[] is an array of status indicators for remembering
51 * whether a DMA has ever been attempted on each channel, pausing
54 static int MCD_chStatus
[NCHANNELS
] =
56 MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
,
57 MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
,
58 MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
,
59 MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
, MCD_NO_DMA
63 * Prototypes for local functions
65 static void MCD_memcpy(int *dest
, int *src
, u32 size
);
66 static void MCD_resmActions(int channel
);
69 * Buffer descriptors used for storage of progress info for single Dmas
70 * Also used as storage for the DMA for CRCs for single DMAs
71 * Otherwise, the DMA does not parse these buffer descriptors
74 extern MCD_bufDesc MCD_singleBufDescs
[NCHANNELS
];
76 MCD_bufDesc MCD_singleBufDescs
[NCHANNELS
];
78 MCD_bufDesc
*MCD_relocBuffDesc
;
82 * Defines for the debug control register's functions
84 #define DBG_CTL_COMP1_TASK (0x00002000)
85 /* have comparator 1 look for a task # */
86 #define DBG_CTL_ENABLE (DBG_CTL_AUTO_ARM | \
90 #define DBG_CTL_DISABLE (DBG_CTL_AUTO_ARM | \
93 #define DBG_KILL_ALL_STAT (0xFFFFFFFF)
96 * Offset to context save area where progress info is stored
98 #define CSAVE_OFFSET 10
101 * Defines for Byte Swapping
103 #define MCD_BYTE_SWAP_KILLER 0xFFF8888F
104 #define MCD_NO_BYTE_SWAP_ATALL 0x00040000
107 * Execution Unit Identifiers
109 #define MAC 0 /* legacy - not used */
110 #define LUAC 1 /* legacy - not used */
111 #define CRC 2 /* legacy - not used */
112 #define LURC 3 /* Logic Unit with CRC */
117 #define TASK_CHAINNOEU 0
118 #define TASK_SINGLENOEU 1
119 #ifdef MCD_INCLUDE_EU
120 #define TASK_CHAINEU 2
121 #define TASK_SINGLEEU 3
125 #define TASK_CHAINEU 0
126 #define TASK_SINGLEEU 1
132 * Structure to remember which variant is on which channel
134 typedef struct MCD_remVariants_struct MCD_remVariant
;
135 struct MCD_remVariants_struct
{
136 int remDestRsdIncr
[NCHANNELS
]; /* -1,0,1 */
137 int remSrcRsdIncr
[NCHANNELS
]; /* -1,0,1 */
138 s16 remDestIncr
[NCHANNELS
]; /* DestIncr */
139 s16 remSrcIncr
[NCHANNELS
]; /* srcIncr */
140 u32 remXferSize
[NCHANNELS
]; /* xferSize */
144 * Structure to remember the startDma parameters for each channel
146 MCD_remVariant MCD_remVariants
;
148 /********************************************************************/
150 * Function: MCD_initDma
151 * Purpose: Initializes the DMA API by setting up a pointer to the DMA
152 * registers, relocating and creating the appropriate task
153 * structures, and setting up some global settings
155 * dmaBarAddr - pointer to the multichannel DMA registers
156 * taskTableDest - location to move DMA task code and structs to
157 * flags - operational parameters
159 * MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
162 extern u32 MCD_funcDescTab0
[];
164 int MCD_initDma(dmaRegs
*dmaBarAddr
, void *taskTableDest
, u32 flags
)
167 TaskTableEntry
*entryPtr
;
169 /* Setup the local pointer to register set */
170 MCD_dmaBar
= dmaBarAddr
;
172 /* Do we need to move/create a task table */
173 if ((flags
& MCD_RELOC_TASKS
) != 0) {
176 int varTabsOffset
, funcDescTabsOffset
;
177 int contextSavesOffset
;
178 int taskDescTabsOffset
;
179 int taskTableSize
, varTabsSize
;
180 int funcDescTabsSize
, contextSavesSize
;
184 /* Check if physical address is
185 * aligned on 512 byte boundary */
186 if (((u32
)taskTableDest
& 0x000001ff) != 0)
187 return MCD_TABLE_UNALIGNED
;
189 MCD_taskTable
= taskTableDest
;
190 /* set up local pointer to task Table */
193 * Create a task table:
194 * compute aligned base offsets for variable tables and
195 * function descriptor tables, then
196 * loop through the task table and setup the pointers
197 *copy over model task table with the the actual
198 *task descriptor tables
200 taskTableSize
= NCHANNELS
* sizeof(TaskTableEntry
);
201 /* Align variable tables to size */
202 varTabsOffset
= taskTableSize
+ (u32
)taskTableDest
;
203 if ((varTabsOffset
& (VAR_TAB_SIZE
- 1)) != 0)
204 varTabsOffset
= (varTabsOffset
+ VAR_TAB_SIZE
)
206 /* Align function descriptor tables */
207 varTabsSize
= NCHANNELS
* VAR_TAB_SIZE
;
208 funcDescTabsOffset
= varTabsOffset
+ varTabsSize
;
210 if ((funcDescTabsOffset
& (FUNCDESC_TAB_SIZE
- 1)) != 0)
211 funcDescTabsOffset
= (funcDescTabsOffset
212 + FUNCDESC_TAB_SIZE
) &
213 (~FUNCDESC_TAB_SIZE
);
215 funcDescTabsSize
= FUNCDESC_TAB_NUM
* FUNCDESC_TAB_SIZE
;
216 contextSavesOffset
= funcDescTabsOffset
218 contextSavesSize
= (NCHANNELS
* CONTEXT_SAVE_SIZE
);
219 fixedSize
= taskTableSize
+ varTabsSize
+
220 funcDescTabsSize
+ contextSavesSize
;
222 /* Zero the thing out */
223 fixedPtr
= (u32
*)taskTableDest
;
224 for (i
= 0; i
< (fixedSize
/4); i
++)
227 entryPtr
= (TaskTableEntry
*)MCD_taskTable
;
228 /* Set up fixed pointers */
229 for (i
= 0; i
< NCHANNELS
; i
++) {
230 entryPtr
[i
].varTab
= (u32
)varTabsOffset
;
231 /* update ptr to local value */
232 entryPtr
[i
].FDTandFlags
=
233 (u32
)funcDescTabsOffset
| MCD_TT_FLAGS_DEF
;
234 entryPtr
[i
].contextSaveSpace
=
235 (u32
)contextSavesOffset
;
236 varTabsOffset
+= VAR_TAB_SIZE
;
237 #ifdef MCD_INCLUDE_EU
238 /* if not there is only one,
239 * just point to the same one */
240 funcDescTabsOffset
+= FUNCDESC_TAB_SIZE
;
242 contextSavesOffset
+= CONTEXT_SAVE_SIZE
;
244 /* Copy over the function descriptor table */
245 for (i
= 0; i
< FUNCDESC_TAB_NUM
; i
++) {
246 MCD_memcpy((void *)(entryPtr
[i
].FDTandFlags
247 & ~MCD_TT_FLAGS_MASK
),
248 (void *)MCD_funcDescTab0
,
252 /* Copy model task table to where the
253 * context save stuff leaves off */
255 (TaskTableEntry
*)contextSavesOffset
;
257 MCD_memcpy((void *)MCD_modelTaskTable
,
258 (void *)MCD_modelTaskTableSrc
,
259 NUMOFVARIANTS
* sizeof(TaskTableEntry
));
261 /* Point to local version of model task table */
262 entryPtr
= MCD_modelTaskTable
;
263 taskDescTabsOffset
= (u32
)MCD_modelTaskTable
+
264 (NUMOFVARIANTS
* sizeof(TaskTableEntry
));
266 /* Copy actual task code and update TDT ptrs
267 * in local model task table */
268 for (i
= 0; i
< NUMOFVARIANTS
; i
++) {
269 taskDescTabSize
= entryPtr
[i
].TDTend
270 - entryPtr
[i
].TDTstart
+ 4;
271 MCD_memcpy((void *)taskDescTabsOffset
,
272 (void *)entryPtr
[i
].TDTstart
,
274 entryPtr
[i
].TDTstart
=
275 (u32
)taskDescTabsOffset
;
276 taskDescTabsOffset
+= taskDescTabSize
;
278 (u32
)taskDescTabsOffset
- 4;
280 #ifdef MCD_INCLUDE_EU
282 * Tack single DMA BDs onto end of
283 * code so API controls where
284 * they are since DMA might write to them
286 MCD_relocBuffDesc
= (MCD_bufDesc
*)
287 (entryPtr
[NUMOFVARIANTS
- 1].TDTend
+ 4);
290 * DMA does not touch them so they
291 * can be wherever and we don't need to
294 MCD_relocBuffDesc
= MCD_singleBufDescs
;
298 * Point the would-be relocated task tables and
299 * the buffer descriptors
300 * to the ones the linker generated
302 if (((u32
)MCD_realTaskTableSrc
& 0x000001ff) != 0)
303 return MCD_TABLE_UNALIGNED
;
305 entryPtr
= MCD_realTaskTableSrc
;
306 for (i
= 0; i
< NCHANNELS
; i
++) {
307 if (((entryPtr
[i
].varTab
308 & (VAR_TAB_SIZE
- 1)) != 0) ||
309 ((entryPtr
[i
].FDTandFlags
&
310 (FUNCDESC_TAB_SIZE
- 1)) != 0))
311 return MCD_TABLE_UNALIGNED
;
314 MCD_taskTable
= MCD_realTaskTableSrc
;
315 MCD_modelTaskTable
= MCD_modelTaskTableSrc
;
316 MCD_relocBuffDesc
= MCD_singleBufDescs
;
319 /* Make all channels inactive,
320 * and remember them as such: */
321 MCD_dmaBar
->taskbar
= (u32
) MCD_taskTable
;
322 for (i
= 0; i
< NCHANNELS
; i
++) {
323 MCD_dmaBar
->taskControl
[i
] = 0x0;
324 MCD_chStatus
[i
] = MCD_NO_DMA
;
327 /* Set up pausing mechanism to inactive state: */
328 MCD_dmaBar
->debugComp1
= 0;
329 MCD_dmaBar
->debugComp2
= 0;
330 MCD_dmaBar
->debugControl
= DBG_CTL_DISABLE
;
331 MCD_dmaBar
->debugStatus
= DBG_KILL_ALL_STAT
;
333 /* Enable or disable commbus prefetch */
334 if ((flags
& MCD_COMM_PREFETCH_EN
) != 0)
335 MCD_dmaBar
->ptdControl
&= ~PTD_CTL_COMM_PREFETCH
;
337 MCD_dmaBar
->ptdControl
|= PTD_CTL_COMM_PREFETCH
;
341 /*********************** End of MCD_initDma() ***********************/
343 /********************************************************************/
344 /* Function: MCD_dmaStatus
345 * Purpose: Returns the status of the DMA on the requested channel
346 * Arguments: channel - channel number
347 * Returns: Predefined status indicators
349 int MCD_dmaStatus(int channel
)
353 if ((channel
< 0) || (channel
>= NCHANNELS
))
354 return MCD_CHANNEL_INVALID
;
356 tcrValue
= MCD_dmaBar
->taskControl
[channel
];
357 if ((tcrValue
& TASK_CTL_EN
) == 0) {
358 /* Nothing running if last reported
359 * with task enabled */
360 if (MCD_chStatus
[channel
] == MCD_RUNNING
361 || MCD_chStatus
[channel
] == MCD_IDLE
)
362 MCD_chStatus
[channel
] = MCD_DONE
;
363 } else /* something is running */{
364 /* There are three possibilities:
365 * paused, running or idle. */
366 if (MCD_chStatus
[channel
] == MCD_RUNNING
367 || MCD_chStatus
[channel
] == MCD_IDLE
) {
368 MCD_dmaBar
->ptdDebug
= PTD_DBG_TSK_VLD_INIT
;
369 /* Determine which initiator
371 if ((MCD_dmaBar
->ptdDebug
>> channel
) & 0x1)
372 MCD_chStatus
[channel
] = MCD_RUNNING
;
374 MCD_chStatus
[channel
] = MCD_IDLE
;
375 /* Do not change the status if it is already paused */
378 return MCD_chStatus
[channel
];
380 /******************** End of MCD_dmaStatus() ************************/
382 /********************************************************************/
383 /* Function: MCD_startDma
384 * Ppurpose: Starts a particular kind of DMA
385 * Arguments: see below
386 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
391 /* the channel on which to run the DMA */
393 /* the address to move data from,
394 * or physical buffer-descriptor address */
396 /* the amount to increment the source
397 * address per transfer */
399 /* the address to move data to */
401 /* the amount to increment the
402 * destination address per transfer */
404 /* the number of bytes to transfer
405 * independent of the transfer size */
407 /* the number bytes in of each data
408 * movement (1, 2, or 4) */
410 /* what device initiates the DMA */
412 /* priority of the DMA */
414 /* flags describing the DMA */
416 /* a description of byte swapping,
417 * bit swapping, and CRC actions */
418 #ifdef MCD_NEED_ADDR_TRANS
420 /* virtual buffer descriptor address TBD*/
424 int srcRsdIncr
, destRsdIncr
;
428 #ifdef MCD_INCLUDE_EU
432 if ((channel
< 0) || (channel
>= NCHANNELS
))
433 return MCD_CHANNEL_INVALID
;
435 #ifndef MCD_INCLUDE_EU
436 funcDesc
= MCD_FUNC_NOEU1
;
440 printf("startDma:Setting up params\n");
443 /* Enable task-wise priority */
444 MCD_dmaBar
->ptdControl
|= (u16
) 0x8000;
446 /* Calculate additional parameters
447 * to the regular DMA calls. */
448 srcRsdIncr
= srcIncr
< 0 ? -1 : (srcIncr
> 0 ? 1 : 0);
449 destRsdIncr
= destIncr
< 0 ? -1 : (destIncr
> 0 ? 1 : 0);
450 xferSizeIncr
= (xferSize
& 0xffff) | 0x20000000;
452 /* Remember which variant is running for each channel */
453 MCD_remVariants
.remSrcRsdIncr
[channel
] = srcRsdIncr
;
454 MCD_remVariants
.remDestRsdIncr
[channel
] = destRsdIncr
;
455 MCD_remVariants
.remDestIncr
[channel
] = destIncr
;
456 MCD_remVariants
.remSrcIncr
[channel
] = srcIncr
;
457 MCD_remVariants
.remXferSize
[channel
] = xferSize
;
459 cSave
= (int *)(MCD_taskTable
[channel
].contextSaveSpace
)
463 #ifdef MCD_INCLUDE_EU
464 realFuncArray
= (u32
*)(MCD_taskTable
[channel
].FDTandFlags
468 * Modify the LURC's normal and byte-residue-loop functions
469 * according to parameter.
473 realFuncArray
[(LURC
*16)] = funcDesc
;
476 realFuncArray
[(LURC
*16)] = funcDesc
& 0xfffff00f;
480 realFuncArray
[(LURC
*16)] = funcDesc
& 0xffff000f;
484 realFuncArray
[(LURC
*16 + 1)] = 0
485 | (funcDesc
& MCD_BYTE_SWAP_KILLER
)
486 | MCD_NO_BYTE_SWAP_ATALL
;
489 /* Write the initiator field in the TCR and
490 * set the initiator-hold bit*/
491 MCD_dmaBar
->taskControl
[channel
] = 0
493 | TASK_CTL_HIPRITSKEN
494 | TASK_CTL_HLDINITNUM
;
497 * Current versions of the MPC8220 MCD have a hardware quirk that could
498 * cause the write to the TCR to collide with an MDE access to the
499 * initiator-register file, so we have to verify that the write occurred
500 * correctly by reading back the value. On MCF547x/8x devices and any
501 * future revisions of the MPC8220, this loop will not be entered.
503 while (((MCD_dmaBar
->taskControl
[channel
] & 0x1fff) !=
504 ((initiator
<< 8) | TASK_CTL_HIPRITSKEN
505 | TASK_CTL_HLDINITNUM
)) && (tcrCount
< 1000)) {
507 MCD_dmaBar
->taskControl
[channel
] = 0
509 | TASK_CTL_HIPRITSKEN
510 | TASK_CTL_HLDINITNUM
;
513 MCD_dmaBar
->priority
[channel
] = (u8
)priority
& PRIORITY_PRI_MASK
;
515 if (channel
< 8 && channel
>= 0) {
516 MCD_dmaBar
->taskSize0
&= ~(0xf << (7-channel
)*4);
517 MCD_dmaBar
->taskSize0
518 |= (xferSize
& 3) << (((7 - channel
)*4) + 2);
519 MCD_dmaBar
->taskSize0
520 |= (xferSize
& 3) << ((7 - channel
)*4);
522 MCD_dmaBar
->taskSize1
&= ~(0xf << (15-channel
)*4);
523 MCD_dmaBar
->taskSize1
524 |= (xferSize
& 3) << (((15 - channel
)*4) + 2);
525 MCD_dmaBar
->taskSize1
526 |= (xferSize
& 3) << ((15 - channel
)*4);
529 /* Setup task table flags/options */
530 MCD_taskTable
[channel
].FDTandFlags
&= ~MCD_TT_FLAGS_MASK
;
531 MCD_taskTable
[channel
].FDTandFlags
|= (MCD_TT_FLAGS_MASK
& flags
);
533 if (flags
& MCD_FECTX_DMA
) {
534 /* TDTStart and TDTEnd */
535 MCD_taskTable
[channel
].TDTstart
=
536 MCD_modelTaskTable
[TASK_FECTX
].TDTstart
;
537 MCD_taskTable
[channel
].TDTend
=
538 MCD_modelTaskTable
[TASK_FECTX
].TDTend
;
539 MCD_startDmaENetXmit(srcAddr
, srcAddr
, destAddr
,
540 MCD_taskTable
, channel
);
541 } else if (flags
& MCD_FECRX_DMA
) {
542 /* TDTStart and TDTEnd */
543 MCD_taskTable
[channel
].TDTstart
=
544 MCD_modelTaskTable
[TASK_FECRX
].TDTstart
;
545 MCD_taskTable
[channel
].TDTend
=
546 MCD_modelTaskTable
[TASK_FECRX
].TDTend
;
547 MCD_startDmaENetRcv(srcAddr
, srcAddr
, destAddr
,
548 MCD_taskTable
, channel
);
549 } else if (flags
& MCD_SINGLE_DMA
) {
551 * This buffer descriptor is used for storing off
552 * initial parameters for later progress query
553 * calculation and for the DMA to write the resulting
554 * checksum. The DMA does not use this to determine how
555 * to operate, that info is passed with the init routine
557 MCD_relocBuffDesc
[channel
].srcAddr
= srcAddr
;
558 MCD_relocBuffDesc
[channel
].destAddr
= destAddr
;
559 MCD_relocBuffDesc
[channel
].lastDestAddr
= destAddr
;
560 MCD_relocBuffDesc
[channel
].dmaSize
= dmaSize
;
561 MCD_relocBuffDesc
[channel
].flags
= 0;
563 MCD_relocBuffDesc
[channel
].csumResult
= 0;
565 MCD_relocBuffDesc
[channel
].next
= 0;
568 /* Initialize the progress-querying stuff
569 * to show no progress:*/
570 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
571 SRCPTR
+ CSAVE_OFFSET
] = (int)srcAddr
;
572 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
573 DESTPTR
+ CSAVE_OFFSET
] = (int)destAddr
;
574 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
575 DCOUNT
+ CSAVE_OFFSET
] = 0;
576 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
577 CURRBD
+ CSAVE_OFFSET
] =
578 (u32
) &(MCD_relocBuffDesc
[channel
]);
580 if ((funcDesc
== MCD_FUNC_NOEU1
)
581 || (funcDesc
== MCD_FUNC_NOEU2
)) {
582 /* TDTStart and TDTEnd */
583 MCD_taskTable
[channel
].TDTstart
=
584 MCD_modelTaskTable
[TASK_SINGLENOEU
].TDTstart
;
585 MCD_taskTable
[channel
].TDTend
=
586 MCD_modelTaskTable
[TASK_SINGLENOEU
].TDTend
;
587 MCD_startDmaSingleNoEu(srcAddr
, srcIncr
, destAddr
,
588 destIncr
, dmaSize
, xferSizeIncr
, flags
,
589 (int *)&(MCD_relocBuffDesc
[channel
]),
590 cSave
, MCD_taskTable
, channel
);
592 /* TDTStart and TDTEnd */
593 MCD_taskTable
[channel
].TDTstart
=
594 MCD_modelTaskTable
[TASK_SINGLEEU
].TDTstart
;
595 MCD_taskTable
[channel
].TDTend
=
596 MCD_modelTaskTable
[TASK_SINGLEEU
].TDTend
;
597 MCD_startDmaSingleEu(srcAddr
, srcIncr
, destAddr
,
598 destIncr
, dmaSize
, xferSizeIncr
, flags
,
599 (int *)&(MCD_relocBuffDesc
[channel
]),
600 cSave
, MCD_taskTable
, channel
);
602 } else /* Chained DMA */ {
603 /* Initialize the progress-querying
604 * stuff to show no progress:*/
605 #if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */
606 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
607 SRCPTR
+ CSAVE_OFFSET
]
608 = (int)((MCD_bufDesc
*) srcAddr
)->srcAddr
;
609 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
610 DESTPTR
+ CSAVE_OFFSET
]
611 = (int)((MCD_bufDesc
*) srcAddr
)->destAddr
;
613 /* if using address translation, need the
614 * virtual addr of the first buffdesc */
615 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
616 SRCPTR
+ CSAVE_OFFSET
]
617 = (int)((MCD_bufDesc
*) srcAddrVirt
)->srcAddr
;
618 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
619 DESTPTR
+ CSAVE_OFFSET
]
620 = (int)((MCD_bufDesc
*) srcAddrVirt
)->destAddr
;
622 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
623 DCOUNT
+ CSAVE_OFFSET
] = 0;
624 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
625 CURRBD
+ CSAVE_OFFSET
] = (u32
) srcAddr
;
627 if (funcDesc
== MCD_FUNC_NOEU1
628 || funcDesc
== MCD_FUNC_NOEU2
) {
629 /* TDTStart and TDTEnd */
630 MCD_taskTable
[channel
].TDTstart
=
631 MCD_modelTaskTable
[TASK_CHAINNOEU
].TDTstart
;
632 MCD_taskTable
[channel
].TDTend
=
633 MCD_modelTaskTable
[TASK_CHAINNOEU
].TDTend
;
634 MCD_startDmaChainNoEu((int *)srcAddr
, srcIncr
,
635 destIncr
, xferSize
, xferSizeIncr
, cSave
,
636 MCD_taskTable
, channel
);
638 /* TDTStart and TDTEnd */
639 MCD_taskTable
[channel
].TDTstart
=
640 MCD_modelTaskTable
[TASK_CHAINEU
].TDTstart
;
641 MCD_taskTable
[channel
].TDTend
=
642 MCD_modelTaskTable
[TASK_CHAINEU
].TDTend
;
643 MCD_startDmaChainEu((int *)srcAddr
, srcIncr
, destIncr
,
644 xferSize
, xferSizeIncr
, cSave
,
645 MCD_taskTable
, channel
);
649 MCD_chStatus
[channel
] = MCD_IDLE
;
653 /************************ End of MCD_startDma() *********************/
655 /********************************************************************/
656 /* Function: MCD_XferProgrQuery
657 * Purpose: Returns progress of DMA on requested channel
658 * Arguments: channel - channel to retrieve progress for
659 * progRep - pointer to user supplied MCD_XferProg struct
660 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
663 * MCD_XferProgrQuery() upon completing or after aborting a DMA, or
664 * while the DMA is in progress, this function returns the first
665 * DMA-destination address not (or not yet) used in the DMA. When
666 * encountering a non-ready buffer descriptor, the information for
667 * the last completed descriptor is returned.
669 * MCD_XferProgQuery() has to avoid the possibility of getting
670 * partially-updated information in the event that we should happen
671 * to query DMA progress just as the DMA is updating it. It does that
672 * by taking advantage of the fact context is not saved frequently for
673 * the most part. We therefore read it at least twice until we get the
674 * same information twice in a row.
676 * Because a small, but not insignificant, amount of time is required
677 * to write out the progress-query information, especially upon
678 * completion of the DMA, it would be wise to guarantee some time lag
679 * between successive readings of the progress-query information.
683 * How many iterations of the loop below to execute to stabilize values
687 int MCD_XferProgrQuery(int channel
, MCD_XferProg
*progRep
)
689 MCD_XferProg prevRep
;
691 /* true if we are to try again to get consistent results */
692 int i
; /* used as a time-waste counter */
694 /* Total number of bytes that we think actually got xfered. */
695 int numIterations
; /* number of iterations */
696 int bytesNotXfered
; /* bytes that did not get xfered. */
697 s8
*LWAlignedInitDestAddr
, *LWAlignedCurrDestAddr
;
698 int subModVal
, addModVal
;
699 /* Mode values to added and subtracted from the final destAddr */
701 if ((channel
< 0) || (channel
>= NCHANNELS
))
702 return MCD_CHANNEL_INVALID
;
704 /* Read a trial value for the progress-reporting values*/
705 prevRep
.lastSrcAddr
=
706 (s8
*)((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
707 SRCPTR
+ CSAVE_OFFSET
];
708 prevRep
.lastDestAddr
=
709 (s8
*)((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
710 DESTPTR
+ CSAVE_OFFSET
];
712 ((volatile int *)MCD_taskTable
[channel
].contextSaveSpace
)[
713 DCOUNT
+ CSAVE_OFFSET
];
714 prevRep
.currBufDesc
=
715 (MCD_bufDesc
*)((volatile int *)MCD_taskTable
[
716 channel
].contextSaveSpace
)[CURRBD
+ CSAVE_OFFSET
];
718 /* Repeatedly reread those values until
719 * they match previous values: */
721 /* Take a little bit of time to ensure stability: */
722 for (i
= 0; i
< STABTIME
; i
++)
724 /* make sure this loop does something so that it
725 doesn't get optimized out */
726 /* Check them again: */
727 progRep
->lastSrcAddr
=
728 (s8
*)((volatile int *)MCD_taskTable
[
729 channel
].contextSaveSpace
)[SRCPTR
+ CSAVE_OFFSET
];
730 progRep
->lastDestAddr
=
731 (s8
*)((volatile int *)MCD_taskTable
[
732 channel
].contextSaveSpace
)[DESTPTR
+ CSAVE_OFFSET
];
733 progRep
->dmaSize
= ((volatile int *)MCD_taskTable
[
734 channel
].contextSaveSpace
)[DCOUNT
+ CSAVE_OFFSET
];
735 progRep
->currBufDesc
=
736 (MCD_bufDesc
*)((volatile int *)MCD_taskTable
[
737 channel
].contextSaveSpace
)[CURRBD
+ CSAVE_OFFSET
];
739 /* See if they match: */
740 if (prevRep
.lastSrcAddr
!= progRep
->lastSrcAddr
741 || prevRep
.lastDestAddr
!= progRep
->lastDestAddr
742 || prevRep
.dmaSize
!= progRep
->dmaSize
743 || prevRep
.currBufDesc
!= progRep
->currBufDesc
) {
744 /* If they don't match, remember previous
745 values and try again:*/
746 prevRep
.lastSrcAddr
= progRep
->lastSrcAddr
;
747 prevRep
.lastDestAddr
= progRep
->lastDestAddr
;
748 prevRep
.dmaSize
= progRep
->dmaSize
;
749 prevRep
.currBufDesc
= progRep
->currBufDesc
;
753 } while (again
== MCD_TRUE
);
756 /* Update dmaSize and lastDestAddr */
757 switch (MCD_remVariants
.remDestRsdIncr
[channel
]) {
759 subModVal
= ((int)progRep
->lastDestAddr
)
760 & ((MCD_remVariants
.remXferSize
[channel
]) - 1);
761 addModVal
= ((int)progRep
->currBufDesc
->destAddr
)
762 & ((MCD_remVariants
.remXferSize
[channel
]) - 1);
763 LWAlignedInitDestAddr
= (progRep
->currBufDesc
->destAddr
)
765 LWAlignedCurrDestAddr
= (progRep
->lastDestAddr
) - subModVal
;
766 destDiffBytes
= LWAlignedInitDestAddr
- LWAlignedCurrDestAddr
;
768 (destDiffBytes
/MCD_remVariants
.remDestIncr
[channel
]) *
769 (MCD_remVariants
.remDestIncr
[channel
]
770 + MCD_remVariants
.remXferSize
[channel
]);
771 progRep
->dmaSize
= destDiffBytes
- bytesNotXfered
772 + addModVal
- subModVal
;
775 progRep
->lastDestAddr
= progRep
->currBufDesc
->destAddr
;
778 /* This value has to be subtracted
779 from the final calculated dmaSize. */
780 subModVal
= ((int)progRep
->currBufDesc
->destAddr
)
781 & ((MCD_remVariants
.remXferSize
[channel
]) - 1);
782 /* These bytes are already in lastDestAddr. */
783 addModVal
= ((int)progRep
->lastDestAddr
)
784 & ((MCD_remVariants
.remXferSize
[channel
]) - 1);
785 LWAlignedInitDestAddr
= (progRep
->currBufDesc
->destAddr
)
787 LWAlignedCurrDestAddr
= (progRep
->lastDestAddr
) - addModVal
;
788 destDiffBytes
= (progRep
->lastDestAddr
- LWAlignedInitDestAddr
);
789 numIterations
= (LWAlignedCurrDestAddr
-
790 LWAlignedInitDestAddr
)/MCD_remVariants
.remDestIncr
[channel
];
791 bytesNotXfered
= numIterations
*
792 (MCD_remVariants
.remDestIncr
[channel
]
793 - MCD_remVariants
.remXferSize
[channel
]);
794 progRep
->dmaSize
= destDiffBytes
- bytesNotXfered
- subModVal
;
800 /* This covers M1,P1,Z for source */
801 switch (MCD_remVariants
.remSrcRsdIncr
[channel
]) {
803 progRep
->lastSrcAddr
=
804 progRep
->currBufDesc
->srcAddr
+
805 (MCD_remVariants
.remSrcIncr
[channel
] *
806 (progRep
->dmaSize
/MCD_remVariants
.remXferSize
[channel
]));
809 progRep
->lastSrcAddr
= progRep
->currBufDesc
->srcAddr
;
812 progRep
->lastSrcAddr
=
813 progRep
->currBufDesc
->srcAddr
+
814 (MCD_remVariants
.remSrcIncr
[channel
] *
815 (progRep
->dmaSize
/MCD_remVariants
.remXferSize
[channel
]));
823 /******************* End of MCD_XferProgrQuery() ********************/
825 /********************************************************************/
826 /* MCD_resmActions() does the majority of the actions of a DMA resume.
827 * It is called from MCD_killDma() and MCD_resumeDma(). It has to be
828 * a separate function because the kill function has to negate the task
829 * enable before resuming it, but the resume function has to do nothing
830 * if there is no DMA on that channel (i.e., if the enable bit is 0).
832 static void MCD_resmActions(int channel
)
834 MCD_dmaBar
->debugControl
= DBG_CTL_DISABLE
;
835 MCD_dmaBar
->debugStatus
= MCD_dmaBar
->debugStatus
;
837 /* Determine which initiators are asserted */
838 MCD_dmaBar
->ptdDebug
= PTD_DBG_TSK_VLD_INIT
;
840 if ((MCD_dmaBar
->ptdDebug
>> channel
) & 0x1)
841 MCD_chStatus
[channel
] = MCD_RUNNING
;
843 MCD_chStatus
[channel
] = MCD_IDLE
;
845 /********************* End of MCD_resmActions() *********************/
847 /********************************************************************/
848 /* Function: MCD_killDma
849 * Purpose: Halt the DMA on the requested channel, without any
850 * intention of resuming the DMA.
851 * Arguments: channel - requested channel
852 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
855 * A DMA may be killed from any state, including paused state, and it
856 * always goes to the MCD_HALTED state even if it is killed while in
857 * the MCD_NO_DMA or MCD_IDLE states.
859 int MCD_killDma(int channel
)
861 if ((channel
< 0) || (channel
>= NCHANNELS
))
862 return MCD_CHANNEL_INVALID
;
864 MCD_dmaBar
->taskControl
[channel
] = 0x0;
866 /* Clean up after a paused task */
867 if (MCD_chStatus
[channel
] == MCD_PAUSED
) {
868 MCD_dmaBar
->debugControl
= DBG_CTL_DISABLE
;
869 MCD_dmaBar
->debugStatus
= MCD_dmaBar
->debugStatus
;
872 MCD_chStatus
[channel
] = MCD_HALTED
;
876 /************************ End of MCD_killDma() **********************/
878 /********************************************************************/
879 /* Function: MCD_continDma
880 * Purpose: Continue a DMA which as stopped due to encountering an
881 * unready buffer descriptor.
882 * Arguments: channel - channel to continue the DMA on
883 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
886 * This routine does not check to see if there is a task which can
887 * be continued. Also this routine should not be used with single DMAs.
889 int MCD_continDma(int channel
)
891 if ((channel
< 0) || (channel
>= NCHANNELS
))
892 return MCD_CHANNEL_INVALID
;
894 MCD_dmaBar
->taskControl
[channel
] |= TASK_CTL_EN
;
895 MCD_chStatus
[channel
] = MCD_RUNNING
;
899 /********************** End of MCD_continDma() **********************/
901 /*********************************************************************
902 * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
903 * to freeze a task and resume it. We freeze a task by breakpointing
904 * on the stated task. That is, not any specific place in the task,
905 * but any time that task executes. In particular, when that task
906 * executes, we want to freeze that task and only that task.
908 * The bits of the debug control register influence interrupts vs.
909 * breakpoints as follows:
910 * - Bits 14 and 0 enable or disable debug functions. If enabled, you
911 * will get the interrupt but you may or may not get a breakpoint.
912 * - Bits 2 and 1 decide whether you also get a breakpoint in addition
915 * The debug unit can do these actions in response to either internally
916 * detected breakpoint conditions from the comparators, or in response
917 * to the external breakpoint pin, or both.
918 * - Bits 14 and 1 perform the above-described functions for
919 * internally-generated conditions, i.e., the debug comparators.
920 * - Bits 0 and 2 perform the above-described functions for external
921 * conditions, i.e., the breakpoint external pin.
923 * Note that, although you "always" get the interrupt when you turn
924 * the debug functions, the interrupt can nevertheless, if desired, be
925 * masked by the corresponding bit in the PTD's IMR. Note also that
926 * this means that bits 14 and 0 must enable debug functions before
927 * bits 1 and 2, respectively, have any effect.
929 * NOTE: It's extremely important to not pause more than one DMA channel
931 ********************************************************************/
933 /********************************************************************/
934 /* Function: MCD_pauseDma
935 * Purpose: Pauses the DMA on a given channel (if any DMA is running
938 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
940 int MCD_pauseDma(int channel
)
942 if ((channel
< 0) || (channel
>= NCHANNELS
))
943 return MCD_CHANNEL_INVALID
;
945 if (MCD_dmaBar
->taskControl
[channel
] & TASK_CTL_EN
) {
946 MCD_dmaBar
->debugComp1
= channel
;
947 MCD_dmaBar
->debugControl
=
948 DBG_CTL_ENABLE
| (1 << (channel
+ 16));
949 MCD_chStatus
[channel
] = MCD_PAUSED
;
954 /************************* End of MCD_pauseDma() ********************/
956 /********************************************************************/
957 /* Function: MCD_resumeDma
958 * Purpose: Resumes the DMA on a given channel (if any DMA is
959 * running on that channel).
960 * Arguments: channel - channel on which to resume DMA
961 * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
963 int MCD_resumeDma(int channel
)
965 if ((channel
< 0) || (channel
>= NCHANNELS
))
966 return MCD_CHANNEL_INVALID
;
968 if (MCD_dmaBar
->taskControl
[channel
] & TASK_CTL_EN
)
969 MCD_resmActions(channel
);
973 /************************ End of MCD_resumeDma() ********************/
975 /********************************************************************/
976 /* Function: MCD_csumQuery
977 * Purpose: Provide the checksum after performing a non-chained DMA
978 * Arguments: channel - channel to report on
979 * csum - pointer to where to write the checksum/CRC
980 * Returns: MCD_ERROR if the channel is invalid, else MCD_OK
985 int MCD_csumQuery(int channel
, u32
*csum
)
987 #ifdef MCD_INCLUDE_EU
988 if ((channel
< 0) || (channel
>= NCHANNELS
))
989 return MCD_CHANNEL_INVALID
;
991 *csum
= MCD_relocBuffDesc
[channel
].csumResult
;
997 /*********************** End of MCD_resumeDma() *********************/
999 /********************************************************************/
1000 /* Function: MCD_getCodeSize
1001 * Purpose: Provide the size requirements of the microcoded tasks
1002 * Returns: Size in bytes
1004 int MCD_getCodeSize(void)
1006 #ifdef MCD_INCLUDE_EU
1012 /********************** End of MCD_getCodeSize() ********************/
1014 /********************************************************************/
1015 /* Function: MCD_getVersion
1016 * Purpose: Provide the version string and number
1017 * Arguments: longVersion - user supplied pointer to a pointer to a char
1018 * which points to the version string
1019 * Returns: Version number and version string (by reference)
1021 char MCD_versionString
[] = "Multi-channel DMA API v1.0";
1022 #define MCD_REV_MAJOR 0x01
1023 #define MCD_REV_MINOR 0x00
1025 int MCD_getVersion(char **longVersion
)
1028 *longVersion
= MCD_versionString
;
1029 ret
= (MCD_REV_MAJOR
<< 8) | MCD_REV_MINOR
;
1032 /********************** End of MCD_getVersion() *********************/
1034 /********************************************************************/
1035 /* Private version of memcpy()
1036 * Note that everything this is used for is longword-aligned.
1038 static void MCD_memcpy(int *dest
, int *src
, u32 size
)
1042 for (i
= 0; i
< size
; i
+= sizeof(int), dest
++, src
++)
1045 /********************************************************************/