/****************************************************************************** * * Copyright (c) 2004 Freescale Semiconductor, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * ******************************************************************************/ /*! * \mainpage Introduction * * \author Motorola Semiconductor Products Sector * \date 2 Apr 2004 */ /*! * \file bestcomm_api.c * * Bestcomm_api.c implements most of the BestComm C API. The * TaskSetup() function is generated by the BestComm Task API tools * in capi/task_api/tasksetup_general.h as configured and included by * code_dma/image_rtos?/task_capi/(*).c. Other functions are defined as * inline in capi/bestcomm_api.h. */ #include "include/ppctypes.h" #include "bestcomm_api.h" #include "task_api/bestcomm_cntrl.h" #include "task_api/bestcomm_api_mem.h" #include "task_api/tasksetup_bdtable.h" /*********************************************************************** */ static const char* const TaskVersionString = "BestComm API v2.2 20041209"; /* * Hidden API data per task. */ static BDIdx BDHead[MAX_TASKS]; static BDIdx BDTail[MAX_TASKS]; /* * Virtual memory location of the MBAR. System registers and SRAM are * offset from this address. */ uint8 *MBarGlobal; /* * Offset from MBarGlobal to get the physical memory address of the * MBAR. This will be zero for systems that do not use virtual memory in * their device driver model. */ sint64 MBarPhysOffsetGlobal; /* * Offset to free space in SRAM after task code and buffer descriptors. */ uint32 SramOffsetGlobal = 0; /* * This flag is false when TaskStart() has not yet been called on a * task newly configured by TaskSetup() or TaskStop() has been called. * Otherwise it is true. It is possible that a task disabled itself * (transfer complete or BD ring empty) which will not show up in this * flag. * * It is really only useful for BD tasks that assign buffers (via * TaskBDAssign()) before TaskStart() or after TaskStop() are called. */ int TaskRunning[MAX_TASKS]; /*! * \brief Get a string containing API version information. * \returns Pointer to the API version string */ const char *TaskVersion(void) { return TaskVersionString; } /*! * \brief Initialize the API. * \param MBarRef Reference pointer to the device register memory * map. * * \returns TASK_ERR_NO_ERR on successful initialization. * or TASK_ERR_API_ALREADY_INITIALIZED. * * This function is only used with physical addresses. * * This function will also initialize API internal variables. The return * value TASK_ERR_API_ALREADY_INITIALIZED is intended to help determine if * another process has already instantiated a version of the API. */ int TasksInitAPI(uint8 *MBarRef) { /* * Copy pointer of register space to global variable. * for use by other functions. */ MBarGlobal = MBarRef; /* * The offset is 0 if physical and virtual are the same. */ MBarPhysOffsetGlobal = 0; /* * IF API has not been initialized yet then... * Make sure all BestComm interrupts are disabled and not pending. * Make sure all tasks are disabled. * This feature can only be put in after a way has been found to * communicaticate with other processes. */ return TASK_ERR_NO_ERR; } /*! * \brief Initialize the API when virtual memory is used. * \param MBarRef Reference pointer to the device register memory * map. * \param MBarPhys Actual physical location of MBAR device register * memory map. * * \returns TASK_ERR_NO_ERR on successful initialization. * or TASK_ERR_API_ALREADY_INITIALIZED. * * This function allows using virtual memory addresses as well as physical * addresses. All device registers are offset to the address supplied here, * so the virtual memory space should include enough space for the entire * register set of the device to include the SRAM space. * * This function will also initialize API internal variables. The return * value TASK_ERR_API_ALREADY_INITIALIZED is intended to help determine if * another process has already instantiated a version of the API. */ int TasksInitAPI_VM(uint8 *MBarRef, uint8 *MBarPhys) { /* * Copy pointer of register space to global variable. * for use by other functions. */ MBarGlobal = MBarRef; MBarPhysOffsetGlobal = MBarPhys - MBarRef; /* * If API has not been initialized yet then... * Make sure all BestComm interrupts are disabled and not pending. * Make sure all tasks are disabled. * This feature can only be put in after a way has been found to * communicaticate with other processes. */ return TASK_ERR_NO_ERR; } /*! * \brief \em Deprecated * \param sdma Base address of the BestComm register set * * \returns TASK_ERR_NO_ERR * * Use of this function is no longer necessary. It is retained for * compatibility with previous versions of the API. */ int TasksAttachImage(sdma_regs *sdma) { return TASK_ERR_NO_ERR; } /*! * \brief This function returns the value of the internal variable * used to keep track of used space in SRAM. * * \returns The number of bytes from the beginning of SRAM to the end * used space in the SRAM. * * This function will return the offset to free space in the SRAM * not used by the CAPI. \b Note: The returned value is based * on what is in TasksSetSramOffset. This function can * not determine what SRAM space was used by another process. There must * be some way external to the CAPI to keep track of SRAM space. This * function only returns the internal variable used to keep track of buffer * descriptors. */ uint32 TasksGetSramOffset(void) { return SramOffsetGlobal; } /*! * \brief This function stores the number of bytes from the * beginning of SRAM to the end of the used space. * * \param sram_offset Number of bytes until the beginning of * free space in the SRAM. * * This function sets the free space offset in SRAM. It must be called * before setup in multi-task environments. It is the application's * job to determine where the free space in SRAM is. This sets the * base offset for the buffer descriptor variables during setup, so to * deallocate buffers that have already been set this function should be * called with a new offset. */ void TasksSetSramOffset(uint32 sram_offset) { /* * Set the SramOffsetGlobal variable to be used by TaskSetup_BDTable */ SramOffsetGlobal = sram_offset; } /*! * \brief Start an initialized task running. * \param taskId Task handle passed back from a successful TaskSetup() * \param autoStartEnable Boolean for whether autostart bit is enabled. * If this is set then the parameter autoStartTask * defines the task to auto start. * \param autoStartTask TaskId for task to autostart. If autoStartEnable * is not set then this parameter is a don't care. * \param intrEnable Boolean for interrupt enable for this task. * \returns TASK_ERR_NO_ERR on success or TASK_ERR_INVALID_ARG if taskId * is invalid. */ int TaskStart(TaskId taskId, uint32 autoStartEnable, TaskId autoStartTask, uint32 intrEnable) { if (intrEnable) { SDMA_INT_ENABLE(SDMA_INT_MASK, taskId); } else { SDMA_INT_DISABLE(SDMA_INT_MASK, taskId); } SDMA_TASK_AUTO_START(SDMA_TCR, taskId, autoStartEnable, autoStartTask) SDMA_TASK_ENABLE(SDMA_TCR, taskId); TaskRunning[taskId] = 1; return TASK_ERR_NO_ERR; } /*! * \brief Stop a running task. * \param taskId Task handle passed back from a successful TaskSetup() * \returns TASK_ERR_NO_ERR on success or TASK_ERR_INVALID_ARG if taskId * is invalid. * * \em Note: Stopping a polling buffer descriptor task is a catastrophic * operation. It does not merely pause execution. Context is not * saved. The task's pointer into the BD ring is reset back to the * beginning. * * \em Note: This is not the case for the new "fall-through" BD tasks. * They save the BD ring pointer across stop/start boundaries. The * previous polling tasks are considered deprecated. */ int TaskStop(TaskId taskId) { SDMA_INT_DISABLE(SDMA_INT_MASK, taskId); SDMA_TASK_DISABLE(SDMA_TCR, taskId); TaskRunning[taskId] = 0; return TASK_ERR_NO_ERR; } /*! * \brief Assign a buffer to a buffer descriptor. * \param taskId Task handle passed back from a successful TaskSetup() * \param buffer0 A buffer to send data from or receive data into a device * \param buffer1 A second buffer to send data from or receive data into * a device for use with double-buffer tasks. * \param size Size of the buffer in bytes. * \param bdFlags Buffer descriptor flags to set. Used by ethernet BD tasks. * \returns Handle to the buffer descriptor used by this DMA transfer. * Error is indicated by a negative return value (see TaskErr_t). * * This function is used for both transmit and receive buffer descriptor * tasks. The buffer may be freed by the TaskBDRelease() function. * In the case of tasks with a buffer descriptor with two buffer pointers * this function uses both buffer0 and buffer1 where buffer0 is a source * and buffer1 is a destination. When the buffer descriptor is a single * pointer type, the buffer0 is the only pointer used and buffer1 is ignored. * * Using this function on non-buffer descriptor tasks will produce * unpredictable results. */ BDIdx TaskBDAssign(TaskId taskId, void *buffer0, void *buffer1, int size, uint32 bdFlags) { BDIdx *bdHead; TaskBD_t *bd; BDIdx r = TASK_ERR_NO_ERR; if (TaskBDIdxTable[taskId].currBDInUse == TaskBDIdxTable[taskId].numBD) { /* * The buffer ring is full. */ r = TASK_ERR_BD_RING_FULL; } else if ( (TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG) && ((uint32)size & (uint32)(~SDMA_DRD_MASK_LENGTH))) { r = TASK_ERR_SIZE_TOO_LARGE; } else if ( !(TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG) && ((uint32)size & (uint32)(0xffffffff<DataPtr[0] = (uint32)buffer0; } else { bd = (TaskBD_t *)&(((TaskBD2_t *)bd)[*bdHead]); ((TaskBD2_t *)bd)->DataPtr[0] = (uint32)buffer0; ((TaskBD2_t *)bd)->DataPtr[1] = (uint32)buffer1; } if (bd->Status & SDMA_BD_MASK_READY) { /* * This BD is in use. */ r = TASK_ERR_BD_BUSY; } else { /* * Set status bits and length. As soon as Status is written, the * BestComm may perform the transfer. */ if (TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG) { bd->Status = ( ((uint32)SDMA_DRD_MASK_FLAGS & bdFlags) | ((uint32)SDMA_DRD_MASK_LENGTH & (uint32)size) | ((uint32)SDMA_BD_MASK_READY)); } else { bd->Status = ( ((uint32)SDMA_BD_MASK_SIGN & (uint32)size) | ((uint32)SDMA_BD_MASK_READY)); } /* * Return the current BD index and increment. */ r = *bdHead; *bdHead = (BDIdx)((*bdHead + 1) % (BDIdx)TaskBDIdxTable[taskId].numBD); } } /* * Reenable a fall-through BD tasks that might have exited. */ if (TaskRunning[taskId]) { SDMA_TASK_ENABLE(SDMA_TCR, taskId); } return r; } /*! * \brief Release last buffer in the buffer descriptor ring. * \param taskId Task handle passed back from a successful TaskSetup() * * \returns Buffer descriptor index of next buffer index that will be released * by another call of this function. * TASK_ERR_BD_RING_EMPTY is returned if the ring is already empty. * * This function allows the system to reallocate the memory used by * the buffer. It also cleans up the structure in the BD ring by * removing the tail buffer in the ring. The buffer descriptor tasks * are designed around this. Non-BD tasks do not use this function. * * Using this function on non-buffer descriptor tasks will produce * unpredictable results. */ BDIdx TaskBDRelease(TaskId taskId) { BDIdx *bdTail; TaskBD_t *bd; bdTail = &BDTail[taskId]; if (TaskBDIdxTable[taskId].currBDInUse == 0) { /* * Buffer Descriptor ring is empty, Can't Release! */ return TASK_ERR_BD_RING_EMPTY; } /* * Get a generic TaskBD_t pointer to the next BD to be released. */ bd = TaskGetBD(taskId, *bdTail); /* * Verify the ready bit is clear. */ if (bd->Status & SDMA_BD_MASK_READY) { return TASK_ERR_BD_BUSY; } /* * Increment the tail pointer around the ring, decrement in-use. */ *bdTail = (BDIdx)((*bdTail + 1) % (BDIdx)TaskBDIdxTable[taskId].numBD); --TaskBDIdxTable[taskId].currBDInUse; return *bdTail; } /*! * \brief Release all buffers. * \param taskId Task handle passed back from a successful TaskSetup() * * \returns Buffer descriptor index of next buffer that will be * assigned by TaskBDAssign() which will also be the first * released by the next call to TaskBDRelease() or * TASK_ERR_TASK_RUNNING if the task has not been stopped. * * This function is similar to TaskBDRelease() except that it releases * all assigned buffers including those not yet processed by the BestComm * task; i.e. SDMA_BD_MASK_READY is set. * Non-BD tasks do not use this * function. * * The task should not be running. Call TaskStop() first. * * \em Note: Partially transmitted buffers are up to the user to handle. * * Using this function on non-buffer descriptor tasks will produce * unpredictable results. */ BDIdx TaskBDReset(TaskId taskId) { BDIdx i; TaskBD_t *bd, *bdTab; if (TaskRunning[taskId]) { return TASK_ERR_TASK_RUNNING; } bdTab = TaskBDIdxTable[taskId].BDTablePtr; for (i = (BDIdx)TaskBDIdxTable[taskId].numBD - 1; i >= 0; --i) { if (TaskBDIdxTable[taskId].numPtr == 1) { bd = (TaskBD_t *)&(((TaskBD1_t *)bdTab)[i]); } else { bd = (TaskBD_t *)&(((TaskBD2_t *)bdTab)[i]); } bd->Status = 0x0; } TaskBDIdxTable[taskId].currBDInUse = 0; *TaskBDIdxTable[taskId].BDStartPtr = (volatile uint32)((volatile uint32)TaskBDIdxTable[taskId].BDTablePtr + MBarPhysOffsetGlobal); return BDHead[taskId] = BDTail[taskId] = 0; } /*! * \brief Return BestComm debug information. * \param taskId Task handle passed back from a successful TaskSetup() * \param paramSet TBD * \returns TBD * * The implementation of this function is yet to be determined. */ int TaskDebug(TaskId taskId, TaskDebugParamSet_t *paramSet) { if ((taskId < 0) || (taskId >= MAX_TASKS)) { return TASK_ERR_INVALID_ARG; } if (paramSet == NULL) { return TASK_ERR_INVALID_ARG; } return TASK_ERR_NO_ERR; }