⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.cpp

📁 ARM9基于WINDOWSCE的BSP源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 0
#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(LOGINTR_DMA);

    if(dwSysIntr!=SYSINTR_UNDEFINED) {
        DEBUGMSG(1, (TEXT("AllocateDMAChannel(Got SYSINTR: %d LOGINTR: %d)\r\n"), dwSysIntr, LOGINTR_DMA));
    } else {
        DEBUGMSG(1, (TEXT("+[ERR]AllocateDMAChannel(SYSINTR: %d LOGINTR: %d)\r\n"), dwSysIntr, LOGINTR_DMA));
        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);
    // Setup the source width
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_SWIDTH;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth << DMAC_SWIDTH_SHIFT);
    // Setup the destination burst size
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_DBSIZE;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestBurstSize << DMAC_DBSIZE_SHIFT);
    // Setup the source burst size
    pDMACChannelRegs->DMACCxControl &= ~(DWORD)DMAC_SBSIZE;
    pDMACChannelRegs->DMACCxControl |=
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceBurstSize << DMAC_SBSIZE_SHIFT);
    // Determine whether to increment the source and destination
    if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementSource)
        pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_SI;    // Increment the source
    if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementDest)
        pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_DI;    // Increment the destination

    // Setup the dest device

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -