📄 ddk_sdma.c
字号:
//-----------------------------------------------------------------------------
//
// Copyright (C) 2006, Freescale Semiconductor, Inc. All Rights Reserved
// THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
// BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
// FREESCALE SEMICONDUCTOR, INC.
//
//-----------------------------------------------------------------------------
//
// File: ddk_sdma.c
//
// This file contains a DDK interface for the SDMA module.
//
//-----------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include "mxarm11.h"
//-----------------------------------------------------------------------------
// External Functions
extern BOOL SdmaLoadRamScripts(void * pBuf);
extern BOOL SdmaSetChanDesc(DDK_DMA_REQ dmaReq, PSDMA_CHAN_DESC pChanDesc);
extern BOOL SdmaUpdateChanDesc(DDK_DMA_REQ dmaReq, PSDMA_CHAN_DESC pChanDesc);
extern BOOL SdmaSetChanContext(UINT8 chan, PSDMA_CHAN_DESC pChanDesc,
UINT8 waterMark, PSDMA_CHANNEL_CONTEXT pChanCtxt);
extern PVOID BSPSdmaAllocChain(UINT8 chan, UINT32 numBufDesc,
PPHYSICAL_ADDRESS phyAddr);
extern VOID BSPSdmaFreeChain(UINT8 chan);
extern UINT32 BSPSdmaGetSharedSize(VOID);
//-----------------------------------------------------------------------------
// External Variables
//-----------------------------------------------------------------------------
// Defines
#define CHAN_MASK(chan) (1 << (chan))
#define CMD_SETCTX(chan) (((chan) << 3) | SDMA_CMD_C0_SETCTX)
// #define DDK_SDMA_VERBOSE
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
// Global Variables
DMA_ADAPTER_OBJECT g_DmaAdapter = { sizeof(DMA_ADAPTER_OBJECT),
Internal, 0 };
PSDMA_HOST_SHARED_REGION g_pHostSharedUA = NULL;
PSDMA_HOST_SHARED_REGION g_pHostSharedPA = NULL;
//-----------------------------------------------------------------------------
// Local Variables
static PCSP_SDMA_REGS g_pSDMA = NULL;
static HANDLE g_hSdmaMutex;
static HANDLE g_hAcrMutex;
//-----------------------------------------------------------------------------
// Local Functions
BOOL SdmaInit(void);
BOOL SdmaDeinit(void);
BOOL SdmaAlloc(void);
BOOL SdmaDealloc(void);
static BOOL SdmaWritePM(UINT32 srcAddrPA, UINT32 dstAddrPM, UINT16 count);
static BOOL SdmaWriteChanContext(UINT8 chan, UINT32 srcAddrPA);
static void SdmaSetChanOverride(UINT8 chan, BOOL bHostOvr,
BOOL bEventOvr, BOOL bDspOvr);
static void SdmaSetChanPriority(UINT8 chan, UINT8 priority);
static BOOL SdmaGetChanStatus(UINT8 chan);
static UINT8 SdmaFindUnusedChan(UINT8 priority);
static void SdmaLockCtrlChan(void);
static void SdmaUnlockCtrlChan(void);
static BOOL SdmaValidChan(UINT8 chan);
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaOpenChan
//
// This function tries to find an available virtual SDMA channel that can
// be used to support a memory-to-memory, peripheral-to-memory, or
// memory-to-peripheral transfer.
//
// Parameters:
// dmaReq
// [in] - Specifies the DMA request that will be bound to
// a virtual channel.
//
// priority
// [in] - Priority assigned to the opened channel.
//
// lpName
// [in] - Pointer to a null-terminated string that specifies the name
// of the event object signaled when a transfer interrupt occurs
// This parameter will be passed to CreateEvent to open a handle to a
// named event object. To signal a registered interrupt handler,
// set this parameter to NULL and use sysIntr parameter to specify
// the logical interrupt.
//
// irq
// [in] - Only used if lpName is set to NULL. Specifies the harware
// IRQ that will be translated into a registered SYSINTR within
// OEMInterruptHandler when a transfer interrupt occurs. Set to
// IRQ_NONE if no interrupt will be generated by the channel.
//
// Returns:
// Returns the virtual channel index if successful,
// otherwise returns NULL.
//
//-----------------------------------------------------------------------------
UINT8 DDKSdmaOpenChan(DDK_DMA_REQ dmaReq, UINT8 priority, LPTSTR lpName,
DWORD irq)
{
UINT8 chan;
DMA_IRQ_MAP_PARMS dmaIrqMap;
UINT32 i, dmaMask;
// Try to find an available channel
chan = SdmaFindUnusedChan(priority);
// If available channel was found
if (chan == 0)
{
ERRORMSG(1, (_T("No available channel!\r\n")));
goto cleanUp;
}
// Reset CCB
g_pHostSharedUA->chanCtrlBlk[chan].curBufDescPA = 0;
g_pHostSharedUA->chanCtrlBlk[chan].baseBufDescPA = 0;
g_pHostSharedUA->chanCtrlBlk[chan].chanDesc = 0;
g_pHostSharedUA->chanCtrlBlk[chan].chanStatus = 0;
// Reset channel descriptor fields for buffer descriptors
g_pHostSharedUA->chanDesc[chan].pBaseBufDescUA = NULL;
g_pHostSharedUA->chanDesc[chan].numBufDesc = 0;
// Attempt to configure remaining channel descriptor fields based DMA request
if (!SdmaSetChanDesc(dmaReq, &g_pHostSharedUA->chanDesc[chan]))
{
ERRORMSG(1, (_T("SdmaSetChanDesc failed!\r\n")));
goto cleanUp;
}
// If the channel has an associated DMA request
if (g_pHostSharedUA->chanDesc[chan].dmaMask)
{
// Search through the DMA requests specified for this channel
for (i = 0, dmaMask = 0x1; i < SDMA_NUM_CHANNELS; i++, dmaMask <<= 1)
{
if (dmaMask & g_pHostSharedUA->chanDesc[chan].dmaMask)
{
// Bind DMA requests to virtual channel
SETREG32(&g_pSDMA->CHNENBL[i], CHAN_MASK(chan));
}
}
// Clear event override
SdmaSetChanOverride(chan, FALSE, FALSE, TRUE);
}
else
{
// No DMAREQ for memory-to-memory, set event override
SdmaSetChanOverride(chan, FALSE, TRUE, TRUE);
}
// If event object to signal not specified
if ((lpName == NULL) && (irq != IRQ_NONE))
{
// Map SDMA channel to a hardware IRQ
dmaIrqMap.irq = irq;
dmaIrqMap.chan = chan;
if (!KernelIoControl(IOCTL_HAL_REQUEST_DMA_IRQ_MAP, &dmaIrqMap,
sizeof(dmaIrqMap), NULL, 0, NULL))
{
ERRORMSG(1, (_T("IOCTL_HAL_REQUEST_DMA_IRQ_MAP failed!\r\n")));
goto cleanUp;
}
}
return chan;
cleanUp:
DDKSdmaCloseChan(chan);
return 0;
}
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaUpdateSharedChan
//
// This function allows a channel that has multiple DMA requests combined into
// a shared DMA event to be reconfigured for one of the alternate DMA requests.
//
// Parameters:
// dmaReq
// [in] - Specifies one of the possible DMA requests valid for
// a channel with a shared DMA event. The DMA request
// must be one of the set of requests valid for the opened
// channel.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKSdmaUpdateSharedChan(UINT8 chan, DDK_DMA_REQ dmaReq)
{
BOOL rc = FALSE;
// Validate channel
if (!SdmaValidChan(chan))
{
ERRORMSG(1, (_T("Channel validation failed!\r\n")));
goto cleanUp;
}
rc = SdmaUpdateChanDesc(dmaReq, &g_pHostSharedUA->chanDesc[chan]);
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaCloseChan
//
// This function closes a channel previously opened by the DDKSdmaOpenChan
// routine.
//
// Parameters:
// chan
// [in] - Virtual channel returned by DDKSdmaOpenChan function.
//
// Returns:
// Returns TRUE if the close operation was successful, otherwise
// returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKSdmaCloseChan(UINT8 chan)
{
BOOL rc = FALSE;
UINT32 i, dmaMask;
// Validate channel
if (!SdmaValidChan(chan))
{
ERRORMSG(1, (_T("Channel validation failed!\r\n")));
goto cleanUp;
}
// If the channel has an associated DMA request
if (g_pHostSharedUA->chanDesc[chan].dmaMask)
{
// Search through the DMA requests specified for this channel
for (i = 0, dmaMask = 0x1; i < SDMA_NUM_CHANNELS; i++, dmaMask <<= 1)
{
if (dmaMask & g_pHostSharedUA->chanDesc[chan].dmaMask)
{
// Unbind DMA request from virtual channel
CLRREG32(&g_pSDMA->CHNENBL[i], CHAN_MASK(chan));
}
}
// Clear event override
SdmaSetChanOverride(chan, FALSE, FALSE, TRUE);
}
// Make sure event override is cleared
SdmaSetChanOverride(chan, FALSE, FALSE, TRUE);
// Unmap the buffer descriptors
DDKSdmaFreeChain(chan);
// Unmap channel from hardware IRQ
KernelIoControl(IOCTL_HAL_RELEASE_DMA_IRQ_MAP, &chan, sizeof(chan),
NULL, 0, NULL);
// Reset CCB
g_pHostSharedUA->chanCtrlBlk[chan].curBufDescPA = 0;
g_pHostSharedUA->chanCtrlBlk[chan].baseBufDescPA = 0;
g_pHostSharedUA->chanCtrlBlk[chan].chanDesc = 0;
g_pHostSharedUA->chanCtrlBlk[chan].chanStatus = 0;
// Return channel back to pool of unused channels
SdmaSetChanPriority(chan, SDMA_CHNPRI_CHNPRI_DISABLE);
rc = TRUE;
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaAllocChain
//
// This function allocates a chain of buffer descriptors for
// a virtual DMA channel.
//
// Parameters:
// chan
// [in] - Virtual channel returned by DDKSdmaOpenChan function.
//
// numBufDesc
// [in] - Number of buffer descriptors to allocate for the chain.
//
// Returns:
// Returns TRUE if the chain allocation succeeded, otherwise returns
// FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKSdmaAllocChain(UINT8 chan, UINT32 numBufDesc)
{
BOOL rc = FALSE;
PVOID pBufDesc;
PHYSICAL_ADDRESS phyAddr;
// Validate channel
if (!SdmaValidChan(chan))
{
ERRORMSG(1, (_T("Channel validation failed!\r\n")));
goto cleanUp;
}
// Allocate storage for buffer descriptor chain
pBufDesc = BSPSdmaAllocChain(chan, numBufDesc, &phyAddr);
if (pBufDesc == NULL)
{
ERRORMSG(1, (_T("BSPSdmaAllocChain failed!\r\n")));
goto cleanUp;
}
// Save chain information in CCB and channel descriptor
g_pHostSharedUA->chanCtrlBlk[chan].baseBufDescPA = phyAddr.LowPart;
g_pHostSharedUA->chanCtrlBlk[chan].curBufDescPA = phyAddr.LowPart;
g_pHostSharedUA->chanDesc[chan].pBaseBufDescUA = pBufDesc;
g_pHostSharedUA->chanDesc[chan].numBufDesc = numBufDesc;
rc = TRUE;
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaFreeChain
//
// This function frees a chain of buffer descriptors previously
// allocated with DDKSdmaAllocChain.
//
// Parameters:
// chan
// [in] - Virtual channel returned by DDKSdmaOpenChan function.
//
// Returns:
// Returns TRUE if the chain could be deallocated, otherwise
// returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKSdmaFreeChain(UINT8 chan)
{
BOOL rc = FALSE;
// Validate channel parameter
if (chan <= 0 || chan >= SDMA_NUM_CHANNELS)
{
ERRORMSG(1, (_T("Invalid channel!\r\n")));
goto cleanUp;
}
// Check if descriptors have been allocated for this channel
if (g_pHostSharedUA->chanDesc[chan].numBufDesc == 0)
{
// Nothing to unmap, return success
rc = TRUE;
goto cleanUp;
}
// Kill the channel
if (!DDKSdmaStopChan(chan, TRUE))
{
ERRORMSG(1, (_T("Cannot kill channel!\r\n")));
goto cleanUp;
}
// Deallocate storage for buffer descriptor chain
if (g_pHostSharedUA->chanDesc[chan].pBaseBufDescUA)
{
BSPSdmaFreeChain(chan);
}
// Reset chain information in CCB
g_pHostSharedUA->chanCtrlBlk[chan].baseBufDescPA = 0;
g_pHostSharedUA->chanCtrlBlk[chan].curBufDescPA = 0;
g_pHostSharedUA->chanDesc[chan].pBaseBufDescUA = NULL;
g_pHostSharedUA->chanDesc[chan].numBufDesc = 0;
rc = TRUE;
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: DDKSdmaSetBufDesc
//
// This function configures a buffer descriptor for a DMA transfer.
//
// Parameters:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -