blob: a02e8679fc31cda5862ef7c4ca140b61626a9d41 [file] [log] [blame]
/******************************************************************************
* Filename: udma.c
* Revised: 2015-04-07 14:16:28 +0200 (Tue, 07 Apr 2015)
* Revision: 43160
*
* Description: Driver for the uDMA controller
*
* Copyright (c) 2015 - 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of the ORGANIZATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#include <driverlib/udma.h>
//*****************************************************************************
//
// Handle support for DriverLib in ROM:
// This section will undo prototype renaming made in the header file
//
//*****************************************************************************
#if !defined(DOXYGEN)
#undef uDMAChannelAttributeEnable
#define uDMAChannelAttributeEnable NOROM_uDMAChannelAttributeEnable
#undef uDMAChannelAttributeDisable
#define uDMAChannelAttributeDisable NOROM_uDMAChannelAttributeDisable
#undef uDMAChannelAttributeGet
#define uDMAChannelAttributeGet NOROM_uDMAChannelAttributeGet
#undef uDMAChannelControlSet
#define uDMAChannelControlSet NOROM_uDMAChannelControlSet
#undef uDMAChannelTransferSet
#define uDMAChannelTransferSet NOROM_uDMAChannelTransferSet
#undef uDMAChannelScatterGatherSet
#define uDMAChannelScatterGatherSet NOROM_uDMAChannelScatterGatherSet
#undef uDMAChannelSizeGet
#define uDMAChannelSizeGet NOROM_uDMAChannelSizeGet
#undef uDMAChannelModeGet
#define uDMAChannelModeGet NOROM_uDMAChannelModeGet
#endif
//*****************************************************************************
//
//! Enables attributes of a uDMA channel
//
//*****************************************************************************
void
uDMAChannelAttributeEnable(uint32_t ui32Base, uint32_t ui32ChannelNum,
uint32_t ui32Attr)
{
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
//
// Set the useburst bit for this channel if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_USEBURST)
{
HWREG(ui32Base + UDMA_O_SETBURST) = 1 << ui32ChannelNum;
}
//
// Set the alternate control select bit for this channel,
// if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_ALTSELECT)
{
HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) = 1 << ui32ChannelNum;
}
//
// Set the high priority bit for this channel, if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
{
HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) = 1 << ui32ChannelNum;
}
//
// Set the request mask bit for this channel, if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_REQMASK)
{
HWREG(ui32Base + UDMA_O_SETREQMASK) = 1 << ui32ChannelNum;
}
}
//*****************************************************************************
//
//! Disables attributes of an uDMA channel
//
//*****************************************************************************
void
uDMAChannelAttributeDisable(uint32_t ui32Base, uint32_t ui32ChannelNum,
uint32_t ui32Attr)
{
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
//
// Clear the useburst bit for this channel if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_USEBURST)
{
HWREG(ui32Base + UDMA_O_CLEARBURST) = 1 << ui32ChannelNum;
}
//
// Clear the alternate control select bit for this channel, if set in
// ululAttr.
//
if(ui32Attr & UDMA_ATTR_ALTSELECT)
{
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
}
//
// Clear the high priority bit for this channel, if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
{
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIORITY) = 1 << ui32ChannelNum;
}
//
// Clear the request mask bit for this channel, if set in ui32Attr.
//
if(ui32Attr & UDMA_ATTR_REQMASK)
{
HWREG(ui32Base + UDMA_O_CLEARREQMASK) = 1 << ui32ChannelNum;
}
}
//*****************************************************************************
//
//! Gets the enabled attributes of a uDMA channel
//
//*****************************************************************************
uint32_t
uDMAChannelAttributeGet(uint32_t ui32Base, uint32_t ui32ChannelNum)
{
uint32_t ui32Attr = 0;
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
//
// Check to see if useburst bit is set for this channel.
//
if(HWREG(ui32Base + UDMA_O_SETBURST) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_USEBURST;
}
//
// Check to see if the alternate control bit is set for this channel.
//
if(HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_ALTSELECT;
}
//
// Check to see if the high priority bit is set for this channel.
//
if(HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_HIGH_PRIORITY;
}
//
// Check to see if the request mask bit is set for this channel.
//
if(HWREG(ui32Base + UDMA_O_SETREQMASK) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_REQMASK;
}
//
// Return the configuration flags.
//
return(ui32Attr);
}
//*****************************************************************************
//
//! Sets the control parameters for a uDMA channel control structure
//
//*****************************************************************************
void
uDMAChannelControlSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex,
uint32_t ui32Control)
{
tDMAControlTable *pControlTable;
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
//
// Get the current control word value and mask off the fields to be
// changed, then OR in the new settings.
//
pControlTable[ui32ChannelStructIndex].ui32Control =
((pControlTable[ui32ChannelStructIndex].ui32Control &
~(UDMA_DST_INC_M |
UDMA_SRC_INC_M |
UDMA_SIZE_M |
UDMA_ARB_M |
UDMA_NEXT_USEBURST)) |
ui32Control);
}
//*****************************************************************************
//
//! Sets the transfer parameters for a uDMA channel control structure
//
//*****************************************************************************
void
uDMAChannelTransferSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex,
uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr,
uint32_t ui32TransferSize)
{
tDMAControlTable *pControlTable;
uint32_t ui32Control;
uint32_t ui32Inc;
uint32_t ui32BufferBytes;
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
ASSERT(ui32Mode <= UDMA_MODE_PER_SCATTER_GATHER);
ASSERT((uint32_t)pvSrcAddr >= SRAM_BASE);
ASSERT((uint32_t)pvDstAddr >= SRAM_BASE);
ASSERT((ui32TransferSize != 0) && (ui32TransferSize <= UDMA_XFER_SIZE_MAX));
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
//
// Get the current control word value and mask off the mode and size
// fields.
//
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
~(UDMA_XFER_SIZE_M | UDMA_MODE_M));
//
// Adjust the mode if the alt control structure is selected.
//
if(ui32ChannelStructIndex & UDMA_ALT_SELECT)
{
if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
{
ui32Mode |= UDMA_MODE_ALT_SELECT;
}
}
//
// Set the transfer size and mode in the control word (but don't write the
// control word yet as it could kick off a transfer).
//
ui32Control |= ui32Mode | ((ui32TransferSize - 1) << UDMA_XFER_SIZE_S);
//
// Get the address increment value for the source, from the control word.
//
ui32Inc = (ui32Control & UDMA_SRC_INC_M);
//
// Compute the ending source address of the transfer. If the source
// increment is set to none, then the ending address is the same as the
// beginning.
//
if(ui32Inc != UDMA_SRC_INC_NONE)
{
ui32Inc = ui32Inc >> UDMA_SRC_INC_S;
ui32BufferBytes = ui32TransferSize << ui32Inc;
pvSrcAddr = (void *)((uint32_t)pvSrcAddr + ui32BufferBytes - (1 << ui32Inc));
}
//
// Load the source ending address into the control block.
//
pControlTable[ui32ChannelStructIndex].pvSrcEndAddr = pvSrcAddr;
//
// Get the address increment value for the destination, from the control
// word.
//
ui32Inc = ui32Control & UDMA_DST_INC_M;
//
// Compute the ending destination address of the transfer. If the
// destination increment is set to none, then the ending address is the
// same as the beginning.
//
if(ui32Inc != UDMA_DST_INC_NONE)
{
//
// There is a special case if this is setting up a scatter-gather
// transfer. The destination pointer needs to point to the end of
// the alternate structure for this channel instead of calculating
// the end of the buffer in the normal way.
//
if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
{
pvDstAddr =
(void *)&pControlTable[ui32ChannelStructIndex |
UDMA_ALT_SELECT].ui32Spare;
}
//
// Not a scatter-gather transfer, calculate end pointer normally.
//
else
{
ui32Inc = ui32Inc >> UDMA_DST_INC_S;
ui32BufferBytes = ui32TransferSize << ui32Inc;
pvDstAddr = (void *)((uint32_t)pvDstAddr + ui32BufferBytes - 1);
}
}
//
// Load the destination ending address into the control block.
//
pControlTable[ui32ChannelStructIndex].pvDstEndAddr = pvDstAddr;
//
// Write the new control word value.
//
pControlTable[ui32ChannelStructIndex].ui32Control = ui32Control;
}
//*****************************************************************************
//
//! Configures a uDMA channel for scatter-gather mode
//
//*****************************************************************************
void
uDMAChannelScatterGatherSet(uint32_t ui32Base, uint32_t ui32ChannelNum,
uint32_t ui32TaskCount, void *pvTaskList,
uint32_t ui32IsPeriphSG)
{
tDMAControlTable *pControlTable;
tDMAControlTable *pTaskTable;
//
// Check the parameters.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
ASSERT(pvTaskList != 0);
ASSERT(ui32TaskCount <= UDMA_XFER_SIZE_MAX);
ASSERT(ui32TaskCount != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
//
// Get a handy pointer to the task list.
//
pTaskTable = (tDMAControlTable *)pvTaskList;
//
// Compute the ending address for the source pointer. This will be the
// last element of the last task in the task table.
//
pControlTable[ui32ChannelNum].pvSrcEndAddr =
&pTaskTable[ui32TaskCount - 1].ui32Spare;
//
// Compute the ending address for the destination pointer. This will be
// the end of the alternate structure for this channel.
//
pControlTable[ui32ChannelNum].pvDstEndAddr =
&pControlTable[ui32ChannelNum | UDMA_ALT_SELECT].ui32Spare;
//
// Compute the control word. Most configurable items are fixed for
// scatter-gather. Item and increment sizes are all 32-bit and arb
// size must be 4. The count is the number of items in the task list
// times 4 (4 words per task).
//
pControlTable[ui32ChannelNum].ui32Control =
(UDMA_DST_INC_32 | UDMA_SRC_INC_32 |
UDMA_SIZE_32 | UDMA_ARB_4 |
(((ui32TaskCount * 4) - 1) << UDMA_XFER_SIZE_S) |
(ui32IsPeriphSG ? UDMA_MODE_PER_SCATTER_GATHER :
UDMA_MODE_MEM_SCATTER_GATHER));
//
// Scatter-gather operations can leave the alt bit set. So if doing
// back to back scatter-gather transfers, the second attempt may not
// work correctly because the alt bit is set. Therefore, clear the
// alt bit here to ensure that it is always cleared before a new SG
// transfer is started.
//
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
}
//*****************************************************************************
//
//! Gets the current transfer size for a uDMA channel control structure
//
//*****************************************************************************
uint32_t
uDMAChannelSizeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex)
{
tDMAControlTable *pControlTable;
uint32_t ui32Control;
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
//
// Get the current control word value and mask off all but the size field
// and the mode field.
//
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
(UDMA_XFER_SIZE_M | UDMA_MODE_M));
//
// If the size field and mode field are 0 then the transfer is finished
// and there are no more items to transfer.
//
if(ui32Control == 0)
{
return(0);
}
//
// Otherwise, if either the size field or more field is non-zero, then
// not all the items have been transferred.
//
else
{
//
// Shift the size field and add one, then return to user.
//
return((ui32Control >> UDMA_XFER_SIZE_S) + 1);
}
}
//*****************************************************************************
//
//! Gets the transfer mode for a uDMA channel control structure
//
//*****************************************************************************
uint32_t
uDMAChannelModeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex)
{
tDMAControlTable *pControlTable;
uint32_t ui32Control;
//
// Check the arguments.
//
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
//
// Get the current control word value and mask off all but the mode field.
//
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
UDMA_MODE_M);
//
// Check if scatter/gather mode, and if so, mask off the alt bit.
//
if(((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_MEM_SCATTER_GATHER) ||
((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_PER_SCATTER_GATHER))
{
ui32Control &= ~UDMA_MODE_ALT_SELECT;
}
//
// Return the mode to the caller.
//
return(ui32Control);
}