⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c55xx_dma_mcbsp.c

📁 DSP/BIOS Driver Developer Kit 1.11 The DSP/BIOS Driver Developer Kit (DDK) provides a selection of
💻 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)" */
/*
 *  ======== c55xx_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 <c55xx_dma_mcbsp.h>

#define NUMPORTS        MCBSP_PORT_CNT
#define NUMCHANS     2  /* IOM_INPUT and IOM_OUTPUT */
#define INPUT        0
#define OUTPUT       1

/* Channel Object -- intialized by mdCreateChan() */
typedef struct ChanObj {
    Uns         inUse;          /* TRUE => channel has been opened */

    Uns         dmaId;          /* DMA channel */

    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         rxIerMask[2];
    Uns         txIerMask[2];
} PortObj, *PortHandle;

#define PORTOBJINIT { \
    FALSE,              /* inUse */             \
    NULL,               /* hMcbsp */            \
    {                   /* chans */             \
        CHANOBJINIT,                            \
        CHANOBJINIT                             \
    },                                          \
    {                                           \
        NULL,                                   \
        NULL                                    \
    },                                          \
    {                                           \
        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 C55XX_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);


/*
 *  ======== mdBindDev ========
 */
#pragma CODE_SECTION(mdBindDev, ".text:init")
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
    C55XX_DMA_MCBSP_DevParams *params = 
        (C55XX_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 != C55XX_DMA_MCBSP_VERSION_1){
        /* Unsupported Version */
        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->rxIerMask[0] = params->rxIerMask[0];
    port->rxIerMask[1] = params->rxIerMask[1];
    port->txIerMask[0] = params->txIerMask[0];
    port->txIerMask[1] = params->txIerMask[1];
    
    *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;
    C55XX_DMA_MCBSP_ChanParams  *params =
        (C55XX_DMA_MCBSP_ChanParams *)chanParams;
    HWI_Attrs                   attrs;
    ChanHandle                  chan;
    Int                         event;
    volatile Uns                temp;

    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.ier0mask = (mode == IOM_INPUT) ? port->rxIerMask[0] : port->txIerMask[0];
    attrs.ier1mask = (mode == IOM_INPUT) ? port->rxIerMask[1] : port->txIerMask[1];
    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) {       
                MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0);
        }
        else {
            MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0);
        }
    }

    HWI_restore(imask);

    return (IOM_PENDING);
}

/*
 *  ======== C55XX_DMA_MCBSP_init ========
 */
#pragma CODE_SECTION(C55XX_DMA_MCBSP_init, ".text:init")
Void C55XX_DMA_MCBSP_init(Void)
{
    /* beware ... this is a global register! */
    /* Set DMA to continue transfer even during emulation stop */  
    DMA_FSET(DMAGCR, FREE, 1);
}

/*
 *  ======== startDma ========
 */
static Void startDma(ChanHandle chan, IOM_Packet *packet)
{
    /*
     *  Program upper and lower addresses in appropriate DMA channel
     *  and start transfer.
     *  By default, the TMS320C55xx compiler assigns all data symbols word
     *  addresses. The DMA however, expects all addresses to be byte
     *  addresses. Therefore, we must shift the address by 2 in order to
     *  change the word address to a byte address for the DMA transfer.
     */ 

    Uint16 dmaAddrU = (Uint16)( ((Uint32)packet->addr>>15) & 0xFFFF );
    Uint16 dmaAddrL = (Uint16)( ((Uint32)packet->addr<<1) & 0xFFFF );

    if (packet->cmd == IOM_READ) {
        DMA_RSETH(chan->hDma, DMACDSAL, dmaAddrL); 
        DMA_RSETH(chan->hDma, DMACDSAU, dmaAddrU);
        DMA_RSETH(chan->hDma, DMACEN, packet->size);
        DMA_start(chan->hDma);
    }
    else {      
        DMA_RSETH(chan->hDma, DMACSSAL, dmaAddrL); 
        DMA_RSETH(chan->hDma, DMACSSAU, dmaAddrU);
        DMA_RSETH(chan->hDma, DMACEN, packet->size);
        DMA_start(chan->hDma);
    }
}

/*
 *  ======== dmaIsr ========
 */
Void dmaIsr(ChanHandle chan)
{
    IOM_Packet *packet = chan->dataPacket;
    volatile Uns temp;

    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;
    }
    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;
    volatile Uns temp;

    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);
        }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -