/**************************************************************************//**
 * @file     DrvEDMA.c
 * @version  V3.00
 * @brief    N9H26 series EDMA driver source file
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include "wblib.h"
#include "DrvEDMA.h"

static PFN_DRVEDMA_CALLBACK  g_pfnEDMACallback[MAX_CHANNEL_NUM+1][4]  = {
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},	
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0},
								{0,0,0,0}
};								


#define	MAX_GS_TRANSFER_SIZE	32*1024

void DrvEDMA_EnableScatterGather(
    E_DRVEDMA_CHANNEL_INDEX eChannel
);

  
void DrvEDMA_DisableScatterGather(
    E_DRVEDMA_CHANNEL_INDEX eChannel
);

UINT32  
DrvEDMA_Open(void)
{
	// 1.Check I/O pins. If I/O pins are used by other IPs, return error code.
	// 2.Enable IP¡¦s clock --> Enable Channel clock in DrvEDMA_SetCHOperation( ) function
	// 3.Reset IP
	// 4.Configure IP according to inputted arguments.
	// 5.Enable IP I/O pins
	// 6.Return 0 to present success
	return E_SUCCESS;    
}

void DrvEDMA_Close(void)
{
    UINT32 u32Mask;
    
	// 1.Disable IP I/O pins
	// 2.Disable IP¡¦s clock --> Disable Channel Clock in DrvEDMA_SetCHOperation( ) function
	u32Mask = EDMA0_CKE | EDMA1_CKE | EDMA2_CKE | EDMA3_CKE | EDMA4_CKE;
	outp32(REG_AHBCLK,inp32(REG_AHBCLK) & ~u32Mask);

	u32Mask = EDMA5_CKE | EDMA20_CKE | EDMA21_CKE | EDMA22_CKE | EDMA23_CKE | EDMA24_CKE;
	outp32(REG_AHBCLK2,inp32(REG_AHBCLK2) & ~u32Mask);
	
}

// Get Channel Enable/Disable status
ERRCODE  
DrvEDMA_IsCHBusy(
	E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;    
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    
    if (inp32(u32SFR) &  TRIG_EN)
        return TRUE;
    else
        return FALSE;    
}

// Set Channel Enable/Disable & Enable Channel Clock
void DrvEDMA_EnableCH(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_OPERATION eOP
)
{
	UINT32 u32SFR,u32Mask;

	if (eChannel <= eDRVEDMA_CHANNEL_4)
	{
		u32Mask = 0x00000400 << eChannel;
		u32SFR = REG_VDMA_CSR + eChannel * 0x100;

		if (eOP == eDRVEDMA_DISABLE)
		{
			outp32(u32SFR, inp32(u32SFR) & ~EDMACEN);     
			outp32(REG_AHBCLK,inp32(REG_AHBCLK) & ~u32Mask);					// Disable Channel Clock    			
		}    	
		else 
		{
			outp32(REG_AHBCLK,inp32(REG_AHBCLK) | u32Mask);						// Enable Channel Clock    	
			outp32(u32SFR, inp32(u32SFR) | EDMACEN); 	   	
		}    	
	}
	else
	{
		if(eChannel == eDRVEDMA_CHANNEL_5)
			u32Mask = 0x01;
		else
			u32Mask = 0x800 << (eChannel % eDRVEDMA_CHANNEL_8);
		
		u32SFR = REG_VDMA_CSR + eChannel * 0x100;

		if (eOP == eDRVEDMA_DISABLE)
		{
			outp32(u32SFR, inp32(u32SFR) & ~EDMACEN);
			outp32(REG_AHBCLK2,inp32(REG_AHBCLK2) & ~u32Mask);					// Disable Channel Clock    			     
		}    	
		else 
		{
			outp32(REG_AHBCLK2,inp32(REG_AHBCLK2) | u32Mask);						// Enable Channel Clock    	
			outp32(u32SFR, inp32(u32SFR) | EDMACEN); 	   	
		}  
	}
	
}


// Get Channel Enable/Disable status
ERRCODE  
DrvEDMA_IsEnabledCH(
	E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;    
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    
    return inp32(u32SFR) & EDMACEN;
}

// Set Source/Destination Address and Direction and Transfer Length for Channelx
ERRCODE  
DrvEDMA_SetTransferSetting(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    S_DRVEDMA_CH_ADDR_SETTING* psSrcAddr, 
    S_DRVEDMA_CH_ADDR_SETTING* psDestAddr, 
    UINT32 u32TransferLength
)
{
    UINT32 u32SFR, u32Value; 
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;    
    
    DrvEDMA_DisableScatterGather(eChannel);
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    u32Value = inp32(u32SFR);        
        
    outp32(REG_VDMA_SAR + eChannel * 0x100, psSrcAddr->u32Addr);   
    
    u32Value = (u32Value & ~SAD_SEL) | (psSrcAddr->eAddrDirection << SOURCE_DIRECTION_BIT);
    
    outp32(REG_VDMA_DAR + eChannel * 0x100, psDestAddr->u32Addr);
    u32Value = (u32Value & ~DAD_SEL) | (psDestAddr->eAddrDirection << DESTINATION_DIRECTION_BIT);
    outp32(u32SFR,u32Value);

    if (u32TransferLength > MAX_TRANSFER_BYTE_COUNT)
        return E_DRVEDMA_FALSE_INPUT;
        
    outp32(REG_VDMA_BCR + eChannel * 0x100,u32TransferLength);
    
    return E_SUCCESS;     
}

// Get Source/Destination Address and Direction from Channelx
ERRCODE    
DrvEDMA_GetTransferSetting(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_TARGET eTarget, 
    UINT32* pu32Addr, 
    E_DRVEDMA_DIRECTION_SELECT* peDirection
)
{
    UINT32 u32SFR, u32Value;

    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;     
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    
    if ((eTarget != eDRVEDMA_TARGET_SOURCE) && (eTarget != eDRVEDMA_TARGET_DESTINATION))
        return E_DRVEDMA_FALSE_INPUT;
    
    u32Value = inp32(u32SFR);
    
    if (eTarget == eDRVEDMA_TARGET_SOURCE)
    {
        *pu32Addr = inp32(REG_VDMA_SAR + eChannel * 0x100);
        *peDirection = (E_DRVEDMA_DIRECTION_SELECT)((u32Value & SAD_SEL) >> SOURCE_DIRECTION_BIT);
    }
    else
    {
        *pu32Addr = inp32(REG_VDMA_DAR + eChannel * 0x100);
        *peDirection = (E_DRVEDMA_DIRECTION_SELECT)((u32Value & DAD_SEL) >> DESTINATION_DIRECTION_BIT);        
    }
    
    return E_SUCCESS;     
}

// Get Transfer Length from Channelx
ERRCODE    
DrvEDMA_GetTransferLength(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    UINT32* pu32TransferLength
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT; 
            
    u32SFR = REG_VDMA_BCR + eChannel * 0x100;
    
    *pu32TransferLength = inp32(u32SFR);
    
    return E_SUCCESS;       
}


// Set APB Transfer Width for Channelx
ERRCODE  
DrvEDMA_SetAPBTransferWidth(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_TRANSFER_WIDTH eTransferWidth
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return E_DRVEDMA_FALSE_INPUT; 
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    outp32(u32SFR,(inp32(u32SFR) & ~APB_TWS) | (eTransferWidth << TRANSFER_WIDTH_BIT));
        
    return E_SUCCESS;     
}

// Get Transfer Width from Channelx
ERRCODE    
DrvEDMA_GetAPBTransferWidth(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_TRANSFER_WIDTH* peTransferWidth
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return E_DRVEDMA_FALSE_INPUT; 
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    *peTransferWidth = (E_DRVEDMA_TRANSFER_WIDTH)((inp32(u32SFR) & APB_TWS) >> TRANSFER_WIDTH_BIT);    
    
    return E_SUCCESS;    
}

ERRCODE  
DrvEDMA_ClearCHForAPBDevice(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
	UINT32 u32Mask;
	if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return E_DRVEDMA_FALSE_INPUT; 
		
	if(eChannel <= eDRVEDMA_CHANNEL_4)
	{
		u32Mask = 0x00070000 << ((eChannel-1)*4);
		u32Mask = u32Mask |(0x00000007 << ((eChannel-1)*4));
		outp32(REG_ED0SSR, inp32(REG_ED0SSR) | u32Mask);
	}
	else
	{		
		u32Mask = 0x00070000 << ((eChannel-9)*4);
		u32Mask = u32Mask |(0x00000007 << ((eChannel-9)*4));
		outp32(REG_ED1SSR, inp32(REG_ED1SSR) | u32Mask);
	}

	return E_SUCCESS; 
}

// Select EDMA channel for APB Device
ERRCODE  
DrvEDMA_SetCHForAPBDevice(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_APB_DEVICE eDevice,
    E_DRVEDMA_APB_RW eRWAPB    
)
{
    UINT32 u32Value,u32Mask,i,u32OrMask; 
    UINT32 u32SFR;       
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return E_DRVEDMA_FALSE_INPUT; 
            
    if ((eRWAPB == eDRVEDMA_WRITE_APB) && (eDevice == eDRVEDMA_ADC))
        return E_DRVEDMA_FALSE_INPUT;
            	
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;        	          

	if(eChannel <= eDRVEDMA_CHANNEL_4)
	{
		// Let Tx and Rx does not use the same channel         	
	    if (eRWAPB == eDRVEDMA_WRITE_APB)
	    {
		    outp32(u32SFR,(inp32(u32SFR) & ~MODE_SEL) | (eDRVEDMA_MEMORY_TO_DEVICE << MODE_SELECT_BIT));    
	        u32Mask = 0x000F0000 << ((eChannel-1)*4);
	        u32OrMask = 0x0007 << ((eChannel-1)*4);
		}        
	    else
	    {
		    outp32(u32SFR,(inp32(u32SFR) & ~MODE_SEL) | (eDRVEDMA_DEVICE_TO_MEMORY << MODE_SELECT_BIT));      
	        u32Mask = 0x0000000F << ((eChannel-1)*4);
	        u32OrMask = 0x00070000 << ((eChannel-1)*4);        
		} 
		
	    u32Value = inp32(REG_ED0SSR) & ~u32Mask;
	    
	    if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
		    u32Value &= ~u32OrMask;    
	    else
		    u32Value |= u32OrMask;

		// let Tx or Rx does not use two channel concurrently    
	    if (eRWAPB == eDRVEDMA_WRITE_APB)
	    {
		    u32Mask = 0x070000;
	       	for(i=1;i<=4;i++)
	       	{
	       		if (i != eChannel)
	       		{
		       		if (((u32Value & u32Mask)>>((i-1)*4+16)) == eDevice)
		       		{
		       			u32Value |= u32Mask;
		       			
				   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
				   			u32Value |=  0x07 << ((i-1)*4);	       			
					}	       			
				}       			
	       		u32Mask <<= 4;	
			}        
			

	   		u32Value |=  eDevice << ((eChannel-1)*4 + 16);
	   		
	   		// TX and RX use same channel for SPIM0 & 1 
	   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
	   			u32Value |=  eDevice << ((eChannel-1)*4);
	    }
	    else
	    {
		    u32Mask = 0x07;
	       	for(i=1;i<=4;i++)
	       	{
	       		if (i != eChannel)
	       		{
		      		if (((u32Value & u32Mask)>>(i-1)*4) == eDevice)
		      		{
		       			u32Value |= u32Mask;
		       			
				   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
				   			u32Value |=  0x070000 << ((i-1)*4);	  	       			
					}			   			
	       		}	
	       		u32Mask <<= 4;	
			}  
			    
	    	u32Value |=  eDevice << ((eChannel-1)*4);    
	    	
	    	// TX and RX use same channel for SPIM0 & 1 
	   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
	   			u32Value |=  eDevice << ((eChannel-1)*4+16);    	
	    }

	    outp32(REG_ED0SSR,u32Value);
	}
	else
	{
		// Let Tx and Rx does not use the same channel         	
	    if (eRWAPB == eDRVEDMA_WRITE_APB)
	    {
		    outp32(u32SFR,(inp32(u32SFR) & ~MODE_SEL) | (eDRVEDMA_MEMORY_TO_DEVICE << MODE_SELECT_BIT));    
	        u32Mask = 0x000F0000 << ((eChannel-9)*4);
	        u32OrMask = 0x0007 << ((eChannel-9)*4);
		}        
	    else
	    {
		    outp32(u32SFR,(inp32(u32SFR) & ~MODE_SEL) | (eDRVEDMA_DEVICE_TO_MEMORY << MODE_SELECT_BIT));      
	        u32Mask = 0x0000000F << ((eChannel-9)*4);
	        u32OrMask = 0x00070000 << ((eChannel-9)*4);        
		} 
	
	    u32Value = inp32(REG_ED1SSR) & ~u32Mask;
	    
	    if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
		    u32Value &= ~u32OrMask;    
	    else
		    u32Value |= u32OrMask;

		// let Tx or Rx does not use two channel concurrently    
	    if (eRWAPB == eDRVEDMA_WRITE_APB)
	    {
		    u32Mask = 0x070000;
	       	for(i=9;i<=12;i++)
	       	{
	       		if (i != eChannel)
	       		{
		       		if (((u32Value & u32Mask)>>((i-9)*4+16)) == eDevice)
		       		{
		       			u32Value |= u32Mask;
		       			
				   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
				   			u32Value |=  0x07 << ((i-9)*4);	       			
					}	       			
				}       			
	       		u32Mask <<= 4;	
			}        
			

	   		u32Value |=  eDevice << ((eChannel-9)*4 + 16);
	   		
	   		// TX and RX use same channel for SPIM0 & 1 
	   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
	   			u32Value |=  eDevice << ((eChannel-9)*4);
	    }
	    else
	    {
		    u32Mask = 0x07;
	       	for(i=9;i<=12;i++)
	       	{
	       		if (i != eChannel)
	       		{
		      		if (((u32Value & u32Mask)>>(i-9)*4) == eDevice)
		      		{
		       			u32Value |= u32Mask;
		       			
				   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
				   			u32Value |=  0x070000 << ((i-9)*4);	  	       			
					}			   			
	       		}	
	       		u32Mask <<= 4;	
			}  
			    
	    	u32Value |=  eDevice << ((eChannel-9)*4);    
	    	
	    	// TX and RX use same channel for SPIM0 & 1 
	   		if ((eDevice == eDRVEDMA_SPIMS0) || (eDevice == eDRVEDMA_SPIMS1))
	   			u32Value |=  eDevice << ((eChannel-9)*4+16);    	
	    }

	    outp32(REG_ED1SSR,u32Value);
	}
        
    return E_SUCCESS;     
}

// Get EDMA channel for APB Device
E_DRVEDMA_CHANNEL_INDEX  
DrvEDMA_GetCHForAPBDevice(
    E_DRVEDMA_APB_DEVICE eDevice,
    E_DRVEDMA_APB_RW eRWAPB    
)
{
	UINT32 u32Value,i;
	
    if ((eDevice < eDRVEDMA_SPIMS0) || (eDevice > eDRVEDMA_RS_CODEC))
    	return (E_DRVEDMA_CHANNEL_INDEX)E_DRVEDMA_FALSE_INPUT;
    	
	if (eRWAPB == eDRVEDMA_WRITE_APB)
	{
		u32Value = inp32(REG_ED0SSR)>>16;
	}
	else
	{
		u32Value = inp32(REG_ED0SSR);
	}
	
   	for(i=1;i<=4;i++)
   	{
   		if (((u32Value >> (i-1)*4) & 0x07) == eDevice)
   			return (E_DRVEDMA_CHANNEL_INDEX)i;
	} 

	if (eRWAPB == eDRVEDMA_WRITE_APB)
	{
		u32Value = inp32(REG_ED1SSR)>>16;
	}
	else
	{
		u32Value = inp32(REG_ED1SSR);
	}
	
   	for(i=9;i<=12;i++)
   	{
   		if (((u32Value >> (i-9)*4) & 0x07) == eDevice)
   			return (E_DRVEDMA_CHANNEL_INDEX)i;
	} 
	
   	return (E_DRVEDMA_CHANNEL_INDEX)0;  
}

// Set Wrap Around Transfer Byte count interrupt Select for Channelx
ERRCODE  
DrvEDMA_SetWrapIntType(
    E_DRVEDMA_CHANNEL_INDEX eChannel,
    E_DRVEDMA_WRAPAROUND_SELECT eType
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return E_DRVEDMA_FALSE_INPUT;
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    
    if (eType > 0x0F)  
        return E_DRVEDMA_FALSE_INPUT;    
        
    outp32(u32SFR,(inp32(u32SFR) & ~WAR_BCR_SEL) | (eType<<12));    
    
    return E_SUCCESS;  
}

// Get Wrap Around Transfer Byte count interrupt Select from Channelx
E_DRVEDMA_WRAPAROUND_SELECT  
DrvEDMA_GetWrapIntType(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel ==0) || (eChannel ==5) || (eChannel >= 6 && eChannel <=8))
        return (E_DRVEDMA_WRAPAROUND_SELECT)E_DRVEDMA_FALSE_INPUT;
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;  
    
    return (E_DRVEDMA_WRAPAROUND_SELECT)((inp32(u32SFR) & WAR_BCR_SEL )>> 12);  
}

// Software reset Channelx
ERRCODE  
DrvEDMA_CHSoftwareReset(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;  
    
    outp32(u32SFR, inp32(u32SFR) | SW_RST);  
    
    return E_SUCCESS;     
}

// Enable EDMA data read or write Transfer
ERRCODE  
DrvEDMA_CHEnablelTransfer(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;
            
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;  
    
    outp32(u32SFR, inp32(u32SFR) | TRIG_EN | EDMACEN);  
    
    return E_SUCCESS;      
}

// Get Current Source Address from Channelx
UINT32  
DrvEDMA_GetCurrentSourceAddr(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_CSAR + eChannel * 0x100;   
    
    return inp32(u32SFR);      
}

// Get Current Destination Address from Channelx
UINT32  
DrvEDMA_GetCurrentDestAddr(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_CDAR + eChannel * 0x100;   
    
    return inp32(u32SFR);      
}

// Get Current Transfer Count from Channelx
UINT32  
DrvEDMA_GetCurrentTransferCount(
    E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_CBCR + eChannel * 0x100;   
    
    return inp32(u32SFR);   
}

// Enable Interrupt for Channelx
ERRCODE  
DrvEDMA_EnableInt(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_INT_ENABLE eIntSource
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_IER + eChannel * 0x100;        
    
    if ((eIntSource <1) || (eIntSource >15)) 
        return E_DRVEDMA_FALSE_INPUT;

    outp32(u32SFR, inp32(u32SFR) | eIntSource);  
    
    return E_SUCCESS;      
}

// Disable Interrupt for Channelx
void DrvEDMA_DisableInt(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_INT_ENABLE eIntSource
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_IER + eChannel * 0x100;        
    
    outp32(u32SFR, inp32(u32SFR) & ~eIntSource);  
              
}

// Check if the specified interrupt source is enabled in Channelx
UINT32  
DrvEDMA_IsIntEnabled(
    E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_INT_ENABLE eIntSource    
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_ISR + eChannel * 0x100;    
    
    switch(eIntSource)
    {
    	case eDRVEDMA_TABORT:
		    return inp32(u32SFR) & EDMATABORT_IE;     	
//    		break;
    	case eDRVEDMA_BLKD:
		    return inp32(u32SFR) & BLKD_IE;     	
//    		break;
    	case eDRVEDMA_WAR:
		    return inp32(u32SFR) & WAR_IE;     	
//    		break;
    	case eDRVEDMA_SG:
		    return inp32(u32SFR) & SG_IEN;     	
//    		break;    		
		default :
	    	return E_DRVEDMA_FALSE_INPUT;		    		
	}    
}

// Clear Interrupt Status for Channelx
void DrvEDMA_ClearInt(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_INT_FLAG eIntFlag
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_ISR + eChannel * 0x100;    
    
    outp32(u32SFR, eIntFlag);
}

BOOL
DrvEDMA_PollInt(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_INT_FLAG eIntFlag
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_ISR + eChannel * 0x100;    
    
    return inp32(u32SFR) & eIntFlag;
}

// Set Color Format Transform for Channel0,5,8
ERRCODE  
DrvEDMA_SetColorTransformFormat(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_COLOR_FORMAT eSourceFormat,
	E_DRVEDMA_COLOR_FORMAT eDestFormat
)
{ 
	UINT32 u32SFR;

	 if ((eChannel > MAX_CHANNEL_NUM) || (eChannel != eDRVEDMA_CHANNEL_0 && eChannel != eDRVEDMA_CHANNEL_5 && eChannel != eDRVEDMA_CHANNEL_8))
        	return E_DRVEDMA_FALSE_INPUT;
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
	
	outp32(u32SFR, (inp32(u32SFR) & ~(SOUR_FORMAT | DEST_FORMAT)) | eSourceFormat<<24 | eDestFormat<<16);
	return E_SUCCESS;  
}

// Get Color Format Transform from Channel0,5,8
void DrvEDMA_GetColorTransformFormat(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_COLOR_FORMAT* peSourceFormat,
	E_DRVEDMA_COLOR_FORMAT* peDestFormat
)
{
	UINT32 u32SFR;	 
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
		
	*peSourceFormat = (E_DRVEDMA_COLOR_FORMAT)((inp32(u32SFR) & SOUR_FORMAT) >> 24);
	*peDestFormat = (E_DRVEDMA_COLOR_FORMAT)((inp32(u32SFR) & DEST_FORMAT) >> 16);	
}

ERRCODE  
DrvEDMA_SetColorTransformOperation(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_OPERATION eColorSpaceTran,
	E_DRVEDMA_OPERATION eStrideMode
)
{ 
	UINT32 u32SFR;

	 if ((eChannel > MAX_CHANNEL_NUM) || (eChannel != eDRVEDMA_CHANNEL_0 && eChannel != eDRVEDMA_CHANNEL_5 && eChannel != eDRVEDMA_CHANNEL_8))
        	return E_DRVEDMA_FALSE_INPUT;
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
		
	outp32(u32SFR, (inp32(u32SFR) & ~(COL_TRA_EN | STRIDE_EN)) | eColorSpaceTran<<1 | eStrideMode);
	return E_SUCCESS;  
}

void DrvEDMA_GetColorTransformOperation(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_OPERATION* peColorSpaceTran,
	E_DRVEDMA_OPERATION* peStrideMode
)
{ 
	UINT32 u32SFR;	 
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
	
	*peColorSpaceTran = (E_DRVEDMA_OPERATION)((inp32(u32SFR) & COL_TRA_EN) >> 1);
	*peStrideMode = (E_DRVEDMA_OPERATION)(inp32(u32SFR) & STRIDE_EN );	
}



// Set Source Stride Transfer Byte Count & Offset Byte Length
// Only Channel0 support this function
ERRCODE  
DrvEDMA_SetSourceStride(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
    UINT32 u32StrideByteCount,
    UINT32 u32OffsetByteLength
)
{
	UINT32 u32SFR;

	 if ((eChannel > MAX_CHANNEL_NUM) || (eChannel != eDRVEDMA_CHANNEL_0 && eChannel != eDRVEDMA_CHANNEL_5 && eChannel != eDRVEDMA_CHANNEL_8))
        	return E_DRVEDMA_FALSE_INPUT;
    
    	u32SFR = REG_VDMA_SASOCR + eChannel * 0x100;
    
    outp32(u32SFR,(u32StrideByteCount<<16) |u32OffsetByteLength);   
    
    return E_SUCCESS;     
}

// Get Source/Destination Stride Transfer Byte Count & Offset Byte Length
void DrvEDMA_GetSourceStride(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
    UINT32* pu32StrideByteCount,
    UINT32* pu32OffsetByteLength
)
{
	UINT32 u32SFR;	
    
    	u32SFR = REG_VDMA_SASOCR + eChannel * 0x100;
     
    *pu32StrideByteCount = (inp32(u32SFR) & STBC) >> 16;   
    *pu32OffsetByteLength = (inp32(u32SFR) & SASTOBL);     
}

// Set Destination Stride Transfer Byte Count & Offset Byte Length
// Only Channel0 support this function
ERRCODE  
DrvEDMA_SetDestinationStrideOffset(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
    UINT32 u32OffsetByteLength
)
{
	UINT32 u32SFR;

	 if ((eChannel > MAX_CHANNEL_NUM) || (eChannel != eDRVEDMA_CHANNEL_0 && eChannel != eDRVEDMA_CHANNEL_5 && eChannel != eDRVEDMA_CHANNEL_8))
        	return E_DRVEDMA_FALSE_INPUT;
    
    	u32SFR = REG_VDMA_DASOCR + eChannel * 0x100;
    
    outp32(u32SFR,u32OffsetByteLength & DASTOBL);   
    
    return E_SUCCESS;     
}

// Get Destination Stride Offset Byte Length
void DrvEDMA_GetDestinationStrideOffset(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
    UINT32* pu32OffsetByteLength
)
{
     UINT32 u32SFR;	
    
    	u32SFR = REG_VDMA_DASOCR + eChannel * 0x100;
		
    *pu32OffsetByteLength = (inp32(u32SFR) & DASTOBL);     
}

// Set Channel0,5 Clamping function 
ERRCODE
DrvEDMA_SetClamping(
	E_DRVEDMA_CHANNEL_INDEX eChannel,
	E_DRVEDMA_OPERATION eOP
)
{
	UINT32 u32SFR;

	 if ((eChannel > MAX_CHANNEL_NUM) || (eChannel != eDRVEDMA_CHANNEL_0 && eChannel != eDRVEDMA_CHANNEL_5 && eChannel != eDRVEDMA_CHANNEL_8))
        	return E_DRVEDMA_FALSE_INPUT;
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
    
    if (eOP == eDRVEDMA_DISABLE)
    	outp32(u32SFR, inp32(u32SFR) & ~CLAMPING_EN);     
	else 
    	outp32(u32SFR, inp32(u32SFR) | CLAMPING_EN); 	 

	return E_SUCCESS; 
}

// Get Channel0,5 Clamping status
E_DRVEDMA_OPERATION  
DrvEDMA_GetClamping(
E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;	 
    
    	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
		
    return (E_DRVEDMA_OPERATION)((inp32(u32SFR) & CLAMPING_EN) >> 7);
}

// Get Channel 1 ~ 4 Internal Buffer Pointer
UINT32  
DrvEDMA_GetInternalBufPointer(
	E_DRVEDMA_CHANNEL_INDEX eChannel
)
{
    UINT32 u32SFR;
    
    //if ((eChannel > MAX_CHANNEL_NUM) || (eChannel == 0))
    //    return E_DRVEDMA_FALSE_INPUT;    
    
    u32SFR = REG_PDMA_POINT1 + (eChannel-1) * 0x100; 
    
    return (inp32(u32SFR) & PDMA_POINT);
}

// Get Shared Buffer Content from Channelx
UINT32  
DrvEDMA_GetSharedBufData(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    UINT32 u32BufIndex
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_EDMA_SBUF0_C0 + eChannel * 0x100 + u32BufIndex * 4;
    
    return inp32(u32SFR);
    
    
}

// EDMA ISR
void DrvEDMA_ISR(void)
{
    UINT32 u32IntStatus;
    UINT32 u32WraparoundStatus;
    
    if (inp32(REG_VDMA_ISR) & INTR)
    {
    	if (inp32(REG_VDMA_ISR) & INTR0)
    	{
	    	u32IntStatus = inp32(REG_VDMA_ISR) & inp32(REG_VDMA_IER);
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_VDMA_ISR,EDMATABORT_IF);
    			if (g_pfnEDMACallback[0][0] != 0)
	    			(*g_pfnEDMACallback[0][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_VDMA_ISR,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[0][1] != 0)
		    			(*g_pfnEDMACallback[0][1])(0);	    				    			
				}
				else if (u32IntStatus & EDMASG_IF)
				{
				outp32(REG_VDMA_ISR,EDMASG_IF);	
	    			if (g_pfnEDMACallback[0][3] != 0)
		    			(*g_pfnEDMACallback[0][3])(0);	    							
				}
					    			
    		}
    	}
    	else if (inp32(REG_VDMA_ISR) & INTR1)
    	{
    		if (inp32(REG_PDMA_IER1) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR1) & (inp32(REG_PDMA_IER1) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR1) & inp32(REG_PDMA_IER1);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR1,EDMATABORT_IF);
    			if (g_pfnEDMACallback[1][0] != 0)    		
	    			(*g_pfnEDMACallback[1][0])(0);    			
			}    			
    		else
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR1,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[1][1] != 0)    			
		    			(*g_pfnEDMACallback[1][1])(0);	    				    			
				}	   
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR1,EDMASG_IF);
	    			if (g_pfnEDMACallback[1][3] != 0)
		    			(*g_pfnEDMACallback[1][3])(0);	    				    		
	    		}				 			
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR1) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR1,u32WraparoundStatus);				
		    			if (g_pfnEDMACallback[1][2] != 0)		    						
			    			(*g_pfnEDMACallback[1][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}    	
    	}
    	else if (inp32(REG_VDMA_ISR) & INTR2)
    	{
    		if (inp32(REG_PDMA_IER2) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR2) & (inp32(REG_PDMA_IER2) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR2) & inp32(REG_PDMA_IER2);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR2,EDMATABORT_IF);
    			if (g_pfnEDMACallback[2][0] != 0)    		
	    			(*g_pfnEDMACallback[2][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR2,EDMABLKD_IF);	
	    			if (g_pfnEDMACallback[2][1] != 0)    			
		    			(*g_pfnEDMACallback[2][1])(0);	    			    			
				}	
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR2,EDMASG_IF);
	    			if (g_pfnEDMACallback[2][3] != 0)
		    			(*g_pfnEDMACallback[2][3])(0);	    				    		
	    		}					    			
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR2) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR2,u32WraparoundStatus);		
		    			if (g_pfnEDMACallback[2][2] != 0)		    						
			    			(*g_pfnEDMACallback[2][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}     	
    	}
    	else if (inp32(REG_VDMA_ISR) & INTR3)
    	{
    		if (inp32(REG_PDMA_IER3) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR3) & (inp32(REG_PDMA_IER3) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR3) & inp32(REG_PDMA_IER3);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR3,EDMATABORT_IF);
    			if (g_pfnEDMACallback[3][0] != 0)    		
	    			(*g_pfnEDMACallback[3][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR3,EDMABLKD_IF);	
	    			if (g_pfnEDMACallback[3][1] != 0)    			
		    			(*g_pfnEDMACallback[3][1])(0);	    			    			
				}	    
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR3,EDMASG_IF);
	    			if (g_pfnEDMACallback[3][3] != 0)
		    			(*g_pfnEDMACallback[3][3])(0);	    				    		
	    		}						
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR3) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR3,u32WraparoundStatus);				
		    			if (g_pfnEDMACallback[3][2] != 0)		    						
			    			(*g_pfnEDMACallback[3][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}     	
    	}
    	else if (inp32(REG_VDMA_ISR) & INTR4)
    	{
    		if (inp32(REG_PDMA_IER4) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR4) & (inp32(REG_PDMA_IER4) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR4) & inp32(REG_PDMA_IER4);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR4,EDMATABORT_IF);
    			if (g_pfnEDMACallback[4][0] != 0)    		
	    			(*g_pfnEDMACallback[4][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR4,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[4][1] != 0)    			
		    			(*g_pfnEDMACallback[4][1])(0);	    				    			
				}	
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR4,EDMASG_IF);
	    			if (g_pfnEDMACallback[4][3] != 0)
		    			(*g_pfnEDMACallback[4][3])(0);	    				    		
	    		}						
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR4) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR4,u32WraparoundStatus);					
		    			if (g_pfnEDMACallback[4][2] != 0)		    						
			    			(*g_pfnEDMACallback[4][2])(u32WraparoundStatus); 		    				    			   			
	    			}
				}	    			
    		}     	
    	}
	else 
    	{
	    	u32IntStatus = inp32(REG_VDMA_ISR5) & inp32(REG_VDMA_IER5);
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_VDMA_ISR5,EDMATABORT_IF);
    			if (g_pfnEDMACallback[5][0] != 0)
	    			(*g_pfnEDMACallback[5][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_VDMA_ISR5,EDMABLKD_IF);	
	    			if (g_pfnEDMACallback[5][1] != 0)
		    			(*g_pfnEDMACallback[5][1])(0);	    			    			
				}
				else if (u32IntStatus & EDMASG_IF)
				{
				outp32(REG_VDMA_ISR5,EDMASG_IF);
	    			if (g_pfnEDMACallback[5][3] != 0)
		    			(*g_pfnEDMACallback[5][3])(0);	    								
				}
					    			
    		}
    	}	
	}
}

void DrvEDMA1_ISR(void)
{
    UINT32 u32IntStatus;
    UINT32 u32WraparoundStatus;
    
    if (inp32(REG_VDMA_ISR8) & INTR)
    {    
    	if (inp32(REG_VDMA_ISR8) & INTR0)
    	{
	    	u32IntStatus = inp32(REG_VDMA_ISR8) & inp32(REG_VDMA_IER8);
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_VDMA_ISR8,EDMATABORT_IF);
    			if (g_pfnEDMACallback[8][0] != 0)
	    			(*g_pfnEDMACallback[8][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_VDMA_ISR8,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[8][1] != 0)
		    			(*g_pfnEDMACallback[8][1])(0);	    				    			
				}
				else if (u32IntStatus & EDMASG_IF)
				{
				outp32(REG_VDMA_ISR8,EDMASG_IF);	
	    			if (g_pfnEDMACallback[8][3] != 0)
		    			(*g_pfnEDMACallback[8][3])(0);	    							
				}
					    			
    		}
    	}
    	else if (inp32(REG_VDMA_ISR8) & INTR1)
    	{
    		if (inp32(REG_PDMA_IER9) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR9) & (inp32(REG_PDMA_IER9) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR9) & inp32(REG_PDMA_IER9);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR9,EDMATABORT_IF);
    			if (g_pfnEDMACallback[9][0] != 0)    		
	    			(*g_pfnEDMACallback[9][0])(0);    			
			}    			
    		else
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR9,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[9][1] != 0)    			
		    			(*g_pfnEDMACallback[9][1])(0);	    				    			
				}	   
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR9,EDMASG_IF);
	    			if (g_pfnEDMACallback[9][3] != 0)
		    			(*g_pfnEDMACallback[9][3])(0);	    				    		
	    		}				 			
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR9) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR9,u32WraparoundStatus);				
		    			if (g_pfnEDMACallback[9][2] != 0)		    						
			    			(*g_pfnEDMACallback[9][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}    	
    	}
    	else if (inp32(REG_VDMA_ISR8) & INTR2)
    	{
    		if (inp32(REG_PDMA_IER10) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR10) & (inp32(REG_PDMA_IER10) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR10) & inp32(REG_PDMA_IER10);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR10,EDMATABORT_IF);
    			if (g_pfnEDMACallback[10][0] != 0)    		
	    			(*g_pfnEDMACallback[10][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR10,EDMABLKD_IF);	
	    			if (g_pfnEDMACallback[10][1] != 0)    			
		    			(*g_pfnEDMACallback[10][1])(0);	    			    			
				}	
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR10,EDMASG_IF);
	    			if (g_pfnEDMACallback[10][3] != 0)
		    			(*g_pfnEDMACallback[10][3])(0);	    				    		
	    		}					    			
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR10) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR10,u32WraparoundStatus);		
		    			if (g_pfnEDMACallback[10][2] != 0)		    						
			    			(*g_pfnEDMACallback[10][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}     	
    	}
    	else if (inp32(REG_VDMA_ISR8) & INTR3)
    	{
    		if (inp32(REG_PDMA_IER11) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR11) & (inp32(REG_PDMA_IER11) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR11) & inp32(REG_PDMA_IER11);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR11,EDMATABORT_IF);
    			if (g_pfnEDMACallback[11][0] != 0)    		
	    			(*g_pfnEDMACallback[11][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR11,EDMABLKD_IF);	
	    			if (g_pfnEDMACallback[11][1] != 0)    			
		    			(*g_pfnEDMACallback[11][1])(0);	    			    			
				}	    
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR11,EDMASG_IF);
	    			if (g_pfnEDMACallback[11][3] != 0)
		    			(*g_pfnEDMACallback[11][3])(0);	    				    		
	    		}						
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR11) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR11,u32WraparoundStatus);				
		    			if (g_pfnEDMACallback[11][2] != 0)		    						
			    			(*g_pfnEDMACallback[11][2])(u32WraparoundStatus); 		    					    			   			
	    			}
				}	    			
    		}     	
    	}
    	else if (inp32(REG_VDMA_ISR8) & INTR4)
    	{
    		if (inp32(REG_PDMA_IER12) & WAR_IE)
	    		u32IntStatus = inp32(REG_PDMA_ISR12) & (inp32(REG_PDMA_IER12) | 0x0F00);
	    	else
	    		u32IntStatus = inp32(REG_PDMA_ISR12) & inp32(REG_PDMA_IER12);	    	
	    	
    		if (u32IntStatus & EDMATABORT_IF)
    		{
    			outp32(REG_PDMA_ISR12,EDMATABORT_IF);
    			if (g_pfnEDMACallback[12][0] != 0)    		
	    			(*g_pfnEDMACallback[12][0])(0);    			
			}    			
    		else 
    		{
    			if (u32IntStatus & EDMABLKD_IF)
    			{
    				outp32(REG_PDMA_ISR12,EDMABLKD_IF);
	    			if (g_pfnEDMACallback[12][1] != 0)    			
		    			(*g_pfnEDMACallback[12][1])(0);	    				    			
				}	
	    		else if (u32IntStatus & EDMASG_IF)
	    		{
	    			outp32(REG_PDMA_ISR12,EDMASG_IF);
	    			if (g_pfnEDMACallback[12][3] != 0)
		    			(*g_pfnEDMACallback[12][3])(0);	    				    		
	    		}						
    			else
    			{
	    			u32WraparoundStatus = inp32(REG_PDMA_ISR12) & 0x0F00;
	    			if (u32WraparoundStatus)
	    			{
		    			if (u32WraparoundStatus & 0x0200)
		    				u32WraparoundStatus = 0x0200;
		    			else if (u32WraparoundStatus & 0x0400)
		    				u32WraparoundStatus = 0x0400;
		    			else  if (u32WraparoundStatus & 0x0800)
		    				u32WraparoundStatus = 0x0800;
		    			else		   
		    				u32WraparoundStatus = 0x0100; 	

					outp32(REG_PDMA_ISR12,u32WraparoundStatus);					
		    			if (g_pfnEDMACallback[12][2] != 0)		    						
			    			(*g_pfnEDMACallback[12][2])(u32WraparoundStatus); 		    				    			   			
	    			}
				}	    			
    		}     	
    	}
		
	}
}

// Install Call Back Function for Channelx & Interrupt source
ERRCODE  
DrvEDMA_InstallCallBack(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
    E_DRVEDMA_INT_ENABLE eIntSource,
	PFN_DRVEDMA_CALLBACK pfncallback,    
	PFN_DRVEDMA_CALLBACK *pfnOldcallback  	
)
{
    UINT32 u32SFR, index;
    
    u32SFR = REG_VDMA_IER + eChannel * 0x100;        
    
    if ((eChannel > MAX_CHANNEL_NUM) || (eChannel >= 6 && eChannel <=7))
        return E_DRVEDMA_FALSE_INPUT;
            
    if ((eIntSource !=1) && (eIntSource !=2) && (eIntSource !=4) && (eIntSource !=8)) 
        return E_DRVEDMA_FALSE_INPUT;
/*	
	if (*pfnOldcallback != 0)
		*pfnOldcallback = g_pfnEDMACallback[eChannel][eIntSource>>1];
	///g_pfnEDMACallback[eChannel][eIntSource>>1] = pfncallback;
	for(i=0; i<4; i++)
	{
		if((eIntSource>>i) & 0x01)
			g_pfnEDMACallback[eChannel][i] = pfncallback;
	}
*/	
	for (index=0; index<4; index++)
		if ((1<<index) == eIntSource)
			break;
	if (pfnOldcallback != NULL)
		*pfnOldcallback = g_pfnEDMACallback[eChannel][index];
	g_pfnEDMACallback[eChannel][index] = pfncallback;

	if(eChannel <= eDRVEDMA_CHANNEL_5)
	{
		sysInstallISR(IRQ_LEVEL_7, IRQ_EDMA0, (PVOID)DrvEDMA_ISR);
		sysSetInterruptType(IRQ_EDMA0, HIGH_LEVEL_SENSITIVE);
		sysEnableInterrupt(IRQ_EDMA0);	
	}
	else
	{
		sysInstallISR(IRQ_LEVEL_7, IRQ_EDMA1, (PVOID)DrvEDMA1_ISR);
		sysSetInterruptType(IRQ_EDMA1, HIGH_LEVEL_SENSITIVE);
		sysEnableInterrupt(IRQ_EDMA1);
	}
	    
    return E_SUCCESS;      
}

// Get Information about Scatter Gather Descript Table size and Max Transfer Size per Descript Table  
void DrvEDMA_GetScatterGatherInfo(
	UINT32 *pu32TblSize,
	UINT32 *pu32MaxTransferBytePerTbl
)
{
	*pu32TblSize = sizeof(S_DRVEDMA_DESCRIPT_FORMAT);
	*pu32MaxTransferBytePerTbl = MAX_GS_TRANSFER_SIZE;
	
	return;
}

// Set Scatter Gather Descript Format Table Start Address
void DrvEDMA_SetScatterGatherTblStartAddr(
    E_DRVEDMA_CHANNEL_INDEX eChannel, 
	UINT32	u32TblStartAddr
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_SGAR + eChannel * 0x100;	
    outp32(u32SFR, u32TblStartAddr);
}	

// Enable Scatter Gather Function  
void DrvEDMA_EnableScatterGather(
    E_DRVEDMA_CHANNEL_INDEX eChannel 
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;	
    outp32(u32SFR, inp32(u32SFR)| EDMASG_EN);
}

// Disable Scatter Gather Function
void DrvEDMA_DisableScatterGather(
    E_DRVEDMA_CHANNEL_INDEX eChannel 
)
{
    UINT32 u32SFR;
    
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;	
    outp32(u32SFR, inp32(u32SFR) & ~EDMASG_EN);
}

// Set Descript Format for Scatter Gather
// This function only support Order =0 
ERRCODE 
DrvEDMA_SetScatterGatherSetting(
    E_DRVEDMA_CHANNEL_INDEX eChannel,
	UINT32 u32SGTblStartAddr,
	S_DRVEDMA_DESCRIPT_SETTING* psDescript
)
{
    UINT32 u32SFR, u32Value;     
	S_DRVEDMA_DESCRIPT_FORMAT *psSGFmt;
	UINT32 u32TranferByte=0;
	UINT32 u32TotalByteCount;
	UINT32 u32NewSrcAddr, u32NewDestAddr, u32AddSrcAddr, u32AddDestAddr;	
	E_DRVEDMA_COLOR_FORMAT eSrcFormat, eDestFormat;
	UINT32 u32MaxTxfBytePerTbl;	
	
	if ((int)psDescript->u32TransferByteCount <=0)
        return E_DRVEDMA_FALSE_INPUT;
	
	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
        
    eSrcFormat = (E_DRVEDMA_COLOR_FORMAT)((inp32(u32SFR) & SOUR_FORMAT) >> 24);
    eDestFormat = (E_DRVEDMA_COLOR_FORMAT)((inp32(u32SFR) & DEST_FORMAT) >> 16);        	
        
    u32SFR = REG_VDMA_CSR + eChannel * 0x100;
    u32Value = inp32(u32SFR);         
    u32Value = (u32Value & ~SAD_SEL) | (psDescript->eSrcDirection << SOURCE_DIRECTION_BIT);    
    u32Value = (u32Value & ~DAD_SEL) | (psDescript->eDestDirection << DESTINATION_DIRECTION_BIT);
    outp32(u32SFR,u32Value); 
            
	DrvEDMA_EnableScatterGather(eChannel);
	DrvEDMA_SetScatterGatherTblStartAddr(eChannel, u32SGTblStartAddr);
	psSGFmt = (S_DRVEDMA_DESCRIPT_FORMAT *)u32SGTblStartAddr;
	u32TotalByteCount = psDescript->u32TransferByteCount;
	u32NewSrcAddr = psDescript->u32SourceAddr;
	u32NewDestAddr = psDescript->u32DestAddr;	
	u32AddSrcAddr=0;
	u32AddDestAddr=0;	
	
	// Update TransferByteCount for stride mode	
	u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
	
	if ((psDescript->u32Stride) && (inp32(u32SFR) & STRIDE_EN))
	    u32MaxTxfBytePerTbl = MAX_GS_TRANSFER_SIZE / psDescript->u32Stride * psDescript->u32Stride;	
	else    
	    u32MaxTxfBytePerTbl = MAX_GS_TRANSFER_SIZE;
	
    do {
		// Set Phsyical Source Address and Destination Address
		// Set WrapAround and Fixed Direction in Scatter Gather as Fixed Direction    
		if (psDescript->eSrcDirection == eDRVEDMA_DIRECTION_INCREMENTED)
		{
    	    psSGFmt->u32SourceAddr = u32NewSrcAddr + u32AddSrcAddr;
    	    u32NewSrcAddr += u32AddSrcAddr;
		} 
    	else 
    	{
    	    if (psDescript->eSrcDirection == eDRVEDMA_DIRECTION_DECREMENTED)
    	    {
    	        psSGFmt->u32SourceAddr	= u32NewSrcAddr - u32AddSrcAddr;
	    	    u32NewSrcAddr -= u32AddSrcAddr;    	        
    	    }  
    	    else    
	    	    psSGFmt->u32SourceAddr	= u32NewSrcAddr;    	        
    	}
    	
    	if (psDescript->eDestDirection == eDRVEDMA_DIRECTION_INCREMENTED)
    	{
    	    psSGFmt->u32DestAddr = u32NewDestAddr + u32AddDestAddr;
    	    u32NewDestAddr += u32AddDestAddr;
		} 
    	else
    	{
    	    if (psDescript->eDestDirection == eDRVEDMA_DIRECTION_DECREMENTED)
    	    {
    	        psSGFmt->u32DestAddr = u32NewDestAddr - u32AddDestAddr; 
    	         u32NewDestAddr -= u32AddDestAddr;   	    
			}     	    
			else    
				psSGFmt->u32DestAddr = u32NewDestAddr;    	        
    	}
    	
    	if (u32TotalByteCount >= u32MaxTxfBytePerTbl)
    	{
	    	u32TranferByte = u32MaxTxfBytePerTbl;
	    	u32TotalByteCount -= u32MaxTxfBytePerTbl;	    	
		}	    	
	    else
	    {
	    	u32TranferByte = u32TotalByteCount;	  
	    	u32TotalByteCount = 0;  	
		}	  
		
		// Src/Dest format must be set before DrvEDMA_SetScatterGatterSetting() function to calcuate the next address
		u32SFR = REG_VDMA_CTCSR + eChannel * 0x100;
		if ((psDescript->u32Stride) && (inp32(u32SFR) & STRIDE_EN) && ((eChannel ==0) ||(eChannel ==5) ||(eChannel ==8)))
		{   // Calculate the next Src/Destination for Stride mode
		    u32AddSrcAddr = (u32TranferByte / psDescript->u32Stride) * (psDescript->u32SrcOffset + psDescript->u32Stride) + 
		                    u32TranferByte % psDescript->u32Stride;

	    	if (eSrcFormat == eDRVEDMA_RGB888)
	    	{
	    		if (eDestFormat== eDRVEDMA_RGB888)
	    			u32AddDestAddr = (u32TranferByte / psDescript->u32Stride) * (psDescript->u32DestOffset + psDescript->u32Stride) + 
		                    u32TranferByte % psDescript->u32Stride;	
	    		else	
		    		u32AddDestAddr = (u32TranferByte / psDescript->u32Stride) * (psDescript->u32DestOffset + psDescript->u32Stride/2) + 
		                    u32TranferByte % psDescript->u32Stride/2;
	    	}
	    	else
	    	{
	    		if (eDestFormat== eDRVEDMA_RGB888)
	    			u32AddDestAddr = (u32TranferByte / psDescript->u32Stride) * (psDescript->u32DestOffset + psDescript->u32Stride*2) + 
		                    u32TranferByte % psDescript->u32Stride*2;
	    		else	
		    		u32AddDestAddr = (u32TranferByte / psDescript->u32Stride) * (psDescript->u32DestOffset + psDescript->u32Stride) + 
		                    u32TranferByte % psDescript->u32Stride;	    	
	    	}
              
		}
		else
		{   // Calculate the next Src/Destination for non-Stride mode
		    u32AddSrcAddr = u32TranferByte;
		    
		    if ((eChannel ==0) || (eChannel ==5) || (eChannel ==8))
		    {
		    	if (eSrcFormat == eDRVEDMA_RGB888)
		    	{
		    		if (eDestFormat== eDRVEDMA_RGB888)
		    			u32AddDestAddr = u32TranferByte;
		    		else	
			    		u32AddDestAddr = u32TranferByte/2;
		    	}
		    	else
		    	{
		    		if (eDestFormat== eDRVEDMA_RGB888)
		    			u32AddDestAddr = u32TranferByte*2;
		    		else	
			    		u32AddDestAddr =u32TranferByte;    	
		    	}
	    	}
	    	else
	    	{
		    	u32AddDestAddr = u32TranferByte;
	    	}		    
		}		  
		
		// Set Stride Transfer Byte Count & Byte Count	
    	psSGFmt->u32StrideAndByteCount   = ((psDescript->u32Stride & 0x7FFF) << 17) | u32TranferByte;
    	
    	// Set Source Offset Byte Length and Destination Offset Byte Length
  	   	psSGFmt->u32Offset = ((psDescript->u32DestOffset & 0x7FFF) << 16) |
  	   						  (psDescript->u32SrcOffset & 0x7FFF);      	
  	   						  
		// Set EOT for last Descript Format  	   						  
		if (u32TotalByteCount == 0)
			psSGFmt->u32Offset |= 0x80000000;
			
		// Set Next Scatter Gether Table Address	
		psSGFmt->u32NextSGTblAddr = (UINT32)(psSGFmt+1); 	
		
		psSGFmt++;		
  	   	
	} while(u32TotalByteCount > 0);    
	
	return E_SUCCESS;  
}




















































