#ifndef __S5PV210_DMA_CONTROLLER_H__
#define __S5PV210_DMA_CONTROLLER_H__

#if __cplusplus
extern "C"
{
#endif

#define MAX_LLI_ENTRY        (32)
#define STATUS_LOOP_REG_SIZE_CHANNEL    (0x20)
 
typedef unsigned long    u32; 
typedef    unsigned char    u8;

typedef enum{
    DMA_READ = 0,
	DMA_WRITE =1
}OPAction;
typedef enum 
{

    DMA_MDMA=0x0, 
    DMA_PDMA0=0x1,
    DMA_PDMA1=0x2,        
    DMA_DMA=0xFd, // pdma0, pdma1, mdma
    DMA_PDMA=0xFe, // pdma0, pdma1
    DMA_INVALIDUNIT=0xFF
}DMA_UNIT;

typedef enum 
{
    DMA_00, DMA_01, DMA_02, DMA_03, DMA_04, DMA_05, DMA_06, DMA_07, //Mdma
    DMA_10, DMA_11, DMA_12, DMA_13, DMA_14, DMA_15, DMA_16, DMA_17, //Pdma0
    DMA_20, DMA_21, DMA_22, DMA_23, DMA_24, DMA_25, DMA_26, DMA_27, //pdma1
    DMA_InvalidCH=0xff
}DMA_CH;

typedef enum 
{
// Peri DMA 0,1
    PERI_UART_0_RX     = 0x0,
    PERI_UART_0_TX     = 0x1,
    PERI_UART_1_RX     = 0x2,
    PERI_UART_1_TX     = 0x3,
    PERI_UART_2_RX     = 0x4,
    PERI_UART_2_TX     = 0x5,
    PERI_UART_3_RX     = 0x6,
    PERI_UART_3_TX     = 0x7,
    PERI_I2S_0_RX      = 0x9,
    PERI_I2S_0_TX      = 0xa,
    PERI_I2S_0S_TX     = 0xb,
    PERI_I2S_1_RX      = 0xc,
    PERI_I2S_1_TX      = 0xd,
    PERI_SPI_0_RX      = 0x10,
    PERI_SPI_0_TX      = 0x11,
    PERI_SPI_1_RX      = 0x12,
    PERI_SPI_1_TX      = 0x13,
    PERI_SPI_2_RX      = 0x14,
    PERI_SPI_2_TX      = 0x15,
// Peri DMA 0    
    PERI_AC_MICin      = 0x16,
    PERI_AC_PCMin      = 0x17,
    PERI_AC_PCMout     = 0x18,    
    PERI_PWM           = 0x1a,
    PERI_SPDIFO        = 0x1b,
// Peri DMA 1
    PERI_I2S_2_RX      = 0xe,
    PERI_I2S_2_TX      = 0xf,
    PERI_PCM_0_RX      = 0x16,
    PERI_PCM_0_TX      = 0x17,
    PERI_PCM_1_RX      = 0x18,
    PERI_PCM_1_TX      = 0x19,
    PERI_MSM_REQ0      = 0x1a,
    PERI_MSM_REQ1      = 0x1b,
    PERI_MSM_REQ2      = 0x1c,
    PERI_MSM_REQ3      = 0x1d,
    PERI_PCM_2_RX      = 0x1e,
    PERI_PCM_2_TX      = 0x1f,
// Mem DMA    
    PERI_SEC_RX        = 0x0,    
    PERI_SEC_TX        = 0x1,
    PERI_SOFTWARE      = 0xff //0xff
}PERI_NUMBER;

typedef enum 
{
// Peri DMA 0,1
    DMAsrc_UART_0_RX     = 0x0,
    DMAsrc_UART_0_TX     = 0x1,
    DMAsrc_UART_1_RX     = 0x2,
    DMAsrc_UART_1_TX     = 0x3,
    DMAsrc_UART_2_RX     = 0x4,
    DMAsrc_UART_2_TX     = 0x5,
    DMAsrc_UART_3_RX     = 0x6,
    DMAsrc_UART_3_TX     = 0x7,
    DMAsrc_I2S_0_RX      = 0x8,
    DMAsrc_I2S_0_TX      = 0x9,
    DMAsrc_I2S_0S_TX     = 0xa,
    DMAsrc_I2S_1_RX      = 0xb,
    DMAsrc_I2S_1_TX      = 0xc,
    DMAsrc_SPI_0_RX      = 0xd,
    DMAsrc_SPI_0_TX      = 0xe,
    DMAsrc_SPI_1_RX      = 0xf,
    DMAsrc_SPI_1_TX      = 0x10,
    DMAsrc_SPI_2_RX      = 0x11,
    DMAsrc_SPI_2_TX      = 0x12,
// Peri DMA 0    
    DMAsrc_AC_MICin      = 0x13,
    DMAsrc_AC_PCMin      = 0x14,
    DMAsrc_AC_PCMout     = 0x15,    
    DMAsrc_PWM_RX        = 0x16,
    DMAsrc_PWM_TX        = 0x17,
    DMAsrc_SPDIFO_RX     = 0x18,
    DMAsrc_SPDIFO_TX     = 0x19,
// Peri DMA 1
    DMAsrc_I2S_2_RX      = 0x1a,
    DMAsrc_I2S_2_TX      = 0x1b,
    DMAsrc_PCM_0_RX      = 0x1c,
    DMAsrc_PCM_0_TX      = 0x1d, 
    DMAsrc_PCM_1_RX      = 0x1e,
    DMAsrc_PCM_1_TX      = 0x1f,
    DMAsrc_MSM_REQ0_RX   = 0x20,
    DMAsrc_MSM_REQ0_TX   = 0x21,
    DMAsrc_MSM_REQ1_RX   = 0x22,
    DMAsrc_MSM_REQ1_TX   = 0x23,    
    DMAsrc_MSM_REQ2_RX   = 0x24,
    DMAsrc_MSM_REQ2_TX   = 0x25,    
    DMAsrc_MSM_REQ3_RX   = 0x26,
    DMAsrc_MSM_REQ3_TX   = 0x27,
    DMAsrc_PCM_2_RX      = 0x28,
    DMAsrc_PCM_2_TX      = 0x29,
// Mem DMA    
    DMAsrc_SEC_RX        = 0x2a,    
    DMAsrc_SEC_TX        = 0x2b,
    DMAsrc_SOFTWARE_1    = 0x2c,
    DMAsrc_SOFTWARE_2    = 0x2d, 
    DMAsrc_SOFTWARE_3    = 0x2e, 
    DMAsrc_SOFTWARE_4    = 0x2f, 
    DMAsrc_SOFTWARE_5    = 0x30,     
    DMAsrc_SOFTWARE_6    = 0x31,  //for ondNAND
    DMAsrc_DMA_SRC_INVALID=0x32
}DREQ_SRC;


typedef enum
{
    PERI_TO_MEM =0,
    MEM_TO_PERI,
    MEM_TO_MEM ,
    PERI_TO_PERI
} FLOW_CONTROL;


typedef enum
{
    DMA_CH0 = 0,
    DMA_CH1,
    DMA_CH2,
    DMA_CH3,
    DMA_CH4,
    DMA_CH5,
    DMA_CH6,
    DMA_CH7
} DMAC_CH;
 


typedef enum
{
    FIXED =0,
    INCREASE
} ADDRESS_UPDATE;


typedef enum
{
    BYTE_UNIT ,
    HWORD_UNIT ,
    WORD_UNIT ,
    DWORD_UNIT
} TRANSFER_UNIT;

typedef enum
{
    BURST_1 = 0,
    BURST_4,
    BURST_8,
    BURST_16,
    BURST_16X2,
    BURST_32,
    BURST_64,
    BURST_128,
    BURST_256
} BURST_SIZE;

typedef enum
{
    LLI_NEXT_ENTRY,
    LLI_FIRST_ENTRY,
    LLI_THIS_IS_END
} LLI_NEXT_ITEM;




typedef enum 
{
    DMA_DS             =  0x000, //[9:0] RO DMA status
        // [9] DNS                0-operate in secure mode, 1-operate in non-secure mode 
        //                        check boot_manager_ns input port. (boot_manager_ns==1 means Non-secure state.)
        // [8:4] Wakeup event    0-irq0, ..., 31-irq31 (check DMA_CR0's num_events)
        //                        (when executing DMAWFE instruction, it signals the above interrupt HIGH.)
        // [3:0] DMA status        0-stopped, 1-executing, 2-Cache miss, 3-Updating PC, 4-Waiting for event, 0xf-faulting
    DMA_DPC            =  0x004, //[31:0] RO DMA Program Counter
        //                         when boot_from_pc is tied to HIGH, DMA_DPC is updated by boot_addr[31:0].
    DMA_INTEN        =  0x020, //[31:0] RW Interrupt Enable
        // Bit[N]=0 - If executing DMASEV for event N then the DMAC signals event N to all of the threads.
        // Bit[N]=1 - If executing DMASEV for event N then the DMAC sets irq[N] HIGH.
    DMA_ES            =  0x024, //[31:0] RO Event Status
        // Bit[N]=0 - Event N is inactive or irq[N] is LOW
        // Bit[N]=1 - Event N is active or irq[N] is HIGH
    DMA_INTSTATUS    =  0x028, //[31:0] RO Interrupt Status
        // Bit[N]=0 - Event N is inactive or irq[N] is LOW
        // Bit[N]=1 - Event N is active or irq[N] is HIGH    
    DMA_INTCLR        =  0x02c, //[31:0] WO Interrupt Clear
        // Bit[N]=0 - The status of irq[N] does not change
        // Bit[N]=1 - DMAC sets irq[N] LOW if INTEN is enabled, otherwise no change
    DMA_FSM            =  0x030, //[0] RO Fault Status DMA Manager
        // [0] fs_mgr    0-DMA manager thread is not in the Faulting state 1- is in the Faulting state
    DMA_FSC            =  0x034, //[7:0] RO Fault Status DMA Channel
        // Bit[N]=0 - No fault is present on DMA ch N
        // Bit[N]=1 - DMA ch N is in the Faulting state
    DMA_FTM            =  0x038, // RO Fault Type DMA Manager
        // [30] dbg_inst - 
        // [16] instr_fetch_err
        // [5] mgr_event_err
        // [4] dmago_err
        // [1] operand_invalid
        // [0] undef_instr
    DMA_FTC0        =  0x040, // RO Fault Type for DMA ch 0
        // [31] lockup_err
        // [30] dbg_inst
        // [18] data_read_err
        // [17] data_write_err
        // [16] instr_fetch_err
        // [12] mfifo_err
        // [7] ch_rdwr_err
        // [6] ch_periph_err
        // [5] ch_event_err
        // [1] operand_invalid
        // [0] undef_instr
    DMA_FTC1        =  0x044, // RO Fault Type for DMA ch 1
    DMA_FTC2        =  0x048, // RO Fault Type for DMA ch 2
    DMA_FTC3        =  0x04c, // RO Fault Type for DMA ch 3
    DMA_FTC4        =  0x050, // RO Fault Type for DMA ch 4
    DMA_FTC5        =  0x054, // RO Fault Type for DMA ch 5
    DMA_FTC6        =  0x058, // RO Fault Type for DMA ch 6
    DMA_FTC7        =  0x05c, // RO Fault Type for DMA ch 7
    
    DMA_CS_BASE            =  0x100, // RO Channel Status for DMA ch 0
        // [21] CNS        0-DMA ch operates in the Secure state, 1- in the Non-secure state
        // [15] dmawfp_periph    0 - DMAWFP executed with the p operand not set, 1- with the p operand set
        // [14] dmawfp_b_ns        0 - DMAWFP executed with the s operand set, 1 - with the b operand set
        // [8:4] wakeup number    0 - DMA channel is waiting for event 0, ..., 31 - waiting for event 31
        // [3:0] channel status
    DMA_CPC_BASE        =  0x104, //[31:0] RO Channel Program Counter for DMA ch 0

    DMA_CH0_REG        =  0x400,
    DMA_CH1_REG        =  0x420,
    DMA_CH2_REG        =  0x440,
    DMA_CH3_REG        =  0x460,
    DMA_CH4_REG        =  0x480,
    DMA_CH5_REG        =  0x4A0,
    DMA_CH6_REG        =  0x4C0,
    DMA_CH7_REG        =  0x4E0,
    
    DMA_DBGSTATUS        =  0xd00, //[0] RO Debug Status
        // [0] dbgstatus    0-Idle, 1-Busy
    DMA_DBGCMD            =  0xd04, //[1:0] WO Debug Command
        // [1:0] dbgcmd        0-execute the instruction that the DBGINST0,1 registers contain
    DMA_DBGINST0        =  0xd08, //[31:0] WO Debug Instruction 0
        // [31:24] Instruction byte 1
        // [23:16] Instruction byte 0
        // [10:8] Channel number (0~7)
        // [0] Debug thread        0-DMA manager thread, 1-DMA channel (when set to 1, [10:8] will be used
    DMA_DBGINST1        =  0xd0c, //[31:0] WO Debug Instruction 1
        // [31:24] Instruction byte 5
        // [23:16] Instruction byte 4
        // [15:8] Instruction byte 3
        // [7:0] Instruction byte 2
        
    DMA_CR0            =  0xe00, // RO Configuration 0
        // [21:17] num_events    0-1 interrupt output,irq[0], ..., 31-32 interrupt output,irq[31:0]
        // [16:12] num_periph_req    0-1 peripheral request i/f, ..., 31-32 peripheral request i/f
        // [6:4] num_chnls    0-1 DMA ch, ..., 7-8 DMA chs
        // [2] mgr_ns_at_rst    0-boot_manager_ns was LOW, 1-HIGH
        // [1] boot_en            0-boot_from_pc was LOW, 1-HIGH
        // [0] periph_req        0-DMAC does not provide a peripheral request i/f, 1- provide it with num_periph_req
    DMA_CR1            =  0xe04, // RO Configuration 1
        // [7:4] num_i-cache_lines        0-1 i-cache line, ..., 15-16 i-cache lines
        // [2:0] i-cache_len            2-4 bytes, 3-8 bytes, 4-16 bytes, 5-32 bytes
    DMA_CR2            =  0xe08, //[31:0] RO Configuration 2
        // [31:0] boot_addr        Provide the value of boot_addr[31:0] when the DMAC exited from reset
    DMA_CR3            =  0xe0c, // RO Configuration 3
        // [N:0] INS        Provide the security state of the interrupt outputs
        //            0-Assign irq[N] to the Secure state
        //            1-Assign irq[N] to the Non-secure state
        //                    boot_irq_ns input pin
    DMA_CR4            =  0xe10, // RO Configuration 4
        // [N:0] PNS        Provide the security state of the peripheral request interface
        //            0-Assign peripheral request interface N to the Secure state
        //            1-Assign peripheral request interface N to the Non-secure state
        //                    boot_periph_ns input pin
    DMA_CRDn        =  0xe14, // RO Configuration Dn
        // [29:20] data_buffer_dep    0-1 line, ..., 1023-1024 lines
        // [19:16] depth of the read queue        0-1 line, ..., 15-16 lines
        // [14:12] read issuing capability        0-1, ..., 7-8
        // [11:8] depth of the write queue        0-1 line, ..., 15-16 lines
        // [6:4] write issuing capability        0-1, ..., 7-8
        // [2:0] data width on AXI bus            2-32bit, 3-64bit, 4-128bit

    // [24] integration config
    // [19:12] designer's ID - 0x41 for ARM
    // [11:0] part number - 0x330 for the DMAC
    DMA_PERI_ID0    =  0xfe0, //[7:0] RO Peripheral ID 0
        // [7:0] part number 0        set to 0x30
    DMA_PERI_ID1    =  0xfe4, //[7:0] RO Peripheral ID 1
        // [7:4] designer 0            set to 0x1
        // [3:0] part number 1        set to 0x3
    DMA_PERI_ID2    =  0xfe8, //[7:0] RO Peripheral ID 2
        // [7:4] revision            0x0 for r0p0
        // [3:0] designer 1            set to 0x4
    DMA_PERI_ID3    =  0xfec, //[0] RO Peripheral ID 3
        // [0] integration config

    DMA_PCELL_ID0    =  0xff0, //[7:0] RO PrimeCell ID 0
        // [7:0] 0x0d
    DMA_PCELL_ID1    =  0xff4, //[7:0] RO PrimeCell ID 1
        // [7:0] 0xf0
    DMA_PCELL_ID2    =  0xff8, //[7:0] RO PrimeCell ID 2
        // [7:0] 0x05
    DMA_PCELL_ID3    =  0xffc //[7:0] RO PrimeCell ID 3
        // [7:0] 0xb1
}DMA_REG;


typedef enum{
    NON_SECURE = 0,
    SECURE =1
}SECURE_MODE;


typedef enum
{
    DMA_SUCCESS,
    DMA_ERROR_NULL_PARAMETER,
    DMA_ERROR_ILLEGAL_PARAMETER,
    DMA_ERROR_NOT_INITIALIZED,
    DMA_ERROR_NOT_IMPLEMENTED,
    DMA_ERROR_XXX
} DMA_ERROR;


typedef struct 
{
    unsigned uSI        :1;  //[0] Transfer size not count
    unsigned uSBSize    :3 ; //[3:1] Source 1 transfer size
    unsigned uSBLength    :4 ; //[7:4] Sourse burst len
    unsigned uSProt        :3 ; //[10:8] Source Protection set 101b=5
    unsigned uSCache    :3 ; //[13:11] Source Cache control
    unsigned uDI         :1 ; //[14] Destination increment
    unsigned uDBSize    :3 ; //[17:15] Destination 1 transfer size
    unsigned uDBLength    :4 ; //[21:18] Destination burst len
    unsigned uDProt        :3 ; //[24:22] Source Protection set 101b=5
    unsigned uDCache    :3 ; //[27:25] Source Cache control    
    unsigned uESSize    :4 ; //[31:28] endian_swap_size
}pl330_dma_control;


typedef struct
{
    BOOL bValid;
    DREQ_SRC DMASrc;
    DMAC_CH CH0_7; //0~7
    DWORD   PeriNum;
    DMA_CH CH0_24; //0~27 (0~24)
    DWORD dwIRQ; //Event 0~31
    DMA_UNIT Controller; //which controller?     
    unsigned int BaseAddr;
    int LLICount;
    unsigned int SrcAddr;
    unsigned int DstAddr;
    ADDRESS_UPDATE SrcUpdate;
    ADDRESS_UPDATE DstUpdate;
    TRANSFER_UNIT SrcUnit;
    TRANSFER_UNIT DstUnit;
    BURST_SIZE SrcBurst;
    BURST_SIZE DstBurst;
    unsigned int TransferCnt;
    unsigned int CodeStAddr;
    PHYSICAL_ADDRESS CodePhysicalStAddr;
    unsigned int CodeOffset;
    FLOW_CONTROL Dir;
    pl330_dma_control CtrlReg_4Byte;
    unsigned int ProtectionBit;    
} DMA_CH_CONTEXT;


/* Parameter list for a DMA operation */
typedef struct  {
    unsigned long            mBaseController;    /* DMA direction */
    unsigned long            mDirection;    /* DMA direction */
    unsigned long            mPeriNum;    /* DMA Peripheral number */
    unsigned long            mSrcAddr;    /* DMA source address */
    unsigned long            mDstAddr;    /* DMA destination address */
    unsigned long            mTrSize;    /* DMA Transfer size */
    pl330_dma_control        mControl;    /* DMA control */
    unsigned long            mIrqEnable;    /* DMA Send IRQ */
    unsigned long            mLoop;        /* DMA Loop  */
    unsigned long            mBwJump;    /* DMA backward relative offset */
    unsigned long            mLastReq;    /* The last DMA Req.  */
    unsigned long            mMemoryClear; /*for Memset Zero*/    
}pl330_DMA_parameters;



DMA_ERROR DMA_initialize_register_address(void *pDMAC0Reg, void *pDMAC1Reg,void *pMDMACReg, void *pCMUCLKReg);

BOOL DMA_request_channel(DMA_CH_CONTEXT *pCtxt, DREQ_SRC DMASrc);
BOOL DMA_release_channel(DMA_CH_CONTEXT *pCtxt);

DMA_ERROR DMA_initialize_channel(DMA_CH_CONTEXT *pCtxt, BOOL bSync);
DMA_ERROR DMA_set_channel_source(DMA_CH_CONTEXT *pCtxt, unsigned int uiSrcAddr, TRANSFER_UNIT Unit, BURST_SIZE Burst, ADDRESS_UPDATE Update);
DMA_ERROR DMA_set_channel_destination(DMA_CH_CONTEXT *pCtxt, unsigned int uiDstAddr, TRANSFER_UNIT Unit, BURST_SIZE Burst, ADDRESS_UPDATE Update);
DMA_ERROR DMA_set_channel_transfer_size(DMA_CH_CONTEXT *pCtxt, unsigned int uiByteCount);
DMA_ERROR DMA_initialize_LLI(DMA_CH_CONTEXT *pCtxt, int iLLICount);

DMA_ERROR DMA_set_LLI_entry_OND(DMA_CH_CONTEXT *pCtxt, int iEntryNumber, LLI_NEXT_ITEM NextItem, unsigned int uiSrcAddr, unsigned int uiDstAddr, unsigned int uiByteCount,OPAction action );
DMA_ERROR DMA_set_LLI_entry(DMA_CH_CONTEXT *pCtxt, int iEntryNumber, LLI_NEXT_ITEM NextItem, unsigned int uiSrcAddr, unsigned int uiDstAddr, unsigned int uiByteCount);

DMA_ERROR DMA_channel_start(DMA_CH_CONTEXT *pCtxt);
DMA_ERROR DMA_channel_stop(DMA_CH_CONTEXT *pCtxt);
DMA_ERROR DMA_memoryclear(DMA_CH_CONTEXT *pCtxt, unsigned int uiDstAddr, unsigned int uiByteCount);

DMA_ERROR DMA_get_current_channel_sourceaddress(DMA_CH_CONTEXT *pCtxt,unsigned int p_uiBaseSrcAddr, 
    unsigned int* p_uiSrcAddr, unsigned int* p_curBufCount);
DMA_ERROR DMA_get_current_channel_destaddress(DMA_CH_CONTEXT *pCtxt,unsigned int p_uiBaseDestAddr,
    unsigned int* p_uiDestAddr, unsigned int* p_curBufCount);
DMA_ERROR DMA_set_codestartaddr(DMA_CH_CONTEXT *pCtxt, PHYSICAL_ADDRESS PhysicalAddr, unsigned int    VirtualAddr);

void DMA_set_interrupt_mask(DMA_CH_CONTEXT *pCtxt);
void DMA_clear_interrupt_mask(DMA_CH_CONTEXT *pCtxt);
void DMA_clear_interrupt_pending(DMA_CH_CONTEXT *pCtxt);
void DMA_check_interrupt_pending(DMA_CH_CONTEXT *pCtxt);

extern int setup_DMA_channel(u8 * mbuf, pl330_DMA_parameters dma_param, int chanNum); 
extern void start_DMA_channel(u32 * mbuf, int chanNum, u8 * mbufAddr, int secureMode);
extern void stop_DMA_channel(u32 * mbuf, int chanNum) ;

#if __cplusplus
}
#endif

#endif    // __S5PV210_DMA_CONTROLLER_H__
