Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:45

0001 /*
0002  * File:        MCD_dmaApi.c
0003  * Purpose:     Main C file for multi-channel DMA API.
0004  *
0005  * Notes:
0006  */
0007 
0008 #include <mcf548x/MCD_dma.h>
0009 #include <mcf548x/MCD_tasksInit.h>
0010 #include <mcf548x/MCD_progCheck.h>
0011 
0012 /********************************************************************/
0013 /*
0014  * This is an API-internal pointer to the DMA's registers
0015  */
0016 dmaRegs *MCD_dmaBar;
0017 
0018 /*
0019  * These are the real and model task tables as generated by the
0020  * build process
0021  */
0022 extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
0023 extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
0024 
0025 /*
0026  * However, this (usually) gets relocated to on-chip SRAM, at which
0027  * point we access them as these tables
0028  */
0029 volatile TaskTableEntry *MCD_taskTable;
0030 TaskTableEntry *MCD_modelTaskTable;
0031 
0032 
0033 /*
0034  * MCD_chStatus[] is an array of status indicators for remembering
0035  * whether a DMA has ever been attempted on each channel, pausing
0036  * status, etc.
0037  */
0038 static int MCD_chStatus[NCHANNELS] =
0039 {
0040     MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
0041     MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
0042     MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
0043     MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
0044 };
0045 
0046 /*
0047  * Prototypes for local functions
0048  */
0049 static void MCD_memcpy (int *dest, int *src, u32 size);
0050 static void MCD_resmActions (int channel);
0051 
0052 /*
0053  * Buffer descriptors used for storage of progress info for single Dmas
0054  * Also used as storage for the DMA for CRCs for single DMAs
0055  * Otherwise, the DMA does not parse these buffer descriptors
0056  */
0057 #ifdef MCD_INCLUDE_EU
0058 extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
0059 #else
0060 MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
0061 #endif
0062 MCD_bufDesc *MCD_relocBuffDesc;
0063 
0064 
0065 /*
0066  * Defines for the debug control register's functions
0067  */
0068 #define DBG_CTL_COMP1_TASK  (0x00002000) /* have comparator 1 look for a task # */
0069 #define DBG_CTL_ENABLE      (DBG_CTL_AUTO_ARM    | \
0070                              DBG_CTL_BREAK       | \
0071                              DBG_CTL_INT_BREAK   | \
0072                              DBG_CTL_COMP1_TASK)
0073 #define DBG_CTL_DISABLE     (DBG_CTL_AUTO_ARM    | \
0074                              DBG_CTL_INT_BREAK   | \
0075                              DBG_CTL_COMP1_TASK)
0076 #define DBG_KILL_ALL_STAT   (0xFFFFFFFF)
0077 
0078 /*
0079  * Offset to context save area where progress info is stored
0080  */
0081 #define CSAVE_OFFSET        10
0082 
0083 /*
0084  * Defines for Byte Swapping
0085  */
0086 #define MCD_BYTE_SWAP_KILLER    0xFFF8888F
0087 #define MCD_NO_BYTE_SWAP_ATALL  0x00040000
0088 
0089 /*
0090  * Execution Unit Identifiers
0091  */
0092 #define MAC  0  /* legacy - not used */
0093 #define LUAC 1  /* legacy - not used */
0094 #define CRC  2  /* legacy - not used */
0095 #define LURC 3  /* Logic Unit with CRC */
0096 
0097 /*
0098  * Task Identifiers
0099  */
0100 #define TASK_CHAINNOEU  0
0101 #define TASK_SINGLENOEU 1
0102 #ifdef MCD_INCLUDE_EU
0103 #define TASK_CHAINEU    2
0104 #define TASK_SINGLEEU   3
0105 #define TASK_FECRX      4
0106 #define TASK_FECTX      5
0107 #else
0108 #define TASK_CHAINEU    0
0109 #define TASK_SINGLEEU   1
0110 #define TASK_FECRX      2
0111 #define TASK_FECTX      3
0112 #endif
0113 
0114 /*
0115  * Structure to remember which variant is on which channel
0116  * TBD- need this?
0117  */
0118 typedef struct MCD_remVariants_struct MCD_remVariant;
0119 struct MCD_remVariants_struct
0120 {
0121    int remDestRsdIncr[NCHANNELS];  /* -1,0,1 */
0122    int remSrcRsdIncr[NCHANNELS];   /* -1,0,1 */
0123    s16 remDestIncr[NCHANNELS];     /* DestIncr */
0124    s16 remSrcIncr[NCHANNELS];      /* srcIncr */
0125    u32 remXferSize[NCHANNELS];     /* xferSize */
0126 };
0127 
0128 /*
0129  * Structure to remember the startDma parameters for each channel
0130  */
0131 MCD_remVariant MCD_remVariants;
0132 /********************************************************************/
0133 /*
0134  * Function: MCD_initDma
0135  * Purpose:  Initializes the DMA API by setting up a pointer to the DMA
0136  *           registers, relocating and creating the appropriate task
0137  *           structures, and setting up some global settings
0138  * Arguments:
0139  *  dmaBarAddr    - pointer to the multichannel DMA registers
0140  *  taskTableDest - location to move DMA task code and structs to
0141  *  flags         - operational parameters
0142  * Return Value:
0143  *  MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
0144  *  MCD_OK otherwise
0145  */
0146 extern u32 MCD_funcDescTab0[];
0147 
0148 int MCD_initDma (dmaRegs *dmaBarAddr, void *taskTableDest, u32 flags)
0149 {
0150     int i;
0151     TaskTableEntry *entryPtr;
0152 
0153     /* setup the local pointer to register set */
0154     MCD_dmaBar = dmaBarAddr;
0155 
0156     /* do we need to move/create a task table */
0157     if ((flags & MCD_RELOC_TASKS) != 0)
0158     {
0159         int fixedSize;
0160         u32 *fixedPtr;
0161         /*int *tablePtr = taskTableDest;TBD*/
0162         int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
0163         int taskDescTabsOffset;
0164         int taskTableSize, varTabsSize, funcDescTabsSize, contextSavesSize;
0165         int taskDescTabSize;
0166 
0167         int i;
0168 
0169         /* check if physical address is aligned on 512 byte boundary */
0170         if (((u32)taskTableDest & 0x000001ff) != 0)
0171             return(MCD_TABLE_UNALIGNED);
0172 
0173         MCD_taskTable = taskTableDest; /* set up local pointer to task Table */
0174 
0175         /*
0176          * Create a task table:
0177          * - compute aligned base offsets for variable tables and
0178          *   function descriptor tables, then
0179          * - loop through the task table and setup the pointers
0180          * - copy over model task table with the the actual task descriptor
0181          *   tables
0182          */
0183 
0184         taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
0185         /* align variable tables to size */
0186         varTabsOffset = taskTableSize + (u32)taskTableDest;
0187         if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
0188             varTabsOffset = (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
0189         /* align function descriptor tables */
0190         varTabsSize = NCHANNELS * VAR_TAB_SIZE;
0191         funcDescTabsOffset = varTabsOffset + varTabsSize;
0192 
0193         if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
0194             funcDescTabsOffset = (funcDescTabsOffset + FUNCDESC_TAB_SIZE) &
0195             (~FUNCDESC_TAB_SIZE);
0196 
0197         funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
0198         contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
0199         contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
0200         fixedSize = taskTableSize + varTabsSize + funcDescTabsSize +
0201                     contextSavesSize;
0202 
0203         /* zero the thing out */
0204         fixedPtr = (u32 *)taskTableDest;
0205         for (i = 0;i<(fixedSize/4);i++)
0206             fixedPtr[i] = 0;
0207 
0208         entryPtr = (TaskTableEntry*)MCD_taskTable;
0209         /* set up fixed pointers */
0210         for (i = 0; i < NCHANNELS; i++)
0211         {
0212             entryPtr[i].varTab = (u32)varTabsOffset; /* update ptr to local value */
0213             entryPtr[i].FDTandFlags = (u32)funcDescTabsOffset | MCD_TT_FLAGS_DEF;
0214             entryPtr[i].contextSaveSpace = (u32)contextSavesOffset;
0215             varTabsOffset += VAR_TAB_SIZE;
0216 #ifdef MCD_INCLUDE_EU /* if not there is only one, just point to the same one */
0217             funcDescTabsOffset += FUNCDESC_TAB_SIZE;
0218 #endif
0219             contextSavesOffset += CONTEXT_SAVE_SIZE;
0220         }
0221         /* copy over the function descriptor table */
0222         for ( i = 0; i < FUNCDESC_TAB_NUM; i++)
0223         {
0224             MCD_memcpy((void*)(entryPtr[i].FDTandFlags & ~MCD_TT_FLAGS_MASK),
0225                        (void*)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
0226         }
0227 
0228         /* copy model task table to where the context saves stuff leaves off*/
0229         MCD_modelTaskTable = (TaskTableEntry*)contextSavesOffset;
0230 
0231         MCD_memcpy ((void*)MCD_modelTaskTable, (void*)MCD_modelTaskTableSrc,
0232                     NUMOFVARIANTS * sizeof(TaskTableEntry));
0233 
0234         entryPtr = MCD_modelTaskTable; /* point to local version of
0235                                                             model task table */
0236         taskDescTabsOffset = (u32)MCD_modelTaskTable +
0237                             (NUMOFVARIANTS * sizeof(TaskTableEntry));
0238 
0239         /* copy actual task code and update TDT ptrs in local model task table */
0240         for (i = 0; i < NUMOFVARIANTS; i++)
0241         {
0242             taskDescTabSize = entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
0243             MCD_memcpy ((void*)taskDescTabsOffset, (void*)entryPtr[i].TDTstart, taskDescTabSize);
0244             entryPtr[i].TDTstart = (u32)taskDescTabsOffset;
0245             taskDescTabsOffset += taskDescTabSize;
0246             entryPtr[i].TDTend = (u32)taskDescTabsOffset - 4;
0247         }
0248 #ifdef MCD_INCLUDE_EU /* Tack single DMA BDs onto end of code so API controls
0249                          where they are since DMA might write to them */
0250         MCD_relocBuffDesc = (MCD_bufDesc*)(entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
0251 #else /* DMA does not touch them so they can be wherever and we don't need to
0252          waste SRAM on them */
0253         MCD_relocBuffDesc = MCD_singleBufDescs;
0254 #endif
0255     }
0256     else
0257     {
0258         /* point the would-be relocated task tables and the
0259         buffer descriptors to the ones the linker generated */
0260 
0261         if (((u32)MCD_realTaskTableSrc & 0x000001ff) != 0)
0262             return(MCD_TABLE_UNALIGNED);
0263 
0264         /* need to add code to make sure that every thing else is aligned properly TBD*/
0265         /* this is problematic if we init more than once or after running tasks,
0266             need to add variable to see if we have aleady init'd */
0267         entryPtr = MCD_realTaskTableSrc;
0268         for (i = 0; i < NCHANNELS; i++)
0269         {
0270             if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
0271                 ((entryPtr[i].FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
0272                 return(MCD_TABLE_UNALIGNED);
0273         }
0274 
0275         MCD_taskTable = MCD_realTaskTableSrc;
0276         MCD_modelTaskTable = MCD_modelTaskTableSrc;
0277         MCD_relocBuffDesc = MCD_singleBufDescs;
0278     }
0279 
0280 
0281     /* Make all channels as totally inactive, and remember them as such: */
0282 
0283     MCD_dmaBar->taskbar = (u32) MCD_taskTable;
0284     for (i = 0;  i < NCHANNELS;  i++)
0285     {
0286         MCD_dmaBar->taskControl[i] = 0x0;
0287         MCD_chStatus[i] = MCD_NO_DMA;
0288     }
0289 
0290    /* Set up pausing mechanism to inactive state: */
0291     MCD_dmaBar->debugComp1 = 0;  /* no particular values yet for either comparator registers */
0292     MCD_dmaBar->debugComp2 = 0;
0293     MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
0294     MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
0295 
0296     /* enable or disable commbus prefetch, really need an ifdef or
0297        something to keep from trying to set this in the 8220 */
0298     if ((flags & MCD_COMM_PREFETCH_EN) != 0)
0299         MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
0300     else
0301         MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
0302 
0303     return(MCD_OK);
0304 }
0305 /*********************** End of MCD_initDma() ***********************/
0306 
0307 /********************************************************************/
0308 /* Function:   MCD_dmaStatus
0309  * Purpose:    Returns the status of the DMA on the requested channel
0310  * Arguments:  channel - channel number
0311  * Returns:    Predefined status indicators
0312  */
0313 int MCD_dmaStatus (int channel)
0314 {
0315     u16 tcrValue;
0316 
0317     if((channel < 0) || (channel >= NCHANNELS))
0318         return(MCD_CHANNEL_INVALID);
0319 
0320     tcrValue = MCD_dmaBar->taskControl[channel];
0321     if ((tcrValue & TASK_CTL_EN) == 0)
0322     {  /* nothing running */
0323         /* if last reported with task enabled */
0324         if (   MCD_chStatus[channel] == MCD_RUNNING
0325             || MCD_chStatus[channel] == MCD_IDLE)
0326             MCD_chStatus[channel] = MCD_DONE;
0327     }
0328     else /* something is running */
0329     {
0330         /* There are three possibilities: paused, running or idle. */
0331         if (   MCD_chStatus[channel] == MCD_RUNNING
0332             || MCD_chStatus[channel] == MCD_IDLE)
0333         {
0334             MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
0335             /* This register is selected to know which initiator is
0336             actually asserted. */
0337             if ((MCD_dmaBar->ptdDebug >> channel ) & 0x1 )
0338                 MCD_chStatus[channel] = MCD_RUNNING;
0339             else
0340                 MCD_chStatus[channel] = MCD_IDLE;
0341         /* do not change the status if it is already paused. */
0342         }
0343     }
0344     return MCD_chStatus[channel];
0345 }
0346 /******************** End of MCD_dmaStatus() ************************/
0347 
0348 /********************************************************************/
0349 /* Function:    MCD_startDma
0350  * Ppurpose:    Starts a particular kind of DMA
0351  * Arguments:   see below
0352  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0353  */
0354 
0355 int MCD_startDma (
0356     int  channel,   /* the channel on which to run the DMA */
0357     s8   *srcAddr,  /* the address to move data from, or physical buffer-descriptor address */
0358     s16  srcIncr,   /* the amount to increment the source address per transfer */
0359     s8   *destAddr, /* the address to move data to */
0360     s16  destIncr,  /* the amount to increment the destination address per transfer */
0361     u32  dmaSize,   /* the number of bytes to transfer independent of the transfer size */
0362     u32  xferSize,  /* the number bytes in of each data movement (1, 2, or 4) */
0363     u32  initiator, /* what device initiates the DMA */
0364     int  priority,  /* priority of the DMA */
0365     u32  flags,     /* flags describing the DMA */
0366     u32  funcDesc   /* a description of byte swapping, bit swapping, and CRC actions */
0367 #ifdef MCD_NEED_ADDR_TRANS
0368     s8   *srcAddrVirt /* virtual buffer descriptor address TBD*/
0369 #endif
0370 )
0371 {
0372     int srcRsdIncr, destRsdIncr;
0373     int *cSave;
0374     short xferSizeIncr;
0375     int tcrCount = 0;
0376 #ifdef MCD_INCLUDE_EU
0377     u32 *realFuncArray;
0378 #endif
0379 
0380     if((channel < 0) || (channel >= NCHANNELS))
0381         return(MCD_CHANNEL_INVALID);
0382 
0383     /* tbd - need to determine the proper response to a bad funcDesc when not
0384        including EU functions, for now, assign a benign funcDesc, but maybe
0385        should return an error */
0386 #ifndef MCD_INCLUDE_EU
0387     funcDesc = MCD_FUNC_NOEU1;
0388 #endif
0389 
0390 #ifdef MCD_DEBUG
0391 printf("startDma:Setting up params\n");
0392 #endif
0393    /* Set us up for task-wise priority.  We don't technically need to do this on every start, but
0394       since the register involved is in the same longword as other registers that users are in control
0395       of, setting it more than once is probably preferable.  That since the documentation doesn't seem
0396       to be completely consistent about the nature of the PTD control register. */
0397     MCD_dmaBar->ptdControl |= (u16) 0x8000;
0398 #if 1 /* Not sure what we need to keep here rtm TBD */
0399     /* Calculate additional parameters to the regular DMA calls. */
0400     srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
0401     destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
0402 
0403     xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
0404 
0405     /* Remember for each channel which variant is running. */
0406     MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
0407     MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
0408     MCD_remVariants.remDestIncr[channel] = destIncr;
0409     MCD_remVariants.remSrcIncr[channel] = srcIncr;
0410     MCD_remVariants.remXferSize[channel] = xferSize;
0411 #endif
0412 
0413     cSave = (int*)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET + CURRBD;
0414 
0415 #ifdef MCD_INCLUDE_EU /* may move this to EU specific calls */
0416     realFuncArray = (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
0417     /* Modify the LURC's normal and byte-residue-loop functions according to parameter. */
0418     realFuncArray[(LURC*16)] = xferSize == 4 ?
0419                                  funcDesc : xferSize == 2 ?
0420                                      funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
0421     realFuncArray[(LURC*16+1)] = (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
0422 #endif
0423    /* Write the initiator field in the TCR, and also set the initiator-hold
0424       bit.  Note that,due to a hardware quirk, this could collide with an
0425       MDE access to the initiator-register file, so we have to verify that the write
0426       reads back correctly. */
0427 
0428     MCD_dmaBar->taskControl[channel] =
0429         (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
0430 
0431     while(((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
0432           ((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM)) &&
0433             (tcrCount < 1000))
0434     {
0435         tcrCount++;
0436         /*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020;*/
0437         MCD_dmaBar->taskControl[channel] =
0438             (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
0439     }
0440 
0441     MCD_dmaBar->priority[channel] = (u8)priority & PRIORITY_PRI_MASK;
0442     /* should be albe to handle this stuff with only one write to ts reg - tbd */
0443     if (channel < 8 && channel >= 0)
0444     {
0445         MCD_dmaBar->taskSize0 &= ~(0xf << (7-channel)*4);
0446         MCD_dmaBar->taskSize0 |= (xferSize & 3) << (((7 - channel)*4) + 2);
0447         MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel)*4);
0448     }
0449     else
0450     {
0451         MCD_dmaBar->taskSize1 &= ~(0xf << (15-channel)*4);
0452         MCD_dmaBar->taskSize1 |= (xferSize & 3) << (((15 - channel)*4) + 2);
0453         MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel)*4);
0454     }
0455 
0456     /* setup task table flags/options which mostly control the line buffers */
0457     MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
0458     MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
0459 
0460     if (flags & MCD_FECTX_DMA)
0461     {
0462         /* TDTStart and TDTEnd */
0463         MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECTX].TDTstart;
0464         MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECTX].TDTend;
0465         MCD_startDmaENetXmit(srcAddr, srcAddr, destAddr, MCD_taskTable, channel);
0466     }
0467     else if (flags & MCD_FECRX_DMA)
0468     {
0469         /* TDTStart and TDTEnd */
0470         MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECRX].TDTstart;
0471         MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECRX].TDTend;
0472         MCD_startDmaENetRcv(srcAddr, srcAddr, destAddr, MCD_taskTable, channel);
0473     }
0474     else if(flags & MCD_SINGLE_DMA)
0475     {
0476         /* this buffer descriptor is used for storing off initial parameters for later
0477            progress query calculation and for the DMA to write the resulting checksum
0478            The DMA does not use this to determine how to operate, that info is passed
0479            with the init routine*/
0480         MCD_relocBuffDesc[channel].srcAddr = srcAddr;
0481         MCD_relocBuffDesc[channel].destAddr = destAddr;
0482         MCD_relocBuffDesc[channel].lastDestAddr = destAddr;  /* definitely not its final value */
0483         MCD_relocBuffDesc[channel].dmaSize = dmaSize;
0484         MCD_relocBuffDesc[channel].flags = 0;       /* not used */
0485         MCD_relocBuffDesc[channel].csumResult = 0;  /* not used */
0486         MCD_relocBuffDesc[channel].next = 0;        /* not used */
0487 
0488         /* Initialize the progress-querying stuff to show no progress:*/
0489         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
0490         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
0491         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
0492         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
0493                                              (u32) &(MCD_relocBuffDesc[channel]);
0494         /* tbd - need to keep the user from trying to call the EU routine
0495            when MCD_INCLUDE_EU is not defined */
0496         if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2)
0497         {
0498            /* TDTStart and TDTEnd */
0499            MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
0500            MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
0501            MCD_startDmaSingleNoEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize,
0502                                 xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), cSave,
0503                                 MCD_taskTable, channel);
0504         }
0505         else
0506         {
0507            /* TDTStart and TDTEnd */
0508            MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
0509            MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
0510            MCD_startDmaSingleEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize,
0511                               xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), cSave,
0512                               MCD_taskTable, channel);
0513         }
0514     }
0515     else
0516     { /* chained DMAS */
0517         /* Initialize the progress-querying stuff to show no progress:*/
0518 #if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */
0519         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
0520           = (int)((MCD_bufDesc*) srcAddr)->srcAddr;
0521         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
0522           = (int)((MCD_bufDesc*) srcAddr)->destAddr;
0523 #else /* if using address translation, need the virtual addr of the first buffdesc */
0524         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
0525           = (int)((MCD_bufDesc*) srcAddrVirt)->srcAddr;
0526         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
0527           = (int)((MCD_bufDesc*) srcAddrVirt)->destAddr;
0528 #endif
0529         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
0530         ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
0531 
0532         if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2)
0533         {
0534           /*TDTStart and TDTEnd*/
0535           MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
0536           MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
0537           MCD_startDmaChainNoEu((int *)srcAddr, srcIncr, destIncr, xferSize,
0538                                     xferSizeIncr, cSave, MCD_taskTable, channel);
0539         }
0540         else
0541         {
0542           /*TDTStart and TDTEnd*/
0543           MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
0544           MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINEU].TDTend;
0545           MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr, xferSize,
0546                                  xferSizeIncr, cSave, MCD_taskTable, channel);
0547         }
0548     }
0549     MCD_chStatus[channel] = MCD_IDLE;
0550     return(MCD_OK);
0551 }
0552 
0553 /************************ End of MCD_startDma() *********************/
0554 
0555 /********************************************************************/
0556 /* Function:    MCD_XferProgrQuery
0557  * Purpose:     Returns progress of DMA on requested channel
0558  * Arguments:   channel - channel to retrieve progress for
0559  *              progRep - pointer to user supplied MCD_XferProg struct
0560  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0561  *
0562  * Notes:
0563  *  MCD_XferProgrQuery() upon completing or after aborting a DMA, or
0564  *  while the DMA is in progress, this function returns the first
0565  *  DMA-destination address not (or not yet) used in the DMA. When
0566  *  encountering a non-ready buffer descriptor, the information for
0567  *  the last completed descriptor is returned.
0568  *
0569  *  MCD_XferProgQuery() has to avoid the possibility of getting
0570  *  partially-updated information in the event that we should happen
0571  *  to query DMA progress just as the DMA is updating it. It does that
0572  *  by taking advantage of the fact context is not saved frequently for
0573  *  the most part. We therefore read it at least twice until we get the
0574  *  same information twice in a row.
0575  *
0576  *  Because a small, but not insignificant, amount of time is required
0577  *  to write out the progress-query information, especially upon
0578  *  completion of the DMA, it would be wise to guarantee some time lag
0579  *  between successive readings of the progress-query information.
0580  */
0581 
0582 /*
0583  * How many iterations of the loop below to execute to stabilize values
0584  */
0585 #define STABTIME 0
0586 
0587 int MCD_XferProgrQuery (int channel, MCD_XferProg *progRep)
0588 {
0589     MCD_XferProg prevRep;
0590     int again;  /* true if we are to try again to get consistent results */
0591     int i;  /* used as a time-waste counter */
0592     int destDiffBytes; /* Total number of bytes that we think actually got xfered. */
0593     int numIterations; /* number of iterations */
0594     int bytesNotXfered; /* bytes that did not get xfered. */
0595     s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
0596     int subModVal, addModVal; /* Mode values to added and subtracted from the
0597                                 final destAddr */
0598 
0599     if((channel < 0) || (channel >= NCHANNELS))
0600         return(MCD_CHANNEL_INVALID);
0601 
0602     /* Read a trial value for the progress-reporting values*/
0603     prevRep.lastSrcAddr =
0604           (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
0605     prevRep.lastDestAddr =
0606           (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
0607     prevRep.dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
0608     prevRep.currBufDesc =
0609           (MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET];
0610     /* Repeatedly reread those values until they match previous values: */
0611     do {
0612         /* Waste a little bit of time to ensure stability: */
0613         for (i = 0;  i < STABTIME;  i++)
0614             i += i >> 2;  /* make sure this loop does something so that it doesn't get optimized out */
0615         /* Check them again: */
0616         progRep->lastSrcAddr =
0617             (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
0618         progRep->lastDestAddr =
0619             (s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
0620         progRep->dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
0621         progRep->currBufDesc =
0622             (MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET];
0623        /* See if they match: */
0624        if (   prevRep.lastSrcAddr != progRep->lastSrcAddr
0625            || prevRep.lastDestAddr != progRep->lastDestAddr
0626            || prevRep.dmaSize != progRep->dmaSize
0627            || prevRep.currBufDesc != progRep->currBufDesc)
0628        {
0629           /* If they don't match, remember previous values and try again:*/
0630           prevRep.lastSrcAddr = progRep->lastSrcAddr;
0631           prevRep.lastDestAddr = progRep->lastDestAddr;
0632           prevRep.dmaSize = progRep->dmaSize;
0633           prevRep.currBufDesc = progRep->currBufDesc;
0634           again = MCD_TRUE;
0635        }
0636        else
0637           again = MCD_FALSE;
0638     } while (again == MCD_TRUE);
0639 
0640 
0641     /* Update the dCount, srcAddr and destAddr */
0642     /* To calculate dmaCount, we consider destination address. C
0643        overs M1,P1,Z for destination */
0644     switch(MCD_remVariants.remDestRsdIncr[channel]) {
0645         case MINUS1:
0646            subModVal = ((int)progRep->lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
0647            addModVal = ((int)progRep->currBufDesc->destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
0648            LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - addModVal;
0649            LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
0650            destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
0651            bytesNotXfered = (destDiffBytes/MCD_remVariants.remDestIncr[channel]) *
0652                             ( MCD_remVariants.remDestIncr[channel]
0653                             + MCD_remVariants.remXferSize[channel]);
0654            progRep->dmaSize = destDiffBytes - bytesNotXfered + addModVal - subModVal;
0655            break;
0656         case ZERO:
0657            progRep->lastDestAddr = progRep->currBufDesc->destAddr;
0658            break;
0659         case PLUS1:
0660            /* This value has to be subtracted from the final calculated dCount. */
0661            subModVal = ((int)progRep->currBufDesc->destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
0662            /* These bytes are already in lastDestAddr. */
0663             addModVal = ((int)progRep->lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
0664             LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - subModVal;
0665             LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
0666             destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
0667             numIterations = ( LWAlignedCurrDestAddr - LWAlignedInitDestAddr)/MCD_remVariants.remDestIncr[channel];
0668             bytesNotXfered =  numIterations *
0669                 ( MCD_remVariants.remDestIncr[channel]
0670                   - MCD_remVariants.remXferSize[channel]);
0671            progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
0672            break;
0673         default:
0674            break;
0675     }
0676 
0677     /* This covers M1,P1,Z for source */
0678     switch(MCD_remVariants.remSrcRsdIncr[channel]) {
0679         case MINUS1:
0680             progRep->lastSrcAddr =
0681                 progRep->currBufDesc->srcAddr +
0682                  ( MCD_remVariants.remSrcIncr[channel] *
0683                    (progRep->dmaSize/MCD_remVariants.remXferSize[channel]));
0684             break;
0685         case ZERO:
0686             progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
0687             break;
0688        case PLUS1:
0689             progRep->lastSrcAddr =
0690                 progRep->currBufDesc->srcAddr +
0691                  ( MCD_remVariants.remSrcIncr[channel] *
0692                    (progRep->dmaSize/MCD_remVariants.remXferSize[channel]));
0693           break;
0694        default: break;
0695     }
0696 
0697     return(MCD_OK);
0698 }
0699 /******************* End of MCD_XferProgrQuery() ********************/
0700 
0701 /********************************************************************/
0702 /* MCD_resmActions() does the majority of the actions of a DMA resume.
0703  * It is called from MCD_killDma() and MCD_resumeDma().  It has to be
0704  * a separate function because the kill function has to negate the task
0705  * enable before resuming it, but the resume function has to do nothing
0706  * if there is no DMA on that channel (i.e., if the enable bit is 0).
0707  */
0708 static void MCD_resmActions (int channel)
0709 {
0710    MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
0711    MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
0712    MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT; /* This register is selected to know
0713                                         which initiator is actually asserted. */
0714    if((MCD_dmaBar->ptdDebug >> channel ) & 0x1)
0715        MCD_chStatus[channel] = MCD_RUNNING;
0716    else
0717        MCD_chStatus[channel] = MCD_IDLE;
0718 }
0719 /********************* End of MCD_resmActions() *********************/
0720 
0721 /********************************************************************/
0722 /* Function:    MCD_killDma
0723  * Purpose:     Halt the DMA on the requested channel, without any
0724  *              intention of resuming the DMA.
0725  * Arguments:   channel - requested channel
0726  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0727  *
0728  * Notes:
0729  *  A DMA may be killed from any state, including paused state, and it
0730  *  always goes to the MCD_HALTED state even if it is killed while in
0731  *  the MCD_NO_DMA or MCD_IDLE states.
0732  */
0733 int MCD_killDma (int channel)
0734 {
0735    /* MCD_XferProg progRep; */
0736 
0737     if((channel < 0) || (channel >= NCHANNELS))
0738         return(MCD_CHANNEL_INVALID);
0739 
0740     MCD_dmaBar->taskControl[channel] = 0x0;
0741     MCD_resumeDma (channel);
0742     /*
0743      * This must be after the write to the TCR so that the task doesn't
0744      * start up again momentarily, and before the status assignment so
0745      * as to override whatever MCD_resumeDma() may do to the channel
0746      * status.
0747      */
0748     MCD_chStatus[channel] = MCD_HALTED;
0749 
0750     /*
0751      * Update the current buffer descriptor's lastDestAddr field
0752      *
0753      * MCD_XferProgrQuery (channel, &progRep);
0754      * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
0755      */
0756     return(MCD_OK);
0757 }
0758 /************************ End of MCD_killDma() **********************/
0759 
0760 /********************************************************************/
0761 /* Function:    MCD_continDma
0762  * Purpose:     Continue a DMA which as stopped due to encountering an
0763  *              unready buffer descriptor.
0764  * Arguments:   channel - channel to continue the DMA on
0765  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0766  *
0767  * Notes:
0768  *  This routine does not check to see if there is a task which can
0769  *  be continued. Also this routine should not be used with single DMAs.
0770  */
0771 int MCD_continDma (int channel)
0772 {
0773     if((channel < 0) || (channel >= NCHANNELS))
0774         return(MCD_CHANNEL_INVALID);
0775 
0776     MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
0777     MCD_chStatus[channel] = MCD_RUNNING;
0778 
0779     return(MCD_OK);
0780 }
0781 /********************** End of MCD_continDma() **********************/
0782 
0783 /*********************************************************************
0784  * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
0785  * to freeze a task and resume it.  We freeze a task by breakpointing
0786  * on the stated task.  That is, not any specific place in the task,
0787  * but any time that task executes.  In particular, when that task
0788  * executes, we want to freeze that task and only that task.
0789  *
0790  * The bits of the debug control register influence interrupts vs.
0791  * breakpoints as follows:
0792  * - Bits 14 and 0 enable or disable debug functions.  If enabled, you
0793  *   will get the interrupt but you may or may not get a breakpoint.
0794  * - Bits 2 and 1 decide whether you also get a breakpoint in addition
0795  *   to an interrupt.
0796  *
0797  * The debug unit can do these actions in response to either internally
0798  * detected breakpoint conditions from the comparators, or in response
0799  * to the external breakpoint pin, or both.
0800  * - Bits 14 and 1 perform the above-described functions for
0801  *   internally-generated conditions, i.e., the debug comparators.
0802  * - Bits 0 and 2 perform the above-described functions for external
0803  *   conditions, i.e., the breakpoint external pin.
0804  *
0805  * Note that, although you "always" get the interrupt when you turn
0806  * the debug functions, the interrupt can nevertheless, if desired, be
0807  * masked by the corresponding bit in the PTD's IMR. Note also that
0808  * this means that bits 14 and 0 must enable debug functions before
0809  * bits 1 and 2, respectively, have any effect.
0810  *
0811  * NOTE: It's extremely important to not pause more than one DMA channel
0812  *  at a time.
0813  ********************************************************************/
0814 
0815 /********************************************************************/
0816 /* Function:    MCD_pauseDma
0817  * Purpose:     Pauses the DMA on a given channel (if any DMA is running
0818  *              on that channel).
0819  * Arguments:   channel
0820  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0821  */
0822 int MCD_pauseDma (int channel)
0823 {
0824     /* MCD_XferProg progRep; */
0825 
0826     if((channel < 0) || (channel >= NCHANNELS))
0827         return(MCD_CHANNEL_INVALID);
0828 
0829     if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
0830     {
0831         MCD_dmaBar->debugComp1 = channel;
0832         MCD_dmaBar->debugControl = DBG_CTL_ENABLE | (1 << (channel + 16));
0833         MCD_chStatus[channel] = MCD_PAUSED;
0834 
0835         /*
0836          * Update the current buffer descriptor's lastDestAddr field
0837          *
0838          * MCD_XferProgrQuery (channel, &progRep);
0839          * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
0840          */
0841     }
0842     return(MCD_OK);
0843 }
0844 /************************* End of MCD_pauseDma() ********************/
0845 
0846 /********************************************************************/
0847 /* Function:    MCD_resumeDma
0848  * Purpose:     Resumes the DMA on a given channel (if any DMA is
0849  *              running on that channel).
0850  * Arguments:   channel - channel on which to resume DMA
0851  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
0852  */
0853 int MCD_resumeDma (int channel)
0854 {
0855     if((channel < 0) || (channel >= NCHANNELS))
0856         return(MCD_CHANNEL_INVALID);
0857 
0858     if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
0859         MCD_resmActions (channel);
0860 
0861     return(MCD_OK);
0862 }
0863 /************************ End of MCD_resumeDma() ********************/
0864 
0865 /********************************************************************/
0866 /* Function:    MCD_csumQuery
0867  * Purpose:     Provide the checksum after performing a non-chained DMA
0868  * Arguments:   channel - channel to report on
0869  *              csum - pointer to where to write the checksum/CRC
0870  * Returns:     MCD_ERROR if the channel is invalid, else MCD_OK
0871  *
0872  * Notes:
0873  *
0874  */
0875 int MCD_csumQuery (int channel, u32 *csum)
0876 {
0877 #ifdef MCD_INCLUDE_EU
0878     if((channel < 0) || (channel >= NCHANNELS))
0879         return(MCD_CHANNEL_INVALID);
0880 
0881     *csum = MCD_relocBuffDesc[channel].csumResult;
0882     return(MCD_OK);
0883 #else
0884     return(MCD_ERROR);
0885 #endif
0886 }
0887 /*********************** End of MCD_resumeDma() *********************/
0888 
0889 /********************************************************************/
0890 /* Function:    MCD_getCodeSize
0891  * Purpose:     Provide the size requirements of the microcoded tasks
0892  * Returns:     Size in bytes
0893  */
0894 int MCD_getCodeSize(void)
0895 {
0896 #ifdef MCD_INCLUDE_EU
0897     return(0x2b5c);
0898 #else
0899     return(0x173c);
0900 #endif
0901 }
0902 /********************** End of MCD_getCodeSize() ********************/
0903 
0904 /********************************************************************/
0905 /* Function:    MCD_getVersion
0906  * Purpose:     Provide the version string and number
0907  * Arguments:   longVersion - user supplied pointer to a pointer to a char
0908  *                    which points to the version string
0909  * Returns:     Version number and version string (by reference)
0910  */
0911 char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
0912 #define MCD_REV_MAJOR   0x00
0913 #define MCD_REV_MINOR   0x03
0914 
0915 int MCD_getVersion(char **longVersion)
0916 {
0917     *longVersion = MCD_versionString;
0918     return((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
0919 }
0920 /********************** End of MCD_getVersion() *********************/
0921 
0922 /********************************************************************/
0923 /* Private version of memcpy()
0924  * Note that everything this is used for is longword-aligned.
0925  */
0926 static void MCD_memcpy (int *dest, int *src, u32 size)
0927 {
0928     u32 i;
0929 
0930     for (i = 0;  i < size;  i += sizeof(int), dest++, src++)
0931         *dest = *src;
0932 }
0933 /********************************************************************/