📄 dma.c
字号:
/**************************************************************************************
*
* Project Name : S3C6400 Validation
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6400.
* Anybody can use this software without our permission.
*
*--------------------------------------------------------------------------------------
*
* File Name : Dma.c
*
* File Description : This file implements the API functons for OneNand controller.
*
* Author : Wonjoon Jang
* Dept. : AP Development Team
* Created Date : 2006/12/29
* Version : 0.1
*
* History
* - Created(wonjoon.jang 2006/12/29)
*
**************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6400.h"
#include "system.h"
#include "sysc.h"
#include "dma.h"
#include "intc.h"
enum DMA_REG
{
DMA_INT = 0x000, //[7:0] RO Interrupt status
DMA_INTTC = 0x004, //[7:0] RO Interrupt terminal count status
DMA_INTTCC = 0x008, //[7:0] WO Interrupt terminal count clear
DMA_INTERR = 0x00C, //[7:0] RO Interrupt error status
DMA_INTERRC = 0x010, //[7:0] WO Interrupt error clear
DMA_RAWINTTC = 0x014, //[7:0] RO Raw interrupt terminal count state
DMA_RAWINTERR = 0x018, //[7:0] RO Raw Interrupt error status
DMA_ENBLDCH = 0x01C, //[7:0] RO enabled channels
DMA_SOFTBREQ = 0x020, //[15:0] RW Software Burst Request 16peripheral
DMA_SOFTSREQ = 0x024, //[15:0] RW Software Single Request 16peripheral
DMA_SOFTLBREQ = 0x028, //[15:0] RW Software Last Burst Request 16peripheral
DMA_SOFTLSREQ = 0x02C, //[15:0] RW Software Last Single Request 16peripheral
DMA_CONFIG = 0x030,
// [2] M2 AHB Master 2 endianness configuration 0=little,1=big
// [1] M1 AHB Master 2 endianness configuration 0=little,1=big
// [0] DMAC enable 0=disabled,1=enabled
DMA_SYNC = 0x034,
DMA_CH0 = 0x100,
DMA_CH1 = 0x120,
DMA_CH2 = 0x140,
DMA_CH3 = 0x160,
DMA_CH4 = 0x180,
DMA_CH5 = 0x1A0,
DMA_CH6 = 0x1C0,
DMA_CH7 = 0x1E0
};
enum DMA_CH_REG
{
DMA_CH_SRCADDR = 0x00,
DMA_CH_DSTADDR = 0x04,
DMA_CH_LLI = 0x08,
//[31:2] Linked list item Address bits[1:0] are 0
//[1] Undefined
//[0] AHB master select next LLI 0=M1 1=M2
DMA_CH_CONTROL0 = 0x0C,
DMA_CH_CONTROL1 = 0x10,
DMA_CH_CONFIG = 0x14
//[18] RW Halt 0=enable DMA requests 1=ignore extra source DMA
//[17] RO 0=FIFO empty 1=FIFO has data
//[16] RW Lock
//[15] RW Terminal count interrupt mask
//[14] RW Interrupt error mask
//[13:11]RW FlowCntrl
//[9:6] RW DestPeripheral
//[4:1] RW SrcPeripheral
//[0] RW Channel enable
};
// DMA Controller Register
#define DmaOutp32(offset, value) Outp32(sCh->m_uBaseAddr+offset, value)
#define DmaInp32(offset) Inp32(sCh->m_uBaseAddr+offset)
// DMA Channel Register
#define DmaChOutp32(offset, value) Outp32(sCh->m_uBaseAddr+sCh->m_uChAddr+offset, value)
#define DmaChInp32(offset) Inp32(sCh->m_uBaseAddr+sCh->m_uChAddr+offset)
//////////
// Function Name : DMAC_InitCh
// Function Description : This function initializes a certain DMA Controller
// Input : eUnit - DMA Controller Number,
// eCh - Used DMA Channel, DMA_A ~ DMA_H
// Output : void
//
// Version : v0.1
void DMAC_InitCh(DMA_UNIT eUnit, DMA_CH eCh, DMAC *sCh)
{
u32 x;
if ( eUnit == DMA0 )
sCh->m_uBaseAddr = DMA0_BASE;
else if ( eUnit == DMA1 )
sCh->m_uBaseAddr = DMA1_BASE;
else if ( eUnit == SDMA0 )
sCh->m_uBaseAddr = SDMA0_BASE;
else if ( eUnit == SDMA1 )
sCh->m_uBaseAddr = SDMA1_BASE;
else
Assert(0);
DmaOutp32(DMA_CONFIG, 0x1); // DMAC enabled
x = eCh;
DmaOutp32(DMA_INTTCC, x); //clear pending
DmaOutp32(DMA_INTERRC, x); //clear pending
}
//////////
// Function Name : DMAC_Close
// Function Description : This function close a certain DMA Controller
// Input : eUnit - DMA Controller Number,
// eCh - Used DMA Channel, DMA_A ~ DMA_H
// Output : void
//
// Version : v0.1
void DMAC_Close(DMA_UNIT eUnit, DMA_CH eCh, DMAC *sCh)
{
u32 x;
if ( eUnit == DMA0 )
sCh->m_uBaseAddr = DMA0_BASE;
else if ( eUnit == DMA1 )
sCh->m_uBaseAddr = DMA1_BASE;
else if ( eUnit == SDMA0 )
sCh->m_uBaseAddr = SDMA0_BASE;
else if ( eUnit == SDMA1 )
sCh->m_uBaseAddr = SDMA1_BASE;
else
Assert(0);
DmaOutp32(DMA_CONFIG, 0x0); // DMAC enabled
x = eCh;
DmaOutp32(DMA_INTTCC, x); //clear pending
DmaOutp32(DMA_INTERRC, x); //clear pending
}
//////////
// Function Name : DMAC_IsTransferDone
// Function Description : This function check the transferring datas are done.
// Input : *sCh : DMAC, Enabled Channel address
// Output : true : Transfer is done
// false : Tranfser is not done
// Version : v0.1
bool DMACH_IsTransferDone(DMAC *sCh)
{
u32 x;
bool res;
x = DmaChInp32(DMA_CH_CONFIG);
if ( (x&0x1) == 0 )
res = true;
else
res = false;
return res;
}
u32 DMAC_IntStatus(DMAC *sCh)
{
return DmaInp32(DMA_INT);
}
u32 DMACH_Configuration(DMAC *sCh)
{
return DmaChInp32(DMA_CH_CONFIG);
}
//////////
// Function Name : DMAC_Stop
// Function Description : Stop DMA Operation.
// Input : *sCh : DMAC , Enabled Channel address
// Output : void
//
// Version : v0.1
void DMACH_Stop(DMAC *sCh)
{
u32 uReg;
uReg = DmaChInp32(DMA_CH_CONFIG);
uReg &= ~(1<<0);
DmaChOutp32(DMA_CH_CONFIG, uReg);
}
//////////
// Function Name : DMACH_GetChannelNumber
// Function Description : This function get dma channel number.
// Input : *sCh : DMAC , Enabled Channel address
// Output : Channel status.
//
// Version : v0.1
DMA_CH DMACH_GetChannelNumber(DMAC *sCh)
{
u32 uRead;
uRead = DmaInp32(DMA_INT);
return (DMA_CH)uRead;
}
//////////
// Function Name : DMAC_ClearIntPending
// Function Description : This function clear the dma TC interrupt pending register.
// Input : *sCh : DMAC , Enabled Channel address
// Output : void
//
// Version : v0.1
void DMACH_ClearIntPending(DMAC *sCh)
{
u32 uRead;
uRead = DmaInp32(DMA_INTTC);
DmaOutp32(DMA_INTTCC, uRead);
}
//////////
// Function Name : DMAC_ClearErrIntPending
// Function Description : This function clear the dma Err interrupt pending register.
// Input : *sCh : DMAC , Enabled Channel address
// Output : void
//
// Version : v0.1
void DMACH_ClearErrIntPending(DMAC *sCh)
{
u32 uRead;
uRead = DmaInp32(DMA_INTERR);
DmaOutp32(DMA_INTERRC, uRead);
}
//////////
// Function Name : DMAC_Setup
// Function Description : Set Channel information
// Input : eCh : Selected channel.
// uLLIAddr : Linked List Item Address
// : not using LLI => Write 0 (Default)
// uSrcAddr : Source Address
// bSrcFixed : "1" Source Fixed. "0" Source Increment.
// uDstAddr : Destination Address
// bDstFixed : "1" Destination Fixed. "0" Destination Increment.
// eDataSz : Transfer Width => BYTE/HWORD(Half-Word/WORD
// uDataCnt : Transfer Size [24:0] => 1 ~ 0x200_0000
// eOpMode : not using in pl080, DEMAND
// eSrcReq&eDstReq : Peripheral Request Source, Memory => MEM
// [DMAC0, SDMAC0]
// DMA0_UART0_0, DMA0_UART0_1, DMA0_UART1_0, DMA0_UART1_1,
// DMA0_UART2_0, DMA0_UART2_1, DMA0_UART3_0, DMA0_UART3_1,
// DMA0_PCM0_TX,DMA0_PCM0_RX, DMA0_I2S0_TX, DMA0_I2S0_RX,
// DMA0_SPI0_TX, DMA0_SPI0_RX, DMA0_HSI_TX, DMA0_HSI_RX,
// [DMAC1, SDMAC1]
// DMA1_PCM1_TX, DMA1_PCM1_RX, DMA1_I2S1_TX, DMA1_I2S1_RX,
// DMA1_SPI1_TX, DMA1_SPI1_RX, DMA1_AC_PCMout, DMA1_AC_PCMin,
// DMA1_AC_MICin, DMA1_PWM, DMA1_IrDA, DMA1_EXTERNAL
// SDMA1_SECU_RX, SDMA1_SEXU_TX => Only SDMAC1
// eBurstMode : Burst Size,
// SINGLE, BURST4, BURST8, BURST16, BURST32, BURST64, BURST128, BURST256
//
// Output : void
//
// Version : v0.1
void DMACH_Setup(
DMA_CH eCh, u32 uLLIAddr, u32 uSrcAddr, bool bSrcFixed, u32 uDstAddr, bool bDstFixed, DATA_SIZE eDataSz, u32 uDataCnt,
DMA_HS_MODE eOpMode, DREQ_SRC eSrcReq, DREQ_SRC eDstReq, BURST_MODE eBurstMode, DMAC *sCh)
{
u32 uReg;
u32 uBurstSz;
u32 uTrWidth;
u32 uTCEnable;
DMA_AHB eSrcAhb, eDstAhb;
switch(eCh)
{
case DMA_A: sCh->m_uChAddr = DMA_CH0; break;
case DMA_B: sCh->m_uChAddr = DMA_CH1; break;
case DMA_C: sCh->m_uChAddr = DMA_CH2; break;
case DMA_D: sCh->m_uChAddr = DMA_CH3; break;
case DMA_E: sCh->m_uChAddr = DMA_CH4; break;
case DMA_F: sCh->m_uChAddr = DMA_CH5; break;
case DMA_G: sCh->m_uChAddr = DMA_CH6; break;
case DMA_H: sCh->m_uChAddr = DMA_CH7; break;
default : Assert(0);
}
Assert(uDataCnt < 0x2000000);
#if 0
if (uSrcAddr >= _DRAM_BaseAddress && uSrcAddr <= _DRAM_BaseAddress+0x8000000)
eSrcAhb = AHB_MASTER1;
else
eSrcAhb = AHB_MASTER2;
if (uDstAddr >= _DRAM_BaseAddress && uDstAddr <= _DRAM_BaseAddress+0x8000000)
eDstAhb = AHB_MASTER1;
else
eDstAhb = AHB_MASTER2;
#else
if(eSrcReq == MEM)
eSrcAhb = AHB_MASTER1;
else if(eSrcReq == DMA1_NAND_TX)
eSrcAhb = AHB_MASTER2;
else
eSrcAhb = AHB_MASTER2;
if(eDstReq == MEM)
eDstAhb = AHB_MASTER1;
else if(eDstReq == DMA1_NAND_RX)
eDstAhb = AHB_MASTER2;
else
eDstAhb = AHB_MASTER2;
#if 0
if ((uSrcAddr >= SROM_BASE) && (uSrcAddr <= (u32)((u32)SROM_BASE+0x10000000)))
eSrcAhb = AHB_MASTER2;
else
eSrcAhb = AHB_MASTER1;
if ((uDstAddr >= SROM_BASE) && (uDstAddr <= (u32)((u32)SROM_BASE+0x10000000)))
eDstAhb = AHB_MASTER2;
else
eDstAhb = AHB_MASTER1;
#endif
#endif
DmaChOutp32(DMA_CH_SRCADDR, uSrcAddr);
DmaChOutp32(DMA_CH_DSTADDR, uDstAddr);
switch(eDataSz)
{
case WORD : uTrWidth = ((2<<21)|(2<<18));break;
case HWORD : uTrWidth = ((1<<21)|(1<<18));break;
case BYTE : uTrWidth = ((0<<21)|(0<<18));break;
default : Assert(0);
}
switch(eBurstMode)
{
case SINGLE : uBurstSz = ((0<<15)|(0<<12));break;
case BURST4 : uBurstSz = ((1<<15)|(1<<12));break;
case BURST8 : uBurstSz = ((2<<15)|(2<<12));break;
case BURST16 : uBurstSz = ((3<<15)|(3<<12));break;
case BURST32 : uBurstSz = ((4<<15)|(4<<12));break;
case BURST64 : uBurstSz = ((5<<15)|(5<<12));break;
case BURST128 : uBurstSz = ((6<<15)|(6<<12));break;
case BURST256 : uBurstSz = ((7<<15)|(7<<12));break;
default : Assert(0);
}
//Channel LLI Register Setting => not using => 0x0
uReg =
(uLLIAddr&~(0x3))|
(AHB_MASTER1);
DmaChOutp32(DMA_CH_LLI, uReg);
if(uLLIAddr == 0)
uTCEnable = 1;
else
uTCEnable = 0;
// Channel Control Register0 Setting
// [31]: Terminal Count interrupt
uReg =
(uTCEnable<<31) |
(bDstFixed? 0 : 1)<<27 |
(bSrcFixed? 0 : 1)<<26 |
(eDstAhb? 1 : 0)<<25 |
(eSrcAhb? 1 : 0)<<24 |
(uTrWidth) |
(uBurstSz);
DmaChOutp32(DMA_CH_CONTROL0, uReg);
// Channel Control Register1 Setting => Transfer Size
DmaChOutp32(DMA_CH_CONTROL1, uDataCnt);
// Channel Configuration Register1 Setting
uReg =
(0<<18) | // enable DMA requests
(0<<16) | // disables locked transfers
(1<<15) | // Teminal count interrupt enable
(0<<14) | // Interrupt error mask
((((eSrcReq == MEM)||(eSrcReq == DMA1_NAND_TX))? 0 : 1)<<12) |
((((eDstReq == MEM)||(eDstReq == DMA1_NAND_RX))? 0 : 1)<<11) |
(((eDstReq == MEM)? 0:eDstReq)<<6) | // DstPerpheral
(((eSrcReq == MEM)? 0:eSrcReq)<<1) ; // SrcPeripheral
// (eDstReq <<6) | // DstPerpheral
// (eSrcReq <<1) ; // SrcPeripheral
DmaChOutp32(DMA_CH_CONFIG, uReg);
}
//////////
// Function Name : DMAC_Start
// Function Description : Enable DMA Channel
// Input : *sCh : DMAC , Enabled Channel address
// Output : void
//
// Version : v0.1
void DMACH_Start(DMAC *sCh)
{
u32 uReg;
uReg = DmaChInp32(DMA_CH_CONFIG);
uReg |= (1<<0); // Channel Enable
DmaChOutp32(DMA_CH_CONFIG, uReg);
}
//////////
// Function Name : DMACH_AddrSetup
// Function Description : Set Source address and destination address.
// Input : eCh : Selected channel.
// uSrcAddr : Source Address
// uDstAddr : Destination Address
//
// Output : void
//
// Version : v0.1
void DMACH_AddrSetup(DMA_CH eCh, u32 uSrcAddr, u32 uDstAddr, DMAC *sCh)
{
switch(eCh)
{
case DMA_A: sCh->m_uChAddr = DMA_CH0; break;
case DMA_B: sCh->m_uChAddr = DMA_CH1; break;
case DMA_C: sCh->m_uChAddr = DMA_CH2; break;
case DMA_D: sCh->m_uChAddr = DMA_CH3; break;
case DMA_E: sCh->m_uChAddr = DMA_CH4; break;
case DMA_F: sCh->m_uChAddr = DMA_CH5; break;
case DMA_G: sCh->m_uChAddr = DMA_CH6; break;
case DMA_H: sCh->m_uChAddr = DMA_CH7; break;
default : Assert(0);
}
DmaChOutp32(DMA_CH_SRCADDR, uSrcAddr);
DmaChOutp32(DMA_CH_DSTADDR, uDstAddr);
}
//////////
// Function Name : DMACH_ReadSrcAddr
// Function Description : Read Source Address
// Input : Structure definition of DMAC
// Output : Source Address
// Version : v0.1
// added by Woojin
u32 DMACH_ReadSrcAddr(DMAC *sCh)
{
return DmaChInp32(DMA_CH_SRCADDR);
}
//////////
// Function Name : DMACH_ReadDstAddr
// Function Description : Read Destination Address
// Input : Structure definition of DMAC
// Output : Destination Address
// Version : v0.1
// added by Woojin
u32 DMACH_ReadDstAddr(DMAC *sCh)
{
return DmaChInp32(DMA_CH_DSTADDR);
}
//added by rb1004
void DMACH_WriteSrcAddr(DMAC *sCh, u32 uSrcAddr)
{
DmaChOutp32(DMA_CH_SRCADDR, uSrcAddr);
}
//added by rb1004
void DMACH_WriteDstAddr(DMAC *sCh, u32 uDstAddr)
{
DmaChOutp32(DMA_CH_DSTADDR, uDstAddr);
}
//added by rb1004
void DMACH_WriteTransferSize(DMAC *sCh, u32 uSize)
{
DmaChOutp32(DMA_CH_CONTROL1, uSize);
}
//added by rb1004
void DMACH_SoftBurstReq(DMAC *sCh, DREQ_SRC eSrcReq)
{
DmaOutp32(DMA_SOFTBREQ, (1<<eSrcReq));
//while(!(DmaInp32(DMA_SOFTBREQ) & (1<<eSrcReq)));
}
//added by rb1004
void DMACH_SoftBurstLastReq(DMAC *sCh, DREQ_SRC eSrcReq)
{
DmaOutp32(DMA_SOFTLBREQ, (1<<eSrcReq));
//while(!(DmaInp32(DMA_SOFTLBREQ) & (1<<eSrcReq)));
}
//////////
// Function Name : DMACH_SetTransferSize
// Function Description : This function sets TransferSize
// Input : Transfer Size
// Output : NONE
// Version : v0.1
// added by Woojin
void DMACH_SetTransferSize(u32 uSize, DMAC *sCh)
{
DmaChOutp32(DMA_CH_CONTROL1, uSize);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -