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

📄 s3c6400_dma_controller.c

📁 Samsung公司S3C6400芯片的BSP源码包
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -