Add files via upload
initial upload
This commit is contained in:
932
dma/MCD_dmaApi.c
Normal file
932
dma/MCD_dmaApi.c
Normal file
@@ -0,0 +1,932 @@
|
||||
/*
|
||||
* File: MCD_dmaApi.c
|
||||
* Purpose: Main C file for multi-channel DMA API.
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
|
||||
#include "MCD_dma.h"
|
||||
#include "MCD_tasksInit.h"
|
||||
#include "MCD_progCheck.h"
|
||||
|
||||
/********************************************************************/
|
||||
/*
|
||||
* This is an API-internal pointer to the DMA's registers
|
||||
*/
|
||||
dmaRegs *MCD_dmaBar;
|
||||
|
||||
/*
|
||||
* These are the real and model task tables as generated by the
|
||||
* build process
|
||||
*/
|
||||
extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
|
||||
extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
|
||||
|
||||
/*
|
||||
* However, this (usually) gets relocated to on-chip SRAM, at which
|
||||
* point we access them as these tables
|
||||
*/
|
||||
volatile TaskTableEntry *MCD_taskTable;
|
||||
TaskTableEntry *MCD_modelTaskTable;
|
||||
|
||||
|
||||
/*
|
||||
* MCD_chStatus[] is an array of status indicators for remembering
|
||||
* whether a DMA has ever been attempted on each channel, pausing
|
||||
* status, etc.
|
||||
*/
|
||||
static int MCD_chStatus[NCHANNELS] =
|
||||
{
|
||||
MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
|
||||
MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
|
||||
MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
|
||||
MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
|
||||
};
|
||||
|
||||
/*
|
||||
* Prototypes for local functions
|
||||
*/
|
||||
static void MCD_memcpy (int *dest, int *src, u32 size);
|
||||
static void MCD_resmActions (int channel);
|
||||
|
||||
/*
|
||||
* Buffer descriptors used for storage of progress info for single Dmas
|
||||
* Also used as storage for the DMA for CRCs for single DMAs
|
||||
* Otherwise, the DMA does not parse these buffer descriptors
|
||||
*/
|
||||
#ifdef MCD_INCLUDE_EU
|
||||
extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
|
||||
#else
|
||||
MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
|
||||
#endif
|
||||
MCD_bufDesc *MCD_relocBuffDesc;
|
||||
|
||||
|
||||
/*
|
||||
* Defines for the debug control register's functions
|
||||
*/
|
||||
#define DBG_CTL_COMP1_TASK (0x00002000) /* have comparator 1 look for a task # */
|
||||
#define DBG_CTL_ENABLE (DBG_CTL_AUTO_ARM | \
|
||||
DBG_CTL_BREAK | \
|
||||
DBG_CTL_INT_BREAK | \
|
||||
DBG_CTL_COMP1_TASK)
|
||||
#define DBG_CTL_DISABLE (DBG_CTL_AUTO_ARM | \
|
||||
DBG_CTL_INT_BREAK | \
|
||||
DBG_CTL_COMP1_TASK)
|
||||
#define DBG_KILL_ALL_STAT (0xFFFFFFFF)
|
||||
|
||||
/*
|
||||
* Offset to context save area where progress info is stored
|
||||
*/
|
||||
#define CSAVE_OFFSET 10
|
||||
|
||||
/*
|
||||
* Defines for Byte Swapping
|
||||
*/
|
||||
#define MCD_BYTE_SWAP_KILLER 0xFFF8888F
|
||||
#define MCD_NO_BYTE_SWAP_ATALL 0x00040000
|
||||
|
||||
/*
|
||||
* Execution Unit Identifiers
|
||||
*/
|
||||
#define MAC 0 /* legacy - not used */
|
||||
#define LUAC 1 /* legacy - not used */
|
||||
#define CRC 2 /* legacy - not used */
|
||||
#define LURC 3 /* Logic Unit with CRC */
|
||||
|
||||
/*
|
||||
* Task Identifiers
|
||||
*/
|
||||
#define TASK_CHAINNOEU 0
|
||||
#define TASK_SINGLENOEU 1
|
||||
#ifdef MCD_INCLUDE_EU
|
||||
#define TASK_CHAINEU 2
|
||||
#define TASK_SINGLEEU 3
|
||||
#define TASK_FECRX 4
|
||||
#define TASK_FECTX 5
|
||||
#else
|
||||
#define TASK_CHAINEU 0
|
||||
#define TASK_SINGLEEU 1
|
||||
#define TASK_FECRX 2
|
||||
#define TASK_FECTX 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Structure to remember which variant is on which channel
|
||||
* TBD- need this?
|
||||
*/
|
||||
typedef struct MCD_remVariants_struct MCD_remVariant;
|
||||
struct MCD_remVariants_struct
|
||||
{
|
||||
int remDestRsdIncr[NCHANNELS]; /* -1,0,1 */
|
||||
int remSrcRsdIncr[NCHANNELS]; /* -1,0,1 */
|
||||
s16 remDestIncr[NCHANNELS]; /* DestIncr */
|
||||
s16 remSrcIncr[NCHANNELS]; /* srcIncr */
|
||||
u32 remXferSize[NCHANNELS]; /* xferSize */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to remember the startDma parameters for each channel
|
||||
*/
|
||||
MCD_remVariant MCD_remVariants;
|
||||
/********************************************************************/
|
||||
/*
|
||||
* Function: MCD_initDma
|
||||
* Purpose: Initializes the DMA API by setting up a pointer to the DMA
|
||||
* registers, relocating and creating the appropriate task
|
||||
* structures, and setting up some global settings
|
||||
* Arguments:
|
||||
* dmaBarAddr - pointer to the multichannel DMA registers
|
||||
* taskTableDest - location to move DMA task code and structs to
|
||||
* flags - operational parameters
|
||||
* Return Value:
|
||||
* MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
|
||||
* MCD_OK otherwise
|
||||
*/
|
||||
extern u32 MCD_funcDescTab0[];
|
||||
|
||||
int MCD_initDma (dmaRegs *dmaBarAddr, void *taskTableDest, u32 flags)
|
||||
{
|
||||
int i;
|
||||
TaskTableEntry *entryPtr;
|
||||
|
||||
/* setup the local pointer to register set */
|
||||
MCD_dmaBar = dmaBarAddr;
|
||||
|
||||
/* do we need to move/create a task table */
|
||||
if ((flags & MCD_RELOC_TASKS) != 0)
|
||||
{
|
||||
int fixedSize;
|
||||
u32 *fixedPtr;
|
||||
/*int *tablePtr = taskTableDest;TBD*/
|
||||
int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
|
||||
int taskDescTabsOffset;
|
||||
int taskTableSize, varTabsSize, funcDescTabsSize, contextSavesSize;
|
||||
int taskDescTabSize;
|
||||
|
||||
|
||||
/* check if physical address is aligned on 512 byte boundary */
|
||||
if (((u32) taskTableDest & 0x000001ff) != 0)
|
||||
return MCD_TABLE_UNALIGNED;
|
||||
|
||||
MCD_taskTable = taskTableDest; /* set up local pointer to task Table */
|
||||
|
||||
/*
|
||||
* Create a task table:
|
||||
* - compute aligned base offsets for variable tables and
|
||||
* function descriptor tables, then
|
||||
* - loop through the task table and setup the pointers
|
||||
* - copy over model task table with the the actual task descriptor
|
||||
* tables
|
||||
*/
|
||||
|
||||
taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
|
||||
/* align variable tables to size */
|
||||
varTabsOffset = taskTableSize + (u32)taskTableDest;
|
||||
if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
|
||||
varTabsOffset = (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
|
||||
/* align function descriptor tables */
|
||||
varTabsSize = NCHANNELS * VAR_TAB_SIZE;
|
||||
funcDescTabsOffset = varTabsOffset + varTabsSize;
|
||||
|
||||
if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
|
||||
funcDescTabsOffset = (funcDescTabsOffset + FUNCDESC_TAB_SIZE) &
|
||||
(~FUNCDESC_TAB_SIZE);
|
||||
|
||||
funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
|
||||
contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
|
||||
contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
|
||||
fixedSize = taskTableSize + varTabsSize + funcDescTabsSize +
|
||||
contextSavesSize;
|
||||
|
||||
/* zero the thing out */
|
||||
fixedPtr = (u32 *)taskTableDest;
|
||||
for (i = 0;i<(fixedSize/4);i++)
|
||||
fixedPtr[i] = 0;
|
||||
|
||||
entryPtr = (TaskTableEntry*)MCD_taskTable;
|
||||
/* set up fixed pointers */
|
||||
for (i = 0; i < NCHANNELS; i++)
|
||||
{
|
||||
entryPtr[i].varTab = (u32)varTabsOffset; /* update ptr to local value */
|
||||
entryPtr[i].FDTandFlags = (u32)funcDescTabsOffset | MCD_TT_FLAGS_DEF;
|
||||
entryPtr[i].contextSaveSpace = (u32)contextSavesOffset;
|
||||
varTabsOffset += VAR_TAB_SIZE;
|
||||
#ifdef MCD_INCLUDE_EU /* if not there is only one, just point to the same one */
|
||||
funcDescTabsOffset += FUNCDESC_TAB_SIZE;
|
||||
#endif
|
||||
contextSavesOffset += CONTEXT_SAVE_SIZE;
|
||||
}
|
||||
/* copy over the function descriptor table */
|
||||
for ( i = 0; i < FUNCDESC_TAB_NUM; i++)
|
||||
{
|
||||
MCD_memcpy((void*)(entryPtr[i].FDTandFlags & ~MCD_TT_FLAGS_MASK),
|
||||
(void*)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
|
||||
}
|
||||
|
||||
/* copy model task table to where the context saves stuff leaves off*/
|
||||
MCD_modelTaskTable = (TaskTableEntry*)contextSavesOffset;
|
||||
|
||||
MCD_memcpy ((void*)MCD_modelTaskTable, (void*)MCD_modelTaskTableSrc,
|
||||
NUMOFVARIANTS * sizeof(TaskTableEntry));
|
||||
|
||||
entryPtr = MCD_modelTaskTable; /* point to local version of
|
||||
model task table */
|
||||
taskDescTabsOffset = (u32)MCD_modelTaskTable +
|
||||
(NUMOFVARIANTS * sizeof(TaskTableEntry));
|
||||
|
||||
/* copy actual task code and update TDT ptrs in local model task table */
|
||||
for (i = 0; i < NUMOFVARIANTS; i++)
|
||||
{
|
||||
taskDescTabSize = entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
|
||||
MCD_memcpy ((void*)taskDescTabsOffset, (void*)entryPtr[i].TDTstart, taskDescTabSize);
|
||||
entryPtr[i].TDTstart = (u32)taskDescTabsOffset;
|
||||
taskDescTabsOffset += taskDescTabSize;
|
||||
entryPtr[i].TDTend = (u32)taskDescTabsOffset - 4;
|
||||
}
|
||||
#ifdef MCD_INCLUDE_EU /* Tack single DMA BDs onto end of code so API controls
|
||||
where they are since DMA might write to them */
|
||||
MCD_relocBuffDesc = (MCD_bufDesc*)(entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
|
||||
#else /* DMA does not touch them so they can be wherever and we don't need to
|
||||
waste SRAM on them */
|
||||
MCD_relocBuffDesc = MCD_singleBufDescs;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* point the would-be relocated task tables and the
|
||||
buffer descriptors to the ones the linker generated */
|
||||
|
||||
if (((u32)MCD_realTaskTableSrc & 0x000001ff) != 0)
|
||||
return(MCD_TABLE_UNALIGNED);
|
||||
|
||||
/* need to add code to make sure that every thing else is aligned properly TBD*/
|
||||
/* this is problematic if we init more than once or after running tasks,
|
||||
need to add variable to see if we have aleady init'd */
|
||||
entryPtr = MCD_realTaskTableSrc;
|
||||
for (i = 0; i < NCHANNELS; i++)
|
||||
{
|
||||
if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
|
||||
((entryPtr[i].FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
|
||||
return(MCD_TABLE_UNALIGNED);
|
||||
}
|
||||
|
||||
MCD_taskTable = MCD_realTaskTableSrc;
|
||||
MCD_modelTaskTable = MCD_modelTaskTableSrc;
|
||||
MCD_relocBuffDesc = MCD_singleBufDescs;
|
||||
}
|
||||
|
||||
|
||||
/* Make all channels as totally inactive, and remember them as such: */
|
||||
|
||||
MCD_dmaBar->taskbar = (u32) MCD_taskTable;
|
||||
for (i = 0; i < NCHANNELS; i++)
|
||||
{
|
||||
MCD_dmaBar->taskControl[i] = 0x0;
|
||||
MCD_chStatus[i] = MCD_NO_DMA;
|
||||
}
|
||||
|
||||
/* Set up pausing mechanism to inactive state: */
|
||||
MCD_dmaBar->debugComp1 = 0; /* no particular values yet for either comparator registers */
|
||||
MCD_dmaBar->debugComp2 = 0;
|
||||
MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
|
||||
MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
|
||||
|
||||
/* enable or disable commbus prefetch, really need an ifdef or
|
||||
something to keep from trying to set this in the 8220 */
|
||||
if ((flags & MCD_COMM_PREFETCH_EN) != 0)
|
||||
MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
|
||||
else
|
||||
MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
|
||||
|
||||
return MCD_OK;
|
||||
}
|
||||
/*********************** End of MCD_initDma() ***********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_dmaStatus
|
||||
* Purpose: Returns the status of the DMA on the requested channel
|
||||
* Arguments: channel - channel number
|
||||
* Returns: Predefined status indicators
|
||||
*/
|
||||
int MCD_dmaStatus (int channel)
|
||||
{
|
||||
u16 tcrValue;
|
||||
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
tcrValue = MCD_dmaBar->taskControl[channel];
|
||||
if ((tcrValue & TASK_CTL_EN) == 0)
|
||||
{ /* nothing running */
|
||||
/* if last reported with task enabled */
|
||||
if ( MCD_chStatus[channel] == MCD_RUNNING
|
||||
|| MCD_chStatus[channel] == MCD_IDLE)
|
||||
MCD_chStatus[channel] = MCD_DONE;
|
||||
}
|
||||
else /* something is running */
|
||||
{
|
||||
/* There are three possibilities: paused, running or idle. */
|
||||
if ( MCD_chStatus[channel] == MCD_RUNNING
|
||||
|| MCD_chStatus[channel] == MCD_IDLE)
|
||||
{
|
||||
MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
|
||||
/* This register is selected to know which initiator is
|
||||
actually asserted. */
|
||||
if ((MCD_dmaBar->ptdDebug >> channel ) & 0x1 )
|
||||
MCD_chStatus[channel] = MCD_RUNNING;
|
||||
else
|
||||
MCD_chStatus[channel] = MCD_IDLE;
|
||||
/* do not change the status if it is already paused. */
|
||||
}
|
||||
}
|
||||
return MCD_chStatus[channel];
|
||||
}
|
||||
/******************** End of MCD_dmaStatus() ************************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_startDma
|
||||
* Ppurpose: Starts a particular kind of DMA
|
||||
* Arguments: see below
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*/
|
||||
|
||||
int MCD_startDma (
|
||||
int channel, /* the channel on which to run the DMA */
|
||||
s8 *srcAddr, /* the address to move data from, or physical buffer-descriptor address */
|
||||
s16 srcIncr, /* the amount to increment the source address per transfer */
|
||||
s8 *destAddr, /* the address to move data to */
|
||||
s16 destIncr, /* the amount to increment the destination address per transfer */
|
||||
u32 dmaSize, /* the number of bytes to transfer independent of the transfer size */
|
||||
u32 xferSize, /* the number bytes in of each data movement (1, 2, or 4) */
|
||||
u32 initiator, /* what device initiates the DMA */
|
||||
int priority, /* priority of the DMA */
|
||||
u32 flags, /* flags describing the DMA */
|
||||
u32 funcDesc /* a description of byte swapping, bit swapping, and CRC actions */
|
||||
#ifdef MCD_NEED_ADDR_TRANS
|
||||
s8 *srcAddrVirt /* virtual buffer descriptor address TBD*/
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int srcRsdIncr, destRsdIncr;
|
||||
int *cSave;
|
||||
short xferSizeIncr;
|
||||
int tcrCount = 0;
|
||||
#ifdef MCD_INCLUDE_EU
|
||||
u32 *realFuncArray;
|
||||
#endif
|
||||
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
/* tbd - need to determine the proper response to a bad funcDesc when not
|
||||
including EU functions, for now, assign a benign funcDesc, but maybe
|
||||
should return an error */
|
||||
#ifndef MCD_INCLUDE_EU
|
||||
funcDesc = MCD_FUNC_NOEU1;
|
||||
#endif
|
||||
|
||||
#ifdef MCD_DEBUG
|
||||
printf("startDma:Setting up params\n");
|
||||
#endif
|
||||
/* Set us up for task-wise priority. We don't technically need to do this on every start, but
|
||||
since the register involved is in the same longword as other registers that users are in control
|
||||
of, setting it more than once is probably preferable. That since the documentation doesn't seem
|
||||
to be completely consistent about the nature of the PTD control register. */
|
||||
MCD_dmaBar->ptdControl |= (u16) 0x8000;
|
||||
#if 1 /* Not sure what we need to keep here rtm TBD */
|
||||
/* Calculate additional parameters to the regular DMA calls. */
|
||||
srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
|
||||
destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
|
||||
|
||||
xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
|
||||
|
||||
/* Remember for each channel which variant is running. */
|
||||
MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
|
||||
MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
|
||||
MCD_remVariants.remDestIncr[channel] = destIncr;
|
||||
MCD_remVariants.remSrcIncr[channel] = srcIncr;
|
||||
MCD_remVariants.remXferSize[channel] = xferSize;
|
||||
#endif
|
||||
|
||||
cSave = (int*)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET + CURRBD;
|
||||
|
||||
#ifdef MCD_INCLUDE_EU /* may move this to EU specific calls */
|
||||
realFuncArray = (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
|
||||
/* Modify the LURC's normal and byte-residue-loop functions according to parameter. */
|
||||
realFuncArray[(LURC*16)] = xferSize == 4 ?
|
||||
funcDesc : xferSize == 2 ?
|
||||
funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
|
||||
realFuncArray[(LURC*16+1)] = (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
|
||||
#endif
|
||||
/* Write the initiator field in the TCR, and also set the initiator-hold
|
||||
bit. Note that,due to a hardware quirk, this could collide with an
|
||||
MDE access to the initiator-register file, so we have to verify that the write
|
||||
reads back correctly. */
|
||||
|
||||
MCD_dmaBar->taskControl[channel] =
|
||||
(initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
|
||||
|
||||
while(((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
|
||||
((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM)) &&
|
||||
(tcrCount < 1000))
|
||||
{
|
||||
tcrCount++;
|
||||
/*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020;*/
|
||||
MCD_dmaBar->taskControl[channel] =
|
||||
(initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
|
||||
}
|
||||
|
||||
MCD_dmaBar->priority[channel] = (u8)priority & PRIORITY_PRI_MASK;
|
||||
/* should be albe to handle this stuff with only one write to ts reg - tbd */
|
||||
if (channel < 8 && channel >= 0)
|
||||
{
|
||||
MCD_dmaBar->taskSize0 &= ~(0xf << (7-channel)*4);
|
||||
MCD_dmaBar->taskSize0 |= (xferSize & 3) << (((7 - channel)*4) + 2);
|
||||
MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel)*4);
|
||||
}
|
||||
else
|
||||
{
|
||||
MCD_dmaBar->taskSize1 &= ~(0xf << (15-channel)*4);
|
||||
MCD_dmaBar->taskSize1 |= (xferSize & 3) << (((15 - channel)*4) + 2);
|
||||
MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel)*4);
|
||||
}
|
||||
|
||||
/* setup task table flags/options which mostly control the line buffers */
|
||||
MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
|
||||
MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
|
||||
|
||||
if (flags & MCD_FECTX_DMA)
|
||||
{
|
||||
/* TDTStart and TDTEnd */
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECTX].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECTX].TDTend;
|
||||
MCD_startDmaENetXmit(srcAddr, srcAddr, destAddr, MCD_taskTable, channel);
|
||||
}
|
||||
else if (flags & MCD_FECRX_DMA)
|
||||
{
|
||||
/* TDTStart and TDTEnd */
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECRX].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECRX].TDTend;
|
||||
MCD_startDmaENetRcv(srcAddr, srcAddr, destAddr, MCD_taskTable, channel);
|
||||
}
|
||||
else if(flags & MCD_SINGLE_DMA)
|
||||
{
|
||||
/* this buffer descriptor is used for storing off initial parameters for later
|
||||
progress query calculation and for the DMA to write the resulting checksum
|
||||
The DMA does not use this to determine how to operate, that info is passed
|
||||
with the init routine*/
|
||||
MCD_relocBuffDesc[channel].srcAddr = srcAddr;
|
||||
MCD_relocBuffDesc[channel].destAddr = destAddr;
|
||||
MCD_relocBuffDesc[channel].lastDestAddr = destAddr; /* definitely not its final value */
|
||||
MCD_relocBuffDesc[channel].dmaSize = dmaSize;
|
||||
MCD_relocBuffDesc[channel].flags = 0; /* not used */
|
||||
MCD_relocBuffDesc[channel].csumResult = 0; /* not used */
|
||||
MCD_relocBuffDesc[channel].next = 0; /* not used */
|
||||
|
||||
/* Initialize the progress-querying stuff to show no progress:*/
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
|
||||
(u32) &(MCD_relocBuffDesc[channel]);
|
||||
/* tbd - need to keep the user from trying to call the EU routine
|
||||
when MCD_INCLUDE_EU is not defined */
|
||||
if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2)
|
||||
{
|
||||
/* TDTStart and TDTEnd */
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
|
||||
MCD_startDmaSingleNoEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize,
|
||||
xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), cSave,
|
||||
MCD_taskTable, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TDTStart and TDTEnd */
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
|
||||
MCD_startDmaSingleEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize,
|
||||
xferSizeIncr, flags, (int *)&(MCD_relocBuffDesc[channel]), cSave,
|
||||
MCD_taskTable, channel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* chained DMAS */
|
||||
/* Initialize the progress-querying stuff to show no progress:*/
|
||||
#if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
|
||||
= (int)((MCD_bufDesc*) srcAddr)->srcAddr;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
|
||||
= (int)((MCD_bufDesc*) srcAddr)->destAddr;
|
||||
#else /* if using address translation, need the virtual addr of the first buffdesc */
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
|
||||
= (int)((MCD_bufDesc*) srcAddrVirt)->srcAddr;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
|
||||
= (int)((MCD_bufDesc*) srcAddrVirt)->destAddr;
|
||||
#endif
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
|
||||
((volatile int *)MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
|
||||
|
||||
if( funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2)
|
||||
{
|
||||
/*TDTStart and TDTEnd*/
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
|
||||
MCD_startDmaChainNoEu((int *)srcAddr, srcIncr, destIncr, xferSize,
|
||||
xferSizeIncr, cSave, MCD_taskTable, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*TDTStart and TDTEnd*/
|
||||
MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
|
||||
MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINEU].TDTend;
|
||||
MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr, xferSize,
|
||||
xferSizeIncr, cSave, MCD_taskTable, channel);
|
||||
}
|
||||
}
|
||||
MCD_chStatus[channel] = MCD_IDLE;
|
||||
return MCD_OK;
|
||||
}
|
||||
|
||||
/************************ End of MCD_startDma() *********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_XferProgrQuery
|
||||
* Purpose: Returns progress of DMA on requested channel
|
||||
* Arguments: channel - channel to retrieve progress for
|
||||
* progRep - pointer to user supplied MCD_XferProg struct
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*
|
||||
* Notes:
|
||||
* MCD_XferProgrQuery() upon completing or after aborting a DMA, or
|
||||
* while the DMA is in progress, this function returns the first
|
||||
* DMA-destination address not (or not yet) used in the DMA. When
|
||||
* encountering a non-ready buffer descriptor, the information for
|
||||
* the last completed descriptor is returned.
|
||||
*
|
||||
* MCD_XferProgQuery() has to avoid the possibility of getting
|
||||
* partially-updated information in the event that we should happen
|
||||
* to query DMA progress just as the DMA is updating it. It does that
|
||||
* by taking advantage of the fact context is not saved frequently for
|
||||
* the most part. We therefore read it at least twice until we get the
|
||||
* same information twice in a row.
|
||||
*
|
||||
* Because a small, but not insignificant, amount of time is required
|
||||
* to write out the progress-query information, especially upon
|
||||
* completion of the DMA, it would be wise to guarantee some time lag
|
||||
* between successive readings of the progress-query information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* How many iterations of the loop below to execute to stabilize values
|
||||
*/
|
||||
#define STABTIME 0
|
||||
|
||||
int MCD_XferProgrQuery (int channel, MCD_XferProg *progRep)
|
||||
{
|
||||
MCD_XferProg prevRep;
|
||||
int again; /* true if we are to try again to get consistent results */
|
||||
int i; /* used as a time-waste counter */
|
||||
int destDiffBytes; /* Total number of bytes that we think actually got xfered. */
|
||||
int numIterations; /* number of iterations */
|
||||
int bytesNotXfered; /* bytes that did not get xfered. */
|
||||
s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
|
||||
int subModVal, addModVal; /* Mode values to added and subtracted from the
|
||||
final destAddr */
|
||||
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
/* Read a trial value for the progress-reporting values*/
|
||||
prevRep.lastSrcAddr =
|
||||
(s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
|
||||
prevRep.lastDestAddr =
|
||||
(s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
|
||||
prevRep.dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
|
||||
prevRep.currBufDesc =
|
||||
(MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET];
|
||||
/* Repeatedly reread those values until they match previous values: */
|
||||
do {
|
||||
/* Waste a little bit of time to ensure stability: */
|
||||
for (i = 0; i < STABTIME; i++)
|
||||
i += i >> 2; /* make sure this loop does something so that it doesn't get optimized out */
|
||||
/* Check them again: */
|
||||
progRep->lastSrcAddr =
|
||||
(s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
|
||||
progRep->lastDestAddr =
|
||||
(s8 *) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
|
||||
progRep->dmaSize = ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
|
||||
progRep->currBufDesc =
|
||||
(MCD_bufDesc*) ((volatile int*) MCD_taskTable[channel].contextSaveSpace)[CURRBD + CSAVE_OFFSET];
|
||||
/* See if they match: */
|
||||
if ( prevRep.lastSrcAddr != progRep->lastSrcAddr
|
||||
|| prevRep.lastDestAddr != progRep->lastDestAddr
|
||||
|| prevRep.dmaSize != progRep->dmaSize
|
||||
|| prevRep.currBufDesc != progRep->currBufDesc)
|
||||
{
|
||||
/* If they don't match, remember previous values and try again:*/
|
||||
prevRep.lastSrcAddr = progRep->lastSrcAddr;
|
||||
prevRep.lastDestAddr = progRep->lastDestAddr;
|
||||
prevRep.dmaSize = progRep->dmaSize;
|
||||
prevRep.currBufDesc = progRep->currBufDesc;
|
||||
again = MCD_TRUE;
|
||||
}
|
||||
else
|
||||
again = MCD_FALSE;
|
||||
} while (again == MCD_TRUE);
|
||||
|
||||
|
||||
/* Update the dCount, srcAddr and destAddr */
|
||||
/* To calculate dmaCount, we consider destination address. C
|
||||
overs M1,P1,Z for destination */
|
||||
switch(MCD_remVariants.remDestRsdIncr[channel]) {
|
||||
case MINUS1:
|
||||
subModVal = ((int)progRep->lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
|
||||
addModVal = ((int)progRep->currBufDesc->destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
|
||||
LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - addModVal;
|
||||
LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
|
||||
destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
|
||||
bytesNotXfered = (destDiffBytes/MCD_remVariants.remDestIncr[channel]) *
|
||||
( MCD_remVariants.remDestIncr[channel]
|
||||
+ MCD_remVariants.remXferSize[channel]);
|
||||
progRep->dmaSize = destDiffBytes - bytesNotXfered + addModVal - subModVal;
|
||||
break;
|
||||
case ZERO:
|
||||
progRep->lastDestAddr = progRep->currBufDesc->destAddr;
|
||||
break;
|
||||
case PLUS1:
|
||||
/* This value has to be subtracted from the final calculated dCount. */
|
||||
subModVal = ((int)progRep->currBufDesc->destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
|
||||
/* These bytes are already in lastDestAddr. */
|
||||
addModVal = ((int)progRep->lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
|
||||
LWAlignedInitDestAddr = (progRep->currBufDesc->destAddr) - subModVal;
|
||||
LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
|
||||
destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
|
||||
numIterations = ( LWAlignedCurrDestAddr - LWAlignedInitDestAddr)/MCD_remVariants.remDestIncr[channel];
|
||||
bytesNotXfered = numIterations *
|
||||
( MCD_remVariants.remDestIncr[channel]
|
||||
- MCD_remVariants.remXferSize[channel]);
|
||||
progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* This covers M1,P1,Z for source */
|
||||
switch(MCD_remVariants.remSrcRsdIncr[channel]) {
|
||||
case MINUS1:
|
||||
progRep->lastSrcAddr =
|
||||
progRep->currBufDesc->srcAddr +
|
||||
( MCD_remVariants.remSrcIncr[channel] *
|
||||
(progRep->dmaSize/MCD_remVariants.remXferSize[channel]));
|
||||
break;
|
||||
case ZERO:
|
||||
progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
|
||||
break;
|
||||
case PLUS1:
|
||||
progRep->lastSrcAddr =
|
||||
progRep->currBufDesc->srcAddr +
|
||||
( MCD_remVariants.remSrcIncr[channel] *
|
||||
(progRep->dmaSize/MCD_remVariants.remXferSize[channel]));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return MCD_OK;
|
||||
}
|
||||
/******************* End of MCD_XferProgrQuery() ********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* MCD_resmActions() does the majority of the actions of a DMA resume.
|
||||
* It is called from MCD_killDma() and MCD_resumeDma(). It has to be
|
||||
* a separate function because the kill function has to negate the task
|
||||
* enable before resuming it, but the resume function has to do nothing
|
||||
* if there is no DMA on that channel (i.e., if the enable bit is 0).
|
||||
*/
|
||||
static void MCD_resmActions (int channel)
|
||||
{
|
||||
MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
|
||||
MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
|
||||
MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT; /* This register is selected to know
|
||||
which initiator is actually asserted. */
|
||||
if((MCD_dmaBar->ptdDebug >> channel ) & 0x1)
|
||||
MCD_chStatus[channel] = MCD_RUNNING;
|
||||
else
|
||||
MCD_chStatus[channel] = MCD_IDLE;
|
||||
}
|
||||
/********************* End of MCD_resmActions() *********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_killDma
|
||||
* Purpose: Halt the DMA on the requested channel, without any
|
||||
* intention of resuming the DMA.
|
||||
* Arguments: channel - requested channel
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*
|
||||
* Notes:
|
||||
* A DMA may be killed from any state, including paused state, and it
|
||||
* always goes to the MCD_HALTED state even if it is killed while in
|
||||
* the MCD_NO_DMA or MCD_IDLE states.
|
||||
*/
|
||||
int MCD_killDma (int channel)
|
||||
{
|
||||
/* MCD_XferProg progRep; */
|
||||
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
MCD_dmaBar->taskControl[channel] = 0x0;
|
||||
MCD_resumeDma (channel);
|
||||
/*
|
||||
* This must be after the write to the TCR so that the task doesn't
|
||||
* start up again momentarily, and before the status assignment so
|
||||
* as to override whatever MCD_resumeDma() may do to the channel
|
||||
* status.
|
||||
*/
|
||||
MCD_chStatus[channel] = MCD_HALTED;
|
||||
|
||||
/*
|
||||
* Update the current buffer descriptor's lastDestAddr field
|
||||
*
|
||||
* MCD_XferProgrQuery (channel, &progRep);
|
||||
* progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
|
||||
*/
|
||||
return MCD_OK;
|
||||
}
|
||||
/************************ End of MCD_killDma() **********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_continDma
|
||||
* Purpose: Continue a DMA which as stopped due to encountering an
|
||||
* unready buffer descriptor.
|
||||
* Arguments: channel - channel to continue the DMA on
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*
|
||||
* Notes:
|
||||
* This routine does not check to see if there is a task which can
|
||||
* be continued. Also this routine should not be used with single DMAs.
|
||||
*/
|
||||
int MCD_continDma (int channel)
|
||||
{
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
|
||||
MCD_chStatus[channel] = MCD_RUNNING;
|
||||
|
||||
return MCD_OK;
|
||||
}
|
||||
/********************** End of MCD_continDma() **********************/
|
||||
|
||||
/*********************************************************************
|
||||
* MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
|
||||
* to freeze a task and resume it. We freeze a task by breakpointing
|
||||
* on the stated task. That is, not any specific place in the task,
|
||||
* but any time that task executes. In particular, when that task
|
||||
* executes, we want to freeze that task and only that task.
|
||||
*
|
||||
* The bits of the debug control register influence interrupts vs.
|
||||
* breakpoints as follows:
|
||||
* - Bits 14 and 0 enable or disable debug functions. If enabled, you
|
||||
* will get the interrupt but you may or may not get a breakpoint.
|
||||
* - Bits 2 and 1 decide whether you also get a breakpoint in addition
|
||||
* to an interrupt.
|
||||
*
|
||||
* The debug unit can do these actions in response to either internally
|
||||
* detected breakpoint conditions from the comparators, or in response
|
||||
* to the external breakpoint pin, or both.
|
||||
* - Bits 14 and 1 perform the above-described functions for
|
||||
* internally-generated conditions, i.e., the debug comparators.
|
||||
* - Bits 0 and 2 perform the above-described functions for external
|
||||
* conditions, i.e., the breakpoint external pin.
|
||||
*
|
||||
* Note that, although you "always" get the interrupt when you turn
|
||||
* the debug functions, the interrupt can nevertheless, if desired, be
|
||||
* masked by the corresponding bit in the PTD's IMR. Note also that
|
||||
* this means that bits 14 and 0 must enable debug functions before
|
||||
* bits 1 and 2, respectively, have any effect.
|
||||
*
|
||||
* NOTE: It's extremely important to not pause more than one DMA channel
|
||||
* at a time.
|
||||
********************************************************************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_pauseDma
|
||||
* Purpose: Pauses the DMA on a given channel (if any DMA is running
|
||||
* on that channel).
|
||||
* Arguments: channel
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*/
|
||||
int MCD_pauseDma (int channel)
|
||||
{
|
||||
/* MCD_XferProg progRep; */
|
||||
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
|
||||
{
|
||||
MCD_dmaBar->debugComp1 = channel;
|
||||
MCD_dmaBar->debugControl = DBG_CTL_ENABLE | (1 << (channel + 16));
|
||||
MCD_chStatus[channel] = MCD_PAUSED;
|
||||
|
||||
/*
|
||||
* Update the current buffer descriptor's lastDestAddr field
|
||||
*
|
||||
* MCD_XferProgrQuery (channel, &progRep);
|
||||
* progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
|
||||
*/
|
||||
}
|
||||
return MCD_OK;
|
||||
}
|
||||
/************************* End of MCD_pauseDma() ********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_resumeDma
|
||||
* Purpose: Resumes the DMA on a given channel (if any DMA is
|
||||
* running on that channel).
|
||||
* Arguments: channel - channel on which to resume DMA
|
||||
* Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
|
||||
*/
|
||||
int MCD_resumeDma (int channel)
|
||||
{
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
|
||||
MCD_resmActions (channel);
|
||||
|
||||
return MCD_OK;
|
||||
}
|
||||
/************************ End of MCD_resumeDma() ********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_csumQuery
|
||||
* Purpose: Provide the checksum after performing a non-chained DMA
|
||||
* Arguments: channel - channel to report on
|
||||
* csum - pointer to where to write the checksum/CRC
|
||||
* Returns: MCD_ERROR if the channel is invalid, else MCD_OK
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
*/
|
||||
int MCD_csumQuery (int channel, u32 *csum)
|
||||
{
|
||||
#ifdef MCD_INCLUDE_EU
|
||||
if((channel < 0) || (channel >= NCHANNELS))
|
||||
return(MCD_CHANNEL_INVALID);
|
||||
|
||||
*csum = MCD_relocBuffDesc[channel].csumResult;
|
||||
return(MCD_OK);
|
||||
#else
|
||||
return MCD_ERROR;
|
||||
#endif
|
||||
}
|
||||
/*********************** End of MCD_resumeDma() *********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_getCodeSize
|
||||
* Purpose: Provide the size requirements of the microcoded tasks
|
||||
* Returns: Size in bytes
|
||||
*/
|
||||
int MCD_getCodeSize(void)
|
||||
{
|
||||
#ifdef MCD_INCLUDE_EU
|
||||
return(0x2b5c);
|
||||
#else
|
||||
return(0x173c);
|
||||
#endif
|
||||
}
|
||||
/********************** End of MCD_getCodeSize() ********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Function: MCD_getVersion
|
||||
* Purpose: Provide the version string and number
|
||||
* Arguments: longVersion - user supplied pointer to a pointer to a char
|
||||
* which points to the version string
|
||||
* Returns: Version number and version string (by reference)
|
||||
*/
|
||||
char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
|
||||
#define MCD_REV_MAJOR 0x00
|
||||
#define MCD_REV_MINOR 0x03
|
||||
|
||||
int MCD_getVersion(char **longVersion)
|
||||
{
|
||||
*longVersion = MCD_versionString;
|
||||
return((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
|
||||
}
|
||||
/********************** End of MCD_getVersion() *********************/
|
||||
|
||||
/********************************************************************/
|
||||
/* Private version of memcpy()
|
||||
* Note that everything this is used for is longword-aligned.
|
||||
*/
|
||||
static void MCD_memcpy (int *dest, int *src, u32 size)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < size; i += sizeof(int), dest++, src++)
|
||||
*dest = *src;
|
||||
}
|
||||
/********************************************************************/
|
||||
2449
dma/MCD_tasks.c
Normal file
2449
dma/MCD_tasks.c
Normal file
File diff suppressed because it is too large
Load Diff
224
dma/MCD_tasksInit.c
Normal file
224
dma/MCD_tasksInit.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* File: MCD_tasksInit.c
|
||||
* Purpose: Functions for initializing variable tables of different
|
||||
* types of tasks.
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do not edit!
|
||||
*/
|
||||
|
||||
#include "MCD_dma.h"
|
||||
|
||||
extern dmaRegs *MCD_dmaBar;
|
||||
|
||||
|
||||
/*
|
||||
* Task 0
|
||||
*/
|
||||
|
||||
void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)currBD); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 11, (u32)xferSize); /* var[11] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)0x00000000); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000000); /* var[12] */
|
||||
MCD_SET_VAR(taskTable+channel, 13, (u32)0x80000000); /* var[13] */
|
||||
MCD_SET_VAR(taskTable+channel, 14, (u32)0x00000010); /* var[14] */
|
||||
MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000004); /* var[15] */
|
||||
MCD_SET_VAR(taskTable+channel, 16, (u32)0x08000000); /* var[16] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000000); /* inc[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000001); /* inc[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 30, (u32)0x40000000); /* inc[6] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Task 1
|
||||
*/
|
||||
|
||||
void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)srcAddr); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)destAddr); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)dmaSize); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)flags); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)currBD); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000004); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x08000000); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000001); /* inc[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 29, (u32)0x40000000); /* inc[5] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Task 2
|
||||
*/
|
||||
|
||||
void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr, int xferSize, short xferSizeIncr, int *cSave, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 12, (u32)xferSize); /* var[12] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 11, (u32)0x00000000); /* var[11] */
|
||||
MCD_SET_VAR(taskTable+channel, 13, (u32)0x00000000); /* var[13] */
|
||||
MCD_SET_VAR(taskTable+channel, 14, (u32)0x80000000); /* var[14] */
|
||||
MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000010); /* var[15] */
|
||||
MCD_SET_VAR(taskTable+channel, 16, (u32)0x00000001); /* var[16] */
|
||||
MCD_SET_VAR(taskTable+channel, 17, (u32)0x00000004); /* var[17] */
|
||||
MCD_SET_VAR(taskTable+channel, 18, (u32)0x08000000); /* var[18] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 28, (u32)0x80000000); /* inc[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 29, (u32)0xc0000000); /* inc[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 30, (u32)0x80000001); /* inc[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 31, (u32)0x40000000); /* inc[7] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Task 3
|
||||
*/
|
||||
|
||||
void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr, short destIncr, int dmaSize, short xferSizeIncr, int flags, int *currBD, int *cSave, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)srcAddr); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)(0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)destAddr); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)(0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)dmaSize); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)(0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)flags); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)currBD); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)cSave); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000001); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 11, (u32)0x00000004); /* var[11] */
|
||||
MCD_SET_VAR(taskTable+channel, 12, (u32)0x08000000); /* var[12] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0x00000000); /* inc[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 28, (u32)0xc0000000); /* inc[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000000); /* inc[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 30, (u32)0x80000001); /* inc[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 31, (u32)0x40000000); /* inc[7] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Task 4
|
||||
*/
|
||||
|
||||
void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)bDBase); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)rcvFifoPtr); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x0000ffff); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x30000000); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 11, (u32)0x0fffffff); /* var[11] */
|
||||
MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000008); /* var[12] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)0x00000000); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)0x60000000); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)0x20000004); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0x40000000); /* inc[3] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Task 5
|
||||
*/
|
||||
|
||||
void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr, volatile TaskTableEntry *taskTable, int channel)
|
||||
{
|
||||
|
||||
MCD_SET_VAR(taskTable+channel, 0, (u32)bDBase); /* var[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 3, (u32)currBD); /* var[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 11, (u32)xmitFifoPtr); /* var[11] */
|
||||
MCD_SET_VAR(taskTable+channel, 1, (u32)0x00000000); /* var[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 2, (u32)0x00000000); /* var[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 4, (u32)0x00000000); /* var[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 5, (u32)0x00000000); /* var[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 6, (u32)0x00000000); /* var[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 7, (u32)0x00000000); /* var[7] */
|
||||
MCD_SET_VAR(taskTable+channel, 8, (u32)0x00000000); /* var[8] */
|
||||
MCD_SET_VAR(taskTable+channel, 9, (u32)0x00000000); /* var[9] */
|
||||
MCD_SET_VAR(taskTable+channel, 10, (u32)0x00000000); /* var[10] */
|
||||
MCD_SET_VAR(taskTable+channel, 12, (u32)0x00000000); /* var[12] */
|
||||
MCD_SET_VAR(taskTable+channel, 13, (u32)0x0000ffff); /* var[13] */
|
||||
MCD_SET_VAR(taskTable+channel, 14, (u32)0xffffffff); /* var[14] */
|
||||
MCD_SET_VAR(taskTable+channel, 15, (u32)0x00000004); /* var[15] */
|
||||
MCD_SET_VAR(taskTable+channel, 16, (u32)0x00000008); /* var[16] */
|
||||
MCD_SET_VAR(taskTable+channel, 24, (u32)0x00000000); /* inc[0] */
|
||||
MCD_SET_VAR(taskTable+channel, 25, (u32)0x60000000); /* inc[1] */
|
||||
MCD_SET_VAR(taskTable+channel, 26, (u32)0x40000000); /* inc[2] */
|
||||
MCD_SET_VAR(taskTable+channel, 27, (u32)0xc000fffc); /* inc[3] */
|
||||
MCD_SET_VAR(taskTable+channel, 28, (u32)0xe0000004); /* inc[4] */
|
||||
MCD_SET_VAR(taskTable+channel, 29, (u32)0x80000000); /* inc[5] */
|
||||
MCD_SET_VAR(taskTable+channel, 30, (u32)0x4000ffff); /* inc[6] */
|
||||
MCD_SET_VAR(taskTable+channel, 31, (u32)0xe0000001); /* inc[7] */
|
||||
|
||||
/* Set the task's Enable bit in its Task Control Register */
|
||||
MCD_dmaBar->taskControl[channel] |= (u16)0x8000;
|
||||
}
|
||||
674
dma/dma.c
Normal file
674
dma/dma.c
Normal file
@@ -0,0 +1,674 @@
|
||||
/*
|
||||
* dma.c
|
||||
*
|
||||
*
|
||||
* This file is part of BaS_gcc.
|
||||
*
|
||||
* BaS_gcc is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* BaS_gcc is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with BaS_gcc. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Created on: 26.02.2013
|
||||
* Author: Markus Fröschle
|
||||
*/
|
||||
|
||||
#include "dma.h"
|
||||
#include <MCD_dma.h>
|
||||
#include "mcd_initiators.h"
|
||||
#include "bas_printf.h"
|
||||
#include "bas_string.h"
|
||||
#include "cache.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
#include "firebee.h"
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
#include "m5484l.h"
|
||||
#elif defined(MACHINE_M54455)
|
||||
#include "m54455.h"
|
||||
#else
|
||||
#error "unknown machine!"
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
extern char _SYS_SRAM[];
|
||||
#define SYS_SRAM &_SYS_SRAM[0]
|
||||
|
||||
struct dma_channel
|
||||
{
|
||||
int req;
|
||||
void (*handler)(void);
|
||||
};
|
||||
|
||||
static char used_reqs[32] =
|
||||
{
|
||||
DMA_ALWAYS, DMA_DSPI_RXFIFO, DMA_DSPI_TXFIFO, DMA_DREQ0,
|
||||
DMA_PSC0_RX, DMA_PSC0_TX, DMA_USB_EP0, DMA_USB_EP1,
|
||||
DMA_USB_EP2, DMA_USB_EP3, DMA_PCI_TX, DMA_PCI_RX,
|
||||
DMA_PSC1_RX, DMA_PSC1_TX, DMA_I2C_RX, DMA_I2C_TX,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
static struct dma_channel dma_channel[NCHANNELS] =
|
||||
{
|
||||
{-1, NULL}, {-1, NULL}, {-1, NULL}, {-1, NULL},
|
||||
{-1, NULL}, {-1, NULL}, {-1, NULL}, {-1, NULL},
|
||||
{-1, NULL}, {-1, NULL}, {-1, NULL}, {-1, NULL},
|
||||
{-1, NULL}, {-1, NULL}, {-1, NULL}, {-1, NULL},
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable all DMA interrupts
|
||||
*
|
||||
*/
|
||||
void dma_irq_enable(void)
|
||||
{
|
||||
/* Unmask all task interrupts */
|
||||
MCF_DMA_DIMR = 0;
|
||||
|
||||
/* Clear the interrupt pending register */
|
||||
MCF_DMA_DIPR = 0;
|
||||
|
||||
dbg("DMA task interrupts unmasked.\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable all DMA interrupts
|
||||
*/
|
||||
void dma_irq_disable(void)
|
||||
{
|
||||
/* Mask all task interrupts */
|
||||
MCF_DMA_DIMR = (uint32_t) ~0;
|
||||
|
||||
/* Clear any pending task interrupts */
|
||||
MCF_DMA_DIPR = (uint32_t) ~0;
|
||||
|
||||
/* Mask the DMA interrupt in the interrupt controller */
|
||||
MCF_INTC_IMRH |= MCF_INTC_IMRH_INT_MASK48;
|
||||
|
||||
dbg("DMA interrupts masked and disabled\r\n");
|
||||
}
|
||||
|
||||
int dma_set_initiator(int initiator)
|
||||
{
|
||||
switch (initiator)
|
||||
{
|
||||
/* these initiators are always active */
|
||||
case DMA_ALWAYS:
|
||||
case DMA_DSPI_RXFIFO:
|
||||
case DMA_DSPI_TXFIFO:
|
||||
case DMA_DREQ0:
|
||||
case DMA_PSC0_RX:
|
||||
case DMA_PSC0_TX:
|
||||
case DMA_USB_EP0:
|
||||
case DMA_USB_EP1:
|
||||
case DMA_USB_EP2:
|
||||
case DMA_USB_EP3:
|
||||
case DMA_PCI_TX:
|
||||
case DMA_PCI_RX:
|
||||
case DMA_PSC1_RX:
|
||||
case DMA_I2C_RX:
|
||||
case DMA_I2C_TX:
|
||||
break;
|
||||
|
||||
case DMA_FEC0_RX:
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC16(3)) | MCF_DMA_IMCR_IMC16_FEC0RX;
|
||||
used_reqs[16] = DMA_FEC0_RX;
|
||||
break;
|
||||
|
||||
case DMA_FEC0_TX:
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC17(3)) | MCF_DMA_IMCR_IMC17_FEC0TX;
|
||||
used_reqs[17] = DMA_FEC0_TX;
|
||||
break;
|
||||
|
||||
case DMA_FEC1_RX:
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC20(3)) | MCF_DMA_IMCR_IMC20_FEC1RX;
|
||||
used_reqs[20] = DMA_FEC1_RX;
|
||||
break;
|
||||
|
||||
case DMA_FEC1_TX:
|
||||
if (used_reqs[21] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC21(3)) | MCF_DMA_IMCR_IMC21_FEC1TX;
|
||||
used_reqs[21] = DMA_FEC1_TX;
|
||||
}
|
||||
else if (used_reqs[25] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC25(3)) | MCF_DMA_IMCR_IMC25_FEC1TX;
|
||||
used_reqs[25] = DMA_FEC1_TX;
|
||||
}
|
||||
else if (used_reqs[31] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC31(3)) | MCF_DMA_IMCR_IMC31_FEC1TX;
|
||||
used_reqs[31] = DMA_FEC1_TX;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot found\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_DREQ1:
|
||||
if (used_reqs[29] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC29(3)) | MCF_DMA_IMCR_IMC29_DREQ1;
|
||||
used_reqs[29] = DMA_DREQ1;
|
||||
}
|
||||
else if (used_reqs[21] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC21(3)) | MCF_DMA_IMCR_IMC21_DREQ1;
|
||||
used_reqs[21] = DMA_DREQ1;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM0:
|
||||
if (used_reqs[24] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC24(3)) | MCF_DMA_IMCR_IMC24_CTM0;
|
||||
used_reqs[24] = DMA_CTM0;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM1:
|
||||
if (used_reqs[25] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC25(3)) | MCF_DMA_IMCR_IMC25_CTM1;
|
||||
used_reqs[25] = DMA_CTM1;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM2:
|
||||
if (used_reqs[26] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC26(3)) | MCF_DMA_IMCR_IMC26_CTM2;
|
||||
used_reqs[26] = DMA_CTM2;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM3:
|
||||
if (used_reqs[27] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC27(3)) | MCF_DMA_IMCR_IMC27_CTM3;
|
||||
used_reqs[27] = DMA_CTM3;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM4:
|
||||
if (used_reqs[28] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC28(3)) | MCF_DMA_IMCR_IMC28_CTM4;
|
||||
used_reqs[28] = DMA_CTM4;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM5:
|
||||
if (used_reqs[29] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC29(3)) | MCF_DMA_IMCR_IMC29_CTM5;
|
||||
used_reqs[29] = DMA_CTM5;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM6:
|
||||
if (used_reqs[30] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC30(3)) | MCF_DMA_IMCR_IMC30_CTM6;
|
||||
used_reqs[30] = DMA_CTM6;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_CTM7:
|
||||
if (used_reqs[31] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC31(3)) | MCF_DMA_IMCR_IMC31_CTM7;
|
||||
used_reqs[31] = DMA_CTM7;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_USBEP4:
|
||||
if (used_reqs[26] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC26(3)) | MCF_DMA_IMCR_IMC26_USBEP4;
|
||||
used_reqs[26] = DMA_USBEP4;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_USBEP5:
|
||||
if (used_reqs[27] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC27(3)) | MCF_DMA_IMCR_IMC27_USBEP5;
|
||||
used_reqs[27] = DMA_USBEP5;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_USBEP6:
|
||||
if (used_reqs[28] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC28(3)) | MCF_DMA_IMCR_IMC28_USBEP6;
|
||||
used_reqs[28] = DMA_USBEP6;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_PSC2_RX:
|
||||
if (used_reqs[28] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC28(3)) | MCF_DMA_IMCR_IMC28_PSC2RX;
|
||||
used_reqs[28] = DMA_PSC2_RX; }
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_PSC2_TX:
|
||||
if (used_reqs[29] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC29(3)) | MCF_DMA_IMCR_IMC29_PSC2TX;
|
||||
used_reqs[29] = DMA_PSC2_TX;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_PSC3_RX:
|
||||
if (used_reqs[30] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC30(3)) | MCF_DMA_IMCR_IMC30_PSC3RX;
|
||||
used_reqs[30] = DMA_PSC3_RX;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_PSC3_TX:
|
||||
if (used_reqs[31] == 0)
|
||||
{
|
||||
MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_IMC31(3)) | MCF_DMA_IMCR_IMC31_PSC3TX;
|
||||
used_reqs[31] = DMA_PSC3_TX;
|
||||
}
|
||||
else /* No empty slots */
|
||||
{
|
||||
err("no free slot\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
err("don't know what to do\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the initiator number for the given requestor
|
||||
*
|
||||
* Parameters:
|
||||
* requestor Initiator/Requestor identifier
|
||||
*
|
||||
* Return Value:
|
||||
* The initiator number (0-31) if initiator has been assigned
|
||||
* 0 (always initiator) otherwise
|
||||
*/
|
||||
uint32_t dma_get_initiator(int requestor)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < sizeof(used_reqs); ++i)
|
||||
{
|
||||
if (used_reqs[i] == requestor)
|
||||
return i;
|
||||
}
|
||||
err("no initiator found for requestor %d\r\n", requestor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given initiator from the active list
|
||||
*
|
||||
* Parameters:
|
||||
* requestor Initiator/Requestor identifier
|
||||
*/
|
||||
void dma_free_initiator(int requestor)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 16; i < sizeof(used_reqs); ++i)
|
||||
{
|
||||
if (used_reqs[i] == requestor)
|
||||
{
|
||||
used_reqs[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dbg("DMA requestor %d freed\r\n", requestor);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to find an available channel and mark it as used
|
||||
*
|
||||
* Parameters:
|
||||
* requestor Initiator/Requestor identifier
|
||||
*
|
||||
* Return Value:
|
||||
* First available channel or -1 if they are all occupied
|
||||
*/
|
||||
int dma_set_channel(int requestor, void (*handler)(void))
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check to see if this requestor is already assigned to a channel */
|
||||
dbg("check if requestor %d is already assigned to a channel\r\n", requestor);
|
||||
if ((i = dma_get_channel(requestor)) != -1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; i < NCHANNELS; ++i)
|
||||
{
|
||||
if (dma_channel[i].req == -1)
|
||||
{
|
||||
dma_channel[i].req = requestor;
|
||||
dma_channel[i].handler = handler;
|
||||
dbg("assigned channel %d to requestor %d\r\n", i, requestor);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
err("no free DMA channel found for requestor %d\r\n", requestor);
|
||||
|
||||
/* All channels taken */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dma_clear_channel(int channel)
|
||||
{
|
||||
if(channel >= 0 && channel < NCHANNELS)
|
||||
{
|
||||
dma_channel[channel].req = -1;
|
||||
dma_channel[channel].handler = NULL;
|
||||
dbg("cleared DMA channel %d\r\n", channel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the channel being initiated by the given requestor
|
||||
*
|
||||
* Parameters:
|
||||
* requestor Initiator/Requestor identifier
|
||||
*
|
||||
* Return Value:
|
||||
* Channel that the requestor is controlling or -1 if hasn't been
|
||||
* activated
|
||||
*/
|
||||
int dma_get_channel(int requestor)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NCHANNELS; ++i)
|
||||
{
|
||||
if (dma_channel[i].req == requestor)
|
||||
return i;
|
||||
}
|
||||
dbg("no channel occupied by requestor %d\r\n", requestor);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the channel being initiated by the given requestor from
|
||||
* the active list
|
||||
*
|
||||
* Parameters:
|
||||
* requestor Initiator/Requestor identifier
|
||||
*/
|
||||
void dma_free_channel(int requestor)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NCHANNELS; ++i)
|
||||
{
|
||||
if (dma_channel[i].req == requestor)
|
||||
{
|
||||
dma_channel[i].req = -1;
|
||||
dma_channel[i].handler = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the catch-all interrupt handler for the mult-channel DMA
|
||||
*/
|
||||
bool dma_interrupt_handler(void *arg1, void *arg2)
|
||||
{
|
||||
int i, interrupts;
|
||||
uint32_t ipl;
|
||||
|
||||
ipl = set_ipl(7); /* do not disturb */
|
||||
|
||||
/*
|
||||
* Determine which interrupt(s) triggered by AND'ing the
|
||||
* pending interrupts with those that aren't masked.
|
||||
*/
|
||||
interrupts = MCF_DMA_DIPR & ~MCF_DMA_DIMR;
|
||||
|
||||
/* Make sure we are here for a reason */
|
||||
if (interrupts == 0)
|
||||
{
|
||||
err("not DMA interrupt!\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("");
|
||||
/* Clear the interrupt in the pending register */
|
||||
MCF_DMA_DIPR = interrupts;
|
||||
|
||||
for (i = 0; i < 16; ++i, interrupts >>= 1)
|
||||
{
|
||||
if (interrupts & 0x1)
|
||||
{
|
||||
/* If there is a handler, call it */
|
||||
if (dma_channel[i].handler != NULL)
|
||||
{
|
||||
dbg("call handler for DMA channel %d (%p)\r\n", i, dma_channel[i].handler);
|
||||
dma_channel[i].handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_ipl(ipl);
|
||||
|
||||
return true; /* handled */
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
void *dma_memcpy(void *dst, void *src, size_t n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef DBG_DMA
|
||||
int32_t time;
|
||||
int32_t start;
|
||||
int32_t end;
|
||||
|
||||
start = MCF_SLT0_SCNT;
|
||||
#endif /* DBG_DMA */
|
||||
|
||||
ret = MCD_startDma(1, src, 4, dst, 4, n, 4, DMA_ALWAYS, 0, MCD_SINGLE_DMA, 0);
|
||||
if (ret == MCD_OK)
|
||||
{
|
||||
dbg("DMA on channel 1 successfully started\r\n");
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
ret = MCD_dmaStatus(1);
|
||||
#ifdef _NOT_USED_ /* suppress annoying printout for now */
|
||||
switch (ret)
|
||||
{
|
||||
case MCD_NO_DMA:
|
||||
xprintf("MCD_NO_DMA: no DMA active on this channel\r\n");
|
||||
return NULL;
|
||||
break;
|
||||
case MCD_IDLE:
|
||||
xprintf("MCD_IDLE: DMA defined but not active (initiator not ready)\r\n");
|
||||
break;
|
||||
case MCD_RUNNING:
|
||||
xprintf("MCD_RUNNING: DMA active and working on this channel\r\n");
|
||||
break;
|
||||
case MCD_PAUSED:
|
||||
xprintf("MCD_PAUSED: DMA defined and enabled, but currently paused\r\n");
|
||||
break;
|
||||
case MCD_HALTED:
|
||||
xprintf("MCD_HALTED: DMA killed\r\n");
|
||||
return NULL;
|
||||
break;
|
||||
case MCD_DONE:
|
||||
xprintf("MCD_DONE: DMA finished\r\n");
|
||||
break;
|
||||
case MCD_CHANNEL_INVALID:
|
||||
xprintf("MCD_CHANNEL_INVALID: invalid DMA channel\r\n");
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
xprintf("unknown DMA status %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} while (ret != MCD_DONE);
|
||||
|
||||
#ifdef DBG_DMA
|
||||
end = MCF_SLT0_SCNT;
|
||||
time = (start - end) / (SYSCLK / 1000) / 1000;
|
||||
dbg("took %d ms (%f Mbytes/second)\r\n", time, n / (float) time / 1000.0);
|
||||
#endif /* DBG_DMA */
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int dma_init(void)
|
||||
{
|
||||
int i;
|
||||
int res;
|
||||
|
||||
dbg("MCD DMA API initialization: ");
|
||||
res = MCD_initDma((dmaRegs *) &_MBAR[0x8000], SYS_SRAM, MCD_RELOC_TASKS | MCD_COMM_PREFETCH_EN);
|
||||
if (res != MCD_OK)
|
||||
{
|
||||
err("DMA API initialization failed (0x%x)\r\n", res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure dma_channel array is properly initialized
|
||||
*/
|
||||
for (i = 0; i < NCHANNELS; i++)
|
||||
{
|
||||
dma_channel[i].req = -1;
|
||||
dma_channel[i].handler = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user