📄 s3c6400_dma_controller.c
字号:
pLLIEntry = (DMA_LLI_ENTRY *)(pCtxt->LLIVirAddr+sizeof(DMA_LLI_ENTRY)*iEntryNumber);
pLLIEntry->SrcAddr = uiSrcAddr;
pLLIEntry->DestAddr = uiDstAddr;
pLLIEntry->Control0 = TCINT_ENABLE |(pCtxt->DstUpdate<<27) | (pCtxt->SrcUpdate<<26)
| (pCtxt->DstAHBM<<25) | (pCtxt->SrcAHBM<<24)|(pCtxt->DstUnit<<21)
| (pCtxt->SrcUnit<<18) | (pCtxt->DstBurst<<15) | (pCtxt->SrcBurst<<12);
switch(pCtxt->SrcUnit)
{
case BYTE_UNIT:
pLLIEntry->Control1 = TRANSFERCOUNT(uiByteCount);
break;
case HWORD_UNIT:
pLLIEntry->Control1 = TRANSFERCOUNT(uiByteCount/2);
break;
case WORD_UNIT:
pLLIEntry->Control1 = TRANSFERCOUNT(uiByteCount/4);
break;
}
switch(NextItem)
{
case LLI_NEXT_ENTRY:
if (iEntryNumber+1 > pCtxt->LLICount-1)
{
DMA_ERR((_T("[DMA:ERR] DMA_set_LLI_entry() : This Entry is Last. Can't set LLI to Next Entry (%d)\n\r"), iEntryNumber));
error = DMA_ERROR_ILLEGAL_PARAMETER;
goto CleanUp;
}
else
{
pLLIEntry->LLI = NEXT_LLI_ITEM(pCtxt->LLIPhyAddr+sizeof(DMA_LLI_ENTRY)*(iEntryNumber+1)) |pCtxt->LLIAHBM;
}
break;
case LLI_FIRST_ENTRY:
pLLIEntry->LLI = NEXT_LLI_ITEM(pCtxt->LLIPhyAddr) |pCtxt->LLIAHBM;
break;
case LLI_THIS_IS_END:
pLLIEntry->LLI = 0;
break;
}
CleanUp:
DMA_MSG((_T("[DMA]--DMA_set_LLI_entry() : %d\n\r"), error));
return error;
}
DMA_ERROR DMA_channel_start(DMA_CH_CONTEXT *pCtxt)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
DMA_ERROR error = DMA_SUCCESS;
DMA_MSG((_T("[DMA]++DMA_channel_start() : Ch%d in DMAC%d\n\r"), pCtxt->Channel, pCtxt->Controller));
if (pCtxt->bValid == FALSE)
{
DMA_ERR((_T("[DMA:ERR] DMA_channel_start() : Invalid DMA_CH_CONTEXT\n\r")));
error = DMA_ERROR_ILLEGAL_PARAMETER;
goto CleanUp;
}
pDMACHReg = (S3C6400_DMA_CH_REG *)pCtxt->pCHReg;
if (pDMACHReg->Configuration & CHANNEL_ENABLE)
{
DMA_ERR((_T("[DMA:ERR] DMA_channel_start() : Channel Alread in Use\n\r")));
error = DMA_ERROR_ILLEGAL_PARAMETER;
goto CleanUp;
}
// Clear Interrupt Pending
DMA_clear_interrupt_pending(pCtxt);
// Clear Interrupt Mask
DMA_clear_interrupt_mask(pCtxt);
// Clear Halt Bit
pDMACHReg->Configuration &= ~HALT;
// Enable Channel
pDMACHReg->Configuration |= CHANNEL_ENABLE;
CleanUp:
DMA_MSG((_T("[DMA]--DMA_channel_start() : %d\n\r"), error));
return error;
}
DMA_ERROR DMA_channel_stop(DMA_CH_CONTEXT *pCtxt)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
DMA_ERROR error = DMA_SUCCESS;
DMA_MSG((_T("[DMA]++DMA_channel_stop() : Ch%d in DMAC%d\n\r"), pCtxt->Channel, pCtxt->Controller));
if (pCtxt->bValid == FALSE)
{
DMA_ERR((_T("[DMA:ERR] DMA_channel_stop() : Invalid DMA_CH_CONTEXT\n\r")));
error = DMA_ERROR_ILLEGAL_PARAMETER;
goto CleanUp;
}
pDMACHReg = (S3C6400_DMA_CH_REG *)pCtxt->pCHReg;
if (!(pDMACHReg->Configuration & CHANNEL_ENABLE))
{
DMA_INF((_T("[DMA:INF] DMA_channel_stop() : Channel Already Disabled\n\r")));
}
else
{
// Set Interrupt Mask
DMA_set_interrupt_mask(pCtxt);
// Set Halt Bit
pDMACHReg->Configuration |= HALT;
#if 0 // TODO: Sometimes Channel is not inactivated when TC reached to "0"
// Wait For Channel Inactive
while(pDMACHReg->Configuration & ACTIVE);
#endif
// Disable Channel
pDMACHReg->Configuration &= ~CHANNEL_ENABLE;
}
// Clear Interrupt Pending
DMA_clear_interrupt_pending(pCtxt);
CleanUp:
DMA_MSG((_T("[DMA]--DMA_channel_stop() : %d\n\r"), error));
return error;
}
DMA_INT_STATUS DMA_get_interrupt_status(DMA_CH_CONTEXT *pCtxt)
{
DMA_INT_STATUS status = NO_INT_PEND;
if (pCtxt->Controller == DMAC0) // channel in DMAC0
{
if (g_pDMAC0Reg->DMACIntTCStatus & (1<<(pCtxt->Channel)))
{
status |= TC_INT_PEND;
}
if (g_pDMAC0Reg->DMACIntErrStatus & (1<<(pCtxt->Channel)))
{
status |= ERR_INT_PEND;
}
}
else if (pCtxt->Controller == DMAC1) // channel in DMAC1
{
if (g_pDMAC1Reg->DMACIntTCStatus & (1<<(pCtxt->Channel)))
{
status |= TC_INT_PEND;
}
if (g_pDMAC1Reg->DMACIntErrStatus & (1<<(pCtxt->Channel)))
{
status |= ERR_INT_PEND;
}
}
return status;
}
void DMA_set_interrupt_mask(DMA_CH_CONTEXT *pCtxt)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
pDMACHReg = (S3C6400_DMA_CH_REG *)pCtxt->pCHReg;
pDMACHReg->Configuration &= ~(TCINT_UNMASK|ERRINT_UNMASK); // Mask is Bit Clear, Unmask is Bit Set
}
void DMA_clear_interrupt_mask(DMA_CH_CONTEXT *pCtxt)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
pDMACHReg = (S3C6400_DMA_CH_REG *)pCtxt->pCHReg;
pDMACHReg->Configuration |= (TCINT_UNMASK|ERRINT_UNMASK); // Mask is Bit Clear, Unmask is Bit Set
}
void DMA_clear_interrupt_pending(DMA_CH_CONTEXT *pCtxt)
{
if (pCtxt->Controller == DMAC0) // channel in DMAC0
{
g_pDMAC0Reg->DMACIntTCClear = (1<<(pCtxt->Channel));
g_pDMAC0Reg->DMACIntErrClear = (1<<(pCtxt->Channel));
}
else if (pCtxt->Controller == DMAC1) // channel in DMAC1
{
g_pDMAC1Reg->DMACIntTCClear = (1<<(pCtxt->Channel));
g_pDMAC1Reg->DMACIntErrClear = (1<<(pCtxt->Channel));
}
}
static BOOL DMA_dmac0_enable(void)
{
if (!(g_pDMAC0Reg->DMACConfiguration & DMAC_ENABLE)) // DMAC0 is Disabled
{
// Enable DMAC0
g_pDMAC0Reg->DMACConfiguration = M1_LITTLE_ENDIAN | M2_LITTLE_ENDIAN | DMAC_ENABLE;
DMA_MSG((_T("[DMA] DMA_dmac0_enable() : DMAC0 Enabled\n\r")));
}
return TRUE;
}
static BOOL DMA_dmac0_disable(void)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
BOOL bInUse = FALSE;
int i;
if (g_pDMAC0Reg->DMACConfiguration & DMAC_ENABLE) // DMAC0 is Enabled
{
for (i=0; i<8; i++) // Check channel in Use
{
pDMACHReg = (S3C6400_DMA_CH_REG *)((ULONG)g_pDMAC0Reg + DMA_CH_REG_OFFSET + i*DMA_CH_REG_SIZE);
if (pDMACHReg->Control0 & TCINT_ENABLE) // Check channel in use with TC Int Enable Bit !!!
{
bInUse = TRUE;
break;
}
}
if (bInUse == FALSE)
{
if (g_pDMAC0Reg->DMACEnbldChns & 0xff)
{
DMA_ERR((_T("[DMA:ERR] DMA_dmac0_disable() : All TCINT_ENABLE Bit is Clear, But Channel Enabled [0x%02x]\n\r"), (g_pDMAC0Reg->DMACEnbldChns&0xff)));
}
else // There is no channel enabled
{
// Disable DMAC0
g_pDMAC0Reg->DMACConfiguration &= ~DMAC_ENABLE;
g_pSysConReg->HCLK_GATE &= ~(1<<12); // DMAC0 HCLK Mask
DMA_MSG((_T("[DMA] DMA_dmac0_disable() : DMAC0 Disabled\n\r")));
}
}
}
return TRUE;
}
static BOOL DMA_dmac1_enable(void)
{
if (!(g_pDMAC1Reg->DMACConfiguration & DMAC_ENABLE)) // DMAC1 is Disabled
{
// Enable DMAC1
g_pDMAC1Reg->DMACConfiguration = M1_LITTLE_ENDIAN | M2_LITTLE_ENDIAN | DMAC_ENABLE;
DMA_MSG((_T("[DMA] DMA_dmac1_enable() : DMAC1 Enabled\n\r")));
}
return TRUE;
}
static BOOL DMA_dmac1_disable(void)
{
volatile S3C6400_DMA_CH_REG *pDMACHReg;
BOOL bInUse = FALSE;
int i;
if (g_pDMAC1Reg->DMACConfiguration & DMAC_ENABLE) // DMAC0 is Enabled
{
for (i=0; i<8; i++) // Check channel in Use
{
pDMACHReg = (S3C6400_DMA_CH_REG *)((ULONG)g_pDMAC1Reg + DMA_CH_REG_OFFSET + i*DMA_CH_REG_SIZE);
if (pDMACHReg->Control0 & TCINT_ENABLE) // Check channel in use with TC Int Enable Bit !!!
{
bInUse = TRUE;
break;
}
}
if (bInUse == FALSE)
{
if (g_pDMAC1Reg->DMACEnbldChns & 0xff)
{
DMA_ERR((_T("[DMA:ERR] DMA_dmac1_disable() : All TCINT_ENABLE Bit is Clear, But Channel Enabled [0x%02x]\n\r"), (g_pDMAC1Reg->DMACEnbldChns&0xff)));
}
else // There is no channel enabled
{
// Disable DMAC1
g_pDMAC1Reg->DMACConfiguration &= ~DMAC_ENABLE;
g_pSysConReg->HCLK_GATE &= ~(1<<13); // DMAC1 HCLK Mask
DMA_MSG((_T("[DMA] DMA_dmac1_disable() : DMAC1 Disabled\n\r")));
}
}
}
return TRUE;
}
static BOOL DMA_allocate_LLI_context(DMA_CH_CONTEXT *pCtxt)
{
DMA_ADAPTER_OBJECT Adapter;
PHYSICAL_ADDRESS PhysicalAddress;
PVOID pVirtualAddress;
BOOL bRet = TRUE;
DMA_MSG((_T("[DMA] ++DMA_allocate_LLI_context()\n\r")));
if ((pCtxt->LLICount > MAX_LLI_ENTRY) || pCtxt->LLICount == 0)
{
DMA_ERR((_T("[DMA] DMA_allocate_LLI_context() : LLICount [%d] Out of Range \n\r"), pCtxt->LLICount));
bRet = FALSE;
goto CleanUp;
}
if (pCtxt->LLIVirAddr) // for Reinitialize LLI case
{
DMA_free_LLI_context(pCtxt);
}
memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
Adapter.InterfaceType = Internal;
pVirtualAddress = HalAllocateCommonBuffer(&Adapter, pCtxt->LLICount*sizeof(DMA_LLI_ENTRY), &PhysicalAddress, FALSE);
if (pVirtualAddress == NULL)
{
DMA_ERR((_T("[DMA] DMA_allocate_LLI_context() : HalAllocateCommonBuffer() Failed \n\r")));
bRet = FALSE;
goto CleanUp;
}
pCtxt->LLIPhyAddr = (unsigned int)PhysicalAddress.LowPart;
pCtxt->LLIVirAddr = (unsigned int)pVirtualAddress;
CleanUp:
if (bRet == FALSE)
{
pCtxt->LLIPhyAddr = 0;
pCtxt->LLIVirAddr = 0;
}
DMA_MSG((_T("[DMA] --DMA_allocate_LLI_context() : %d\n\r"), bRet));
return bRet;
}
static BOOL DMA_free_LLI_context(DMA_CH_CONTEXT *pCtxt)
{
PHYSICAL_ADDRESS PhysicalAddress;
PVOID pVirtualAddress;
BOOL bRet = TRUE;
DMA_MSG((_T("[DMA] ++DMA_free_LLI_context()\n\r")));
if (pCtxt->LLIVirAddr)
{
PhysicalAddress.LowPart = pCtxt->LLIPhyAddr; // No Meaning just for compile
pVirtualAddress = (PVOID)pCtxt->LLIVirAddr;
HalFreeCommonBuffer(0, 0, PhysicalAddress, pVirtualAddress, FALSE);
pCtxt->LLIPhyAddr = 0;
pCtxt->LLIVirAddr = 0;
}
DMA_MSG((_T("[DMA] --DMA_free_LLI_context() : %d\n\r"), bRet));
return bRet;
}
static BOOL DMA_lock(void)
{
DWORD dwRet;
dwRet = WaitForSingleObject(g_hMutex, INFINITE);
if (dwRet != WAIT_OBJECT_0)
{
DMA_ERR((_T("[DMA] DMA_lock() : WaitForSingleObject() Failed\n\r")));
return FALSE;
}
return TRUE;
}
static BOOL DMA_unlock(void)
{
BOOL bRet;
bRet = ReleaseMutex(g_hMutex);
if (bRet == FALSE)
{
DMA_ERR((_T("[DMA] DMA_unlock() : ReleaseMutex() Failed\n\r")));
return FALSE;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -