source: rtems/bsps/m68k/genmcf548x/mcdma/MCD_dmaApi.c @ d7d66d7

5
Last change on this file since d7d66d7 was 945095d, checked in by Sebastian Huber <sebastian.huber@…>, on 03/26/18 at 11:08:07

bsps/genmcf548x: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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