📄 wmxscaledma.c
字号:
pChannelDetails = WMDMAGetChannelDetails( hDevice, APIChannel );
if ( NULL == pChannelDetails )
{
return FALSE;
}
if ( WM_WIDE & pChannelDetails->flags )
return TRUE;
else
return FALSE;
}
#if WM_USE_DYNAMIC_DMA_CHANNEL
/*-----------------------------------------------------------------------------
* Function: WMDMAGetEventHandle
*
* This function returns the DMA interrupt event handle for the given channel
* (if relevant for this platform).
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* channel the channel ID.
*
* Returns: WMEvent_t
* the DMA event interrupt handle, or NULL if this is not relevant.
*---------------------------------------------------------------------------*/
WMEvent_t WMDMAGetEventHandle( WM_DEVICE_HANDLE hDevice,
WMDMA_CHAN_HANDLE channel
)
{
ChannelDef *pChannelDef = (ChannelDef *)channel;
char EventName[WM_DMA_EVENT_STRING];
WMFormatString( EventName, "%s%d", DMA_CHANNEL_PREFIX, pChannelDef->DMAChannel );
return WMGetNamedEvent( hDevice, EventName );
}
#endif /* WM_USE_DYNAMIC_DMA_CHANNEL */
/*-----------------------------------------------------------------------------
* Function: WMDMAEnableInterrupts
*
* This function enables DMA interrupts.
* NOTE: This function is intended for use only by the Wolfson test
* code and should not be used by standard library code.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: void
*---------------------------------------------------------------------------*/
void WMDMAEnableInterrupts( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
volatile XLLP_INTC_T *v_pIntRegs = pDeviceContext->v_pIntRegs;
v_pIntRegs->icmr |= XLLP_INTC_DMAC;
}
/*-----------------------------------------------------------------------------
* Function: WMDMADisableInterrupts
*
* This function disables DMA interrupts.
* NOTE: This function is intended for use only by the Wolfson test
* code and should not be used by standard library code.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
*
* Returns: void
*---------------------------------------------------------------------------*/
void WMDMADisableInterrupts( WM_DEVICE_HANDLE hDevice )
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
volatile XLLP_INTC_T *v_pIntRegs = pDeviceContext->v_pIntRegs;
v_pIntRegs->icmr &= ~XLLP_INTC_DMAC;
}
/*-----------------------------------------------------------------------------
* Function: private_GetNextBuffer
*
* Returns a pointer to the next DMA buffer for the channel.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* channel the channel to return the buffer for.
*
* Returns: void *
* A pointer to the DMA buffer (of size as configured in WMDMAInit).
*---------------------------------------------------------------------------*/
void *private_GetNextBuffer( WM_DEVICE_HANDLE hDevice,
WMDMA_CHAN_HANDLE channel
)
{
void *pBuffer;
ChannelDef *pChannelDef = (ChannelDef *)channel;
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
/*
* Default to the first buffer.
*/
pBuffer = pChannelDef->buffer1;
/*
* If it's an active channel, we pick the buffer that's not currently
* being transmitted. If it's inactive we stick with the first buffer.
*/
if ( pChannelDef->flags & WMCHAN_ACTIVE )
{
const void *pNextDescriptor = (const void *)
pDeviceContext->v_pDmaReg->DDG[pChannelDef->DMAChannel].DDADR;
if ( pNextDescriptor == pChannelDef->desc2Physical )
{
pBuffer = pChannelDef->buffer2;
}
/* else we've defaulted to buffer1 */
}
return pBuffer;
}
/*-----------------------------------------------------------------------------
* Function: private_PrepareDescriptors
*
* Sets up the DMA descriptors for the given channel (non-XLLP version).
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* pChannelDef DMA Channel definition structure.
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static WMSTATUS private_PrepareDescriptors( WM_DEVICE_HANDLE hDevice,
ChannelDef *pChannelDef
)
{
WM_BOOL isInput;
void *channelAddr;
unsigned int width, size;
WMSTATUS result;
union DmaCmdReg CmdBuff = {0};
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
DMAContext *pDMAContext = pDeviceContext->pDMAContext;
/*
* Parameter validation.
*/
WM_ASSERT( hDevice, NULL != pChannelDef );
/*
* Variation for different channels.
*/
channelAddr = pChannelDef->pDetails->channelAddr;
isInput = pChannelDef->pDetails->flags & WM_INPUT;
/*
* Allocate DMA channel
*/
result = private_AllocateChannel( hDevice, pChannelDef, pChannelDef->APIChannel );
if ( WM_ERROR( result ) )
{
goto error;
}
switch ( pChannelDef->pDetails->nBytesPerSample )
{
case 1:
width = 0x01;
break;
case 2:
width = 0x02;
break;
case 4:
width = 0x03;
break;
default:
WM_TRACE( hDevice,
( "WMDMA PrepareDescriptors: invalid number of bytes per sample: %d\n",
pChannelDef->pDetails->nBytesPerSample
));
WM_ASSERT( hDevice, FALSE );
}
/*
* Maximum burst size of each data transfer.
*/
size = pChannelDef->pDetails->nBurstSize;
/*
* Construct the DCMD register.
*/
CmdBuff.DcmdReg.len = 0; // length of the memory buffer
CmdBuff.DcmdReg.width = width; // as above
CmdBuff.DcmdReg.size = size; // as above
CmdBuff.DcmdReg.endian = 0; // little endian
CmdBuff.DcmdReg.flybyt = 0; // Flowthrough
CmdBuff.DcmdReg.flybys = 0; // Flowthrough
CmdBuff.DcmdReg.endirqen = 1; // 1 means Interrupt when decrement length = 0;
CmdBuff.DcmdReg.startirqen = 0; // 1 means Interrupt when the desc is loaded
/*
* Now the stuff which varies depending on whether it's input or output.
*/
if ( isInput )
{
CmdBuff.DcmdReg.flowtrg = 0; // 1 means the target is an external peripheral
CmdBuff.DcmdReg.flowsrc = 1; // 1 means the source is an external peripheral (and needs flow control)
CmdBuff.DcmdReg.inctrgadd = 1; // 1 means increment the target address (since it's memory)
CmdBuff.DcmdReg.incsrcadd = 0; // 1 means increment the source address (since it's a peripheral)
}
else
{
CmdBuff.DcmdReg.flowtrg = 1; // 1 means the target is an external peripheral
CmdBuff.DcmdReg.flowsrc = 0; // 1 means the source is an external peripheral (and needs flow con
CmdBuff.DcmdReg.inctrgadd = 0; // 1 means increment the target address (since it's memory)
CmdBuff.DcmdReg.incsrcadd = 1; // 1 means increment the source address (since it's a peripheral)
}
/*
* Now set up the descriptors.
*/
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->desc2Physical & DESC_ADDRESS_MASK) ==
(unsigned long) pChannelDef->desc2Physical
);
pChannelDef->desc1->DDADR = (unsigned long) pChannelDef->desc2Physical; /* Next descriptor */
pChannelDef->desc1->DCMD = CmdBuff.DcmdDword; /* Command */
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->desc1Physical & DESC_ADDRESS_MASK) ==
(unsigned long) pChannelDef->desc1Physical
);
pChannelDef->desc2->DDADR = (unsigned long) pChannelDef->desc1Physical; /* Next descriptor */
pChannelDef->desc2->DCMD = CmdBuff.DcmdDword; /* Command */
if ( isInput )
{
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->buffer1Physical & FORCE_64BIT_ALIGNMENT) ==
(unsigned long) pChannelDef->buffer1Physical
);
pChannelDef->desc1->DTADR = (unsigned long) pChannelDef->buffer1Physical; /* Source address */
WM_ASSERT( hDevice,
((unsigned long) channelAddr & FORCE_128BIT_ALIGNMENT) ==
(unsigned long) channelAddr
);
pChannelDef->desc1->DSADR = (unsigned long) channelAddr; /* Target address */
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->buffer2Physical & FORCE_64BIT_ALIGNMENT) ==
(unsigned long) pChannelDef->buffer2Physical
);
pChannelDef->desc2->DTADR = (unsigned long) pChannelDef->buffer2Physical; /* Source address */
WM_ASSERT( hDevice,
((unsigned long) channelAddr & FORCE_128BIT_ALIGNMENT) ==
(unsigned long) channelAddr
);
pChannelDef->desc2->DSADR = (unsigned long) channelAddr; /* Target address */
}
else
{
WM_ASSERT( hDevice,
((unsigned long) channelAddr & FORCE_64BIT_ALIGNMENT) ==
(unsigned long) channelAddr
);
pChannelDef->desc1->DTADR = (unsigned long) channelAddr; /* Source address */
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->buffer1Physical & FORCE_128BIT_ALIGNMENT) ==
(unsigned long) pChannelDef->buffer1Physical
);
pChannelDef->desc1->DSADR = (unsigned long) pChannelDef->buffer1Physical; /* Target address */
WM_ASSERT( hDevice,
((unsigned long) channelAddr & FORCE_64BIT_ALIGNMENT) ==
(unsigned long) channelAddr
);
pChannelDef->desc2->DTADR = (unsigned long) channelAddr; /* Source address */
WM_ASSERT( hDevice,
((unsigned long) pChannelDef->buffer2Physical & FORCE_128BIT_ALIGNMENT) ==
(unsigned long) pChannelDef->buffer2Physical
);
pChannelDef->desc2->DSADR = (unsigned long) pChannelDef->buffer2Physical; /* Target address */
}
return ( WMS_SUCCESS );
error:
return ( result );
}
/*-----------------------------------------------------------------------------
* Function: private_AllocateChannel
*
* Allocates a DMA channel for the given API channel.
* Channels are currently preallocated (static model).
*
* Parameters:
*
* hDevice handle to the device (from WMOpenDevice)
* pChannelDef pointer to DMA channel structure.
* APIChannel The API channel.
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static WMSTATUS private_AllocateChannel( WM_DEVICE_HANDLE hDevice,
ChannelDef *pChannelDef,
WMAUDIO_CHANNEL APIChannel
)
{
WMSTATUS status = WMS_INVALID_CHANNEL;
#if WM_USE_DYNAMIC_DMA_CHANNEL
{
XLLP_STATUS_T xllpStatus;
xllpStatus = XllpDmacAllocChannel( &pChannelDef->DMAChannel,
XLLP_DMAC_CHANNEL_PRIORITY_HIGH
);
status = XllpStatusToWMStatus( xllpStatus );
}
#else /* WM_USE_DYNAMIC_DMA_CHANNEL */
{
int i;
/*
* Static mapping - look up channel.
*/
for ( i = 0; i <= WM_ARRAY_COUNT(s_DMAChannelsAvailable); i++ )
{
if ( APIChannel == s_DMAChannelsAvailable[i].APIChannel )
{
/* Set up DMA Channel Number in ChannelDef. */
pChannelDef->DMAChannel = s_DMAChannelsAvailable[i].DMAChannel;
status = WMS_SUCCESS;
break;
}
}
/* As this is a static allocation this should NOT fail */
WM_ASSERT( hDevice, WM_SUCCESS( status ) );
}
#endif /* WM_USE_DYNAMIC_DMA_CHANNEL */
return ( status );
}
/*-----------------------------------------------------------------------------
* Function: private_SetDMABufferLength
*
* Sets the DMA buffer length of transfer in bytes. (non-XLLP version).
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* pChannelDef the channel to prepare.
* bufsize the size of the DMA buffer(s).
*
* Returns: WMSTATUS
* See WMStatus.h
*---------------------------------------------------------------------------*/
static void private_SetDMABufferLength( WM_DEVICE_HANDLE hDevice,
ChannelDef *pChannelDef,
unsigned int bufsize
)
{
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
/*
* Parameter validation.
*/
WM_ASSERT( hDevice, NULL != pChannelDef );
WM_ASSERT( hDevice, bufsize <= WMDMAGetMaxBufferSize( hDevice ) );
/*
* Now set the transfer length for each descriptor.
*/
pChannelDef->desc1->DCMD =
(pChannelDef->desc1->DCMD & ~WMAUDIO_DCMD_LEN_MASK) | bufsize;
pChannelDef->desc2->DCMD =
(pChannelDef->desc2->DCMD & ~WMAUDIO_DCMD_LEN_MASK) | bufsize;
}
/*-----------------------------------------------------------------------------
* Function: private_CleanChannelBuffers
*
* Cleans the channel buffers so they only contain silence.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* pChannelDef the channel to clean.
*
* Returns: void
*---------------------------------------------------------------------------*/
void private_CleanChannelBuffers( WM_DEVICE_HANDLE hDevice, ChannelDef *pChannelDef )
{
/*
* Set both buffers to zero (silence).
*/
memset( pChannelDef->buffer1, 0, WMDMAGetMaxBufferSize( hDevice ) );
memset( pChannelDef->buffer2, 0, WMDMAGetMaxBufferSize( hDevice ) );
}
/*-----------------------------------------------------------------------------
* Function: private_Flush_InputFIFO
*
* Flushes the given input FIFO.
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* pFIFO the FIFO to flush
* depth depth of FIFO to flush
*
* Returns: void
*---------------------------------------------------------------------------*/
void private_Flush_InputFIFO( WM_DEVICE_HANDLE hDevice,
XLLP_VUINT32_T *pFIFO,
unsigned int depth)
{
unsigned int i;
XLLP_VUINT32_T read_flush;
/*
* Reading flushes the FIFO.
*/
for ( i=0; i<depth; i++)
{
read_flush = pFIFO[i];
}
}
#ifdef DEBUG
/*-----------------------------------------------------------------------------
* Function: private_DumpDmacChannel
*
* Purpose: Output the value of channel-specific DMAC registers
* (for debugging purposes only).
*
* Parameters:
* hDevice handle to the device (from WMOpenDevice)
* pChannelDef pointer to ChannelDef for the channel
*
* Returns: void.
*
----------------------------------------------------------------------------*/
static void private_DumpDmacChannel( WM_DEVICE_HANDLE hDevice,
ChannelDef *pChannelDef
)
{
int dmaChannel;
XLLP_DMAC_DRCMR_T device;
volatile XLLP_DMAC_T *v_pDmaReg = NULL;
WM_XSCALE_DEVICE_CONTEXT *pDeviceContext =
(WM_XSCALE_DEVICE_CONTEXT*) hDevice;
if ( NULL == pDeviceContext || NULL == pDeviceContext->v_pDmaReg )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -