c55xx_dma_mcbsp.c
上传用户:dahaojd
上传日期:2008-01-29
资源大小:14357k
文件大小:12k
源码类别:

DSP编程

开发平台:

C/C++

  1. /*
  2.  *  Copyright 2003 by Texas Instruments Incorporated.
  3.  *  All rights reserved. Property of Texas Instruments Incorporated.
  4.  *  Restricted rights to use, duplicate or disclose this code are
  5.  *  granted through contract.
  6.  *  
  7.  */
  8. /* "@(#) DDK 1.10.00.23 07-02-03 (ddk-b12)" */
  9. /*
  10.  *  ======== c55xx_dma_mcbsp.c ========
  11.  */
  12. #include <std.h>
  13. #include <atm.h>
  14. #include <hwi.h>
  15. #include <que.h>
  16. #include <csl.h>
  17. #include <csl_dma.h>
  18. #include <csl_irq.h>
  19. #include <csl_mcbsp.h>
  20. #include <iom.h>
  21. #include <c55xx_dma_mcbsp.h>
  22. #define NUMPORTS        MCBSP_PORT_CNT
  23. #define NUMCHANS     2  /* IOM_INPUT and IOM_OUTPUT */
  24. #define INPUT        0
  25. #define OUTPUT       1
  26. /* Channel Object -- intialized by mdCreateChan() */
  27. typedef struct ChanObj {
  28.     Uns         inUse;          /* TRUE => channel has been opened */
  29.     Uns         dmaId;          /* DMA channel */
  30.     void        *devp;          /* needed for McBSP access */
  31.     DMA_Handle  hDma;           /* DMA handle */
  32.     IOM_Packet  *flushPacket;   /* used for submit/IOM_FLUSH/output */
  33.     IOM_Packet  *dataPacket;    /* current active I/O packet */
  34.     QUE_Obj     pendList;       /* list of packets for I/O */
  35.     IOM_TiomCallback cbFxn;     /* used to notify client when I/O complete */
  36.     Ptr         cbArg;
  37. } ChanObj, *ChanHandle;
  38. #define CHANOBJINIT { 
  39.     FALSE,              /* inUse */             
  40.     0,                  /* dmaId */             
  41.     NULL,               /* devp */              
  42.     NULL,               /* hDma */              
  43.     NULL,               /* flushPacket */       
  44.     NULL,               /* dataPacket */        
  45.     { NULL, NULL },     /* pendList */          
  46.     NULL,               /* cbFxn */             
  47.     NULL                /* cbArg */             
  48. }
  49. /* Device Object -- intialized by mdBindDev() */
  50. typedef struct PortObj {
  51.     Uns         inUse;
  52.     MCBSP_Handle hMcbsp;        /* McBSP handle */
  53.     ChanObj     chans[NUMCHANS];
  54.     Uns         rxIerMask[2];
  55.     Uns         txIerMask[2];
  56. } PortObj, *PortHandle;
  57. #define PORTOBJINIT { 
  58.     FALSE,              /* inUse */             
  59.     NULL,               /* hMcbsp */            
  60.     {                   /* chans */             
  61.         CHANOBJINIT,                            
  62.         CHANOBJINIT                             
  63.     },                                          
  64.     {                                           
  65.         NULL,                                   
  66.         NULL                                    
  67.     },                                          
  68.     {                                           
  69.         NULL,                                   
  70.         NULL                                    
  71.     }                                           
  72. }
  73. #if NUMPORTS == 2
  74. static PortObj ports[NUMPORTS] = {              
  75.     PORTOBJINIT,                                
  76.     PORTOBJINIT                                 
  77. };
  78. #elif NUMPORTS == 3
  79. PortObj ports[NUMPORTS] = {                     
  80.     PORTOBJINIT,                                
  81.     PORTOBJINIT,                                
  82.     PORTOBJINIT                                 
  83. };
  84. #else
  85. #error Number of serials ports undefined!!
  86. #endif
  87. /*
  88.  * Forward declaration of IOM interface functions.
  89.  */
  90. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
  91. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
  92. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  93.         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
  94. static Int mdDeleteChan(Ptr chanp);
  95. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
  96. /*
  97.  * Public IOM interface table.
  98.  */
  99. IOM_Fxns C55XX_DMA_MCBSP_FXNS = {
  100.     mdBindDev,
  101.     IOM_UNBINDDEVNOTIMPL,
  102.     mdControlChan,
  103.     mdCreateChan,
  104.     mdDeleteChan,
  105.     mdSubmitChan,
  106. };
  107. /*
  108.  * local functions
  109.  */
  110. static Void startDma(ChanHandle chan, IOM_Packet *packet);
  111. static Void dmaIsr(ChanHandle chan);
  112. static Void abortio(ChanHandle chan);
  113. /*
  114.  *  ======== mdBindDev ========
  115.  */
  116. #pragma CODE_SECTION(mdBindDev, ".text:init")
  117. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
  118. {
  119.     C55XX_DMA_MCBSP_DevParams *params = 
  120.         (C55XX_DMA_MCBSP_DevParams *)devParams;
  121.     PortHandle port = (PortHandle)&ports[devid];
  122.     if (ATM_setu(&port->inUse, TRUE)) {
  123.         return (IOM_EBADIO);
  124.     }
  125.     /* this driver requires parameters, there are no valid defaults */
  126.     if (params == NULL) {
  127.         return (IOM_EBADARGS);
  128.     }
  129.     /* Check the version number */
  130.     if (params->versionId != C55XX_DMA_MCBSP_VERSION_1){
  131.         /* Unsupported Version */
  132.         return(IOM_EBADARGS);
  133.     }
  134.     /* open the McBSP */
  135.     port->hMcbsp = MCBSP_open(devid, MCBSP_OPEN_RESET);
  136.     
  137.     if (port->hMcbsp == INV) {
  138.         return (IOM_EBADIO);
  139.     }
  140.     MCBSP_config(port->hMcbsp, params->mcbspCfg);
  141.     port->chans[INPUT].dmaId = params->rxDmaId;
  142.     port->chans[OUTPUT].dmaId = params->txDmaId;
  143.     /* store the interrupt masks */
  144.     port->rxIerMask[0] = params->rxIerMask[0];
  145.     port->rxIerMask[1] = params->rxIerMask[1];
  146.     port->txIerMask[0] = params->txIerMask[0];
  147.     port->txIerMask[1] = params->txIerMask[1];
  148.     
  149.     *devp = port;
  150.     
  151.     return (IOM_COMPLETED);
  152. }
  153. /*
  154.  *  ======== mdControlChan ========
  155.  */
  156. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
  157. {
  158.     /*
  159.      * If a channel timeouts(in IOM class driver) a calldown is made to
  160.      * mdControlChan w/ cmd = IOM_CHAN_TIMED out. Timeout processing is
  161.      * optionally implemented here. If not performed return status of
  162.      * IOM_ENOTIMPL.
  163.      */
  164.     /*
  165.      *  Channel timed out. Perform needed channel cleanup.
  166.      */
  167.     if (cmd == IOM_CHAN_TIMEDOUT) {
  168.         abortio(chanp);
  169.     }
  170.     else {
  171.         return (IOM_ENOTIMPL); /* return IOM_ENOTIMPL for codes not handled */
  172.     }
  173.     return (IOM_COMPLETED);
  174. }
  175. /*
  176.  *  ======== mdCreateChan ========
  177.  */
  178. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  179.                 Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
  180. {
  181.     PortHandle                  port = (PortHandle)devp;
  182.     C55XX_DMA_MCBSP_ChanParams  *params =
  183.         (C55XX_DMA_MCBSP_ChanParams *)chanParams;
  184.     HWI_Attrs                   attrs;
  185.     ChanHandle                  chan;
  186.     Int                         event;
  187.     volatile Uns                temp;
  188.     chan = (mode == IOM_INPUT) ? &port->chans[INPUT] : &port->chans[OUTPUT];
  189.     /* this driver requires channel parameters, no reasonable default */
  190.     if (params == NULL) {
  191.         return (IOM_EBADARGS);
  192.     }
  193.     /*
  194.      * Check check if channel is already in use.
  195.      * Use ATM_setu() for atomic test-and-set.
  196.      */
  197.     if (ATM_setu((Uns *)&chan->inUse, TRUE)) {
  198.         return (IOM_EBADIO);    /* ERROR! channel is already open! */
  199.     }
  200.     QUE_new(&chan->pendList);
  201.     chan->devp = devp;
  202.     chan->cbFxn = cbFxn;
  203.     chan->cbArg = cbArg;
  204.     /* open and configure DMA */
  205.     chan->hDma = DMA_open(chan->dmaId, DMA_OPEN_RESET);
  206.     if (chan->hDma == INV) {
  207.         return (IOM_EBADIO);
  208.     }
  209.     DMA_config(chan->hDma, params->dmaCfg);
  210.     
  211.     event = DMA_getEventId(chan->hDma);
  212.     /* plug interrupt vector */
  213.     attrs.ier0mask = (mode == IOM_INPUT) ? port->rxIerMask[0] : port->txIerMask[0];
  214.     attrs.ier1mask = (mode == IOM_INPUT) ? port->rxIerMask[1] : port->txIerMask[1];
  215.     attrs.arg = (Arg)chan;
  216.     HWI_dispatchPlug(event, (Fxn)dmaIsr, &attrs);
  217.     /* enable DMA interrupt */
  218.     IRQ_enable(event);
  219.     *chanp = chan;
  220.     return (IOM_COMPLETED);             /* success */
  221. }
  222. /*
  223.  *  ======== mdDeleteChan ========
  224.  *  Mark the channel available and disable the appropriate interrupt.
  225.  */
  226. static Int mdDeleteChan(Ptr chanp)
  227. {
  228.     ChanHandle chan = (ChanHandle)chanp;
  229.     /* disable DMA interrupt */
  230.     IRQ_disable(DMA_getEventId(chan->hDma));
  231.     /* close the DMA channel */
  232.     DMA_close(chan->hDma);
  233.     chan->inUse = FALSE;
  234.     return (IOM_COMPLETED);
  235. }
  236. /*
  237.  *  ======== mdSubmitChan ========
  238.  */
  239. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
  240. {
  241.     ChanHandle  chan = (ChanHandle)chanp;
  242.     PortHandle  port = (PortHandle)chan->devp;
  243.     Uns         imask;
  244.     if (packet->cmd == IOM_FLUSH || packet->cmd == IOM_ABORT) {
  245.         abortio(chan);
  246.         packet->status = IOM_COMPLETED; /* flush/abort pkt completed */
  247.         return (IOM_COMPLETED);
  248.     }
  249.     imask = HWI_disable();
  250.     if (chan->dataPacket != NULL) {
  251.         QUE_enqueue(&chan->pendList, packet);
  252.     }
  253.     else {
  254.         chan->dataPacket = packet;
  255.         startDma(chan, packet);
  256.         if (packet->cmd == IOM_READ) {       
  257.                 MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0);
  258.         }
  259.         else {
  260.             MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0);
  261.         }
  262.     }
  263.     HWI_restore(imask);
  264.     return (IOM_PENDING);
  265. }
  266. /*
  267.  *  ======== C55XX_DMA_MCBSP_init ========
  268.  */
  269. #pragma CODE_SECTION(C55XX_DMA_MCBSP_init, ".text:init")
  270. Void C55XX_DMA_MCBSP_init(Void)
  271. {
  272.     /* beware ... this is a global register! */
  273.     /* Set DMA to continue transfer even during emulation stop */  
  274.     DMA_FSET(DMAGCR, FREE, 1);
  275. }
  276. /*
  277.  *  ======== startDma ========
  278.  */
  279. static Void startDma(ChanHandle chan, IOM_Packet *packet)
  280. {
  281.     /*
  282.      *  Program upper and lower addresses in appropriate DMA channel
  283.      *  and start transfer.
  284.      *  By default, the TMS320C55xx compiler assigns all data symbols word
  285.      *  addresses. The DMA however, expects all addresses to be byte
  286.      *  addresses. Therefore, we must shift the address by 2 in order to
  287.      *  change the word address to a byte address for the DMA transfer.
  288.      */ 
  289.     Uint16 dmaAddrU = (Uint16)( ((Uint32)packet->addr>>15) & 0xFFFF );
  290.     Uint16 dmaAddrL = (Uint16)( ((Uint32)packet->addr<<1) & 0xFFFF );
  291.     if (packet->cmd == IOM_READ) {
  292.         DMA_RSETH(chan->hDma, DMACDSAL, dmaAddrL); 
  293.         DMA_RSETH(chan->hDma, DMACDSAU, dmaAddrU);
  294.         DMA_RSETH(chan->hDma, DMACEN, packet->size);
  295.         DMA_start(chan->hDma);
  296.     }
  297.     else {      
  298.         DMA_RSETH(chan->hDma, DMACSSAL, dmaAddrL); 
  299.         DMA_RSETH(chan->hDma, DMACSSAU, dmaAddrU);
  300.         DMA_RSETH(chan->hDma, DMACEN, packet->size);
  301.         DMA_start(chan->hDma);
  302.     }
  303. }
  304. /*
  305.  *  ======== dmaIsr ========
  306.  */
  307. Void dmaIsr(ChanHandle chan)
  308. {
  309.     IOM_Packet *packet = chan->dataPacket;
  310.     volatile Uns temp;
  311.     if (packet == NULL) {
  312.         /*  return if spurious interrupt */
  313.         return;
  314.     }
  315.     
  316.     packet->status = IOM_COMPLETED;
  317.     chan->dataPacket = QUE_get(&chan->pendList);
  318.     if (chan->dataPacket == (IOM_Packet *)&chan->pendList) {
  319.         chan->dataPacket = NULL;
  320.     }
  321.     else {
  322.         startDma(chan, chan->dataPacket);
  323.     }
  324.     
  325.     (*chan->cbFxn)(chan->cbArg, packet);
  326. }
  327. /*
  328.  *  ======== abortio ========
  329.  *  Aborts uncompleted i/o packet requests.
  330.  */
  331. static Void abortio(ChanHandle chan)
  332. {
  333.     IOM_Packet *tmpPacket;
  334.     volatile Uns temp;
  335.     DMA_stop(chan->hDma);
  336.     HWI_disable();
  337.     tmpPacket = chan->dataPacket;
  338.     chan->dataPacket = NULL;
  339.     HWI_enable();
  340.     if (tmpPacket) {
  341.         tmpPacket->status = IOM_ABORTED;   /* abort current request */
  342.         (*chan->cbFxn)(chan->cbArg, tmpPacket);
  343.         tmpPacket = QUE_get(&chan->pendList);
  344.         while (tmpPacket != (IOM_Packet *)&chan->pendList) {
  345.             tmpPacket->status = IOM_ABORTED;   /* abort queued requests */
  346.             (*chan->cbFxn)(chan->cbArg, tmpPacket);
  347.             tmpPacket = QUE_get(&chan->pendList);
  348.         }
  349.     }
  350. }