c54xx_dma_mcbsp.c
上传用户:dahaojd
上传日期:2008-01-29
资源大小:14357k
文件大小:12k
- /*
- * 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++) {
- }
- }