mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
ARM: 5659/1: bcmring: add csp dmac source files
add csp dmac source files Signed-off-by: Leo Chen <leochen@broadcom.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
1a4a561bdd
commit
cf2ddacb56
1
arch/arm/mach-bcmring/csp/dmac/Makefile
Normal file
1
arch/arm/mach-bcmring/csp/dmac/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-y += dmacHw.o dmacHw_extra.o
|
917
arch/arm/mach-bcmring/csp/dmac/dmacHw.c
Normal file
917
arch/arm/mach-bcmring/csp/dmac/dmacHw.c
Normal file
@ -0,0 +1,917 @@
|
||||
/*****************************************************************************
|
||||
* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
|
||||
*
|
||||
* Unless you and Broadcom execute a separate written software license
|
||||
* agreement governing use of this software, this software is licensed to you
|
||||
* under the terms of the GNU General Public License version 2, available at
|
||||
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
*
|
||||
* Notwithstanding the above, under no circumstances may you combine this
|
||||
* software in any way with any other Broadcom software provided under a
|
||||
* license other than the GPL, without Broadcom's express prior written
|
||||
* consent.
|
||||
*****************************************************************************/
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @file dmacHw.c
|
||||
*
|
||||
* @brief Low level DMA controller driver routines
|
||||
*
|
||||
* @note
|
||||
*
|
||||
* These routines provide basic DMA functionality only.
|
||||
*/
|
||||
/****************************************************************************/
|
||||
|
||||
/* ---- Include Files ---------------------------------------------------- */
|
||||
#include <csp/stdint.h>
|
||||
#include <csp/string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <csp/dmacHw.h>
|
||||
#include <mach/csp/dmacHw_reg.h>
|
||||
#include <mach/csp/dmacHw_priv.h>
|
||||
#include <mach/csp/chipcHw_inline.h>
|
||||
|
||||
/* ---- External Function Prototypes ------------------------------------- */
|
||||
|
||||
/* Allocate DMA control blocks */
|
||||
dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
|
||||
|
||||
uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
|
||||
uint32_t dmaChannelCount_1 = dmacHw_MAX_CHANNEL_COUNT / 2;
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Get maximum FIFO for a DMA channel
|
||||
*
|
||||
* @return Maximum allowable FIFO size
|
||||
*
|
||||
*
|
||||
*/
|
||||
/****************************************************************************/
|
||||
static uint32_t GetFifoSize(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
|
||||
) {
|
||||
uint32_t val = 0;
|
||||
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
dmacHw_MISC_t *pMiscReg =
|
||||
(dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
|
||||
|
||||
switch (pCblk->channel) {
|
||||
case 0:
|
||||
val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
|
||||
break;
|
||||
case 1:
|
||||
val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
|
||||
break;
|
||||
case 2:
|
||||
val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
|
||||
break;
|
||||
case 3:
|
||||
val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
|
||||
break;
|
||||
case 4:
|
||||
val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
|
||||
break;
|
||||
case 5:
|
||||
val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
|
||||
break;
|
||||
case 6:
|
||||
val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
|
||||
break;
|
||||
case 7:
|
||||
val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
|
||||
break;
|
||||
}
|
||||
|
||||
if (val <= 0x4) {
|
||||
return 8 << val;
|
||||
} else {
|
||||
dmacHw_ASSERT(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Program channel register to initiate transfer
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*
|
||||
* @note
|
||||
* - Descriptor buffer MUST ALWAYS be flushed before calling this function
|
||||
* - This function should also be called from ISR to program the channel with
|
||||
* pending descriptors
|
||||
*/
|
||||
/****************************************************************************/
|
||||
void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
|
||||
dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
|
||||
void *pDescriptor /* [ IN ] Descriptor buffer */
|
||||
) {
|
||||
dmacHw_DESC_RING_t *pRing;
|
||||
dmacHw_DESC_t *pProg;
|
||||
dmacHw_CBLK_t *pCblk;
|
||||
|
||||
pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
pRing = dmacHw_GET_DESC_RING(pDescriptor);
|
||||
|
||||
if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
|
||||
/* Not safe yet to program the channel */
|
||||
return;
|
||||
}
|
||||
|
||||
if (pCblk->varDataStarted) {
|
||||
if (pCblk->descUpdated) {
|
||||
pCblk->descUpdated = 0;
|
||||
pProg =
|
||||
(dmacHw_DESC_t *) ((uint32_t)
|
||||
dmacHw_REG_LLP(pCblk->module,
|
||||
pCblk->channel) +
|
||||
pRing->virt2PhyOffset);
|
||||
|
||||
/* Load descriptor if not loaded */
|
||||
if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) {
|
||||
dmacHw_SET_SAR(pCblk->module, pCblk->channel,
|
||||
pProg->sar);
|
||||
dmacHw_SET_DAR(pCblk->module, pCblk->channel,
|
||||
pProg->dar);
|
||||
dmacHw_REG_CTL_LO(pCblk->module,
|
||||
pCblk->channel) =
|
||||
pProg->ctl.lo;
|
||||
dmacHw_REG_CTL_HI(pCblk->module,
|
||||
pCblk->channel) =
|
||||
pProg->ctl.hi;
|
||||
} else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) {
|
||||
/* Return as end descriptor is processed */
|
||||
return;
|
||||
} else {
|
||||
dmacHw_ASSERT(0);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) {
|
||||
/* Do not make a single chain, rather process one descriptor at a time */
|
||||
pProg = pRing->pHead;
|
||||
/* Point to the next descriptor for next iteration */
|
||||
dmacHw_NEXT_DESC(pRing, pHead);
|
||||
} else {
|
||||
/* Return if no more pending descriptor */
|
||||
if (pRing->pEnd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pProg = pRing->pProg;
|
||||
if (pConfig->transferMode ==
|
||||
dmacHw_TRANSFER_MODE_CONTINUOUS) {
|
||||
/* Make sure a complete ring can be formed */
|
||||
dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd->
|
||||
llp == pRing->pProg);
|
||||
/* Make sure pProg pointing to the pHead */
|
||||
dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg ==
|
||||
pRing->pHead);
|
||||
/* Make a complete ring */
|
||||
do {
|
||||
pRing->pProg->ctl.lo |=
|
||||
(dmacHw_REG_CTL_LLP_DST_EN |
|
||||
dmacHw_REG_CTL_LLP_SRC_EN);
|
||||
pRing->pProg =
|
||||
(dmacHw_DESC_t *) pRing->pProg->llp;
|
||||
} while (pRing->pProg != pRing->pHead);
|
||||
} else {
|
||||
/* Make a single long chain */
|
||||
while (pRing->pProg != pRing->pEnd) {
|
||||
pRing->pProg->ctl.lo |=
|
||||
(dmacHw_REG_CTL_LLP_DST_EN |
|
||||
dmacHw_REG_CTL_LLP_SRC_EN);
|
||||
pRing->pProg =
|
||||
(dmacHw_DESC_t *) pRing->pProg->llp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Program the channel registers */
|
||||
dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar);
|
||||
dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar);
|
||||
dmacHw_SET_LLP(pCblk->module, pCblk->channel,
|
||||
(uint32_t) pProg - pRing->virt2PhyOffset);
|
||||
dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) =
|
||||
pProg->ctl.lo;
|
||||
dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) =
|
||||
pProg->ctl.hi;
|
||||
if (pRing->pEnd) {
|
||||
/* Remember the descriptor to use next */
|
||||
pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp;
|
||||
}
|
||||
/* Indicate no more pending descriptor */
|
||||
pRing->pEnd = (dmacHw_DESC_t *) NULL;
|
||||
}
|
||||
/* Start DMA operation */
|
||||
dmacHw_DMA_START(pCblk->module, pCblk->channel);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Initializes DMA
|
||||
*
|
||||
* This function initializes DMA CSP driver
|
||||
*
|
||||
* @note
|
||||
* Must be called before using any DMA channel
|
||||
*/
|
||||
/****************************************************************************/
|
||||
void dmacHw_initDma(void)
|
||||
{
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
dmaChannelCount_0 = dmacHw_GET_NUM_CHANNEL(0);
|
||||
dmaChannelCount_1 = dmacHw_GET_NUM_CHANNEL(1);
|
||||
|
||||
/* Enable access to the DMA block */
|
||||
chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0);
|
||||
chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1);
|
||||
|
||||
if ((dmaChannelCount_0 + dmaChannelCount_1) > dmacHw_MAX_CHANNEL_COUNT) {
|
||||
dmacHw_ASSERT(0);
|
||||
}
|
||||
|
||||
memset((void *)dmacHw_gCblk, 0,
|
||||
sizeof(dmacHw_CBLK_t) * (dmaChannelCount_0 + dmaChannelCount_1));
|
||||
for (i = 0; i < dmaChannelCount_0; i++) {
|
||||
dmacHw_gCblk[i].module = 0;
|
||||
dmacHw_gCblk[i].channel = i;
|
||||
}
|
||||
for (i = 0; i < dmaChannelCount_1; i++) {
|
||||
dmacHw_gCblk[i + dmaChannelCount_0].module = 1;
|
||||
dmacHw_gCblk[i + dmaChannelCount_0].channel = i;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Exit function for DMA
|
||||
*
|
||||
* This function isolates DMA from the system
|
||||
*
|
||||
*/
|
||||
/****************************************************************************/
|
||||
void dmacHw_exitDma(void)
|
||||
{
|
||||
/* Disable access to the DMA block */
|
||||
chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0);
|
||||
chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Gets a handle to a DMA channel
|
||||
*
|
||||
* This function returns a handle, representing a control block of a particular DMA channel
|
||||
*
|
||||
* @return -1 - On Failure
|
||||
* handle - On Success, representing a channel control block
|
||||
*
|
||||
* @note
|
||||
* None Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
|
||||
*/
|
||||
/****************************************************************************/
|
||||
dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId /* [ IN ] DMA Channel Id */
|
||||
) {
|
||||
int idx;
|
||||
|
||||
switch ((channelId >> 8)) {
|
||||
case 0:
|
||||
dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_0);
|
||||
idx = (channelId & 0xff);
|
||||
break;
|
||||
case 1:
|
||||
dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_1);
|
||||
idx = dmaChannelCount_0 + (channelId & 0xff);
|
||||
break;
|
||||
default:
|
||||
dmacHw_ASSERT(0);
|
||||
return (dmacHw_HANDLE_t) -1;
|
||||
}
|
||||
|
||||
return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[idx]);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Initializes a DMA channel for use
|
||||
*
|
||||
* This function initializes and resets a DMA channel for use
|
||||
*
|
||||
* @return -1 - On Failure
|
||||
* 0 - On Success
|
||||
*
|
||||
* @note
|
||||
* None
|
||||
*/
|
||||
/****************************************************************************/
|
||||
int dmacHw_initChannel(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
|
||||
) {
|
||||
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
int module = pCblk->module;
|
||||
int channel = pCblk->channel;
|
||||
|
||||
/* Reinitialize the control block */
|
||||
memset((void *)pCblk, 0, sizeof(dmacHw_CBLK_t));
|
||||
pCblk->module = module;
|
||||
pCblk->channel = channel;
|
||||
|
||||
/* Enable DMA controller */
|
||||
dmacHw_DMA_ENABLE(pCblk->module);
|
||||
/* Reset DMA channel */
|
||||
dmacHw_RESET_CONTROL_LO(pCblk->module, pCblk->channel);
|
||||
dmacHw_RESET_CONTROL_HI(pCblk->module, pCblk->channel);
|
||||
dmacHw_RESET_CONFIG_LO(pCblk->module, pCblk->channel);
|
||||
dmacHw_RESET_CONFIG_HI(pCblk->module, pCblk->channel);
|
||||
|
||||
/* Clear all raw interrupt status */
|
||||
dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
|
||||
/* Mask event specific interrupts */
|
||||
dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
dmacHw_STRAN_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
dmacHw_DTRAN_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Finds amount of memory required to form a descriptor ring
|
||||
*
|
||||
*
|
||||
* @return Number of bytes required to form a descriptor ring
|
||||
*
|
||||
*
|
||||
*/
|
||||
/****************************************************************************/
|
||||
uint32_t dmacHw_descriptorLen(uint32_t descCnt /* [ IN ] Number of descriptor in the ring */
|
||||
) {
|
||||
/* Need extra 4 byte to ensure 32 bit alignment */
|
||||
return (descCnt * sizeof(dmacHw_DESC_t)) + sizeof(dmacHw_DESC_RING_t) +
|
||||
sizeof(uint32_t);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Initializes descriptor ring
|
||||
*
|
||||
* This function will initializes the descriptor ring of a DMA channel
|
||||
*
|
||||
*
|
||||
* @return -1 - On failure
|
||||
* 0 - On success
|
||||
* @note
|
||||
* - "len" parameter should be obtained from "dmacHw_descriptorLen"
|
||||
* - Descriptor buffer MUST be 32 bit aligned and uncached as it is
|
||||
* accessed by ARM and DMA
|
||||
*/
|
||||
/****************************************************************************/
|
||||
int dmacHw_initDescriptor(void *pDescriptorVirt, /* [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
|
||||
uint32_t descriptorPhyAddr, /* [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
|
||||
uint32_t len, /* [ IN ] Size of the pBuf */
|
||||
uint32_t num /* [ IN ] Number of descriptor in the ring */
|
||||
) {
|
||||
uint32_t i;
|
||||
dmacHw_DESC_RING_t *pRing;
|
||||
dmacHw_DESC_t *pDesc;
|
||||
|
||||
/* Check the alignment of the descriptor */
|
||||
if ((uint32_t) pDescriptorVirt & 0x00000003) {
|
||||
dmacHw_ASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if enough space has been allocated for descriptor ring */
|
||||
if (len < dmacHw_descriptorLen(num)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pRing = dmacHw_GET_DESC_RING(pDescriptorVirt);
|
||||
pRing->pHead =
|
||||
(dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t));
|
||||
pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
|
||||
pRing->pProg = dmacHw_DESC_INIT;
|
||||
/* Initialize link item chain, starting from the head */
|
||||
pDesc = pRing->pHead;
|
||||
/* Find the offset between virtual to physical address */
|
||||
pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr;
|
||||
|
||||
/* Form the descriptor ring */
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
/* Clear link list item */
|
||||
memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
|
||||
/* Point to the next item in the physical address */
|
||||
pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset;
|
||||
/* Point to the next item in the virtual address */
|
||||
pDesc->llp = (uint32_t) (pDesc + 1);
|
||||
/* Mark descriptor is ready to use */
|
||||
pDesc->ctl.hi = dmacHw_DESC_FREE;
|
||||
/* Look into next link list item */
|
||||
pDesc++;
|
||||
}
|
||||
|
||||
/* Clear last link list item */
|
||||
memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
|
||||
/* Last item pointing to the first item in the
|
||||
physical address to complete the ring */
|
||||
pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset;
|
||||
/* Last item pointing to the first item in the
|
||||
virtual address to complete the ring
|
||||
*/
|
||||
pDesc->llp = (uint32_t) pRing->pHead;
|
||||
/* Mark descriptor is ready to use */
|
||||
pDesc->ctl.hi = dmacHw_DESC_FREE;
|
||||
/* Set the number of descriptors in the ring */
|
||||
pRing->num = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Configure DMA channel
|
||||
*
|
||||
* @return 0 : On success
|
||||
* -1 : On failure
|
||||
*/
|
||||
/****************************************************************************/
|
||||
int dmacHw_configChannel(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
|
||||
dmacHw_CONFIG_t *pConfig /* [ IN ] Configuration settings */
|
||||
) {
|
||||
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
uint32_t cfgHigh = 0;
|
||||
int srcTrSize;
|
||||
int dstTrSize;
|
||||
|
||||
pCblk->varDataStarted = 0;
|
||||
pCblk->userData = NULL;
|
||||
|
||||
/* Configure
|
||||
- Burst transaction when enough data in available in FIFO
|
||||
- AHB Access protection 1
|
||||
- Source and destination peripheral ports
|
||||
*/
|
||||
cfgHigh =
|
||||
dmacHw_REG_CFG_HI_FIFO_ENOUGH | dmacHw_REG_CFG_HI_AHB_HPROT_1 |
|
||||
dmacHw_SRC_PERI_INTF(pConfig->
|
||||
srcPeripheralPort) |
|
||||
dmacHw_DST_PERI_INTF(pConfig->dstPeripheralPort);
|
||||
/* Set priority */
|
||||
dmacHw_SET_CHANNEL_PRIORITY(pCblk->module, pCblk->channel,
|
||||
pConfig->channelPriority);
|
||||
|
||||
if (pConfig->dstStatusRegisterAddress != 0) {
|
||||
/* Destination status update enable */
|
||||
cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_DST_STAT;
|
||||
/* Configure status registers */
|
||||
dmacHw_SET_DSTATAR(pCblk->module, pCblk->channel,
|
||||
pConfig->dstStatusRegisterAddress);
|
||||
}
|
||||
|
||||
if (pConfig->srcStatusRegisterAddress != 0) {
|
||||
/* Source status update enable */
|
||||
cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_SRC_STAT;
|
||||
/* Source status update enable */
|
||||
dmacHw_SET_SSTATAR(pCblk->module, pCblk->channel,
|
||||
pConfig->srcStatusRegisterAddress);
|
||||
}
|
||||
/* Configure the config high register */
|
||||
dmacHw_GET_CONFIG_HI(pCblk->module, pCblk->channel) = cfgHigh;
|
||||
|
||||
/* Clear all raw interrupt status */
|
||||
dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
|
||||
|
||||
/* Configure block interrupt */
|
||||
if (pConfig->blockTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
|
||||
dmacHw_BLOCK_INT_ENABLE(pCblk->module, pCblk->channel);
|
||||
} else {
|
||||
dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
}
|
||||
/* Configure complete transfer interrupt */
|
||||
if (pConfig->completeTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
|
||||
dmacHw_TRAN_INT_ENABLE(pCblk->module, pCblk->channel);
|
||||
} else {
|
||||
dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
}
|
||||
/* Configure error interrupt */
|
||||
if (pConfig->errorInterrupt == dmacHw_INTERRUPT_ENABLE) {
|
||||
dmacHw_ERROR_INT_ENABLE(pCblk->module, pCblk->channel);
|
||||
} else {
|
||||
dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
|
||||
}
|
||||
/* Configure gather register */
|
||||
if (pConfig->srcGatherWidth) {
|
||||
srcTrSize =
|
||||
dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
|
||||
if (!
|
||||
((pConfig->srcGatherWidth % srcTrSize)
|
||||
&& (pConfig->srcGatherJump % srcTrSize))) {
|
||||
dmacHw_REG_SGR_LO(pCblk->module, pCblk->channel) =
|
||||
((pConfig->srcGatherWidth /
|
||||
srcTrSize) << 20) | (pConfig->srcGatherJump /
|
||||
srcTrSize);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Configure scatter register */
|
||||
if (pConfig->dstScatterWidth) {
|
||||
dstTrSize =
|
||||
dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
|
||||
if (!
|
||||
((pConfig->dstScatterWidth % dstTrSize)
|
||||
&& (pConfig->dstScatterJump % dstTrSize))) {
|
||||
dmacHw_REG_DSR_LO(pCblk->module, pCblk->channel) =
|
||||
((pConfig->dstScatterWidth /
|
||||
dstTrSize) << 20) | (pConfig->dstScatterJump /
|
||||
dstTrSize);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Indicates whether DMA transfer is in progress or completed
|
||||
*
|
||||
* @return DMA transfer status
|
||||
* dmacHw_TRANSFER_STATUS_BUSY: DMA Transfer ongoing
|
||||
* dmacHw_TRANSFER_STATUS_DONE: DMA Transfer completed
|
||||
* dmacHw_TRANSFER_STATUS_ERROR: DMA Transfer error
|
||||
*
|
||||
*/
|
||||
/****************************************************************************/
|
||||
dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
|
||||
) {
|
||||
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
|
||||
if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
|
||||
return dmacHw_TRANSFER_STATUS_BUSY;
|
||||
} else if (dmacHw_REG_INT_RAW_ERROR(pCblk->module) &
|
||||
(0x00000001 << pCblk->channel)) {
|
||||
return dmacHw_TRANSFER_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return dmacHw_TRANSFER_STATUS_DONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Set descriptors for known data length
|
||||
*
|
||||
* When DMA has to work as a flow controller, this function prepares the
|
||||
* descriptor chain to transfer data
|
||||
*
|
||||
* from:
|
||||
* - Memory to memory
|
||||
* - Peripheral to memory
|
||||
* - Memory to Peripheral
|
||||
* - Peripheral to Peripheral
|
||||
*
|
||||
* @return -1 - On failure
|
||||
* 0 - On success
|
||||
*
|
||||
*/
|
||||
/****************************************************************************/
|
||||
int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
|
||||
void *pDescriptor, /* [ IN ] Descriptor buffer */
|
||||
void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
|
||||
void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
|
||||
size_t dataLen /* [ IN ] Data length in bytes */
|
||||
) {
|
||||
dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
|
||||
dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
|
||||
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
|
||||
dmacHw_DESC_t *pStart;
|
||||
dmacHw_DESC_t *pProg;
|
||||
int srcTs = 0;
|
||||
int blkTs = 0;
|
||||
int oddSize = 0;
|
||||
int descCount = 0;
|
||||
int count = 0;
|
||||
int dstTrSize = 0;
|
||||
int srcTrSize = 0;
|
||||
uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
|
||||
|
||||
dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
|
||||
srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
|
||||
|
||||
/* Skip Tx if buffer is NULL or length is unknown */
|
||||
if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
|
||||
/* Do not initiate transfer */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ensure scatter and gather are transaction aligned */
|
||||
if ((pConfig->srcGatherWidth % srcTrSize)
|
||||
|| (pConfig->dstScatterWidth % dstTrSize)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*
|
||||
Background 1: DMAC can not perform DMA if source and destination addresses are
|
||||
not properly aligned with the channel's transaction width. So, for successful
|
||||
DMA transfer, transaction width must be set according to the alignment of the
|
||||
source and destination address.
|
||||
*/
|
||||
|
||||
/* Adjust destination transaction width if destination address is not aligned properly */
|
||||
dstTrWidth = pConfig->dstMaxTransactionWidth;
|
||||
while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
|
||||
dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
|
||||
dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
|
||||
}
|
||||
|
||||
/* Adjust source transaction width if source address is not aligned properly */
|
||||
srcTrWidth = pConfig->srcMaxTransactionWidth;
|
||||
while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
|
||||
srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
|
||||
srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
|
||||
}
|
||||
|
||||
/* Find the maximum transaction per descriptor */
|
||||
if (pConfig->maxDataPerBlock
|
||||
&& ((pConfig->maxDataPerBlock / srcTrSize) <
|
||||
dmacHw_MAX_BLOCKSIZE)) {
|
||||
maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
|
||||
}
|
||||
|
||||
/* Find number of source transactions needed to complete the DMA transfer */
|
||||
srcTs = dataLen / srcTrSize;
|
||||
/* Find the odd number of bytes that need to be transferred as single byte transaction width */
|
||||
if (srcTs && (dstTrSize > srcTrSize)) {
|
||||
oddSize = dataLen % dstTrSize;
|
||||
/* Adjust source transaction count due to "oddSize" */
|
||||
srcTs = srcTs - (oddSize / srcTrSize);
|
||||
} else {
|
||||
oddSize = dataLen % srcTrSize;
|
||||
}
|
||||
/* Adjust "descCount" due to "oddSize" */
|
||||
if (oddSize) {
|
||||
descCount++;
|
||||
}
|
||||
/* Find the number of descriptor needed for total "srcTs" */
|
||||
if (srcTs) {
|
||||
descCount += ((srcTs - 1) / maxBlockSize) + 1;
|
||||
}
|
||||
|
||||
/* Check the availability of "descCount" discriptors in the ring */
|
||||
pProg = pRing->pHead;
|
||||
for (count = 0; (descCount <= pRing->num) && (count < descCount);
|
||||
count++) {
|
||||
if ((pProg->ctl.hi & dmacHw_DESC_FREE) == 0) {
|
||||
/* Sufficient descriptors are not available */
|
||||
return -3;
|
||||
}
|
||||
pProg = (dmacHw_DESC_t *) pProg->llp;
|
||||
}
|
||||
|
||||
/* Remember the link list item to program the channel registers */
|
||||
pStart = pProg = pRing->pHead;
|
||||
/* Make a link list with "descCount(=count)" number of descriptors */
|
||||
while (count) {
|
||||
/* Reset channel control information */
|
||||
pProg->ctl.lo = 0;
|
||||
/* Enable source gather if configured */
|
||||
if (pConfig->srcGatherWidth) {
|
||||
pProg->ctl.lo |= dmacHw_REG_CTL_SG_ENABLE;
|
||||
}
|
||||
/* Enable destination scatter if configured */
|
||||
if (pConfig->dstScatterWidth) {
|
||||
pProg->ctl.lo |= dmacHw_REG_CTL_DS_ENABLE;
|
||||
}
|
||||
/* Set source and destination address */
|
||||
pProg->sar = (uint32_t) pSrcAddr;
|
||||
pProg->dar = (uint32_t) pDstAddr;
|
||||
/* Use "devCtl" to mark that user memory need to be freed later if needed */
|
||||
if (pProg == pRing->pHead) {
|
||||
pProg->devCtl = dmacHw_FREE_USER_MEMORY;
|
||||
} else {
|
||||
pProg->devCtl = 0;
|
||||
}
|
||||
|
||||
blkTs = srcTs;
|
||||
|
||||
/* Special treatmeant for last descriptor */
|
||||
if (count == 1) {
|
||||
/* Mark the last descriptor */
|
||||
pProg->ctl.lo &=
|
||||
~(dmacHw_REG_CTL_LLP_DST_EN |
|
||||
dmacHw_REG_CTL_LLP_SRC_EN);
|
||||
/* Treatment for odd data bytes */
|
||||
if (oddSize) {
|
||||
/* Adjust for single byte transaction width */
|
||||
switch (pConfig->transferType) {
|
||||
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
|
||||
dstTrWidth =
|
||||
dmacHw_DST_TRANSACTION_WIDTH_8;
|
||||
blkTs =
|
||||
(oddSize / srcTrSize) +
|
||||
((oddSize % srcTrSize) ? 1 : 0);
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
|
||||
srcTrWidth =
|
||||
dmacHw_SRC_TRANSACTION_WIDTH_8;
|
||||
blkTs = oddSize;
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
|
||||
srcTrWidth =
|
||||
dmacHw_SRC_TRANSACTION_WIDTH_8;
|
||||
dstTrWidth =
|
||||
dmacHw_DST_TRANSACTION_WIDTH_8;
|
||||
blkTs = oddSize;
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
|
||||
/* Do not adjust the transaction width */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
srcTs -= blkTs;
|
||||
}
|
||||
} else {
|
||||
if (srcTs / maxBlockSize) {
|
||||
blkTs = maxBlockSize;
|
||||
}
|
||||
/* Remaining source transactions for next iteration */
|
||||
srcTs -= blkTs;
|
||||
}
|
||||
/* Must have a valid source transactions */
|
||||
dmacHw_ASSERT(blkTs > 0);
|
||||
/* Set control information */
|
||||
if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
|
||||
pProg->ctl.lo |= pConfig->transferType |
|
||||
pConfig->srcUpdate |
|
||||
pConfig->dstUpdate |
|
||||
srcTrWidth |
|
||||
dstTrWidth |
|
||||
pConfig->srcMaxBurstWidth |
|
||||
pConfig->dstMaxBurstWidth |
|
||||
pConfig->srcMasterInterface |
|
||||
pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
|
||||
} else {
|
||||
uint32_t transferType = 0;
|
||||
switch (pConfig->transferType) {
|
||||
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
|
||||
transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
|
||||
transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
|
||||
break;
|
||||
default:
|
||||
dmacHw_ASSERT(0);
|
||||
}
|
||||
pProg->ctl.lo |= transferType |
|
||||
pConfig->srcUpdate |
|
||||
pConfig->dstUpdate |
|
||||
srcTrWidth |
|
||||
dstTrWidth |
|
||||
pConfig->srcMaxBurstWidth |
|
||||
pConfig->dstMaxBurstWidth |
|
||||
pConfig->srcMasterInterface |
|
||||
pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
|
||||
}
|
||||
|
||||
/* Set block transaction size */
|
||||
pProg->ctl.hi = blkTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
|
||||
/* Look for next descriptor */
|
||||
if (count > 1) {
|
||||
/* Point to the next descriptor */
|
||||
pProg = (dmacHw_DESC_t *) pProg->llp;
|
||||
|
||||
/* Update source and destination address for next iteration */
|
||||
switch (pConfig->transferType) {
|
||||
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
|
||||
if (pConfig->dstScatterWidth) {
|
||||
pDstAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize +
|
||||
(((blkTs * srcTrSize) /
|
||||
pConfig->dstScatterWidth) *
|
||||
pConfig->dstScatterJump);
|
||||
} else {
|
||||
pDstAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize;
|
||||
}
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
|
||||
if (pConfig->srcGatherWidth) {
|
||||
pSrcAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize +
|
||||
(((blkTs * srcTrSize) /
|
||||
pConfig->srcGatherWidth) *
|
||||
pConfig->srcGatherJump);
|
||||
} else {
|
||||
pSrcAddr =
|
||||
(char *)pSrcAddr +
|
||||
blkTs * srcTrSize;
|
||||
}
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
|
||||
if (pConfig->dstScatterWidth) {
|
||||
pDstAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize +
|
||||
(((blkTs * srcTrSize) /
|
||||
pConfig->dstScatterWidth) *
|
||||
pConfig->dstScatterJump);
|
||||
} else {
|
||||
pDstAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize;
|
||||
}
|
||||
|
||||
if (pConfig->srcGatherWidth) {
|
||||
pSrcAddr =
|
||||
(char *)pDstAddr +
|
||||
blkTs * srcTrSize +
|
||||
(((blkTs * srcTrSize) /
|
||||
pConfig->srcGatherWidth) *
|
||||
pConfig->srcGatherJump);
|
||||
} else {
|
||||
pSrcAddr =
|
||||
(char *)pSrcAddr +
|
||||
blkTs * srcTrSize;
|
||||
}
|
||||
break;
|
||||
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
|
||||
/* Do not adjust the address */
|
||||
break;
|
||||
default:
|
||||
dmacHw_ASSERT(0);
|
||||
}
|
||||
} else {
|
||||
/* At the end of transfer "srcTs" must be zero */
|
||||
dmacHw_ASSERT(srcTs == 0);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
|
||||
/* Remember the descriptor to initialize the registers */
|
||||
if (pRing->pProg == dmacHw_DESC_INIT) {
|
||||
pRing->pProg = pStart;
|
||||
}
|
||||
/* Indicate that the descriptor is updated */
|
||||
pRing->pEnd = pProg;
|
||||
/* Head pointing to the next descriptor */
|
||||
pRing->pHead = (dmacHw_DESC_t *) pProg->llp;
|
||||
/* Update Tail pointer if destination is a peripheral,
|
||||
because no one is going to read from the pTail
|
||||
*/
|
||||
if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
|
||||
pRing->pTail = pRing->pHead;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/**
|
||||
* @brief Provides DMA controller attributes
|
||||
*
|
||||
*
|
||||
* @return DMA controller attributes
|
||||
*
|
||||
* @note
|
||||
* None
|
||||
*/
|
||||
/****************************************************************************/
|
||||
uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
|
||||
dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controler attribute of type dmacHw_CONTROLLER_ATTRIB_e */
|
||||
) {
|
||||
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
|
||||
|
||||
switch (attr) {
|
||||
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM:
|
||||
return dmacHw_GET_NUM_CHANNEL(pCblk->module);
|
||||
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE:
|
||||
return (1 <<
|
||||
(dmacHw_GET_MAX_BLOCK_SIZE
|
||||
(pCblk->module, pCblk->module) + 2)) - 8;
|
||||
case dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM:
|
||||
return dmacHw_GET_NUM_INTERFACE(pCblk->module);
|
||||
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH:
|
||||
return 32 << dmacHw_GET_CHANNEL_DATA_WIDTH(pCblk->module,
|
||||
pCblk->channel);
|
||||
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE:
|
||||
return GetFifoSize(handle);
|
||||
}
|
||||
dmacHw_ASSERT(0);
|
||||
return 0;
|
||||
}
|
1017
arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
Normal file
1017
arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user