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

📄 tmdma.c

📁 用于TM1300/PNX1300系列DSP(主要用于视频处理)的设备库的源码
💻 C
字号:
/*
 *  +-------------------------------------------------------------------+
 *  | Copyright (c) 1995,2000 TriMedia Technologies Inc.                |
 *  |                                                                   |
 *  | This software  is furnished under a license  and may only be used |
 *  | and copied in accordance with the terms  and conditions of such a |
 *  | license  and with  the inclusion of this  copyright notice.  This |
 *  | software or any other copies of this software may not be provided |
 *  | or otherwise  made available  to any other person.  The ownership |
 *  | and title of this software is not transferred.                    |
 *  |                                                                   |
 *  | The information  in this software  is subject  to change  without |
 *  | any  prior notice  and should not be construed as a commitment by |
 *  | TriMedia Technologies.                                            |
 *  |                                                                   |
 *  | This  code  and  information  is  provided  "as is"  without  any |
 *  | warranty of any kind,  either expressed or implied, including but |
 *  | not limited  to the implied warranties  of merchantability and/or |
 *  | fitness for any particular purpose.                               |
 *  +-------------------------------------------------------------------+
 *
 *  Module name              : tmDMA.c    1.36
 *
 *  Module type              : IMPLEMENTATION
 *
 *  Title                    : DMA service library
 *
 *  Last update              : 10:39:16 - 00/06/20
 *
 *  Description              :
 *
 */

/*----------------------------includes----------------------------------------*/

#include <stdio.h>
#include <tm1/tmAssert.h>
#include <tmlib/AppModel.h>
#include <tm1/mmio.h>
#include <tm1/tmDMA.h>
#include <tm1/tmInterrupts.h>



/*------------------------- local definitions -------------------------------*/

#define WORDSIZE         sizeof(Pointer)
#define DMA_INTERRUPT    intINT_16
#define ALIGNED4(x)      (!(((int)(x))&3))

/*----------------------------functions---------------------------------------*/


static pdmaRequest_t dma_queue_first;
static pdmaRequest_t dma_current;

static Int  next_instance;

static dmaCapabilities_t capabilities =
{
     /* version                */ {MAJOR_VERSION, MINOR_VERSION, BUILD_VERSION},
     /* numSupportedInstances  */ -1,
     /* numCurrentInstances    */ 0
};

static dmaSetup_t cur_setup = {intPRIO_0};

/*
 * The following macro sets up the next DMA transfer.
 * Although it is not currently done, this macro could
 * inspect the request, and find out if it could cause
 * the completion function or the AppModel resume function
 * to be called. If not, then it could temporarily patch
 * a simpler and cheaper version of the interrupt handler
 * into the exception vector:
 */

#define START_NEXT_TRANSFER() \
{                                                                          \
   pdmaDescription_t current;                                              \
                                                                           \
   current= &(dma_current->descriptions[dma_current->current_description]);\
                                                                           \
   MMIO(SRC_ADR) = (UInt)current->source;                                  \
   MMIO(DEST_ADR)= (UInt)current->destination;                             \
                                                                           \
   MMIO(DMA_CTL) = current->length                                         \
             | ( current->direction << 26 )                                \
             | ( current->write_and_invalidate ? (1<<27) : 0 );            \
}

#define INSERT_REQUEST(x) \
   if (dma_queue_first == NULL) {               \
      x->link         = NULL;                   \
      dma_queue_first = x;                      \
                                                \
   } else {                                     \
      pdmaRequest_t *pnext    = &dma_queue_first; \
      UInt           priority = x->priority;    \
                                                \
      while ( (*pnext) != NULL                  \
            && (*pnext)->priority <= priority   \
            ) {                                 \
          pnext= &(*pnext)->link;               \
      }                                         \
                                                \
      x->link = *pnext;                         \
     *pnext   = x;                              \
   }



static void 
dma_handler(void)
{
#pragma TCS_handler

    if (MMIO(BIU_STATUS) & 0xc00) {

        /*
         * Target- or Master abort; clear the status, and retry the
         * current DMA description
         */
        MMIO(BIU_STATUS) = (0xc00 | 0x20);    /* plus handshake to PCI
                                               * interface */
        dma_current->nrof_retries++;

    }
    else {
        /* else: DMA done; */

        pdmaDescription_t current;
        MMIO(BIU_STATUS) = 0x20;    /* handshake to PCI interface */

        current = &(dma_current->descriptions[dma_current->current_description]);

        if (--(current->nr_of_transfers) == 0) {
            dma_current->current_description++;
        }
        else {
            current->source =
                (Pointer) (((Address) current->source)
                       + current->source_stride);

            current->destination =
                (Pointer) (((Address) current->destination)
                       + current->destination_stride);
        }
    }

    /* -- . -- */


    if (dma_current->current_description >= dma_current->nr_of_descriptions) {
        pdmaRequest_t     current             = dma_current;
        dmaFunc_t         completion_function = current->completion_function;
        AppModel_AppId    requester           = current->requester;
        Bool              synchronous         = current->mode == dmaSynchronous;

        current->done   = True;
        dma_current     = dma_queue_first;

        if (dma_queue_first != NULL) {
            dma_queue_first = dma_queue_first->link;
            START_NEXT_TRANSFER();
        }

        /*
         * These functions should be called at the very end, because
         * they might schedule a higher priority task in, and we
         * can't have that while we are fiddling with the global
         * queue:
         */

        if (synchronous)
            AppModel_resume(requester);

        if (completion_function) {
            AppModel_suspend_scheduling();
            AppModel_run_on_sstack( (Pointer)completion_function, (Pointer)current );
            AppModel_resume_scheduling();
        }
    }

    else if (dma_queue_first != NULL
          && dma_current->priority > dma_queue_first->priority ) {

        INSERT_REQUEST(dma_current);
        dma_current      = dma_queue_first;
        dma_queue_first  = dma_queue_first->link;
        START_NEXT_TRANSFER();
    }

    else {
        START_NEXT_TRANSFER();
    }
}



/*
 * Function         : DMA dispatch function.
 * Parameters       : dma_request  (I) description of required
 *                                     dma actions to be taken
 * Function Result  : True iff a synchronous dma request was
 *                         suspended in order to wait for completion.
 */

tmLibdevErr_t
dmaDispatch(
        Int instance,
        pdmaRequest_t dma_request
)
{
    UInt        ien;

    tmAssert(dma_request != Null, TMLIBDEV_ERR_NULL_PARAMETER);
    tmAssert(capabilities.numCurrentInstances != 0, TMLIBDEV_ERR_NOT_OWNER);

    if (dma_request->nr_of_descriptions == 0)
        return TMLIBDEV_OK;

#ifndef NDEBUG
{
    UInt i;

    for (i= 0; i< dma_request->nr_of_descriptions; i++) {
        pdmaDescription_t p= &dma_request->descriptions[i];

        tmAssert(ALIGNED4(p->source),             DMA_ERR_SOURCE_NOT_ALIGNED        );
        tmAssert(ALIGNED4(p->destination),        DMA_ERR_DEST_NOT_ALIGNED          );
        tmAssert(ALIGNED4(p->length),             DMA_ERR_LENGTH_NOT_ALIGNED        );

        if (p->nr_of_transfers > 1) {
            tmAssert(ALIGNED4(p->source_stride),      DMA_ERR_SOURCE_STRIDE_NOT_ALIGNED );
            tmAssert(ALIGNED4(p->destination_stride), DMA_ERR_DEST_STRIDE_NOT_ALIGNED   );
        }
    }
}
#endif

    /*
     * set current thread, and insert into dma queue:
     */

    dma_request->requester            = AppModel_current_thread;
    dma_request->current_description  = 0;
    dma_request->nrof_retries         = 0;
    dma_request->done                 = False;


    ien = intCLEAR_IEN();

    if (dma_current == NULL) {
        dma_current = dma_request;

        START_NEXT_TRANSFER();

    }
    else {
        INSERT_REQUEST(dma_request);
    }

    intRESTORE_IEN(ien);


    /* -- . -- */


    /*
     * Call slack function, when specified:
     */

    if (dma_request->slack_function) {
        dma_request->slack_function(dma_request);
    }

    /* -- . -- */


    /*
     * Await completion, as specified:
     */

    switch (dma_request->mode) {
    case dmaAsynchronous:
        return TMLIBDEV_OK;

    case dmaSynchronous_By_Polling:
        do {} while (!dma_request->done);
        return TMLIBDEV_OK;

    case dmaSynchronous:
        AppModel_suspend_self();
        return TMLIBDEV_OK;
    default:
        return TMLIBDEV_OK;    /* keep apcc happy */
    }
}


/*----------------------------functions---------------------------------------*/




/*
 * Function         : Fills in the capabilities structure.
 * Parameters       : cap  (O)  returned pointer to
 *                              internal capabilities structure
 * Function Result  : resulting error condition
 */

tmLibdevErr_t
dmaGetCapabilities(pdmaCapabilities_t * cap)
{
    tmAssert(cap != Null, TMLIBDEV_ERR_NULL_PARAMETER);

    *cap = &capabilities;

    return TMLIBDEV_OK;
}



/*
 * Function         : Changes parameters of DMA interface,
 *                    like speed and priority.
 *                    Use is optional.
 * Parameters       : setup  (O)  pointer to buffer holding new capabilities
 * Function Result  : resulting error condition
 */

tmLibdevErr_t
dmaSetup(dmaSetup_t * setup)
{
    UInt ien;
    tmAssert(setup != Null, TMLIBDEV_ERR_NULL_PARAMETER);

    ien= intCLEAR_IEN();
    cur_setup= *setup;

    if (capabilities.numCurrentInstances != 0) {
        intInstanceSetup_t int_setup;

        intGetInstanceSetup(DMA_INTERRUPT, &int_setup);
        int_setup.priority = cur_setup.priority;
        intInstanceSetup(DMA_INTERRUPT, &int_setup);
    }

    intRESTORE_IEN(ien);
    return TMLIBDEV_OK;
}



/*
 * Function         : Retrieve global parameters.
 * Parameters       : setup    (O)  pointer to buffer
 *                                  receiving returned parameters
 * Function Result  : resulting error condition
 */

extern      tmLibdevErr_t
dmaGetSetup(dmaSetup_t * setup)
{
    UInt ien;

    tmAssert(setup != Null, TMLIBDEV_ERR_NULL_PARAMETER);

    ien    = intCLEAR_IEN();
    *setup = cur_setup;
    intRESTORE_IEN(ien);

    return TMLIBDEV_OK;
}



/*
 * Function         : Assigns a unique instance for the caller.
 * Parameters       : instance  (O)  pointer to result variable
 * Function Result  : resulting error condition
 */

tmLibdevErr_t
dmaOpen(Int * instance)
{
    UInt ien;
    tmLibdevErr_t err;

    tmAssert(instance != Null, TMLIBDEV_ERR_NULL_PARAMETER);

    /*
     * Setup DMA handling:
     */

    ien= intCLEAR_IEN();

    if (capabilities.numCurrentInstances == 0) {

        if (err = intOpen(DMA_INTERRUPT)) {
            intRESTORE_IEN(ien);
            return err;
        }
        else {
            intInstanceSetup_t int_setup;

            tmAssert(sizeof (int_setup) == 4 * WORDSIZE, DMA_ERR_STRUCT_CHANGED);

            int_setup.handler          = dma_handler;
            int_setup.priority         = cur_setup.priority;
            int_setup.level_triggered  = True;
            int_setup.enabled          = True;

            intInstanceSetup(DMA_INTERRUPT, &int_setup);

            MMIO(BIU_CTL) |= 0x10;    /* enable DMA interrupt */
        }
    }

    ++capabilities.numCurrentInstances;
    *instance = ++next_instance;

    intRESTORE_IEN(ien);
    return TMLIBDEV_OK;
}




/*
 * Function         : Deallocates the instance.
 * Parameters       : instance  (O)  instance to give up
 * Function Result  : resulting error condition
 */

tmLibdevErr_t
dmaClose(Int instance)
{
    UInt ien;
    tmAssert(capabilities.numCurrentInstances != 0, TMLIBDEV_ERR_NOT_OWNER);

    ien= intCLEAR_IEN();

    if (--capabilities.numCurrentInstances == 0) {
        intClose(DMA_INTERRUPT);
    }

    intRESTORE_IEN(ien);
    return TMLIBDEV_OK;
}

⌨️ 快捷键说明

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