forked from Imagelibrary/rtems
460 lines
14 KiB
C
460 lines
14 KiB
C
/******************************************************************************
|
|
*
|
|
* 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 <bsp/bestcomm/include/ppctypes.h>
|
|
#include <bsp/bestcomm/bestcomm_api.h>
|
|
#include <bsp/bestcomm/task_api/bestcomm_cntrl.h>
|
|
#include <bsp/bestcomm/task_api/bestcomm_api_mem.h>
|
|
#include <bsp/bestcomm/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;
|
|
|
|
/*
|
|
* 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 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<<SDMA_BD_BIT_READY))) {
|
|
r = TASK_ERR_SIZE_TOO_LARGE;
|
|
|
|
} else {
|
|
bdHead = &BDHead[taskId];
|
|
|
|
/*
|
|
* Increase Buffer Descriptor in-use variable.
|
|
*/
|
|
++TaskBDIdxTable[taskId].currBDInUse;
|
|
|
|
/*
|
|
* Get a generic TaskBD_t pointer to the BD to be assigned.
|
|
* Assign the buffer pointers.
|
|
*/
|
|
bd = TaskBDIdxTable[taskId].BDTablePtr;
|
|
if (TaskBDIdxTable[taskId].numPtr == 1) {
|
|
bd = (TaskBD_t *)&(((TaskBD1_t *)bd)[*bdHead]);
|
|
|
|
((TaskBD1_t *)bd)->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;
|
|
}
|