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

📄 s3c6400_dma_controller.c

📁 Samsung公司S3C6400芯片的BSP源码包
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <windows.h>
#include <CEDDK.h>
#include <bsp_cfg.h>
#include <oal_intr.h>
#include <s3c6400.h>
#include "s3c6400_dma_controller_macro.h"
#include "s3c6400_dma_controller.h"

#ifdef	REMOVE_BEFORE_RELEASE
#define DMA_MSG(x)
#define DMA_INF(x)
#define DMA_ERR(x)	RETAILMSG(TRUE, x)
#else
//#define DMA_MSG(x)	RETAILMSG(TRUE, x)
#define DMA_MSG(x)
#define DMA_INF(x)	RETAILMSG(TRUE, x)
//#define DMA_INF(x)
#define DMA_ERR(x)	RETAILMSG(TRUE, x)
//#define DMA_ERR(x)
#endif

#define DMA_MUTEX	TEXT("S3C6400_DMA_Mutex")

static volatile S3C6400_DMAC_REG *g_pDMAC0Reg = NULL;
static volatile S3C6400_DMAC_REG *g_pDMAC1Reg = NULL;
static volatile S3C6400_SYSCON_REG *g_pSysConReg = NULL;
static HANDLE g_hMutex = NULL;

DMA_ERROR DMA_initialize_register_address(void *pDMAC0Reg, void *pDMAC1Reg, void *pSysConReg)
{
	DMA_ERROR error = DMA_SUCCESS;

	DMA_MSG((_T("[DMA]++DMA_initialize_register_address(0x%08x, 0x%08x, 0x%08x)\n\r"), pDMAC0Reg, pDMAC1Reg, pSysConReg));

	if (pDMAC0Reg == NULL || pDMAC1Reg == NULL || pSysConReg == NULL)
	{
		DMA_ERR((_T("[DMA:ERR] DMA_initialize_register_address() : NULL pointer parameter\n\r")));
		error = DMA_ERROR_NULL_PARAMETER;
	}
	else
	{
		g_pDMAC0Reg = (S3C6400_DMAC_REG *)pDMAC0Reg;
		g_pDMAC1Reg = (S3C6400_DMAC_REG *)pDMAC1Reg;
		g_pSysConReg = (S3C6400_SYSCON_REG *)pSysConReg;
		DMA_INF((_T("[DMA:INF] g_pDMAC0Reg = 0x%08x\n\r"), g_pDMAC0Reg));
		DMA_INF((_T("[DMA:INF] g_pDMAC1Reg = 0x%08x\n\r"), g_pDMAC1Reg));
		DMA_INF((_T("[DMA:INF] g_pSysConReg = 0x%08x\n\r"), g_pSysConReg));

		g_pSysConReg->SDMA_SEL = 0xcfffffff;	// All DMA is set to Normal DMA except Security TX, RX
		DMA_INF((_T("[DMA:INF] All DMA Source is set to Normal DMA\n\r")));
	}

	if (g_hMutex == NULL)
	{
		g_hMutex = CreateMutex(NULL, FALSE, DMA_MUTEX);
		if (g_hMutex == NULL)
		{
			DMA_ERR((_T("[DMA:ERR] DMA_initialize_register_address() : CreateMutex() Failed\n\r")));
			error = DMA_ERROR_NOT_INITIALIZED;
		}
	}

	DMA_MSG((_T("[DMA]--DMA_initialize_register_address() : %d\n\r"), error));

	return error;
}

BOOL DMA_request_channel(DMA_CH_CONTEXT *pCtxt, DMA_SOURCE DMASrc)
{
	volatile S3C6400_DMA_CH_REG *pDMACHReg;
	BOOL bRet = TRUE;
	int i;

	DMA_MSG((_T("[DMA]++DMA_request_channel(%d)\n\r"), DMASrc));

	pCtxt->DMASrc = DMASrc;

	if (g_pDMAC0Reg == NULL || g_pDMAC1Reg == NULL)
	{
		DMA_ERR((_T("[DMA:ERR] DMA Register Address is Not initialized\n\r")));
		bRet = FALSE;
		goto CleanUp;
	}

	switch(DMASrc)
	{
	case DMA_UART0_TX:
	case DMA_UART0_RX:
	case DMA_UART1_TX:
	case DMA_UART1_RX:
	case DMA_UART2_TX:
	case DMA_UART2_RX:
	case DMA_UART3_TX:
	case DMA_UART3_RX:
	case DMA_PCM0_TX:
	case DMA_PCM0_RX:
	case DMA_I2S0_TX:
	case DMA_I2S0_RX:
	case DMA_SPI0_TX:
	case DMA_SPI0_RX:
	case DMA_HSI_TX:
	case DMA_HSI_RX:
	case DMA_MEM:
		pCtxt->Controller = DMAC0;
		break;
	case DMA_PCM1_TX:
	case DMA_PCM1_RX:
	case DMA_I2S1_TX:
	case DMA_I2S1_RX:
	case DMA_SPI1_TX:
	case DMA_SPI1_RX:
	case DMA_AC97_PCMOUT:
	case DMA_AC97_PCMIN:
	case DMA_AC97_MICIN:
	case DMA_PWM:
	case DMA_IRDA:
	case DMA_EXTERNAL:
		pCtxt->Controller = DMAC1;
		break;
	default:
		DMA_ERR((_T("[DMA:ERR] DMA_request_channel() : Unknown DMA Source [%d]\n\r"), DMASrc));
		bRet = FALSE;
		goto CleanUp;
		break;
	}

	// Lock DMA Access
	DMA_lock();

	// Enable DMAC HCLK
	g_pSysConReg->HCLK_GATE |= (1<<12);	// DMAC0 HCLK Pass
	g_pSysConReg->HCLK_GATE |= (1<<13);	// DMAC1 HCLK Pass

	if (pCtxt->Controller == DMAC0)	// Find available channel in DMAC0
	{
		for (i=0; i<8; i++)
		{
			if (i == 3) continue;	// for OneNAND DMA channel

			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 !!!
			{
				pDMACHReg->Control0 |= TCINT_ENABLE;	// Set TC Int Enable Bit to reserve this channel!!!
				break;
			}
		}

		if (i < 8)		// there is available channel
		{
			DMA_INF((_T("[DMA:INF] DMA_request_channel() : Ch[%d] in DMAC0 is Available for DMASrc[%d]\n\r"), i, DMASrc));
			pCtxt->Channel = (DMAC_CH)i;
			pCtxt->dwIRQ = IRQ_DMA0_CH0+i;
			pCtxt->pCHReg = (void *)pDMACHReg;
			pCtxt->bValid = TRUE;
			DMA_dmac0_enable();
		}
		else if (DMASrc == DMA_MEM)	// DMA MEM2MEM can use channel in DMAC1
		{
			pCtxt->Controller = DMAC1;
		}
		else			// there is no available channel
		{
			DMA_ERR((_T("[DMA:ERR] DMA_request_channel() : No Available Channel in DMAC0 for DMASrc[%d]\n\r"), DMASrc));
			bRet = FALSE;
			goto CleanUp;
		}
	}

	if (pCtxt->Controller == DMAC1)	// Find available channel in DMAC1
	{
		for (i=0; i<8; i++)
		{
			if (i == 3) continue;	// for OneNAND DMA channel

			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 !!!
			{
				pDMACHReg->Control0 |= TCINT_ENABLE;	// Set TC Int Enable Bit to reserve this channel!!!
				break;
			}
		}

		if (i < 8)		// there is available channel
		{
			DMA_INF((_T("[DMA:INF] DMA_request_channel() : Ch[%d] in DMAC1 is Available for DMASrc[%d]\n\r"), i, DMASrc));
			pCtxt->Channel = (DMAC_CH)i;
			pCtxt->dwIRQ = IRQ_DMA1_CH0+i;
			pCtxt->pCHReg = (void *)pDMACHReg;
			pCtxt->bValid = TRUE;
			DMA_dmac1_enable();
		}
		else			// there is no available channel
		{
			DMA_ERR((_T("[DMA:ERR] DMA_request_channel() : No Available Channel in DMAC1 for DMASrc[%d]\n\r"), DMASrc));
			bRet = FALSE;
			goto CleanUp;
		}
	}

CleanUp:

	// Disable DMAC HCLK when No channel is allocated
	if (!(g_pDMAC0Reg->DMACConfiguration & DMAC_ENABLE))
	{
		g_pSysConReg->HCLK_GATE &= ~(1<<12);	// DMAC0 HCLK Mask
	}

	if (!(g_pDMAC1Reg->DMACConfiguration & DMAC_ENABLE))
	{
		g_pSysConReg->HCLK_GATE |= ~(1<<13);	// DMAC1 HCLK Mask
	}

	// Unlock DMA Access
	DMA_unlock();

	if (bRet == FALSE)		// Request is denied
	{
		// Clear DMA Channel Context
		memset((void *)pCtxt, 0x0, sizeof(DMA_CH_CONTEXT));
	}

	DMA_MSG((_T("[DMA]--DMA_request_channel() : %d\n\r"), bRet));

	return bRet;
}

BOOL DMA_release_channel(DMA_CH_CONTEXT *pCtxt)
{
	volatile S3C6400_DMA_CH_REG *pDMACHReg;
	BOOL bRet = TRUE;

	DMA_MSG((_T("[DMA]++DMA_release_channel() : Ch%d in DMAC%d, \n\r"), pCtxt->Channel, pCtxt->Controller));

	if (pCtxt->bValid == FALSE)
	{
		DMA_ERR((_T("[DMA:ERR] DMA_release_channel() : Invalid DMA_CH_CONTEXT\n\r")));
		bRet = FALSE;
		goto CleanUp;
	}

	// Stop DMA Channel
	DMA_channel_stop(pCtxt);

	// Lock DMA Access
	DMA_lock();

	pDMACHReg = (S3C6400_DMA_CH_REG *)pCtxt->pCHReg;
	pDMACHReg->Control0 &= ~TCINT_ENABLE;		// Clear TC Int Enable Bit to release this channel!!!

	if (pCtxt->Controller == DMAC0)		// Release channel in DMAC0
	{
		DMA_dmac0_disable();
	}
	else if (pCtxt->Controller == DMAC1)	// Release channel in DMAC1
	{
		DMA_dmac1_disable();
	}

	// Unlock DMA Access
	DMA_unlock();

CleanUp:

	// Release LLI buffer
	DMA_free_LLI_context(pCtxt);

	// Clear DMA Channel Context
	memset((void *)pCtxt, 0x0, sizeof(DMA_CH_CONTEXT));

	DMA_MSG((_T("[DMA]--DMA_release_channel() : %d\n\r"), bRet));

	return bRet;
}

DMA_ERROR DMA_initialize_channel(DMA_CH_CONTEXT *pCtxt, BOOL bSync)
{
	volatile S3C6400_DMA_CH_REG *pDMACHReg;
	DMA_ERROR error = DMA_SUCCESS;

	DMA_MSG((_T("[DMA]++DMA_initialize_channel() : Ch%d in DMAC%d (bSync:%d)\n\r"), pCtxt->Channel, pCtxt->Controller, bSync));

	if (pCtxt->bValid == FALSE)
	{
		DMA_ERR((_T("[DMA:ERR] DMA_initialize_channel() : Invalid DMA_CH_CONTEXT\n\r")));
		error = DMA_ERROR_ILLEGAL_PARAMETER;
		goto CleanUp;
	}

	pCtxt->LLICount = 0;
	pCtxt->LLIAHBM = AHB_M1;

	switch(pCtxt->DMASrc)
	{
	//-------------------
	// DMA Source in DMC0
	//-------------------
	case DMA_UART0_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_UART0_TX;		// UART0_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_UART0_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_UART0_RX;		// UART0_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_UART1_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_UART1_TX;		// UART1_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_UART1_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_UART1_RX;		// UART1_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_UART2_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_UART2_TX;		// UART2_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_UART2_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_UART2_RX;		// UART2_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_UART3_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_UART3_TX;		// UART3_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_UART3_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_UART3_RX;		// UART3_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_PCM0_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_PCM0_TX;		// PCM0_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_PCM0_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_PCM0_RX;		// PCM0_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_I2S0_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_I2S0_TX;		// I2S0_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_I2S0_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_I2S0_RX;		// I2S0_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_SPI0_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_SPI0_TX;		// SPI0_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_SPI0_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_SPI0_RX;		// SPI0_RX
		pCtxt->DstPeri = 0;					// Memory (Don't Care)
		pCtxt->FlowCtrl = PERI_TO_MEM;		// Peripheral -> Memory
		break;
	case DMA_HSI_TX:
		pCtxt->SrcAHBM = AHB_M1;			// Memory
		pCtxt->DstAHBM = AHB_M2;			// Peripheral
		pCtxt->SrcPeri = 0;					// Memory (Don't Care)
		pCtxt->DstPeri = DMAC0_HSI_TX;		// SPI0_TX
		pCtxt->FlowCtrl = MEM_TO_PERI;		// Memory -> Peripheral
		break;
	case DMA_HSI_RX:
		pCtxt->SrcAHBM = AHB_M2;			// Peripheral
		pCtxt->DstAHBM = AHB_M1;			// Memory
		pCtxt->SrcPeri = DMAC0_HSI_RX;		// HSI_RX

⌨️ 快捷键说明

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