📄 dma.cpp
字号:
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_DPER;
pDMACChannelRegs->DMACCxConfiguration |=
((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestDevice << DMAC_DPER_SHIFT);
// Setup the source device
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_SPER;
pDMACChannelRegs->DMACCxConfiguration |=
((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceDevice << DMAC_SPER_SHIFT);
// Setup the flow control
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_FLOW;
pDMACChannelRegs->DMACCxConfiguration |=
((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl << DMAC_FLOW_SHIFT);
DEBUGMSG(DMA_ZONE_OPT, (TEXT("-InitializeDMAChannel\r\n")));
return TRUE;
}
//
// FreeDMAChannel - Frees the specified DMA channel
//
extern "C" BOOL FreeDMAChannel(PFREE_DMA_PARAMS pParams, PFREE_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
pvstSP810Regs pstSP810 = (pvstSP810Regs)(VA_SC_BASE);
DEBUGMSG(1, (TEXT("+FreeDMAChannel(channel %d)\r\n"), pParams->ucChannelNumber));
ucDMAChannel = pParams->ucChannelNumber;
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// Disable the DMA channel to ensure no more transfers can occur on it
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_E;
DMAInfo.DMAChannels[ucDMAChannel].fInUse = FALSE; // Set this channel to 'free'
DEBUGMSG(1, (TEXT("-FreeDMAChannel\r\n")));
// Disable the DMA's peripheral clock if there are no more channels allocated
for(ucDMAChannel=0; ucDMAChannel<MAX_DMA_CHANNELS; ucDMAChannel++)
{
if(DMAInfo.DMAChannels[ucDMAChannel].fInUse) break;
}
DEBUGMSG(1, (TEXT("Freed a channel, no of channels = %d\r\n"),(DWORD)ucDMAChannel));
if(MAX_DMA_CHANNELS == ucDMAChannel)
{
DEBUGMSG(1, (TEXT("Switching DMA clock off.\r\n")));
// pstSP810->SCPERDIS = HCLKDMA;
}
return TRUE;
}
//
// FreeDmaSysIntr - Removes the SYSINTR mapping from the chosen channel
//
extern "C" BOOL FreeDmaSysIntr(PFREE_DMA_SYSINTR_PARAMS pParams, PFREE_DMA_SYSINTR_RESULT pResults )
{
DEBUGMSG(1, (TEXT("+FreeDmaSysIntr(Freeing Channel: %d)\r\n"), pParams->ucChannelNumber));
/* Channel number out of range */
if(pParams->ucChannelNumber >= MAX_DMA_CHANNELS)
return FALSE;
/* Attempting to remove an unmapped SYSINTR */
if(SYSINTR_UNDEFINED == DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr) {
DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(Chennel not mapped)\r\n")));
return FALSE;
}
/* Remove from OAL mapping */
if(ERROR_SUCCESS == OEMReleaseSysIntr(DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr))
{
DEBUGMSG(1, (TEXT("FreeDmaSysIntr(SYSINTR: %d now free)\r\n"),
DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
/* Clear in DMAInfo structure */
DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr=SYSINTR_UNDEFINED;
return TRUE;
} else {
DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(SYSINTR: %d unable to free)\r\n"),
DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
}
/* Failed to remove mapping */
return FALSE;
}
//
// StartDMATransfer - Starts a DMA transfer between two devices
//
extern "C" BOOL StartDMATransfer(PSTART_DMA_PARAMS pParams, PSTART_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
PDWORD pdwSourceBuffer;
PDWORD pdwDestBuffer;
DWORD dwTotalSize, dwListOffset , control;
if (!fDMAInitialised) { /* not present */
DEBUGMSG(1, (TEXT("NO DMA blocking StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
return FALSE;
}
ucDMAChannel = pParams->ucChannelNumber;
if (ucDMAChannel >= MAX_DMA_CHANNELS) { /* Illegal */
DEBUGMSG(1, (TEXT("ERROR : DMA blocked: Illegal channel %d\r\n"), pParams->ucChannelNumber));
return FALSE;
}
DEBUGMSG(1, (TEXT("+StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
// Save the parameters in case we need to restart the transfer
dwTotalSize = pParams->dwTransferSize;
DMAInfo.DMAChannels[ucDMAChannel].dwTransferSize = pParams->dwTransferSize;
DMAInfo.DMAChannels[ucDMAChannel].pdwSourceBuffer = pParams->pdwSourceBuffer;
DMAInfo.DMAChannels[ucDMAChannel].pdwDestBuffer = pParams->pdwDestBuffer;
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: source buffer = 0x%X\r\n"), pParams->pdwSourceBuffer));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: dest buffer = 0x%X\r\n"), pParams->pdwDestBuffer));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: total size = 0x%X\r\n"), dwTotalSize));
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// Store the buffer locations
pdwSourceBuffer = pParams->pdwSourceBuffer;
pdwDestBuffer = pParams->pdwDestBuffer;
// Setup the DMA control register
pDMACChannelRegs->DMACCxControl &= ~((DWORD)DMAC_TRANSFER_SIZE); // Clear the size
control = pDMACChannelRegs->DMACCxControl&(~( (DWORD)DMAC_TRANSFER_SIZE | DMAC_CTRL_I ));
control |= DMAC_CTRL_PRIV;
//pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_PRIV; // We are always in privileged mode
// Setup the address registers to the first physical address
// pDMACChannelRegs->DMACCxSrcAddr = pdwSourceBuffer[0];
// pDMACChannelRegs->DMACCxDestAddr = pdwDestBuffer[0];
PLLI_ENTRY lli_vir , lli_phy;
dwListOffset = ucDMAChannel * sizeof(LLI_ENTRY) * MAX_DMA_LIST_ENTRIES;
lli_vir = (PLLI_ENTRY)(DMA_LIST_BUFFER_VIRT + dwListOffset);
lli_phy = (PLLI_ENTRY)(DMA_LIST_BUFFER_PHYS + dwListOffset);
DWORD maxtransfer , firsttransfer , totaltrans;
DWORD flowcontrol = DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl ;
if( flowcontrol == FLOW_PER_MEM_DMAC || flowcontrol == FLOW_PER_MEM_SOURCE)
{
DWORD singlesize ;
if( DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth == TRANSFER_WIDTH_DWORD )
singlesize = sizeof(DWORD);
else if(DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth == TRANSFER_WIDTH_WORD )
singlesize = sizeof(WORD);
else
singlesize = sizeof(BYTE);
maxtransfer = PAGE_SIZE/singlesize ;
firsttransfer = (PAGE_SIZE - BYTE_OFFSET( pdwDestBuffer[0]))/singlesize;
pdwDestBuffer[0] &= ~(PAGE_SIZE-1);
totaltrans = dwTotalSize/singlesize;
DWORD lastleft = firsttransfer , totrans;
do
{
lli_vir->dwSourceAddress = pdwSourceBuffer[0];
lli_vir->dwDestAddress = (DWORD)(*pdwDestBuffer) + PAGE_SIZE - lastleft*singlesize;
totrans = min( totaltrans , min( lastleft , DMAC_TRANSFER_SIZE ));
lastleft -= totrans;
totaltrans -= totrans;
lli_vir->dwControl = control | totrans;
lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
if( !lastleft )
{
pdwDestBuffer ++;
lastleft = maxtransfer;
}
lli_vir ++ ; lli_phy ++ ;
}while( totaltrans );
}
else if( flowcontrol == FLOW_MEM_PER_DMAC || flowcontrol == FLOW_MEM_PER_DEST )
{
DWORD singlesize;
if( DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth == TRANSFER_WIDTH_DWORD )
singlesize = sizeof(DWORD);
else if(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth == TRANSFER_WIDTH_WORD )
singlesize = sizeof(WORD);
else
singlesize = sizeof(BYTE);
firsttransfer = (PAGE_SIZE - BYTE_OFFSET( pdwSourceBuffer[0]))/singlesize;
pdwSourceBuffer[0] &= ~(PAGE_SIZE-1);
maxtransfer = PAGE_SIZE/singlesize;
totaltrans = dwTotalSize/singlesize;
DWORD lastleft = firsttransfer , totrans;
do
{
lli_vir->dwDestAddress = pdwDestBuffer[0];
lli_vir->dwSourceAddress = (DWORD)(*pdwSourceBuffer) + PAGE_SIZE - lastleft*singlesize;
totrans = min( totaltrans , min( lastleft , DMAC_TRANSFER_SIZE ));
lastleft -= totrans;
totaltrans -= totrans;
lli_vir->dwControl = control | totrans;
lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
if( !lastleft )
{
pdwSourceBuffer ++;
lastleft = maxtransfer;
}
lli_vir ++ ; lli_phy ++ ;
}while( totaltrans );
}
else if( flowcontrol == FLOW_MEM_MEM_DMAC )
{
DWORD totrans;
totaltrans = dwTotalSize/sizeof(DWORD);
do
{
lli_vir->dwDestAddress = *pdwDestBuffer++;
lli_vir->dwSourceAddress = *pdwSourceBuffer++;
totrans = min( totaltrans , PAGE_SIZE/sizeof(DWORD) );
totaltrans -= totrans;
lli_vir->dwControl = control | totrans;
lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
lli_vir ++ ; lli_phy ++ ;
}while( totaltrans );
}
lli_vir --;
lli_vir->pNextEntry = 0;
lli_vir->dwControl |= DMAC_CTRL_I;
lli_vir = (PLLI_ENTRY)(DMA_LIST_BUFFER_VIRT + dwListOffset);
pDMACChannelRegs->DMACCxSrcAddr = lli_vir->dwSourceAddress;
pDMACChannelRegs->DMACCxDestAddr = lli_vir->dwDestAddress;
pDMACChannelRegs->DMACCxLLI = (DWORD)lli_vir->pNextEntry;
pDMACChannelRegs->DMACCxControl = lli_vir->dwControl;
// Flush the data cache as the DMA controller needs the LLI information in
// DMA accessible memory
OEMCacheRangeFlush(NULL, 0, CACHE_SYNC_DISCARD);
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Source = 0x%X\r\n"), pDMACChannelRegs->DMACCxSrcAddr));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Dest = 0x%X\r\n"), pDMACChannelRegs->DMACCxDestAddr));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: LLI = 0x%X\r\n"), pDMACChannelRegs->DMACCxLLI));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Control = 0x%X\r\n"), pDMACChannelRegs->DMACCxControl));
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Config = 0x%X\r\n"), pDMACChannelRegs->DMACCxConfiguration));
// Enable the channel, this should start the transfer or allow a peripheral to do so
pDMACChannelRegs->DMACCxConfiguration |= DMAC_CHCONFIG_E;
DEBUGMSG(1, (TEXT("-StartDMATransfer\r\n")));
return TRUE;
}
//
// HaltDMATransfer - Halts a DMA channel
//
// Note: Care should be taken over the state of the Cache at this point
// It is up to the user to make sure the correct data will be accessed
//
extern "C" BOOL HaltDMATransfer(PHALT_DMA_PARAMS pParams, PHALT_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
DEBUGMSG(DMA_ZONE_OPT, (TEXT("+HaltDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
ucDMAChannel = pParams->ucChannelNumber;
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// Halt any transfer (don't disable the channel as this will lose data!)
pDMACChannelRegs->DMACCxConfiguration |= (DWORD)DMAC_CHCONFIG_H;
// Wait for channel to become inactive
while(pDMACChannelRegs->DMACCxConfiguration&(DWORD)DMAC_CHCONFIG_A);
DEBUGMSG(DMA_ZONE_OPT, (TEXT("-HaltDMATransfer\r\n")));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -