📄 c6x1x_edma_mcasp.c
字号:
if (MCASP_FGETH(hMcasp, XSTAT, XCKFAIL)) {
MCASP_FSETSH(hMcasp, XSTAT, XCKFAIL, YES);
events |= C6X1X_EDMA_MCASP_EVT_XCKFAIL;
}
if (MCASP_FGETH(hMcasp, XSTAT, XSYNCERR)) {
MCASP_FSETSH(hMcasp, XSTAT, XSYNCERR, YES);
events |= C6X1X_EDMA_MCASP_EVT_XSYNCERR;
}
if (MCASP_FGETH(hMcasp, XSTAT, XDMAERR)) {
MCASP_FSETH(hMcasp, XSTAT, XDMAERR, 1);
events |= C6X1X_EDMA_MCASP_EVT_XDMAERR;
}
/* Clear not registered events here */
MCASP_RSETH(hMcasp, XSTAT, 0xFFFFFFFF);
}
eventReturn = ports[portNbr].evtMask & events;
if (eventReturn) {
(*ports[portNbr].evtCallback)(eventReturn, portNbr);
}
}
}
}
/*
* ======== linkPacket ========
* Links a packet with the EDMA. When called by mdSubmitChan() it is called
* with all interrupts disabled, but when called by an ISR only the EDMA IRQ
* is disabled.
*/
static Void linkPacket(ChanHandle chan, IOM_Packet *packet)
{
EDMA_Handle pramPtr;
Uns edmaCnt;
/* Store the packet in the packetList */
chan->packetList[chan->writeIndex] = packet;
/* Set up pointer to link PaRAM to write submit job info to */
pramPtr = chan->pramTbl[chan->writeIndex];
chan->writeIndex = nextIndex(chan->writeIndex);
/* Load the buffer pointer into the EDMA */
if (chan->mode == INPUT) {
EDMA_RSETH(pramPtr, DST, (Uint32) packet->addr);
}
else {
EDMA_RSETH(pramPtr, SRC, (Uint32) packet->addr);
}
/*
* Load the transfer count (in samples) into the EDMA. Use the ESIZE
* field of the EDMA job to calculate number of samples.
*/
edmaCnt = (Uint32)packet->size >> (2 - EDMA_FGETH(pramPtr, OPT, ESIZE));
EDMA_FSETH(pramPtr, CNT, FRMCNT, (edmaCnt /
EDMA_FGETH(pramPtr, CNT, ELECNT) - 1));
/*
* Link to loop EDMA job upon termination. This way we won't
* loose the frame sync if the channel is starved.
*/
EDMA_link(pramPtr, chan->loophEdma);
/* Disable the EDMA channel to make sure current job doesn't complete */
EDMA_disableChannel(chan->xferPram);
/*
* Link the currently executing job to the new job. This can be
* either the loop EDMA job or a real data EDMA job.
*/
EDMA_link(chan->xferPram, pramPtr);
if (chan->submitCount > 0) {
/*
* We need to link the parameter space corresponding to the running
* job so that if a breakpoint occurs, we know how to recover.
*/
EDMA_link(chan->prevPramPtr, pramPtr);
}
/* Reenable the EDMA channel */
EDMA_enableChannel(chan->xferPram);
/* Save the new job for the loop above for next time */
chan->prevPramPtr = pramPtr;
}
/*
* ======== mdBindDev ========
* This function allocates and configures the McASP port specified by devId.
*/
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
Uns old;
Int inIrqId;
int outIrqId;
int irqId;
PortHandle port;
HWI_Attrs hwiAttrs;
C6X1X_EDMA_MCASP_DevParams *params =
(C6X1X_EDMA_MCASP_DevParams *) devParams;
/* This driver must receive a valid devparams */
if (params == NULL) {
return (IOM_EBADARGS);
}
/* Check the version number */
if (params->versionId != C6X1X_EDMA_MCASP_VERSION_1){
/* Unsupported version */
return(IOM_EBADARGS);
}
/* Get the device parameters of the specified port */
port = &ports[devid];
/* Mark the port as in use */
old = ATM_setu(&(port->inUse), TRUE);
/* Check if the port was already bound */
if (old) {
return (IOM_EALLOC);
}
/* Map the supplied IRQ to the EDMA event */
if (params->irqId > 0 ) {
irqId = params->irqId;
}
else {
irqId = IRQEDMA;
}
IRQ_map(IRQ_EVT_EDMAINT, irqId);
hwiAttrs.intrMask = params->edmaIntrMask;
hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
hwiAttrs.arg = NULL;
/* Plug the EDMA dispatcher into the HWI dispatcher */
HWI_dispatchPlug(irqId, (Fxn)EDMA_intDispatcher, -1, &hwiAttrs);
/* Set the McASP high frequency sample rate generator */
/* Set the McASP sample rate generator */
/* Set the McASP frame sync generator */
port->enableHclkg = params->enableHclkg;
port->enableClkg = params->enableClkg;
port->enableFsyncg = params->enableFsyncg;
/* True if buffers are in external memory */
port->cacheCalls = params->cacheCalls;
/* Store the devid */
port->devId = devid;
/* No channel create yet */
port->chanCreated = 0;
/* Open and reset the McASP */
port->hMcasp = MCASP_open(devid, MCASP_OPEN_RESET);
if (port->hMcasp == INV) {
return (IOM_EALLOC);
}
/* Configure the McASP with the supplied configuration */
MCASP_config(port->hMcasp, params->mcaspCfgPtr);
if (params->evtCallback != NULL) {
/* register the events */
port->evtCallback = params->evtCallback->evtFxn;
port->evtMask = params->evtCallback->evtMask;
if (params->inEvtIrqId > 0) {
inIrqId = params->inEvtIrqId;
}
else {
inIrqId = IRQEVTINPUT;
}
if (params->outEvtIrqId > 0) {
outIrqId = params->outEvtIrqId;
}
else {
outIrqId = IRQEVTOUTPUT;
}
IRQ_map(MCASP_getXmtEventId(port->hMcasp), outIrqId);
IRQ_map(MCASP_getRcvEventId(port->hMcasp), inIrqId);
hwiAttrs.intrMask = params->inEvtIntrMask;
hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
hwiAttrs.arg = INPUT;
HWI_dispatchPlug(inIrqId, (Fxn)isrEvent, -1, &hwiAttrs);
hwiAttrs.intrMask = params->outEvtIntrMask;
hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
hwiAttrs.arg = OUTPUT;
HWI_dispatchPlug(outIrqId, (Fxn)isrEvent, -1, &hwiAttrs);
}
else {
port->evtCallback = NULL;
}
/* set 0xe for debug, real value should be 0 */
loopSrcBuf = 0;
loopDstBuf = 0;
/* Return the device handle and a status code for success */
*devp = port;
return (IOM_COMPLETED);
}
/*
* ======== mdCreateChan ========
* This function creates and configures a device channel.
*/
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
PortHandle port = (PortHandle) devp;
C6X1X_EDMA_MCASP_ChanParams *params =
(C6X1X_EDMA_MCASP_ChanParams *) chanParams;
ChanHandle chan;
Uns old;
Uns esize;
Uns cnt;
Uns fs;
Uns elerld;
Uns mcaspAddr;
Int edmaChanEvent;
Int i;
#if ENABLELOOPINTR
Int loopTcc;
#endif
/*
* Configuration structure for the loop EDMA job. If the McASP
* is left to free running, this loop job is running when there is
* no data to transfer. This is useful if the McASP is externally
* clocked. If the driver is starved or if an emulation halt
* (breakpoint) occurs, the frame sync will still be correct when
* the driver continues transmitting data.
*/
EDMA_Config loopEdmaCfg = {
EDMA_FMKS(OPT, PRI, HIGH) |
EDMA_FMKS(OPT, ESIZE, 32BIT) |
EDMA_FMKS(OPT, 2DS, NO) |
EDMA_FMKS(OPT, SUM, NONE) |
EDMA_FMKS(OPT, 2DD, NO) |
EDMA_FMKS(OPT, DUM, NONE) |
EDMA_FMKS(OPT, TCINT, NO) |
EDMA_FMKS(OPT, TCC, DEFAULT) |
EDMA_FMKS(OPT, LINK, YES) |
EDMA_FMKS(OPT, FS, NO),
EDMA_FMK (SRC, SRC, NULL),
EDMA_FMK (CNT, FRMCNT, 0) |
EDMA_FMK (CNT, ELECNT, 0),
EDMA_FMKS(IDX, FRMIDX, OF(0)) |
EDMA_FMKS(IDX, ELEIDX, OF(0)),
EDMA_FMK (DST, DST, NULL),
EDMA_FMK (RLD, ELERLD, 0) |
EDMA_FMK (RLD, LINK, NULL)
};
/* This driver needs a valid channel parameter structure passed */
if (params == NULL) {
return (IOM_EBADARGS);
}
/* Use own indexes since IOM mode is a bit mask and not an index */
if (mode == IOM_INPUT) {
chan = &port->chans[INPUT];
chan->mode = INPUT;
}
else {
chan = &port->chans[OUTPUT];
chan->mode = OUTPUT;
}
/* Mark the channel as used */
old = ATM_setu(&(chan->inUse), TRUE);
/* Make sure the channel wasn't already created */
if (old) {
return (IOM_EALLOC);
}
/* Initialise the channel structure */
chan->cbFxn = cbFxn;
chan->cbArg = cbArg;
chan->port = port;
chan->writeIndex = 0;
chan->readIndex = 0;
chan->submitCount = 0;
chan->flushPacket = NULL;
chan->abortPacket = NULL;
/* Initialize the packet queue */
QUE_new(&chan->packetQueue);
/*
* Set the number of elements (corresponding to number of McASP TDM
* channels) used in the Loop job to preserve the frame sync.
* FRMCNT should be (num of TDM slots - 1);
*/
cnt = params->tdmChans - 1;
EDMA_FSETA(&loopEdmaCfg.cnt, CNT, FRMCNT, cnt);
EDMA_FSETA(&loopEdmaCfg.cnt, CNT, ELECNT, params->edmaCfgPtr->cnt);
/* Use the same sample size in the Loop job as in normal jobs */
esize = EDMA_FGETA(¶ms->edmaCfgPtr->opt, OPT, ESIZE);
EDMA_FSETA(&loopEdmaCfg.opt, OPT, ESIZE, esize);
/* Use the same FS info as in the normal job */
fs = EDMA_FGETA(¶ms->edmaCfgPtr->opt, OPT, FS);
EDMA_FSETA(&loopEdmaCfg.opt, OPT, FS, fs);
/* Use the same ELERLD info as in the normal job */
elerld = EDMA_FGETA(¶ms->edmaCfgPtr->rld, RLD, ELERLD);
EDMA_FSETA(&loopEdmaCfg.rld, RLD, ELERLD, elerld);
/* Allocate a TCC for the EDMA */
chan->tcc = EDMA_intAlloc(-1);
/* If tcc > 15 we abort. */
if (chan->tcc == -1 || chan->tcc > 15) {
chanCleanUp(chan, SETFALSE);
return (IOM_EALLOC);
}
#if ENABLELOOPINTR
loopTcc = EDMA_intAlloc(-1);
/* If tcc > 15 we abort. */
if (loopTcc == -1 || loopTcc > 15) {
EDMA_intFree(loopTcc);
chanCleanUp(chan, FREETCC);
return (IOM_EALLOC);
}
#endif
/* Allocate an EDMA PaRAM for the Loop EDMA job. */
chan->loophEdma = EDMA_allocTable(-1);
if (chan->loophEdma == EDMA_HINV) {
chanCleanUp(chan, FREETCC);
return (IOM_EALLOC);
}
/*
* Allocate EDMA PaRAM link area based on max number of
* submits possible.
*/
if (EDMA_allocTableEx(MAXLINKCNT, chan->pramTbl) != MAXLINKCNT) {
chanCleanUp(chan, FREETABLE);
return (IOM_EALLOC);
}
/* workaround for big endian problem in McASP */
if (chan->mode == INPUT) {
mcaspAddr = MCASP_getRbufAddr(port->hMcasp);
}
else {
mcaspAddr = MCASP_getXbufAddr(port->hMcasp);
}
#ifdef _BIG_ENDIAN
if (esize == EDMA_OPT_ESIZE_8BIT) {
mcaspAddr += 3;
}
else if (esize == EDMA_OPT_ESIZE_16BIT) {
mcaspAddr += 2;
}
#endif
if (chan->mode == INPUT) {
/* Put input specific parameters in the Loop EDMA config */
EDMA_RSETA(&loopEdmaCfg.src, SRC, mcaspAddr);
EDMA_RSETA(&loopEdmaCfg.dst, DST, (Uint32) &loopDstBuf);
EDMA_RSETA(¶ms->edmaCfgPtr->src, SRC, mcaspAddr);
/* Register our isrInput with the EDMA dispatcher */
EDMA_intHook(chan->tcc, &isrInput);
}
else {
/* Put output specific parameters in the Loop EDMA config */
EDMA_RSETA(&loopEdmaCfg.src, SRC, (Uint32) &loopSrcBuf);
EDMA_RSETA(&loopEdmaCfg.dst, DST, mcaspAddr);
EDMA_RSETA(¶ms->edmaCfgPtr->dst, DST, mcaspAddr);
/* Register our isrOutput with the EDMA dispatcher */
EDMA_intHook(chan->tcc, &isrOutput);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -