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

📄 c6x1x_edma_mcbsp.c

📁 DSP/BIOS Driver Developer Kit 1.11 The DSP/BIOS Driver Developer Kit (DDK) provides a selection of
💻 C
📖 第 1 页 / 共 2 页
字号:
        port->enableMask |= MCBSP_SRGR_FRAMESYNC;
    }

    /* True if buffers are in external memory */
    port->cacheCalls = params->cacheCalls;

    /* Store the devid */
    port->devid = devid;

    /* Open and reset the McBSP */
    port->hMcbsp = MCBSP_open(devid, MCBSP_OPEN_RESET);

    if (port->hMcbsp == INV) {
        return (IOM_EALLOC);
    }

    /* Configure the McBSP with the supplied configuration */
    MCBSP_config(port->hMcbsp, params->mcbspCfgPtr);

    /* 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_MCBSP_ChanParams *params =
        (C6X1X_EDMA_MCBSP_ChanParams *) chanParams;
    ChanHandle chan;
    Uns mcbspAddr;
    Uns old;
    Uns esize;
    Int i;

    /*
     * Configuration structure for the loop EDMA job. If the McBSP
     * is left to free running, this loop job is running when there is
     * no data to transfer. This is useful if the McBSP 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, DEFAULT)      |
        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, NULL)        |
        EDMA_FMK (CNT, ELECNT, NULL),

        EDMA_FMKS(IDX, FRMIDX, DEFAULT)     |
        EDMA_FMKS(IDX, ELEIDX, DEFAULT),

        EDMA_FMK (DST, DST, NULL),

        EDMA_FMK (RLD, ELERLD, NULL)        |
        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 McBSP TDM
     * channels) used in the Loop job to preserve the frame sync.
     */
    loopEdmaCfg.cnt = EDMA_FMK(CNT, ELECNT, params->tdmChans);

    /* Use the same sample size in the Loop job as in normal jobs */
    esize = EDMA_FGETA(params->edmaCfgPtr, OPT, ESIZE);
    EDMA_FSETA(&loopEdmaCfg, OPT, ESIZE, esize);

    /* Allocate a TCC for the EDMA */
    chan->tcc = EDMA_intAlloc(-1);

    /* If tcc > 15 (possible on c64x) we abort. */
    if (chan->tcc == -1 || chan->tcc > 15) {
        chanCleanUp(chan, SETFALSE);
        return (IOM_EALLOC);
    }

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

    /* 
     * Process the big endian problem for McBSP 
     * See EDMA App Note (spra636) for details setting in big endian
     */
    if (chan->mode == INPUT) {
        mcbspAddr = MCBSP_getRcvAddr(port->hMcbsp);
    }
    else {
        mcbspAddr = MCBSP_getXmtAddr(port->hMcbsp);
    }
#ifdef _BIG_ENDIAN
    if (esize == EDMA_OPT_ESIZE_8BIT) {
        mcbspAddr += 3;
    }
    else if (esize == EDMA_OPT_ESIZE_16BIT) {
        mcbspAddr += 2;
    }
#endif

    if (chan->mode == INPUT) {
        /* Put input specific parameters in the Loop EDMA config */
        loopEdmaCfg.src = mcbspAddr;
        loopEdmaCfg.dst = (Uint32) &loopDstBuf;

        params->edmaCfgPtr->src = mcbspAddr;

        /* Register our isrInput with the EDMA dispatcher */
        EDMA_intHook(chan->tcc, &isrInput);
    }
    else {
        /* Put output specific parameters in the Loop EDMA config */
        loopEdmaCfg.src = (Uint32) &loopSrcBuf;
        loopEdmaCfg.dst = mcbspAddr;

        params->edmaCfgPtr->dst = mcbspAddr;

        /* Register our isrOutput with the EDMA dispatcher */
        EDMA_intHook(chan->tcc, &isrOutput);
    }

    /* Open the EDMA channel */
    chan->xferPram = 
            EDMA_open(eventIds[port->devid][chan->mode], EDMA_OPEN_RESET);

    if (chan->xferPram == EDMA_HINV) {
        chanCleanUp(chan, FREETABLEEX);
        return (IOM_EALLOC);
    }

    /* Program the data EDMA job with the TCC */
    EDMA_FSETA(params->edmaCfgPtr, OPT, TCC, chan->tcc);

    /* Program the link PaRAMs with the config struct */
    for (i=0; i < MAXLINKCNT; i++) {
        EDMA_config(chan->pramTbl[i], params->edmaCfgPtr);
    }

    /* Program the Loop EDMA job with its config struct */
    EDMA_config(chan->loophEdma, &loopEdmaCfg);

    /*
     * Link the Loop EDMA job to itself to make it run
     * continuously when there is no data to transmit.
     */
    EDMA_link(chan->loophEdma, chan->loophEdma);

    /* Configure the EDMA channel to start with the Loop EDMA job */
    EDMA_config(chan->xferPram, &loopEdmaCfg);

    /* Transfer complete is edge triggered, so clear before enabling */
    EDMA_intClear(chan->tcc);
    EDMA_intEnable(chan->tcc);

    /* Enable the EDMA interrupt */
    IRQ_enable(IRQ_EVT_EDMAINT);

    /* Start the McBSP */
    if (chan->mode == INPUT) {
        MCBSP_start(port->hMcbsp, port->enableMask | MCBSP_RCV_START,
                    MCBSP_SRGR_DEFAULT_DELAY);
    }
    else {
        MCBSP_start(port->hMcbsp, port->enableMask | MCBSP_XMIT_START,
                    MCBSP_SRGR_DEFAULT_DELAY);
    }

    *chanp = (Ptr) chan;
    return (IOM_COMPLETED);
}

/*
 * ======== mdDeleteChan ========
 * This function frees a channel and all it's associated resources.
 */
static Int mdDeleteChan(Ptr chanp)
{
    ChanHandle chan = (ChanHandle) chanp;
    PortHandle port = chan->port;

    /* Clean up the channel resources */
    chanCleanUp(chan, DELCHAN);

    /*
     * Reset the McBSP transmitter or receiver. If the channel is
     * recreated, mdCreateChan() will reenable the transmitter/receiver
     * and by pulling it out of reset it will also restart the EDMA channel.
     */
    if (chan->mode == INPUT) {
        MCBSP_FSETSH(port->hMcbsp, SPCR, RRST, YES);
    }
    else {
        MCBSP_FSETSH(port->hMcbsp, SPCR, XRST, YES);
    }

    return (IOM_COMPLETED);
}

/*
 * ======== mdSubmitChan ========
 * This function transmits a buffer to or from the McASP using the EDMA.
 */
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
    ChanHandle chan = (ChanHandle) chanp;
    PortHandle port = chan->port;
    Uns imask;

    /* No packets can be submitted while abort or flush is active */
    if (chan->flushPacket || chan->abortPacket) {
        return (IOM_EBADIO);
    }

    /*
     * Check to see if an abort command has been issued. Note that
     * flushing the input channel is handled the same as abort.
     */
    if ((packet->cmd == IOM_FLUSH && chan->mode == INPUT) ||
        packet->cmd == IOM_ABORT) {

        /* Disable interrupts to protect submitCount */
        imask = HWI_disable();

        /* Store the abort packet for the ISR to check */
        if (chan->submitCount > 0) {
            chan->abortPacket = packet;

            /*
             * Disable the EDMA channel while linking the currently
             * executing job while linking it with the Loop job to make
             * sure the currently executing job doesn't complete before
             * the link is complete.
             */
            EDMA_disableChannel(chan->xferPram);
            EDMA_link(chan->xferPram, chan->loophEdma);
            EDMA_enableChannel(chan->xferPram);
        }

        /* Reenable interrupts */
        HWI_restore(imask);

        if (chan->abortPacket) {
            return(IOM_PENDING);
        }

        /* If there were no buffers in the channel, return synchronously */
        packet->status = IOM_COMPLETED;

        return (IOM_COMPLETED);
    }

    /* Check to see if the submitted packet is an output flush packet */
    if (packet->cmd == IOM_FLUSH && chan->mode == OUTPUT) {
        /* Disable interrupts to protect submitCount */
        imask = HWI_disable();

        /* Store the flush packet for the ISR to check */
        if (chan->submitCount > 0) {
            chan->flushPacket = packet;
        }

        /* Reenable interrupts */
        HWI_restore(imask);

        if (chan->flushPacket) {
            return(IOM_PENDING);
        }

        /* If there were no buffers in the channel, return synchronously */
        packet->status = IOM_COMPLETED;

        return (IOM_COMPLETED);
    }

    if (packet->cmd != IOM_READ && packet->cmd != IOM_WRITE) {
        /* Unsupported command passed */
        return (IOM_ENOTIMPL);
    }

    /* maintain cache coherency */
    if (chan->mode == INPUT) {
        /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
        if (port->cacheCalls) {
            CACHE_clean(CACHE_L2, packet->addr, packet->size >> 2);
        }
    }
    else {
        /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
        if (port->cacheCalls) {
            CACHE_flush(CACHE_L2, packet->addr, packet->size >> 2);
        }
    }

    /* Disable interrupts to protect submitCount */
    imask = HWI_disable();

    /*
     * If there is no space available for the new packet, put it on a
     * queue to be linked in when space is available. Otherwise link it in.
     */
    if (chan->submitCount >= MAXLINKCNT) {
        QUE_enqueue(&chan->packetQueue, packet);
    }
    else {
        linkPacket(chan, packet);
    }

    chan->submitCount++;

    HWI_restore(imask);

    return (IOM_PENDING);
}

/*
 * ======== mdUnBindDev ========
 * This function frees a port and all it's associated resources.
 */
static Int mdUnBindDev(Ptr devp)
{
    PortHandle port = (PortHandle) devp;

    port->inUse = FALSE;

    /* Close the McBSP */
    MCBSP_close(port->hMcbsp);

    return (IOM_COMPLETED);
}

/*
 * ======== C6X1X_EDMA_MCBSP_init ========
 * This function initializes the driver's data structures.
 */
#pragma CODE_SECTION(C6X1X_EDMA_MCBSP_init, ".text:init");
Void C6X1X_EDMA_MCBSP_init()
{
    PortHandle port;
    ChanHandle chan;
    Int i, j;
    /* Make sure initialization only happens once for this driver */
    static Bool curInit = FALSE;
    if (curInit) {
        return;
    }
    curInit = TRUE;

    for (i=0; i<NUMPORTS; i++) {
        port = &ports[i];

        port->inUse = FALSE;

        for (j=0; j<NUMCHANS; j++) {
            chan = &port->chans[j];

            chan->inUse = FALSE;
        }
    }
}

⌨️ 快捷键说明

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