📄 dma.cpp
字号:
/*
* Release Status:OS005-SW-70002-r0p0-00REL0
* $Copyright:
* ----------------------------------------------------------------
* This confidential and proprietary software may be used only as
* authorised by a licensing agreement from ARM Limited
* (C) COPYRIGHT 2004 ARM Limited
* ALL RIGHTS RESERVED
* The entire notice above must be reproduced on all authorised
* copies and copies may only be made to the extent permitted
* by a licensing agreement from ARM Limited.
* ----------------------------------------------------------------
* File: dma.cpp,v
* Revision: 1.2
* ----------------------------------------------------------------
* $
*/
#include <windows.h>
#include <oalintr.h>
#include <ceddk.h>
#include <platform.h>
#include <board.h>
#include <dma.h>
#include <sp810.h> // System Controller
#include "dmakern.h"
// Use globals as we are in kernel (exclusive) mode
static DMA_INFO DMAInfo; // The DMA subsystem info
static volatile PDMAC_REGS pDMACRegs; // Pointer to the DMA controller registers
static BOOL fDMAInitialised = FALSE; // Flag to indicate initialisation complete
/*
We must have a local declaration of this to enable this CPP compiled code
to interface to the C calling conventions of OEMCacheRangeFlush();
*/
extern "C" void OEMCacheRangeFlush(LPVOID, DWORD, DWORD);
/*
This isnt true DMA zones, being in the Kernel,
so we have to define it :-
0 Off - no debug
1 On - lots of debug
*/
#ifdef DEBUG
#define DMA_ZONE_OPT 1
#else
#define DMA_ZONE_OPT 0
#endif
//
// InitDMA - Initialize the DMA subsystem ready for use
//
extern "C" BOOL InitDMA(void)
{
#ifndef ARM_NODMA
UCHAR ucDMAChannel;
lpWriteDebugStringFunc(TEXT("Initialize DMA subsystem\r\n"));
pDMACRegs = (PDMAC_REGS)DMAC_BASE; // Setup a pointer to the DMA registers
// Free all of the DMA channels
for(ucDMAChannel=0; ucDMAChannel<MAX_DMA_CHANNELS; ucDMAChannel++) {
DMAInfo.DMAChannels[ucDMAChannel].fInUse = FALSE;
DMAInfo.DMAChannels[ucDMAChannel].dwDMASysIntr=SYSINTR_UNDEFINED;
DMAInfo.DMAChannels[ucDMAChannel].fPowerDown = FALSE;
}
// Initialize the hardware
pDMACRegs->DMACConfiguration = (DWORD)DMAC_CONFIG_E; // Enable the DMA controller
fDMAInitialised = TRUE;
return TRUE;
#else // if ARM_NODMA defined
DEBUGMSG(1, (TEXT("DMA Init , Ignored due to ARM_NODMA flag\r\n") ));
fDMAInitialised = FALSE;
return FALSE;
#endif // !ARM_NODMA
}
//
// AllocateDMAChannel - Allocates the next free DMA channel with the specified
// priority
//
extern "C" BOOL AllocateDMAChannel(PALLOCATE_DMA_PARAMS pParams, PALLOCATE_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
DWORD dwSysIntr; // Allocated SYSINTR mapping for that channel
pvstSP810Regs pstSP810 = (pvstSP810Regs)(VA_SC_BASE);
DEBUGMSG(1, (TEXT("+AllocateDMAChannel(%d %d %d)\r\n"), pParams->ucSourceDevice,
pParams->ucDestDevice, pParams->ucPreferedPriority));
if( !fDMAInitialised )
{
DEBUGMSG(DMA_ZONE_OPT, (TEXT("AllocateDMAChannel: DMA not initialised\r\n")));
return FALSE;
}
dwSysIntr=OEMRequestSysIntr(IRQ_VIC_DMA);
if(dwSysIntr!=SYSINTR_UNDEFINED) {
DEBUGMSG(1, (TEXT("AllocateDMAChannel(Got SYSINTR: %d LOGINTR: %d)\r\n"), dwSysIntr, LOGINTR_DMAC));
} else {
DEBUGMSG(1, (TEXT("+[ERR]AllocateDMAChannel(SYSINTR: %d LOGINTR: %d)\r\n"), dwSysIntr, LOGINTR_DMAC));
return FALSE;
} // if (dwSysIntr!=SYSINTR_UNDEFINED)
// Check if we can allocate any available channel
if(pParams->ucPreferedPriority == 0xFF)
{
// Search for a free DMA channel
for(ucDMAChannel=0; ucDMAChannel<MAX_DMA_CHANNELS; ucDMAChannel++) {
if(!(DMAInfo.DMAChannels[ucDMAChannel].fInUse))break;
}
if(ucDMAChannel == MAX_DMA_CHANNELS) {
DEBUGMSG(1, (TEXT("AllocateDMAChannel: Error - No free DMA channels!\r\n")));
// Remove mapping as we are not able to use it this time
OEMReleaseSysIntr(dwSysIntr);
return FALSE;
}
} else {
// We want a specific channel
ucDMAChannel = pParams->ucPreferedPriority;
if(DMAInfo.DMAChannels[ucDMAChannel].fInUse) {
DEBUGMSG(1, (TEXT("AllocateDMAChannel: Error - DMA channel %d already allocated\r\n"),
ucDMAChannel));
// Remove mapping as we are not able to use it this time
OEMReleaseSysIntr(dwSysIntr);
return FALSE;
}
} // if (pParams->ucPreferedPriority)
// Ensure the DMA's peripheral clock is enabled
pstSP810->SCPEREN = HCLKDMA;
while (!(pstSP810->SCPERSTAT & HCLKDMA))
{
; // Wait for the clock to be enabled before carrying on
}
DMAInfo.DMAChannels[ucDMAChannel].fInUse = TRUE; // Set this channel to 'in use'
// Save the source and destination devices
DMAInfo.DMAChannels[ucDMAChannel].ucSourceDevice = pParams->ucSourceDevice;
DMAInfo.DMAChannels[ucDMAChannel].ucDestDevice = pParams->ucDestDevice;
// Set the active SYSINTR mapping into the DMAInfo structure
DMAInfo.DMAChannels[ucDMAChannel].dwDMASysIntr = dwSysIntr;
// Set the base pointer to the DMA channel registers
switch(ucDMAChannel) {
case 0:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC0SrcAddr;
break;
case 1:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC1SrcAddr;
break;
case 2:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC2SrcAddr;
break;
case 3:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC3SrcAddr;
break;
case 4:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC4SrcAddr;
break;
case 5:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC5SrcAddr;
break;
case 6:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC6SrcAddr;
break;
case 7:
DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs = (PDMAC_CHANNEL_REGS)&pDMACRegs->DMACC7SrcAddr;
break;
}
pResults->ucChannelNumber = ucDMAChannel; // Return the channel number
pResults->dwInterruptID = DMAInfo.DMAChannels[ucDMAChannel].dwDMASysIntr; // Return the interrupt ID
DEBUGMSG(1, (TEXT("-AllocateDMAChannel - Allocated DMA channel %d\r\n"), ucDMAChannel));
return TRUE;
}
//
// InitializeDMAChannel - Initializes the specified DMA channel
//
extern "C" BOOL InitializeDMAChannel(PINITIALIZE_DMA_PARAMS pParams, PINITIALIZE_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
if( !fDMAInitialised )
{
DEBUGMSG(DMA_ZONE_OPT, (TEXT("AllocateDMAChannel: DMA not initialised\r\n")));
return FALSE;
}
DEBUGMSG(DMA_ZONE_OPT, (TEXT("+InitializeDMAChannel(channel %d)\r\n"), pParams->ucChannelNumber));
ucDMAChannel = pParams->ucChannelNumber;
// Save the settings in case we need to restart the transfer
DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth = pParams->ucSourceWidth;
DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth = pParams->ucDestWidth;
DMAInfo.DMAChannels[ucDMAChannel].ucSourceBurstSize = pParams->ucSourceBurstSize;
DMAInfo.DMAChannels[ucDMAChannel].ucDestBurstSize = pParams->ucDestBurstSize;
DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl = pParams->ucFlowControl;
DMAInfo.DMAChannels[ucDMAChannel].fIncrementSource = pParams->fIncrementSource;
DMAInfo.DMAChannels[ucDMAChannel].fIncrementDest = pParams->fIncrementDest;
// Fetch the pointer to the channel regs
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
//
// Write the channel settings to the hardware
//
// Make sure the DMA channel is disabled
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_E;
// Initialize the control registers to known values
pDMACChannelRegs->DMACCxControl = 0;
pDMACChannelRegs->DMACCxConfiguration &= (DWORD)(DMAC_CHCONFIG_ITC|DMAC_CHCONFIG_IE); // Ints are set elsewhere
// Determine which APB master to use for source and destination
// for Versatile, memory is on AHB 1 and peripherals are on AHB 2
switch(pParams->ucFlowControl)
{
case FLOW_MEM_MEM_DMAC:
// Both are memory so must be on AHB 2
pDMACChannelRegs->DMACCxControl |= (DWORD)DMAC_CTRL_S;
pDMACChannelRegs->DMACCxControl |= (DWORD)DMAC_CTRL_D;
break;
case FLOW_MEM_PER_DMAC:
case FLOW_MEM_PER_DEST:
// Source is memory so AHB 2, dest is peripheral so AHB 1
pDMACChannelRegs->DMACCxControl |= (DWORD)DMAC_CTRL_S;
pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_CTRL_D;
break;
case FLOW_PER_MEM_DMAC:
case FLOW_PER_MEM_SOURCE:
// Source is peripheral so AHB 1, dest is memory so AHB 2
pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_CTRL_S;
pDMACChannelRegs->DMACCxControl |= (DWORD)DMAC_CTRL_D;
break;
case FLOW_PER_PER_DMAC:
case FLOW_PER_PER_DEST:
case FLOW_PER_PER_SOURCE:
// Both are peripheral so must be on AHB 1
pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_CTRL_S;
pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_CTRL_D;
break;
}
// Setup the destination width
pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_DWIDTH;
pDMACChannelRegs->DMACCxControl |=
((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth << DMAC_DWIDTH_SHIFT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -