blob: af0e134522004a907bfbe99dcc33e3f1be7cc5f0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
TsiChungLiewaeaad402008-01-15 13:52:03 -06002/*
3 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
TsiChungLiewaeaad402008-01-15 13:52:03 -06004 */
5
6/*Main C file for multi-channel DMA API. */
7
8#include <common.h>
9
TsiChungLiewaeaad402008-01-15 13:52:03 -060010#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 */
16dmaRegs *MCD_dmaBar;
17
18/*
19 * These are the real and model task tables as generated by the
20 * build process
21 */
22extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
23extern 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 */
29volatile TaskTableEntry *MCD_taskTable;
30TaskTableEntry *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 */
37static 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 */
45static void MCD_memcpy(int *dest, int *src, u32 size);
46static 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
54extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
55#else
56MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
57#endif
58MCD_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 */
103typedef struct MCD_remVariants_struct MCD_remVariant;
104struct 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 */
113MCD_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 */
127extern u32 MCD_funcDescTab0[];
128
129int 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 */
308int 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
359int 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;
TsiChung Liew9a8669c2009-07-22 18:42:45 +0000472 MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
473 (char *)destAddr, MCD_taskTable,
TsiChungLiewaeaad402008-01-15 13:52:03 -0600474 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;
TsiChung Liew9a8669c2009-07-22 18:42:45 +0000481 MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
482 (char *)destAddr, MCD_taskTable,
TsiChungLiewaeaad402008-01-15 13:52:03 -0600483 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;
TsiChung Liew9a8669c2009-07-22 18:42:45 +0000520 MCD_startDmaSingleNoEu((char *)srcAddr, srcIncr,
521 (char *)destAddr, destIncr,
522 (int)dmaSize, xferSizeIncr,
TsiChungLiewaeaad402008-01-15 13:52:03 -0600523 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;
TsiChung Liew9a8669c2009-07-22 18:42:45 +0000532 MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
533 (char *)destAddr, destIncr,
534 (int)dmaSize, xferSizeIncr,
TsiChungLiewaeaad402008-01-15 13:52:03 -0600535 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
622int 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 */
776static 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 */
804int 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 */
843int 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 */
895int 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 */
927int 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 */
950int 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 */
970int 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 */
988char 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
992int 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 */
1004static 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}