📄 c54xx_dma_mcbsp.c
字号:
/*
* Copyright 2003 by Texas Instruments Incorporated.
* All rights reserved. Property of Texas Instruments Incorporated.
* Restricted rights to use, duplicate or disclose this code are
* granted through contract.
*
*/
/* "@(#) DDK 1.11.00.00 11-04-03 (ddk-b13)" */
/*
* ======== c54xx_dma_mcbsp.c ========
*/
#include <std.h>
#include <atm.h>
#include <hwi.h>
#include <que.h>
#include <csl.h>
#include <csl_dma.h>
#include <csl_irq.h>
#include <csl_mcbsp.h>
#include <iom.h>
#include <c54xx_dma_mcbsp.h>
#define NUMPORTS MCBSP_PORT_CNT
#define DELAY 10000
/* Channel Object -- intialized by mdCreateChan() */
typedef struct ChanObj {
Uns inUse; /* TRUE => channel has been opened */
Uns dmaId; /* channel id */
void *devp; /* needed for McBSP access */
DMA_Handle hDma; /* DMA handle */
IOM_Packet *flushPacket; /* used for submit/IOM_FLUSH/output */
IOM_Packet *dataPacket; /* current active I/O packet */
QUE_Obj pendList; /* list of packets for I/O */
IOM_TiomCallback cbFxn; /* used to notify client when I/O complete */
Ptr cbArg;
} ChanObj, *ChanHandle;
#define CHANOBJINIT { \
FALSE, /* inUse */ \
0, /* dmaId */ \
NULL, /* devp */ \
NULL, /* hDma */ \
NULL, /* flushPacket */ \
NULL, /* dataPacket */ \
{ NULL, NULL }, /* pendList */ \
NULL, /* cbFxn */ \
NULL /* cbArg */ \
}
/* Device Object -- intialized by mdBindDev() */
typedef struct PortObj {
Uns inUse;
MCBSP_Handle hMcbsp; /* McBSP handle */
ChanObj chans[NUMCHANS];
Uns rxIntrMask;
Uns txIntrMask;
} PortObj, *PortHandle;
#define PORTOBJINIT { \
FALSE, /* inUse */ \
NULL, /* hMcbsp */ \
{ /* chans */ \
CHANOBJINIT, \
CHANOBJINIT \
}, \
NULL, \
NULL \
}
#if NUMPORTS == 2
static PortObj ports[NUMPORTS] = { \
PORTOBJINIT, \
PORTOBJINIT \
};
#elif NUMPORTS == 3
PortObj ports[NUMPORTS] = { \
PORTOBJINIT, \
PORTOBJINIT, \
PORTOBJINIT \
};
#else
#error Number of serials ports undefined!!
#endif
/*
* Forward declaration of IOM interface functions.
*/
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
static Int mdDeleteChan(Ptr chanp);
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
/*
* Public IOM interface table.
*/
IOM_Fxns C54XX_DMA_MCBSP_FXNS = {
mdBindDev,
IOM_UNBINDDEVNOTIMPL,
mdControlChan,
mdCreateChan,
mdDeleteChan,
mdSubmitChan,
};
/*
* local functions
*/
static Void startDma(ChanHandle chan, IOM_Packet *packet);
static Void dmaIsr(ChanHandle chan);
static Void abortio(ChanHandle chan);
static Void mcbspStartDelay(Void);
/*
* ======== mdBindDev ========
*/
#pragma CODE_SECTION(mdBindDev, ".text:init")
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
C54XX_DMA_MCBSP_DevParams *params =
(C54XX_DMA_MCBSP_DevParams *)devParams;
PortHandle port = (PortHandle)&ports[devid];
if (ATM_setu(&port->inUse, TRUE)) {
return (IOM_EBADIO);
}
/* this driver requires parameters, there are no valid defaults */
if (params == NULL) {
return (IOM_EBADARGS);
}
/* Check the version number */
if (params->versionId != C54XX_DMA_MCBSP_VERSION_1){
return (IOM_EBADARGS);
}
/* open the McBSP */
port->hMcbsp = MCBSP_open(devid, MCBSP_OPEN_RESET);
if (port->hMcbsp == INV) {
return (IOM_EBADIO);
}
MCBSP_config(port->hMcbsp, params->mcbspCfg);
port->chans[INPUT].dmaId = params->rxDmaId;
port->chans[OUTPUT].dmaId = params->txDmaId;
/*store the interrupt masks */
port->rxIntrMask = params->rxIntrMask;
port->txIntrMask = params->txIntrMask;
*devp = port;
return (IOM_COMPLETED);
}
/*
* ======== mdControlChan ========
*/
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
{
/*
* If a channel timeouts(in IOM class driver) a calldown is made to
* mdControlChan w/ cmd = IOM_CHAN_TIMED out. Timeout processing is
* optionally implemented here. If not performed return status of
* IOM_ENOTIMPL.
*/
/*
* Channel timed out. Perform needed channel cleanup.
*/
if (cmd == IOM_CHAN_TIMEDOUT) {
abortio(chanp);
}
else {
return (IOM_ENOTIMPL); /* return IOM_ENOTIMPL for codes not handled */
}
return (IOM_COMPLETED);
}
/*
* ======== mdCreateChan ========
*/
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
PortHandle port = (PortHandle)devp;
C54XX_DMA_MCBSP_ChanParams *params =
(C54XX_DMA_MCBSP_ChanParams *)chanParams;
HWI_Attrs attrs;
ChanHandle chan;
Int event;
chan = (mode == IOM_INPUT) ? &port->chans[INPUT] : &port->chans[OUTPUT];
/* this driver requires channel parameters, no reasonable default */
if (params == NULL) {
return (IOM_EBADARGS);
}
/*
* Check check if channel is already in use.
* Use ATM_setu() for atomic test-and-set.
*/
if (ATM_setu((Uns *)&chan->inUse, TRUE)) {
return (IOM_EBADIO); /* ERROR! channel is already open! */
}
QUE_new(&chan->pendList);
chan->devp = devp;
chan->cbFxn = cbFxn;
chan->cbArg = cbArg;
/* open and configure DMA */
chan->hDma = DMA_open(chan->dmaId, DMA_OPEN_RESET);
if (chan->hDma == INV) {
return (IOM_EBADIO);
}
DMA_config(chan->hDma, params->dmaCfg);
event = DMA_getEventId(chan->hDma);
/* plug interrupt vector */
attrs.intrMask = (mode == IOM_INPUT) ? port->rxIntrMask : port->txIntrMask;
attrs.arg = (Arg)chan;
HWI_dispatchPlug(event, (Fxn)dmaIsr, &attrs);
/* enable DMA interrupt */
IRQ_enable(event);
*chanp = chan;
return (IOM_COMPLETED); /* success */
}
/*
* ======== mdDeleteChan ========
* Mark the channel available and disable the appropriate interrupt.
*/
static Int mdDeleteChan(Ptr chanp)
{
ChanHandle chan = (ChanHandle)chanp;
/* disable DMA interrupt */
IRQ_disable(DMA_getEventId(chan->hDma));
/* close the DMA channel */
DMA_close(chan->hDma);
chan->inUse = FALSE;
return (IOM_COMPLETED);
}
/*
* ======== mdSubmitChan ========
*/
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
ChanHandle chan = (ChanHandle)chanp;
PortHandle port = (PortHandle)chan->devp;
Uns imask;
if (packet->cmd == IOM_FLUSH || packet->cmd == IOM_ABORT) {
abortio(chan);
packet->status = IOM_COMPLETED; /* flush/abort pkt completed */
return (IOM_COMPLETED);
}
imask = HWI_disable();
if (chan->dataPacket != NULL) {
QUE_enqueue(&chan->pendList, packet);
}
else {
chan->dataPacket = packet;
startDma(chan, packet);
if (packet->cmd == IOM_READ) {
/* start the McBSP */
MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0x0);
}
else {
/* start the McBSP */
MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0x0);
}
}
HWI_restore(imask);
return (IOM_PENDING);
}
/*
* ======== C54XX_DMA_MCBSP_init ========
*/
#pragma CODE_SECTION(C54XX_DMA_MCBSP_init, ".text:init")
Void C54XX_DMA_MCBSP_init(Void)
{
/* beware ... this is a global register! */
DMA_FSET(DMPREC, FREE, 1);
}
/*
* ======== startDma ========
*/
static Void startDma(ChanHandle chan, IOM_Packet *packet)
{
/* Program address in appropriate DMA channel and start transfer. */
if (packet->cmd == IOM_READ) {
DMA_RSETH(chan->hDma, DMDST, packet->addr);
DMA_RSETH(chan->hDma, DMCTR, packet->size - 1);
DMA_start(chan->hDma);
}
else {
DMA_RSETH(chan->hDma, DMSRC, packet->addr);
DMA_RSETH(chan->hDma, DMCTR, packet->size - 1);
DMA_start(chan->hDma);
}
}
/*
* ======== dmaIsr ========
*/
Void dmaIsr(ChanHandle chan)
{
PortHandle port = (PortHandle)chan->devp;
IOM_Packet *packet = chan->dataPacket;
if (packet == NULL) {
/* return if spurious interrupt */
return;
}
packet->status = IOM_COMPLETED;
chan->dataPacket = QUE_get(&chan->pendList);
if (chan->dataPacket == (IOM_Packet *)&chan->pendList) {
chan->dataPacket = NULL;
if (packet->cmd == IOM_READ) {
MCBSP_FSETH (port->hMcbsp, SPCR1, RRST, 0);
mcbspStartDelay();
}
else {
MCBSP_FSETH (port->hMcbsp, SPCR2, XRST, 0);
mcbspStartDelay();
}
}
else {
if (packet->cmd == IOM_READ) {
if ( MCBSP_rrdy(port->hMcbsp) ) {
/* reset the McBSP */
MCBSP_FSETH (port->hMcbsp, SPCR1, RRST, 0);
mcbspStartDelay();
startDma(chan, chan->dataPacket);
/* restart the McBSP */
MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0x0);
}
else {
startDma(chan, chan->dataPacket);
}
}
else {
if ( MCBSP_xrdy(port->hMcbsp) ) {
/* reset the McBSP */
MCBSP_FSETH (port->hMcbsp, SPCR2, XRST, 0);
mcbspStartDelay();
startDma(chan, chan->dataPacket);
/* restart the McBSP */
MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0x0);
}
else {
startDma(chan, chan->dataPacket);
}
}
}
(*chan->cbFxn)(chan->cbArg, packet);
}
/*
* ======== abortio ========
* Aborts uncompleted i/o packet requests.
*/
static Void abortio(ChanHandle chan)
{
IOM_Packet *tmpPacket;
DMA_stop(chan->hDma);
HWI_disable();
tmpPacket = chan->dataPacket;
chan->dataPacket = NULL;
HWI_enable();
if (tmpPacket) {
tmpPacket->status = IOM_ABORTED; /* abort current request */
(*chan->cbFxn)(chan->cbArg, tmpPacket);
tmpPacket = QUE_get(&chan->pendList);
while (tmpPacket != (IOM_Packet *)&chan->pendList) {
tmpPacket->status = IOM_ABORTED; /* abort queued requests */
(*chan->cbFxn)(chan->cbArg, tmpPacket);
tmpPacket = QUE_get(&chan->pendList);
}
}
}
static Void mcbspStartDelay(Void)
{
volatile int i;
/* This delay is mainly for allowing
* two mcbsp external clocks to happen from
* the time Mcbsp is put in reset to the time
* Mcbsp is taken out of reset. */
for(i=0; i<DELAY; i++) {
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -