/******************************************************************************

  Copyright (C), 2014, Texas Instrument.

 ******************************************************************************
  File Name     : K2_common.c
  Version       : Initial Draft
  Author        : Brighton Feng
  Created       : June 11, 2014
  Description   : KeyStone 2 common miscellaneous functions and definitions

******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tistdtypes.h>
#include <csl_bootcfgAux.h>
#include <csl_pscAux.h>
#include <cslr_chip.h>
#include <csl_edma3.h>
#include <CSL_msmc.h>
#include <CSL_msmcAux.h>
#include "K2_common.h"
#include "ARMv7_CPU.h"

/*----------------------------------------------*
 * project-wide global variables                *
 *----------------------------------------------*/
CSL_BootcfgRegs * gpBootCfgRegs = (CSL_BootcfgRegs *)CSL_BOOT_CFG_REGS;
CSL_PllcRegs * gpPLLC_regs = (CSL_PllcRegs * )CSL_PLLC_REGS;
CSL_PscRegs *  gpPSC_regs =   (CSL_PscRegs *)CSL_PSC_REGS;
CSL_MsmcRegs * gpMSMC_regs = (CSL_MsmcRegs *)CSL_MSMC_CFG_REGS;
#ifdef CSL_GPIO_CFG_REGS 	//for K2H, K2K, K2E
CSL_GpioRegs * gpGPIO_regs= (CSL_GpioRegs * )CSL_GPIO_CFG_REGS;
#else 	//for K2L
CSL_GpioRegs * gpGPIO_regs= (CSL_GpioRegs * )CSL_GPIO_0_CFG_REGS;
CSL_GpioRegs * gpGPIO1_regs= (CSL_GpioRegs * )CSL_GPIO_1_CFG_REGS;
#endif

CSL_Tetris_vbuspRegs * gpARM_regs= (CSL_Tetris_vbuspRegs *)CSL_TETRIS_REGS;

/*CIC2 for ARM and EDMA events*/
CSL_CPINTCRegs* gpCIC_regs= (CSL_CPINTCRegs*)CSL_CIC_2_REGS;
CSL_Gic400Regs* gpGIC_regs = (CSL_Gic400Regs*)CSL_ARM_GIC_CFG_REGS;

CSL_TpccRegs*  gpEDMA_CC0_regs  = (CSL_TpccRegs*)CSL_EDMACC_0_REGS;
CSL_TpccRegs*  gpEDMA_CC1_regs  = (CSL_TpccRegs*)CSL_EDMACC_1_REGS;
CSL_TpccRegs*  gpEDMA_CC2_regs  = (CSL_TpccRegs*)CSL_EDMACC_2_REGS;
#ifdef CSL_EDMACC_3_REGS	//for K2H, K2K, K2E
CSL_TpccRegs*  gpEDMA_CC3_regs  = (CSL_TpccRegs*)CSL_EDMACC_3_REGS;
#endif
#ifdef CSL_EDMACC_4_REGS	//for K2H, K2K, K2E
CSL_TpccRegs*  gpEDMA_CC4_regs  = (CSL_TpccRegs*)CSL_EDMACC_4_REGS;
#endif
CSL_TpccRegs*  gpEDMA_CC_regs[NUM_EDMA_CC]  = {
	(CSL_TpccRegs*)CSL_EDMACC_0_REGS,
	(CSL_TpccRegs*)CSL_EDMACC_1_REGS,
	(CSL_TpccRegs*)CSL_EDMACC_2_REGS
#ifdef CSL_EDMACC_3_REGS	//for K2H, K2K, K2E
	,(CSL_TpccRegs*)CSL_EDMACC_3_REGS
#endif
#ifdef CSL_EDMACC_4_REGS	//for K2H, K2K, K2E
	,(CSL_TpccRegs*)CSL_EDMACC_4_REGS
#endif
};

CSL_TptcRegs * gpEDMA_TC_0_0_regs=(CSL_TptcRegs *) CSL_EDMACC_0_TC_0_REGS;
CSL_TptcRegs * gpEDMA_TC_0_1_regs=(CSL_TptcRegs *) CSL_EDMACC_0_TC_1_REGS;
CSL_TptcRegs * gpEDMA_TC_1_0_regs=(CSL_TptcRegs *) CSL_EDMACC_1_TC_0_REGS;
CSL_TptcRegs * gpEDMA_TC_1_1_regs=(CSL_TptcRegs *) CSL_EDMACC_1_TC_1_REGS;
CSL_TptcRegs * gpEDMA_TC_1_2_regs=(CSL_TptcRegs *) CSL_EDMACC_1_TC_2_REGS;
CSL_TptcRegs * gpEDMA_TC_1_3_regs=(CSL_TptcRegs *) CSL_EDMACC_1_TC_3_REGS;
CSL_TptcRegs * gpEDMA_TC_2_0_regs=(CSL_TptcRegs *) CSL_EDMACC_2_TC_0_REGS;
CSL_TptcRegs * gpEDMA_TC_2_1_regs=(CSL_TptcRegs *) CSL_EDMACC_2_TC_1_REGS;
CSL_TptcRegs * gpEDMA_TC_2_2_regs=(CSL_TptcRegs *) CSL_EDMACC_2_TC_2_REGS;
CSL_TptcRegs * gpEDMA_TC_2_3_regs=(CSL_TptcRegs *) CSL_EDMACC_2_TC_3_REGS;
#ifdef CSL_EDMACC_3_REGS	//for K2H, K2K, K2E
CSL_TptcRegs * gpEDMA_TC_3_0_regs=(CSL_TptcRegs *) CSL_EDMACC_3_TC_0_REGS;
CSL_TptcRegs * gpEDMA_TC_3_1_regs=(CSL_TptcRegs *) CSL_EDMACC_3_TC_1_REGS;
#endif
#ifdef CSL_EDMACC_4_REGS	//for K2H, K2K, K2E
CSL_TptcRegs * gpEDMA_TC_4_0_regs=(CSL_TptcRegs *) CSL_EDMACC_4_TC_0_REGS;
CSL_TptcRegs * gpEDMA_TC_4_1_regs=(CSL_TptcRegs *) CSL_EDMACC_4_TC_1_REGS;
#endif

CSL_TptcRegs * gpEDMA_TC_regs[NUM_EDMA_TC]= {
	(CSL_TptcRegs *) CSL_EDMACC_0_TC_0_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_0_TC_1_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_1_TC_0_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_1_TC_1_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_1_TC_2_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_1_TC_3_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_2_TC_0_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_2_TC_1_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_2_TC_2_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_2_TC_3_REGS
#ifdef CSL_EDMACC_3_REGS	//for K2H, K2K, K2E
	,(CSL_TptcRegs *) CSL_EDMACC_3_TC_0_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_3_TC_1_REGS
#endif
#ifdef CSL_EDMACC_4_REGS	//for K2H, K2K, K2E
	,(CSL_TptcRegs *) CSL_EDMACC_4_TC_0_REGS,
	(CSL_TptcRegs *) CSL_EDMACC_4_TC_1_REGS
#endif
};
CSL_TmrRegs * gpTimerRegs[20] = {
	(CSL_TmrRegs *)CSL_TIMER_0_REGS,
#ifdef CSL_TIMER_1_REGS	//for K2H, K2K, K2L
	(CSL_TmrRegs *)CSL_TIMER_1_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_2_REGS	//for K2H, K2K, K2L
	(CSL_TmrRegs *)CSL_TIMER_2_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_3_REGS	//for K2H, K2K, K2L
	(CSL_TmrRegs *)CSL_TIMER_3_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_4_REGS	//for K2H, K2K
	(CSL_TmrRegs *)CSL_TIMER_4_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_5_REGS	//for K2H, K2K
	(CSL_TmrRegs *)CSL_TIMER_5_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_6_REGS	//for K2H, K2K
	(CSL_TmrRegs *)CSL_TIMER_6_REGS,
#else
	0,
#endif
#ifdef CSL_TIMER_7_REGS	//for K2H, K2K
	(CSL_TmrRegs *)CSL_TIMER_7_REGS,
#else
	0,
#endif
	(CSL_TmrRegs *)CSL_TIMER_8_REGS,
	(CSL_TmrRegs *)CSL_TIMER_9_REGS,
	(CSL_TmrRegs *)CSL_TIMER_10_REGS,
	(CSL_TmrRegs *)CSL_TIMER_11_REGS,
	(CSL_TmrRegs *)CSL_TIMER_12_REGS,
	(CSL_TmrRegs *)CSL_TIMER_13_REGS,
	(CSL_TmrRegs *)CSL_TIMER_14_REGS,
	(CSL_TmrRegs *)CSL_TIMER_15_REGS,
	(CSL_TmrRegs *)CSL_TIMER_16_REGS,
	(CSL_TmrRegs *)CSL_TIMER_17_REGS
#ifdef CSL_TIMER_18_REGS	//for K2H, K2K
	,(CSL_TmrRegs *)CSL_TIMER_18_REGS
#endif
#ifdef CSL_TIMER_19_REGS	//for K2H, K2K
	,(CSL_TmrRegs *)CSL_TIMER_19_REGS
#endif
};

/*MPU for peripherals registers and data space*/
CSL_MpuRegs * gpMPU_regs[16]= {
	(CSL_MpuRegs *)CSL_MPU_0_REGS,
	(CSL_MpuRegs *)CSL_MPU_1_REGS,
	(CSL_MpuRegs *)CSL_MPU_2_REGS,
#ifdef CSL_MPU_3_REGS	//for K2H, K2K
	(CSL_MpuRegs *)CSL_MPU_3_REGS,
#else
	0,
#endif
#ifdef CSL_MPU_4_REGS	//for K2H, K2K
	(CSL_MpuRegs *)CSL_MPU_4_REGS,
#else
	0,
#endif
	(CSL_MpuRegs *)CSL_MPU_5_REGS,
#ifdef CSL_MPU_6_REGS	//for K2H, K2K
	(CSL_MpuRegs *)CSL_MPU_6_REGS,
#else
	0,
#endif
	(CSL_MpuRegs *)CSL_MPU_7_REGS,
	(CSL_MpuRegs *)CSL_MPU_8_REGS,
	(CSL_MpuRegs *)CSL_MPU_9_REGS,
	(CSL_MpuRegs *)CSL_MPU_10_REGS,
	(CSL_MpuRegs *)CSL_MPU_11_REGS,
	(CSL_MpuRegs *)CSL_MPU_12_REGS,
	(CSL_MpuRegs *)CSL_MPU_13_REGS,
	(CSL_MpuRegs *)CSL_MPU_14_REGS
#ifdef CSL_MPU_15_REGS
	,(CSL_MpuRegs *)CSL_MPU_15_REGS
#else
	,0
#endif
};

#if (2==CSL_DDR3_PER_CNT)	//for K2H, K2K
/*for Device has two DDR3 interfaces*/
CSL_Emif4fvRegs * gpDDR3ControlRegs[CSL_DDR3_PER_CNT]= 
{
	(CSL_Emif4fvRegs *)CSL_DDR3_0_SLV_CFG_REGS,
	(CSL_Emif4fvRegs *)CSL_DDR3_1_SLV_CFG_REGS
};
#else
/*for Device has one DDR3 interface*/
CSL_Emif4fvRegs * gpDDR3ControlRegs= (CSL_Emif4fvRegs *)CSL_DDR3_0_SLV_CFG_REGS;
#endif

unsigned int gARM_Core_Speed_Hz= 1000000000; 	//ARM core clock speed in Hz
unsigned int gMain_Core_Speed_Hz= 1000000000; 	//Main core clock speed in Hz


/*----------------------------------------------*
 * routines' implementations                    *
 *----------------------------------------------*/
/*****************************************************************************
 Prototype    : KeyStone_main_PLL_init
 Description  : Main core PLL configuration
  	Main core will be configured to run at ref_clock_MHz*multiplier/divisor
 Input        : float ref_clock_MHz     
                unsigned int multiplier: 1~4096  
                unsigned int divisor: 1~64  
 Output       : 
 Return Value : 
 
  History        :
  1.Date         : December 12, 2010
    Author       : Brighton Feng
    Modification : Created function
  2.Date         : May 19, 2013
    Author       : Brighton Feng
    Modification : update parameter check; replace constant with macro

*****************************************************************************/
void KeyStone_main_PLL_init (float ref_clock_MHz,
	unsigned int multiplier, unsigned int divisor)
{
	if(0==divisor)
	{
		puts("Error: PLL input divider = 0");
		return;
	}

	if(64<divisor)
	{
		puts("Error: PLL input divider too large");
		return;
	}

	if(0==multiplier)
	{
		puts("Error: PLL multiplier = 0");
		return;
	}

	if(4096<multiplier)
	{
		puts("Error: PLL multiplier too large");
		return;
	}

	CSL_BootCfgUnlockKicker();

	gMain_Core_Speed_Hz= ref_clock_MHz*1000000/divisor*multiplier;
#ifdef DEVICE_K2E
	gARM_Core_Speed_Hz= gMain_Core_Speed_Hz;
#endif

	printf("Initialize main core clock = %.2fMHz/%dx%d = %dMHz\n", 
		ref_clock_MHz, divisor, multiplier, gMain_Core_Speed_Hz/1000000);

	/*1. If executing this sequence immediately after device power-up, you must allow for*/
	/*the PLL to become stable. PLL stabilization time is 100 ¦Ìs.                       */
	delay_us(100);

	/*2. Check the status of BYPASS bit in SECCTL register, execute following steps if   */
	/*BYPASS == 1 (if bypass enabled):                         */
	if(gpPLLC_regs->SECCTL & PLLCTL_BYPASS_MASK)
	{		
		/*a. In MAINPLLCTL1, write ENSAT = 1 (for optimal PLL operation)                     */
		gpBootCfgRegs->MAIN_PLL_CTL1 |= PLLCTL1_ENSAT_MASK;      /*Set ENSAT bit = 1*/

		/*b. In PLLCTL, write PLLEN = 0 (bypass enabled in PLL controller mux)               */
		gpPLLC_regs->PLLCTL &= ~CSL_PLLC_PLLCTL_PLLEN_MASK;

		/*c. In PLLCTL, write PLLENSRC = 0 (enable PLLEN to control PLL controller mux       */
		gpPLLC_regs->PLLCTL &= ~CSL_PLLC_PLLCTL_PLLENSRC_MASK;

		/*d. Wait 4 cycles of the reference clock CLKIN (to make sure the PLL controller     */
		/*mux switches properly to the bypass)                                               */
		delay_us(1);

		/*e. In SECCTL, write BYPASS = 1 (bypass enabled in PLL mux)                         */
		gpPLLC_regs->SECCTL |= PLLCTL_BYPASS_MASK;

		/*f. In PLLCTL, write PLLPWRDN = 1 (power down the PLL)                              */
		gpPLLC_regs->PLLCTL |= CSL_PLLC_PLLCTL_PLLPWRDN_MASK;	//Power down the PLL

		/*g. Wait for at least 5 ¦Ìs based on the reference clock CLKIN (PLL power down      */
		/*toggling time)                                                                     */
		delay_us(5);

		/*h. In PLLCTL, write PLLPWRDN = 0 (power up the PLL)                                */
		gpPLLC_regs->PLLCTL &= ~CSL_PLLC_PLLCTL_PLLPWRDN_MASK;         // Power up PLL
	}
	else
	{
		/*a. In PLLCTL, write PLLEN = 0 (bypass enabled in PLL controller mux)               */
		gpPLLC_regs->PLLCTL &= (~CSL_PLLC_PLLCTL_PLLEN_MASK);

		/*b. In PLLCTL, write PLLENSRC = 0 (enable PLLEN to control PLL controller mux       */
		gpPLLC_regs->PLLCTL &= (~CSL_PLLC_PLLCTL_PLLENSRC_MASK);

		/*c. Wait 4 cycles of the reference clock CLKIN (to make sure the PLL controller     */
		/*mux switches properly to the bypass)                                               */
		delay_us(1);
	}

	/*4. PLLM is split in two different registers. Program PLLM[5:0] in PLL multiplier   */
	/*control register (PLLM) and PLLM[12:6] in MAINPLLCTL0 register                     */
	/*5. BWADJ is split in two different registers. Program BWADJ[7:0] in                */
	/*MAINPLLCTL0 and BWADJ[11:8] in MAINPLLCTL1 register. BWADJ value                   */
	/*must be set to ((PLLM + 1) >> 1) - 1)                                              */
	/*6. Program PLLD in MAINPLLCTL0 register                                            */
	gpBootCfgRegs->MAIN_PLL_CTL0 = ((multiplier-1)<<PLLCTL0_BWADJ_SHIFT)|
		(((multiplier*2-1)&0x1FC0)<<PLLCTL0_PLLM_SHIFT)|(divisor-1);
	
	gpPLLC_regs->PLLM= (multiplier*2-1)&0x3F;
	gpBootCfgRegs->MAIN_PLL_CTL1 &= ~PLLCTL1_BWADJ_MASK; 
	gpBootCfgRegs->MAIN_PLL_CTL1 |= (multiplier-1)>>8;	/*BWADJ[11:8]*/

	/*7. In SECCTL, write OD (Output Divide) = 1 (that is divide-by-2)                   */
	gpPLLC_regs->SECCTL &= ~PLLCTL_OD_MASK;
	gpPLLC_regs->SECCTL |= 1<<PLLCTL_OD_SHIFT;
	
#if 0
	/*8. If necessary, program PLLDIVn. Note that you must apply the GO operation to     */
	/*change these dividers to a new ratios (see Section 3.2 ¡®¡®Divider n (D1 to Dn) and*/
	/*GO Operation ¡¯¡¯ on page 3-3).                                                    */
	/* Step 8a: Check that the GOSTAT bit in PLLSTAT is cleared to show that no GO
	operation is currently in progress*/
	while((gpPLLC_regs->PLLSTAT) & CSL_PLLC_PLLSTAT_GOSTAT_MASK);

	/* Step 8b: Program the RATIO field in PLLDIVn to the desired new divide-down rate.
	If RATIO field is changed, the PLL controller will flag the change in the
	corresponding bit of DCHANGE*/
	gpPLLC_regs->PLLDIV1_3[3-1] = (3-1) | CSL_PLLC_PLLDIV1_3_DNEN_MASK;  //Set PLLDIV3
	gpPLLC_regs->PLLDIV4_16[4-4] = (5-1) | CSL_PLLC_PLLDIV4_16_DNEN_MASK;  //Set PLLDIV4
	gpPLLC_regs->PLLDIV4_16[7-4] = (6-1) | CSL_PLLC_PLLDIV4_16_DNEN_MASK;  //Set PLLDIV7

	/* Step 8c: Set GOSET bit in PLLCMD to initiate the GO operation to change the divide
	values and align the SYSCLKs as programmed */
	gpPLLC_regs->PLLCMD |= CSL_PLLC_PLLCMD_GOSET_MASK;

	/*Step 8d/e: Read the GOSTAT bit in PLLSTAT to make sure the bit returns to 0 to
	indicate that the GO operation has completed */
	while((gpPLLC_regs->PLLSTAT) & CSL_PLLC_PLLSTAT_GOSTAT_MASK);
#endif

	/*9. In PLLCTL , write PLLRST = 1 (PLL reset is asserted)*/
	gpPLLC_regs->PLLCTL |= CSL_PLLC_PLLCTL_PLLRST_MASK;
	
	/*10. Wait for at least 7 ¦Ìs based on the reference clock CLKIN (PLL reset time)     */
	delay_us(7);

	/*11. In PLLCTL, write PLLRST = 0 (PLL reset is released)                            */
	gpPLLC_regs->PLLCTL &= ~CSL_PLLC_PLLCTL_PLLRST_MASK;

	/*12. Wait for at least 2000 ¡Á CLKIN cycles ¡Á (PLLD + 1) (PLL lock time)            */
	delay_us(2*multiplier);

	/*13. In SECCTL, write BYPASS = 0 (enable PLL mux to switch to PLL mode)             */
	gpPLLC_regs->SECCTL &= ~PLLCTL_BYPASS_MASK;
	
	/*14. Set the PLLEN bit in PLLCTL to 1 to enable PLL mode*/
	gpPLLC_regs->PLLCTL |= CSL_PLLC_PLLCTL_PLLEN_MASK;

}
/*****************************************************************************
 Prototype    : KeyStone_PLL_init
 Description  : Config the PLL of ARM, PA and DDR
 	target clock speed will be ref_clock_MHz/inputDivisor*multiplier/outputDivisor
 Input        : unsigned int inputDivisor  
                unsigned int multiplier  
                unsigned int outputDivisor  
 Output       : None
 Return Value : 0 for success, other value for error
 
  History        :
  1.Date         : May 18, 2013
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
int KeyStone_PLL_init (PLL_ControlRegs * PLL_Regs, unsigned int inputDivisor, 
	unsigned int multiplier, unsigned int outputDivisor)
{
	if(0==inputDivisor)
	{
		puts("Error: PLL input divider = 0");
		return 1;
	}

	if(64<inputDivisor)
	{
		puts("Error: PLL input divider too large");
		return 2;
	}

	if(0==multiplier)
	{
		puts("Error: PLL multiplier = 0");
		return 3;
	}

	if(8192<multiplier)
	{
		puts("Error: PLL multiplier too large");
		return 4;
	}

	if(0==outputDivisor)
	{
		puts("Error: PLL output divider = 0");
		return 5;
	}

	if(16<outputDivisor)
	{
		puts("Error: PLL output divider too larger");
		return 6;
	}

	CSL_BootCfgUnlockKicker();

	/*1. In PLLCTL1, write ENSAT = 1 (for optimal PLL operation)*/
	PLL_Regs->PLL_CTL1 = PLLCTL1_ENSAT_MASK;

	/*2. In PLLCTL0, write BYPASS = 1 (set the PLL in Bypass)*/
	PLL_Regs->PLL_CTL0 |= PLLCTL_BYPASS_MASK;

	/*3. Program PLLM and PLLD in PLLCTL0 register*/
	/*4. Program BWADJ[7:0] in PLLCTL0 and BWADJ[11:8] in PLLCTL1 register. 
	BWADJ value must be set to ((PLLM + 1) >> 1) ¨C 1)*/
	PLL_Regs->PLL_CTL0 = ((multiplier/2-1)<<PLLCTL0_BWADJ_SHIFT)
		|((outputDivisor-1)<<PLLCTL_OD_SHIFT)
		|((multiplier-1)<<PLLCTL0_PLLM_SHIFT)
		|(inputDivisor-1);

	PLL_Regs->PLL_CTL1 &= ~PLLCTL1_BWADJ_MASK;
	PLL_Regs->PLL_CTL1 |= (multiplier/2-1)>>8; /*BWADJ[11:8]*/

	/*5. In PLLCTL1, write PLLRST = 1 (PLL is reset)*/
	PLL_Regs->PLL_CTL1 |= PLLCTL1_PLLRESET_MASK;      //Set RESET bit = 1

	/*6. Wait for at least 7 us based on the reference clock (PLL reset time)*/
	delay_us(7);

#if defined(DEVICE_K2L)
	if(PLL_Regs==(PLL_ControlRegs *)&gpBootCfgRegs->DFE_PLL_CTL0)
		gpBootCfgRegs->DFE_CLKDIV_CTL &= ~3;
#endif

	/*7. In PLLCTL1, write PLLRST = 0 (PLL reset is released)*/
	PLL_Regs->PLL_CTL1 &= ~PLLCTL1_PLLRESET_MASK;   //Clear RESET bit

	/*8. Wait for at least 500 * REFCLK cycles * (PLLD + 1) (PLL lock time)*/
	delay_us(500);

	/*9. In PLLCTL0, write BYPASS = 0 (switch to PLL mode)*/
	PLL_Regs->PLL_CTL0 &= ~PLLCTL_BYPASS_MASK ;

	return 0;
}

#ifndef DEVICE_K2E 	//K2E only has main PLL for both ARM and DSP cores
/*****************************************************************************
 Prototype    : K2_ARM_PLL_init
 Description  : Config the ARM PLL
 	target clock speed will be ref_clock_MHz/divisor*multiplier
 Input        : float ref_clock_MHz
                unsigned int multiplier: 1~4096
                unsigned int divisor: 1~64
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2013-2-14
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void K2_ARM_PLL_init (float ref_clock_MHz,
	unsigned int multiplier, unsigned int divisor)
{
	//output divisor for ARM PLL should be 2
	if(0==KeyStone_PLL_init((PLL_ControlRegs *)&gpBootCfgRegs->ARM_PLL_CTL0, 
		divisor, multiplier*2, 2))
	{
		gARM_Core_Speed_Hz= ref_clock_MHz*1000000/divisor*multiplier;

		printf("Initialize ARM clock = %.2fMHz/%dx%d = %dMHz\n", 
			ref_clock_MHz, divisor, multiplier, gARM_Core_Speed_Hz/1000000);
	}

#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	/*For K2H/K2K ARM, In CHIP_MISC_CTL1, write TETRIS_PLL_EN= 1 
	(for selecting the output of ARM PLL as the input to ARM)*/
	gpBootCfgRegs->CHIP_MISC1 |= CSL_BOOTCFG_CHIP_MISC1_TETRIS_PLL_ENABLE_MASK;
#endif

}
#endif

/*****************************************************************************
 Prototype    : K2_PASS_PLL_init
 Description  : Config the PASS PLL
 	target clock speed will be ref_clock_MHz/divisor*multiplier
 Input        : float ref_clock_MHz
                unsigned int multiplier: 1~4096
                unsigned int divisor: 1~64
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2013-2-14
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void K2_PASS_PLL_init (float ref_clock_MHz,
	unsigned int multiplier, unsigned int divisor)
{
	//output divisor for PASS PLL should be 2
	if(0==KeyStone_PLL_init((PLL_ControlRegs *)&gpBootCfgRegs->PASS_PLL_CTL0, 
		divisor, multiplier*2, 2))
	{
		printf("Initialize PASS PLL clock = %.2fMHz/%dx%d = %dMHz\n", 
			ref_clock_MHz, divisor, multiplier, 
			(Uint32)(ref_clock_MHz*multiplier/divisor));
	}
	
	/*For PASS, In PASSPLLCTL1, write PLLSELECT = 1 
	(for selecting the output of PA PLL as the input to PASS)*/
	gpBootCfgRegs->PASS_PLL_CTL1 |= PLLCTL1_PLLSEL_MASK;
}

#ifdef DEVICE_K2L 	//only K2L has DFE
/*****************************************************************************
 Prototype    : K2_DFE_PLL_init
 Description  : Config the DFE PLL
 	target clock speed will be ref_clock_MHz/divisor*multiplier
 Input        : float ref_clock_MHz
                unsigned int multiplier: 1~4096
                unsigned int divisor: 1~64
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014-10-30
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void K2_DFE_PLL_init (float ref_clock_MHz,
	unsigned int multiplier, unsigned int divisor)
{
	//output divisor for DFE PLL should be 2
	if(0==KeyStone_PLL_init((PLL_ControlRegs *)&gpBootCfgRegs->DFE_PLL_CTL0, 
		divisor, multiplier*2, 2))
	{
		printf("Initialize DFE clock = %.2fMHz/%dx%d = %dMHz\n", 
			ref_clock_MHz, divisor, multiplier, 
			(Uint32)(ref_clock_MHz*multiplier/divisor));
	}

	//enable the SYSCLK and SYSREF synchronization logic?
	gpBootCfgRegs->DFE_CLKSYNC_CTL= 1; 

	/*For DFE, In DFEPLLCTL1, write PLLSELECT = 1 
	(for selecting the output of DFE PLL as the input to DFE)*/
	gpBootCfgRegs->DFE_PLL_CTL1 |= PLLCTL1_PLLSEL_MASK;

}
#endif

/*===============================CCNT===================================*/
/*extend the CCNT to 64-bit with software counter guiCCNT_high as the higher 32-bit.
guiCCNT_high increase every time the CCNT overflow*/
unsigned int guiCCNT_high= 0;
unsigned long long gullLastCCNT= 0;
void PMU_CCNT_overflow_INT_handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	guiCCNT_high++;
	gullLastCCNT= ((unsigned long long)guiCCNT_high<<32)+CP15_read_CCNT();

	//clear overflow flag
	CP15_PMU_clear_flags(CP15_PMU_CCNT_MASK);
}

void PMU_CCNT_overflow_INT_setup()
{
	GIC_INT_Config int_cfg;

	//hook PMU interrupt
	int_cfg.trigger_type= GIC_TRIGGER_TYPE_LEVEL;
	int_cfg.ucGroupNum= 0; //route PMN interrupt to group 0, FIQ
	/*give highest priority to get accurate cycle count*/
	int_cfg.ucPriority= GIC400_PRIORITY_HIGHEST; 
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_ARM_NPMUIRQ0+CP15_get_CPU_ID()), 
		&int_cfg, PMU_CCNT_overflow_INT_handler);

	//enable PMU interrupt
	CP15_enable_CCNT_irq();
	//clear PMU overflow flag
	CP15_PMU_clear_flags(CP15_PMU_CCNT_MASK);
}

/*get 64-bit cycle count*/
unsigned long long get_64_bit_cycle_count()
{
	unsigned long long ullCycle_Count;
	unsigned int uiCCNT_high= guiCCNT_high;

	ullCycle_Count= ((unsigned long long)uiCCNT_high<<32)+CP15_read_CCNT();

	/*In case CCNT wrap around, but overflow interrupt is not handled in time*/
	if(ullCycle_Count<gullLastCCNT)
	{
#ifdef ARM_POLL_INTERRUPT
	if(INT_Handlers[GIC_CONVERT_SPI_ID(CSL_ARM_GIC_ARM_NPMUIRQ0+CP15_get_CPU_ID())])
			ARM_poll_interrupts();
		else 	//if the ISR is not hooked, manually increase the guiCCNT_high
			guiCCNT_high++; 	
#endif
		ullCycle_Count += 0x100000000ULL;
	}

	gullLastCCNT= ullCycle_Count;	
	return ullCycle_Count;
}

unsigned int cycle_measure_overhead=50;
/*****************************************************************************
 Prototype    : calc_cycle_measure_overhead
 Description  : calclucate the cycles measurement overhead
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/6/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void calc_cycle_measure_overhead()
{
	int i;
	unsigned int cycle_cold, cycle_warm;
	cycle_cold= CP15_read_CCNT();
	cycle_cold = CCNT_getDelay(cycle_cold);
	for(i=0; i<32; i++)
	{
		cycle_warm= CP15_read_CCNT();
		cycle_warm = CCNT_getDelay(cycle_warm);
	}
	cycle_measure_overhead = (cycle_cold*1 + cycle_warm*31)/32;
}

/*****************************************************************************
 Prototype    : delay_ms
 Description  : Implement the delay function in unit of millisecond
 Input        : Uint32 ms  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/6/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void delay_ms(Uint32 ms)
{
	volatile unsigned long long startCCNT, currentCCNT;
	unsigned long long delay_cycles;
	Uint32 CCNT_L, CCNT_H;

	CCNT_L= CP15_read_CCNT();
	CCNT_H= 0;
	startCCNT= CCNT_L; 
	
	delay_cycles= ((unsigned long long)ms*gARM_Core_Speed_Hz/1000);

	do
	{
		if(CCNT_L> CP15_read_CCNT())//wrap around
			CCNT_H++;
		CCNT_L= CP15_read_CCNT();
		currentCCNT= CCNT_H; 
		currentCCNT <<= 32;
		currentCCNT += CCNT_L; 
	}
	while((currentCCNT-startCCNT)<delay_cycles);
}

/*****************************************************************************
 Prototype    : delay_us
 Description  : Implement the delay function in unit of microsecond
 Input        : Uint32 us  
 Output       : None
 Return Value : 
*****************************************************************************/
void delay_us(Uint32 us)
{
	volatile unsigned long long startCCNT, currentCCNT;
	unsigned long long delay_cycles;
	Uint32 CCNT_L, CCNT_H;

	CCNT_L= CP15_read_CCNT();
	CCNT_H= 0;
	startCCNT= CCNT_L; 
	
	delay_cycles= ((unsigned long long)us*gARM_Core_Speed_Hz/1000000);

	do
	{
		if(CCNT_L> CP15_read_CCNT())//wrap around
			CCNT_H++;
		CCNT_L= CP15_read_CCNT();
		currentCCNT= CCNT_H; 
		currentCCNT <<= 32; 
		currentCCNT += CCNT_L; 
	}
	while((currentCCNT-startCCNT)<delay_cycles);
}

/*==============================Chip level Timer==============================*/
/*****************************************************************************
 Prototype    : Reset_Timer
 Description  : Reset the general timer value
 Input        : int timer_num  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void Reset_Timer(int timer_num)
{
	if(gpTimerRegs[timer_num]->TGCR)
	{
		gpTimerRegs[timer_num]->TGCR= 0;
		gpTimerRegs[timer_num]->TCR= 0;
	}
}

 /*****************************************************************************
 Prototype    : Timer64_Init
 Description  : Initialize a 64-bit timer
 Input        : Timer64_Config * tmrCfg  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void Timer64_Init(Timer64_Config * tmrCfg)
{
	Reset_Timer(tmrCfg->timer_num);

	gpTimerRegs[tmrCfg->timer_num]->CNTLO= 0;
	gpTimerRegs[tmrCfg->timer_num]->CNTHI= 0;

	/*please note, in clock mode, two timer periods generate a clock, 
	one timer period output high voltage level, the other timer period 
	output low voltage level, so, the timer period should be half to the 
	desired output clock period*/
	if(TIMER_PERIODIC_CLOCK==tmrCfg->timerMode)
		tmrCfg->period= tmrCfg->period/2;

	/*the value written into period register is the expected value minus one*/
	gpTimerRegs[tmrCfg->timer_num]->PRDLO= _loll(tmrCfg->period-1);
	gpTimerRegs[tmrCfg->timer_num]->PRDHI= _hill(tmrCfg->period-1);
	if(tmrCfg->reload_period>1)
	{
		gpTimerRegs[tmrCfg->timer_num]->RELLO= _loll(tmrCfg->reload_period-1);
		gpTimerRegs[tmrCfg->timer_num]->RELHI= _hill(tmrCfg->reload_period-1);
	}
	
	if(TIMER_WATCH_DOG==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TGCR= 
			/*Select watch-dog mode*/
			(CSL_TMR_TIMMODE_WDT<<CSL_TMR_TGCR_TIMMODE_SHIFT)
			/*Remove the timer from reset*/
			|(CSL_TMR_TGCR_TIMLORS_RESET_OFF)
			|(CSL_TMR_TGCR_TIMHIRS_RESET_OFF);
	}
#if 1
	else if(TIMER_PERIODIC_WAVE==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TGCR= TMR_TGCR_PLUSEN_MASK
			/*for plus featuers, dual 32-bit unchained timer mode should be used*/
			|(CSL_TMR_TIMMODE_DUAL_UNCHAINED<<CSL_TMR_TGCR_TIMMODE_SHIFT)
			/*Remove the timer from reset*/
			|(CSL_TMR_TGCR_TIMLORS_RESET_OFF)
			|(CSL_TMR_TGCR_TIMHIRS_RESET_ON);

		//in plus mode, interrupt/event must be enabled manually
		gpTimerRegs[tmrCfg->timer_num]->INTCTL_STAT= TMR_INTCTLSTAT_EN_ALL_CLR_ALL;
	}
#else
	else if(TIMER_PERIODIC_WAVE==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TGCR= TMR_TGCR_PLUSEN_MASK
			/*Select 64-bit timer mode*/
			|(CSL_TMR_TIMMODE_GPT<<CSL_TMR_TGCR_TIMMODE_SHIFT)
			/*Remove the timer from reset*/
			|(CSL_TMR_TGCR_TIMLORS_RESET_OFF)
			|(CSL_TMR_TGCR_TIMHIRS_RESET_OFF);

		gpTimerRegs[tmrCfg->timer_num]->INTCTL_STAT= 0x50005;
	}
#endif
	else
	{
		gpTimerRegs[tmrCfg->timer_num]->TGCR= 
			/*Select 64-bit general timer mode*/
			(CSL_TMR_TIMMODE_GPT<<CSL_TMR_TGCR_TIMMODE_SHIFT)
			/*Remove the timer from reset*/
			|(CSL_TMR_TGCR_TIMLORS_RESET_OFF)
			|(CSL_TMR_TGCR_TIMHIRS_RESET_OFF);
	}

	/*make timer stop with emulation*/
#if 0 	//emulation stop is not supported?
	gpTimerRegs[tmrCfg->timer_num]->EMUMGT_CLKSPD = (gpTimerRegs[tmrCfg->timer_num]->EMUMGT_CLKSPD&
		~(CSL_TMR_EMUMGT_CLKSPD_FREE_MASK|CSL_TMR_EMUMGT_CLKSPD_SOFT_MASK));
#else
	gpTimerRegs[tmrCfg->timer_num]->EMUMGT_CLKSPD |= CSL_TMR_EMUMGT_CLKSPD_FREE_MASK;
#endif

	if(TIMER_WATCH_DOG==tmrCfg->timerMode)
	{
		/*enable watchdog timer*/
		gpTimerRegs[tmrCfg->timer_num]->WDTCR = CSL_TMR_WDTCR_WDEN_MASK
			|(CSL_TMR_WDTCR_WDKEY_CMD1<<CSL_TMR_WDTCR_WDKEY_SHIFT);

		gpTimerRegs[tmrCfg->timer_num]->TCR= 
			(CSL_TMR_CLOCK_INP_NOGATE<<CSL_TMR_TCR_TIEN_LO_SHIFT   ) 
			|(CSL_TMR_CLKSRC_INTERNAL<<CSL_TMR_TCR_CLKSRC_LO_SHIFT ) 
			/*The timer is enabled continuously*/
			|(CSL_TMR_ENAMODE_CONT<<CSL_TMR_TCR_ENAMODE_LO_SHIFT) 
			|((tmrCfg->pulseWidth<<CSL_TMR_TCR_PWID_LO_SHIFT)&CSL_TMR_TCR_PWID_LO_MASK) 
			/*select pulse mode*/
			|(CSL_TMR_CP_PULSE<<CSL_TMR_TCR_CP_LO_SHIFT     ) 
			|(CSL_TMR_INVINP_UNINVERTED<<CSL_TMR_TCR_INVINP_LO_SHIFT ) 
			|(CSL_TMR_INVOUTP_UNINVERTED<<CSL_TMR_TCR_INVOUTP_LO_SHIFT) 
			|(0<<CSL_TMR_TCR_TSTAT_LO_SHIFT  );

		/*active watchdog timer*/
		gpTimerRegs[tmrCfg->timer_num]->WDTCR = CSL_TMR_WDTCR_WDEN_MASK
			|(CSL_TMR_WDTCR_WDKEY_CMD2<<CSL_TMR_WDTCR_WDKEY_SHIFT);
	}
	else if(TIMER_ONE_SHOT_PULSE==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TCR= 
			(CSL_TMR_CLOCK_INP_NOGATE<<CSL_TMR_TCR_TIEN_LO_SHIFT   ) 
			|(CSL_TMR_CLKSRC_INTERNAL<<CSL_TMR_TCR_CLKSRC_LO_SHIFT ) 
			/*The timer is enabled one-shot*/
			|(CSL_TMR_ENAMODE_ENABLE<<CSL_TMR_TCR_ENAMODE_LO_SHIFT) 
			|((tmrCfg->pulseWidth<<CSL_TMR_TCR_PWID_LO_SHIFT)&CSL_TMR_TCR_PWID_LO_MASK) 
			/*select pulse mode*/
			|(CSL_TMR_CP_PULSE<<CSL_TMR_TCR_CP_LO_SHIFT     ) 
			|(CSL_TMR_INVINP_UNINVERTED<<CSL_TMR_TCR_INVINP_LO_SHIFT ) 
			|(CSL_TMR_INVOUTP_UNINVERTED<<CSL_TMR_TCR_INVOUTP_LO_SHIFT) 
			|(0<<CSL_TMR_TCR_TSTAT_LO_SHIFT  );
	}
	else if(TIMER_PERIODIC_CLOCK==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TCR= 
			(CSL_TMR_CLOCK_INP_NOGATE<<CSL_TMR_TCR_TIEN_LO_SHIFT   ) 
			|(CSL_TMR_CLKSRC_INTERNAL<<CSL_TMR_TCR_CLKSRC_LO_SHIFT ) 
			/*The timer is enabled continuously*/
			|(CSL_TMR_ENAMODE_CONT<<CSL_TMR_TCR_ENAMODE_LO_SHIFT) 
			|((tmrCfg->pulseWidth<<CSL_TMR_TCR_PWID_LO_SHIFT)&CSL_TMR_TCR_PWID_LO_MASK) 
			/*select clock mode*/
			|(CSL_TMR_CP_CLOCK<<CSL_TMR_TCR_CP_LO_SHIFT     ) 
			|(CSL_TMR_INVINP_UNINVERTED<<CSL_TMR_TCR_INVINP_LO_SHIFT ) 
			|(CSL_TMR_INVOUTP_UNINVERTED<<CSL_TMR_TCR_INVOUTP_LO_SHIFT) 
			|(0<<CSL_TMR_TCR_TSTAT_LO_SHIFT  );
	}
	else if(TIMER_PERIODIC_WAVE==tmrCfg->timerMode)
	{
		gpTimerRegs[tmrCfg->timer_num]->TCR= 
			(CSL_TMR_CLOCK_INP_NOGATE<<CSL_TMR_TCR_TIEN_LO_SHIFT   ) 
			|(CSL_TMR_CLKSRC_INTERNAL<<CSL_TMR_TCR_CLKSRC_LO_SHIFT ) 
			/*The timer is enabled continuously with period reload*/
			|(CSL_TMR_ENAMODE_CONT_RELOAD<<CSL_TMR_TCR_ENAMODE_LO_SHIFT) 
			|((tmrCfg->pulseWidth<<CSL_TMR_TCR_PWID_LO_SHIFT)&CSL_TMR_TCR_PWID_LO_MASK) 
			/*select clock mode*/
			|(CSL_TMR_CP_CLOCK<<CSL_TMR_TCR_CP_LO_SHIFT     ) 
			|(CSL_TMR_INVINP_UNINVERTED<<CSL_TMR_TCR_INVINP_LO_SHIFT ) 
			|(CSL_TMR_INVOUTP_UNINVERTED<<CSL_TMR_TCR_INVOUTP_LO_SHIFT) 
			|(0<<CSL_TMR_TCR_TSTAT_LO_SHIFT  );
	}
	else 	/*TIMER_PERIODIC_PULSE*/
	{
		gpTimerRegs[tmrCfg->timer_num]->TCR= 
			(CSL_TMR_CLOCK_INP_NOGATE<<CSL_TMR_TCR_TIEN_LO_SHIFT   ) 
			|(CSL_TMR_CLKSRC_INTERNAL<<CSL_TMR_TCR_CLKSRC_LO_SHIFT ) 
			/*The timer is enabled continuously*/
			|(CSL_TMR_ENAMODE_CONT<<CSL_TMR_TCR_ENAMODE_LO_SHIFT) 
			|((tmrCfg->pulseWidth<<CSL_TMR_TCR_PWID_LO_SHIFT)&CSL_TMR_TCR_PWID_LO_MASK) 
			/*select clock mode*/
			|(CSL_TMR_CP_PULSE<<CSL_TMR_TCR_CP_LO_SHIFT     ) 
			|(CSL_TMR_INVINP_UNINVERTED<<CSL_TMR_TCR_INVINP_LO_SHIFT ) 
			|(CSL_TMR_INVOUTP_UNINVERTED<<CSL_TMR_TCR_INVOUTP_LO_SHIFT) 
			|(0<<CSL_TMR_TCR_TSTAT_LO_SHIFT  );
	}
}


/*****************************************************************************
 Prototype    : Service_Watchdog
 Description  : Implement the watch dog service
 Input        : int timer_num  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void Service_Watchdog(int timer_num)
{
    /*write sequence of a A5C6h followed by a DA7Eh 
    to services the watchdog timer.*/
    
	gpTimerRegs[timer_num]->WDTCR =
		(CSL_TMR_WDTCR_WDKEY_CMD1<<CSL_TMR_WDTCR_WDKEY_SHIFT);
	gpTimerRegs[timer_num]->WDTCR =
		(CSL_TMR_WDTCR_WDKEY_CMD2<<CSL_TMR_WDTCR_WDKEY_SHIFT);
}

/*===============================PSC===================================*/
/*****************************************************************************
 Prototype    : KeyStone_enable_PSC_module
 Description  : Enable the PSC module in KeyStone device
 Input        : Uint32 pwrDmnNum  
                Uint32 moduleNum  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
Int32 KeyStone_enable_PSC_module (Uint32 pwrDmnNum, Uint32 moduleNum)
{
	Uint32 uiStartCCNT= CP15_read_CCNT();

    if (CSL_PSC_getPowerDomainState(pwrDmnNum) != PSC_PDSTATE_ON)
    {
	    /* Set Power domain to ON */
	    CSL_PSC_enablePowerDomain (pwrDmnNum);
		__asm__(" ISB");

	    /* Start the state transition */
	    CSL_PSC_startStateTransition (pwrDmnNum);
		__asm__(" ISB");

	    /* Wait until the state transition process is completed. */
	    while (!CSL_PSC_isStateTransitionDone (pwrDmnNum))
		{
			if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
			{
				printf("Enable power domain %d timeout! CCNT=0x%x.\n", pwrDmnNum, CP15_read_CCNT());
				return -2;
			}
		}
	}

    if (CSL_PSC_getModuleState (moduleNum) != PSC_MODSTATE_ENABLE)
    {
	    /* Enable the clocks too*/
	    CSL_PSC_setModuleNextState (moduleNum, PSC_MODSTATE_ENABLE);
		__asm__(" ISB");

	    /* Start the state transition */
	    CSL_PSC_startStateTransition (pwrDmnNum);
		__asm__(" ISB");

	    /* Wait until the state transition process is completed. */
	    while (!CSL_PSC_isStateTransitionDone (pwrDmnNum))
		{
			if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
			{
				printf("Enable clock domain %d timeout! CCNT=0x%x.\n", moduleNum, CP15_read_CCNT());
				return -2;
			}
		}
	}
	
    /* Return PSC status */
    if ((CSL_PSC_getPowerDomainState(pwrDmnNum) == PSC_PDSTATE_ON) &&
        (CSL_PSC_getModuleState (moduleNum) == PSC_MODSTATE_ENABLE))
    {
        /*Ready for use */
        return 0;
    }
    else
    {
        /*Return error */
        return -1;
    }
}
/*****************************************************************************
 Prototype    : KeyStone_disable_PSC_module
 Description  : Disable the PSC module in KeyStone device
 Input        : Uint32 pwrDmnNum  
                Uint32 moduleNum  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/2/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
Int32 KeyStone_disable_PSC_module (Uint32 pwrDmnNum, Uint32 moduleNum)
{
	Uint32 uiStartCCNT= CP15_read_CCNT();
	
    if (CSL_PSC_getModuleState (moduleNum) != PSC_MODSTATE_SWRSTDISABLE)
    {
	    /* disable the clocks*/
	    CSL_PSC_setModuleNextState (moduleNum, PSC_MODSTATE_SWRSTDISABLE);
		__asm__(" ISB");

	    /* Start the state transition */
	    CSL_PSC_startStateTransition (pwrDmnNum);
		__asm__(" ISB");

	    /* Wait until the state transition process is completed. */
	    while (!CSL_PSC_isStateTransitionDone (pwrDmnNum))
		{
			if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
			{
				printf("Disable clock domain %d timeout! CCNT=0x%x.\n", moduleNum, CP15_read_CCNT());
				return -2;
			}
		}
	}
	
    /* Return PSC status */
    if (CSL_PSC_getModuleState (moduleNum) == PSC_MODSTATE_SWRSTDISABLE)
    {
        /*Ready for use */
        return 0;
    }
    else
    {
        /*Return error */
        return -1;
    }

}
/*****************************************************************************
 Prototype    : KeyStone_disable_PSC_Power_Domain
 Description  : Disable the PSC power domain
 Input        : Uint32 pwrDmnNum  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
Int32 KeyStone_disable_PSC_Power_Domain (Uint32 pwrDmnNum)
{
	Uint32 uiStartCCNT= CP15_read_CCNT();

    if (CSL_PSC_getPowerDomainState(pwrDmnNum) != PSC_PDSTATE_OFF)
    {
	    /* Set Power domain to OFF */
	    CSL_PSC_disablePowerDomain (pwrDmnNum);
		__asm__(" ISB");

	    /* Start the state transition */
	    CSL_PSC_startStateTransition (pwrDmnNum);
		__asm__(" ISB");

	    /* Wait until the state transition process is completed. */
	    while (!CSL_PSC_isStateTransitionDone (pwrDmnNum))
		{
			if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
			{
				printf("Disable power domain %d timeout!\n", pwrDmnNum);
				return -2;
			}
		}
	}
	
    /* Return PSC status */
    if (CSL_PSC_getPowerDomainState(pwrDmnNum) == PSC_PDSTATE_OFF)
    {
        /*Ready for use */
        return 0;
    }
    else
    {
        /*Return error */
        return -1;
    }

}

/*enable one ARM core through LPSC*/
void K2_ARM_LPSC_eanble(Uint32 uiCoreNum)
{
	K2_ARM_LPSC_Regs * psc_regs;
	psc_regs= (K2_ARM_LPSC_Regs *)&gpARM_regs->PD_CPU0_PTCMD;
	psc_regs += uiCoreNum;

	psc_regs->PDCTL= 0;
	psc_regs->PTCMD= 1;

	delay_ms(5); //wait for a while
}

/*============================EDMA=====================================*/
 /*****************************************************************************
 Prototype    : EDMA_channel_TC_cfg
 Description  : Setup uiChannel of an EDMA to use uiTC
 Input        : Uint32 uiCC  
                Uint32 uiChannel            
                Uint32 uiTC                 
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_channel_TC_cfg (Uint32 uiCC, 
	Uint32 uiChannel, Uint32 uiTC)
{
	gpEDMA_CC_regs[uiCC]->TPCC_DMAQNUM[uiChannel/8] = 
		(gpEDMA_CC_regs[uiCC]->TPCC_DMAQNUM[uiChannel/8]&(~(0xF<<((uiChannel&7)*4))))
		|(uiTC<<((uiChannel&7)*4));
}
/*****************************************************************************
 Prototype    : EDMA_TC_priority_cfg
 Description  : Setup uiChannel of an EDMA TC priority
 Input        : Uint32 uiCC  
                Uint32 uiPri                
                Uint32 uiTC                 
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_TC_priority_cfg(Uint32 uiCC, 
	Uint32 uiPri, Uint32 uiTC)
{
	gpEDMA_CC_regs[uiCC]->TPCC_QUEPRI= 
		(gpEDMA_CC_regs[uiCC]->TPCC_QUEPRI&(~(0xF<<((uiTC&3)*4))))
		|(uiPri<<((uiTC&3)*4));
}
/*****************************************************************************
 Prototype    : EDMA_init
 Description  : Initialize all EDMA registers and clear the event
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_init()
{
	int i, j;
	unsigned int * uipPaRAM;

	for(j=0; j<NUM_EDMA_CC; j++)
	{
		/*clear PaRAM*/
		uipPaRAM= (unsigned int *)&(gpEDMA_CC_regs[j]->PARAMSET[0]);
		for(i=0; i<8*512; i++) 	
			*uipPaRAM++=0;
	}
		
	/*Assign PaRAM for different channels*/
	for(j=0; j<NUM_EDMA_CC; j++)
	{
		for(i=0; i<64; i++) 	
			gpEDMA_CC_regs[j]->TPCC_DCHMAP[i] = i<< CSL_TPCC_TPCC_DCHMAP0_PAENTRY_SHIFT;
	}

	/*Assign TC/Queue for different channels*/
	gpEDMA_CC0_regs->TPCC_DMAQNUM[0]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[1]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[2]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[3]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[4]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[5]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[6]= 0x10101010;
	gpEDMA_CC0_regs->TPCC_DMAQNUM[7]= 0x10101010;

	gpEDMA_CC1_regs->TPCC_DMAQNUM[0]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[1]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[2]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[3]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[4]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[5]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[6]= 0x32103210;
	gpEDMA_CC1_regs->TPCC_DMAQNUM[7]= 0x32103210;

	gpEDMA_CC2_regs->TPCC_DMAQNUM[0]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[1]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[2]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[3]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[4]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[5]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[6]= 0x32103210;
	gpEDMA_CC2_regs->TPCC_DMAQNUM[7]= 0x32103210;

#ifdef CSL_EDMACC_3_REGS
	gpEDMA_CC3_regs->TPCC_DMAQNUM[0]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[1]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[2]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[3]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[4]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[5]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[6]= 0x10101010;
	gpEDMA_CC3_regs->TPCC_DMAQNUM[7]= 0x10101010;
#endif

#ifdef CSL_EDMACC_4_REGS
	gpEDMA_CC4_regs->TPCC_DMAQNUM[0]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[1]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[2]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[3]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[4]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[5]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[6]= 0x10101010;
	gpEDMA_CC4_regs->TPCC_DMAQNUM[7]= 0x10101010;
#endif

	/*clear any events and status*/
	for(j=0; j<NUM_EDMA_CC; j++)
	{
		gpEDMA_CC_regs[j]->TPCC_ECR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_ECRH= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_EECR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_EECRH= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_ICR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_ICRH= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_IECR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_IECRH= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_EMCR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_EMCRH= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_QEMCR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_CCERRCLR= 0xFFFF;
		gpEDMA_CC_regs[j]->TPCC_SECR= 0xFFFFFFFF;
		gpEDMA_CC_regs[j]->TPCC_SECRH= 0xFFFFFFFF;
	}


	for(i=0; i<NUM_EDMA_TC; i++)
	{
		//Clear TC error
		gpEDMA_TC_regs[i]->TPTC_ERRCLR= 0xF;

		//enable error interrupt
		gpEDMA_TC_regs[i]->TPTC_ERREN= 
			(1<<CSL_TPTC_TPTC_ERREN_MMRAERR_SHIFT)
			|(1<<CSL_TPTC_TPTC_ERREN_TRERR_SHIFT)
			|(1<<CSL_TPTC_TPTC_ERREN_BUSERR_SHIFT);
	}
}


void EDMA_event_enable(Uint32 uiCC, Uint32 uiChannel)
{
	if(uiChannel<32)
	{
		//enable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EESR= 1<<(uiChannel);
	}
	else
	{
		//enable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EESRH= 1<<(uiChannel-32);
	}	
}

void EDMA_event_disable(Uint32 uiCC, Uint32 uiChannel)
{
	if(uiChannel<32)
	{
		//disable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EECR= 1<<(uiChannel);
	}
	else
	{
		//disable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EECRH= 1<<(uiChannel-32);
	}	
}

void EDMA_interrupt_enable(Uint32 uiCC, Uint32 uiIntNum)
{
	if(uiIntNum<32)
	{
		//enable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IESR= 1<<(uiIntNum);
	}
	else
	{
		//enable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IESRH= 1<<(uiIntNum-32);
	}	
}

void EDMA_interrupt_disable(Uint32 uiCC, Uint32 uiIntNum)
{
	if(uiIntNum<32)
	{
		//disable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IECR= 1<<(uiIntNum);
	}
	else
	{
		//disable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IECRH= 1<<(uiIntNum-32);
	}	
}

/*****************************************************************************
 Prototype    : EDMA_wait
 Description  : wait the pending EDMA complete
 Input        : EDMA_CC_Channel_Num CC_channel
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/30
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_wait(EDMA_CC_Channel_Num CC_channel)
{
	CSL_TpccRegs*  EDMACCRegs;
	unsigned int uiChannel;
    volatile Uint32 * TPCC_IPR;
    volatile Uint32 * TPCC_ICR;

	EDMACCRegs= gpEDMA_CC_regs[CC_channel>>16];
	uiChannel = CC_channel&0xFF;

	if(uiChannel<32)
	{
		TPCC_IPR= &EDMACCRegs->TPCC_IPR;
		TPCC_ICR= &EDMACCRegs->TPCC_ICR;
	}
	else
	{
		TPCC_IPR= &EDMACCRegs->TPCC_IPRH;
		TPCC_ICR= &EDMACCRegs->TPCC_ICRH;
		uiChannel -= 32;
	}
	
	/*wait for completion*/
	while(0==((*TPCC_IPR)&(1<<(uiChannel))));

	/*clear completion flag*/
	(*TPCC_ICR)= 1<<(uiChannel);
}

/*****************************************************************************
 Prototype    : EDMA_Copy
 Description  : EDMA copy function with manual trigger
 Input        : unsigned int srcAddr     
                unsigned int dstAddr     
                unsigned int byteCount, <64KB   
                EDMA_CC_Channel_Num CC_channel  
                DMA_Wait wait
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/30
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_copy(unsigned int srcAddr, unsigned int dstAddr, 
	unsigned int byteCount, EDMA_CC_Channel_Num CC_channel, DMA_Wait wait)
{
	CSL_TpccRegs*  EDMACCRegs;
	unsigned int uiChannel;
    volatile Uint32 * TPCC_ESR;
    volatile Uint32 * TPCC_IPR;
    volatile Uint32 * TPCC_ICR;

	EDMACCRegs= gpEDMA_CC_regs[CC_channel>>16];
	uiChannel = CC_channel&0xFF;

	EDMACCRegs->PARAMSET[uiChannel].OPT= 
		CSL_EDMA3_OPT_MAKE(CSL_EDMA3_ITCCH_DIS, 
			CSL_EDMA3_TCCH_DIS, 
			CSL_EDMA3_ITCINT_DIS, 
			CSL_EDMA3_TCINT_EN,
			uiChannel,
			CSL_EDMA3_TCC_NORMAL,
			CSL_EDMA3_FIFOWIDTH_NONE, 
			CSL_EDMA3_STATIC_DIS, 
			CSL_EDMA3_SYNC_A, 
			CSL_EDMA3_ADDRMODE_INCR, 
			CSL_EDMA3_ADDRMODE_INCR);
	EDMACCRegs->PARAMSET[uiChannel].SRC= (srcAddr);
	EDMACCRegs->PARAMSET[uiChannel].A_B_CNT=CSL_EDMA3_CNT_MAKE(byteCount&0xFFFF, 1);
	EDMACCRegs->PARAMSET[uiChannel].DST= (dstAddr);
	EDMACCRegs->PARAMSET[uiChannel].SRC_DST_BIDX= 0;
	EDMACCRegs->PARAMSET[uiChannel].LINK_BCNTRLD= CSL_EDMA3_LINKBCNTRLD_MAKE(0xFFFF, 1);
	EDMACCRegs->PARAMSET[uiChannel].SRC_DST_CIDX= 0;
	EDMACCRegs->PARAMSET[uiChannel].CCNT= 1;

	if(uiChannel<32)
	{
		TPCC_ESR= &EDMACCRegs->TPCC_ESR;
		TPCC_IPR= &EDMACCRegs->TPCC_IPR;
		TPCC_ICR= &EDMACCRegs->TPCC_ICR;
	}
	else
	{
		TPCC_ESR= &EDMACCRegs->TPCC_ESRH;
		TPCC_IPR= &EDMACCRegs->TPCC_IPRH;
		TPCC_ICR= &EDMACCRegs->TPCC_ICRH;
		uiChannel -= 32;
	}
	
	/*Manually trigger the EDMA*/
	(*TPCC_ESR)= 1<<(uiChannel);
 
	if(wait)
	{
		/*wait for completion*/
		while(0==((*TPCC_IPR)&(1<<(uiChannel))));

		/*clear completion flag*/
		(*TPCC_ICR)= 1<<(uiChannel);
	}
}

/*****************************************************************************
 Prototype    : EDMA_fill
 Description  : EDMA fill function with manual trigger
 Input        : unsigned int address, must align to 8 bytes boundary     
                unsigned long long data     
                unsigned int byteCount, must be multiple of 8   
                EDMA_CC_Channel_Num CC_channel  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2013/8/11
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_fill(unsigned int address, unsigned long long data, 
	unsigned int byteCount, EDMA_CC_Channel_Num CC_channel)
{
	int i;
	CSL_TpccRegs*  EDMACCRegs;
	unsigned int uiChannel, uiChannelShift, uiBCNT;
    volatile Uint32 * TPCC_ESR;
    volatile Uint32 * TPCC_IPR;
    volatile Uint32 * TPCC_ICR;
    unsigned long long tempBuf[128/8];
    Uint32 tempBufSize=128, headerSize, tailSize;

	if(tempBufSize>byteCount)
		tempBufSize=byteCount;

	for(i=0; i< tempBufSize/8; i++)
		tempBuf[i]= data;

	//CP15_DCacheCleanBuff((unsigned int)tempBuf, 128);

	/*split the transfer into 3 sections at 128 byte boundary*/
	if(address&127)	//header address not start on 128 byte boundary
	{
		headerSize= 128- (address&127);
		if(headerSize>byteCount)
			headerSize=byteCount;
		EDMA_copy((Uint32)tempBuf, address, headerSize, CC_channel, DMA_WAIT);
		address+= headerSize;
		byteCount-= headerSize;
	}

	if(byteCount&&((address+byteCount)&127))//tail address not start on 128 byte boundary
	{
		tailSize= (address+byteCount)&127;
		EDMA_copy((Uint32)tempBuf, address+byteCount-tailSize, tailSize, CC_channel, DMA_WAIT);
		byteCount-= tailSize;
	}
	
	EDMACCRegs= gpEDMA_CC_regs[CC_channel>>16];
	uiChannel = CC_channel&0xFF;
	if(uiChannel<32)
	{
		TPCC_ESR= &EDMACCRegs->TPCC_ESR;
		TPCC_IPR= &EDMACCRegs->TPCC_IPR;
		TPCC_ICR= &EDMACCRegs->TPCC_ICR;
		uiChannelShift= uiChannel;
	}
	else
	{
		TPCC_ESR= &EDMACCRegs->TPCC_ESRH;
		TPCC_IPR= &EDMACCRegs->TPCC_IPRH;
		TPCC_ICR= &EDMACCRegs->TPCC_ICRH;
		uiChannelShift= uiChannel - 32;
	}	

	EDMACCRegs->PARAMSET[uiChannel].OPT= 
		CSL_EDMA3_OPT_MAKE(CSL_EDMA3_ITCCH_DIS, 
			CSL_EDMA3_TCCH_DIS, 
			CSL_EDMA3_ITCINT_DIS, 
			CSL_EDMA3_TCINT_EN,
			uiChannel,
			CSL_EDMA3_TCC_NORMAL,
			CSL_EDMA3_FIFOWIDTH_NONE, 
			CSL_EDMA3_STATIC_EN, //keep PARAM unchanged
			CSL_EDMA3_SYNC_AB, 
			CSL_EDMA3_ADDRMODE_INCR, 
			CSL_EDMA3_ADDRMODE_INCR);
	EDMACCRegs->PARAMSET[uiChannel].SRC= (Uint32)(tempBuf);
	EDMACCRegs->PARAMSET[uiChannel].SRC_DST_BIDX= CSL_EDMA3_BIDX_MAKE(0, 128);
	EDMACCRegs->PARAMSET[uiChannel].LINK_BCNTRLD= CSL_EDMA3_LINKBCNTRLD_MAKE(0xFFFF, 0);
	EDMACCRegs->PARAMSET[uiChannel].SRC_DST_CIDX= 0;
	EDMACCRegs->PARAMSET[uiChannel].CCNT= 1;

	while(byteCount) 	//the reminding must be multiple of 128 bytes
	{
		uiBCNT= byteCount/128;
		if(uiBCNT>65535)
			uiBCNT= 65535;
	
		EDMACCRegs->PARAMSET[uiChannel].A_B_CNT= CSL_EDMA3_CNT_MAKE(128, uiBCNT);
		EDMACCRegs->PARAMSET[uiChannel].DST= (address);
		
		/*Manually trigger the EDMA*/
		(*TPCC_ESR)= 1<<(uiChannelShift);
	 
		/*wait for completion*/
		while(0==((*TPCC_IPR)&(1<<(uiChannelShift))));

		/*clear completion flag*/
		(*TPCC_ICR)= 1<<(uiChannelShift);

		byteCount -= uiBCNT*128;
		address += uiBCNT*128;
	}
}
/*****************************************************************************
 Prototype    : EDMA_CC_error_handler
 Description  : Edma channel controller error processing
 Input        : Uint32 edmaNum, EDMA module number (0~2)  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/11/7
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_CC_error_handler(Uint32 edmaNum)
{
	int i;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[edmaNum];
	Uint32 EMR, EMRH= 0, QEMR, CCERR;

	//read error status
	EMR= EDMACCRegs->TPCC_EMR;
	QEMR= EDMACCRegs->TPCC_QEMR;
	CCERR= EDMACCRegs->TPCC_CCERR;

	//clear error status
	EDMACCRegs->TPCC_EMCR= EMR;
	EDMACCRegs->TPCC_QEMCR= QEMR;
	EDMACCRegs->TPCC_CCERRCLR= CCERR;

	//channel 32~63 for EDMA CC1 and CC2
	if(0<edmaNum)
	{
		//read error status
		EMRH= EDMACCRegs->TPCC_EMRH;

		//clear error status
		EDMACCRegs->TPCC_EMCRH= EMRH;
	}

	for(i=0; i<32; i++)
	{
		if((EMR>>i)&1)
			printf("    EDMA Channel %d event missed.\n", i);
		if((EMRH>>i)&1)
			printf("    EDMA Channel %d event missed.\n", i+32);
	}

	for(i=0; i<8; i++)
	{
		if((QEMR>>i)&1)
			printf("    QDMA Channel %d event missed.\n", i);
	}

	for(i=0; i<4; i++)
	{
		if((CCERR>>i)&1)
			printf("    Queue %d Watermark/threshold has been exceeded.\n", i);
	}

	if(CCERR&CSL_TPCC_TPCC_CCERR_TCCERR_MASK)
		puts("    Total number of allowed TCCs has been reached.");
	
}
/*****************************************************************************
 Prototype    : EDMA_TC_error_handler
 Description  : Edma transfer controller error processing
 Input        : CSL_TptcRegs * edmaTCRegs  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/11/7
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void EDMA_TC_error_handler(CSL_TptcRegs * edmaTCRegs)
{
	Uint32 ERRSTAT, ERRDET, STAT;

	//read error status
	ERRSTAT= edmaTCRegs->TPTC_ERRSTAT;
	ERRDET= edmaTCRegs->TPTC_ERRDET;

	//clear error
	edmaTCRegs->TPTC_ERRCLR= ERRSTAT;

	if(ERRSTAT&CSL_TPTC_TPTC_ERRSTAT_MMRAERR_MASK)
		puts("      User attempted to read or write to an invalid address in configuration memory map.");
	if(ERRSTAT&CSL_TPTC_TPTC_ERRSTAT_TRERR_MASK)
		puts("      TR detected that violates constant addressing mode transfer (SAM or DAM is set) alignment rules or has ACNT or BCNT== 0.");
	if(ERRSTAT&CSL_TPTC_TPTC_ERRSTAT_BUSERR_MASK)
	{
		puts("      EDMA3TC has detected an error at source or destination address.");

		STAT= ERRDET&CSL_TPTC_TPTC_ERRDET_STAT_MASK;

		if(STAT>=8)
			printf("      write error (%d). ",STAT);
		else if(STAT>=1)
			printf("      read error (%d). ",STAT);
		else
			printf("      no error!?");

		printf("TCC= %d. TCINTEN= %d. TCCHEN= %d\n",
			(ERRDET&CSL_TPTC_TPTC_ERRDET_TCC_MASK)>>CSL_TPTC_TPTC_ERRDET_TCC_SHIFT,
			(ERRDET&CSL_TPTC_TPTC_ERRDET_TCINTEN_MASK)>>CSL_TPTC_TPTC_ERRDET_TCINTEN_SHIFT,
			(ERRDET&CSL_TPTC_TPTC_ERRDET_TCCHEN_MASK)>>CSL_TPTC_TPTC_ERRDET_TCCHEN_SHIFT);
	}
		
}
/*****************************************************************************
 Prototype    : EDMA_error_handler
 Description  : EDMA error processing function
 Input        : Uint32 edmaNum    
                Uint32 errorFlag  
					error flag bit fields are defined as below 
					(follow the sequence in CIC)
					0 EDMACC_ERRINT EDMA3CC error interrupt          
					2 EDMATC_ERRINT0 EDMA3TC0 error interrupt
					3 EDMATC_ERRINT1 EDMA3TC1 error interrupt
					4 EDMATC_ERRINT2 EDMA3TC2 error interrupt
					5 EDMATC_ERRINT3 EDMA3TC3 error interrupt
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/28
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void EDMA_error_handler(Uint32 edmaNum, Uint32 errorFlag)
{
	int i;
	
	printf("  EDMA module %d error\n", edmaNum);
	if(errorFlag&1)
		EDMA_CC_error_handler(edmaNum);

	errorFlag >>= 2;

	for(i=0; i<4; i++)
	{
		if(errorFlag&(1<<i))
		{
			printf("    TC %d error happened\n", i);
			if(0==edmaNum)
				EDMA_TC_error_handler(gpEDMA_TC_regs[i]);
			else if(1==edmaNum)
				EDMA_TC_error_handler(gpEDMA_TC_regs[2+i]);
			else if(2==edmaNum)
				EDMA_TC_error_handler(gpEDMA_TC_regs[6+i]);
			else if(3==edmaNum)
				EDMA_TC_error_handler(gpEDMA_TC_regs[10+i]);
			else if(4==edmaNum)
				EDMA_TC_error_handler(gpEDMA_TC_regs[12+i]);
		}
	}
}

/*============================ARM MMU with long format========================*/
/*all internal memories and registers are listed as following, they will be mapped 
flat as device by MMU translation table initialization function*/
#if defined(DEVICE_K2E)
MMU_Memory_Segment MMU_default_flat_map[]=
{
        {0x00000000, 256*1024    },    /*ARM ROM                         */
        {0x01000000, 64*1024     },    /*ARM AXI2VBUSM registers         */
        {0x01100000, 64*1024     },    /*ARM STM Stimulus Ports          */
        {0x01D00000, 128         },    /*Tracer CFG0                     */
        {0x01D08000, 128         },    /*Tracer CFG1                     */
        {0x01D10000, 128         },    /*Tracer CFG2                     */
        {0x01D18000, 128         },    /*Tracer CFG3                     */
        {0x01D20000, 128         },    /*Tracer CFG4                     */
        {0x01D28000, 128         },    /*Tracer CFG5                     */
        {0x01D30000, 128         },    /*Tracer CFG6                     */
        {0x01D38000, 128         },    /*Tracer CFG7                     */
        {0x01D40000, 128         },    /*Tracer CFG8                     */
        {0x01D48000, 128         },    /*Tracer CFG9                     */
        {0x01DA0000, 128         },    /*Tracer CFG20                    */
        {0x01DB0000, 128         },    /*Tracer CFG22                    */
        {0x01DC0000, 128         },    /*Tracer CFG24                    */
        {0x01DC8000, 128         },    /*Tracer CFG25                    */
        {0x01DD0000, 128         },    /*Tracer CFG26                    */
        {0x01DD8000, 128         },    /*Tracer CFG27                    */
        {0x01DE0000, 128         },    /*Tracer CFG28                    */
        {0x01DE0400, 128         },    /*Tracer CFG29                    */
        {0x01DE0800, 128         },    /*Tracer CFG30                    */
        {0x01DE8000, 128         },    /*Tracer CFG31                    */
        {0x01E40000, 256*1024    },    /*TSIP_CFG                        */
        {0x01E80000, 16*1024     },    /*ARM CorePac_CFG                 */
        {0x02000000, 1*1024*1024 },    /*Network Coprocessor 0(Packet    */
        {0x021D0000, 1*1024      },    /*Memory protection unit (MPU) 15 */
        {0x021D0400, 128         },    /*Tracer CFG32                    */
        {0x02200000, 128         },    /*Timer 0                         */
        {0x02280000, 128         },    /*Timer 8                         */
        {0x02290000, 128         },    /*Timer 9                         */
        {0x022A0000, 128         },    /*Timer 10                        */
        {0x022B0000, 128         },    /*Timer 11                        */
        {0x022C0000, 128         },    /*Timer 12                        */
        {0x022D0000, 128         },    /*Timer 13                        */
        {0x022E0000, 128         },    /*Timer 14                        */
        {0x022F0000, 128         },    /*Timer 15                        */
        {0x022F0080, 128         },    /*Timer 16                        */
        {0x022F0100, 128         },    /*Timer 17                        */
        {0x022F0180, 128         },    /*Timer 18                        */
        {0x022F0200, 128         },    /*Timer 19                        */
        {0x02310000, 512         },    /*PLL Controller                  */
        {0x0231A000, 8*1024      },    /*HyperLink0 SerDes Config        */
        {0x0231E000, 8*1024      },    /*10GbE SerDes Config             */
        {0x02320000, 16*1024     },    /*PCIe0 SerDes Config             */
        {0x02324000, 8*1024      },    /*SGMII 1 SerDes Config           */
        {0x02325000, 8*1024      },    /*PCIe1SerDes Config              */
        {0x02329000, 4*1024      },    /*DDRA PHY Config                 */
        {0x0232A000, 8*1024      },    /*SGMII 0 SerDes Config           */
        {0x02330000, 1*1024      },    /*SmartReflex0                    */
        {0x02350000, 4*1024      },    /*Power sleep controller (PSC)    */
        {0x02360000, 1*1024      },    /*Memory protection unit (MPU) 0  */
        {0x02368000, 1*1024      },    /*Memory protection unit (MPU) 1  */
        {0x02370000, 1*1024      },    /*Memory protection unit (MPU) 2  */
        {0x02388000, 1*1024      },    /*Memory protection unit (MPU) 5  */
        {0x02388800, 1*1024      },    /*Memory protection unit (MPU) 7  */
        {0x02388C00, 1*1024      },    /*Memory protection unit (MPU) 8  */
        {0x02389000, 1*1024      },    /*Memory protection unit (MPU) 9  */
        {0x02389400, 1*1024      },    /*Memory protection unit (MPU) 10 */
        {0x02389800, 1*1024      },    /*Memory protection unit (MPU) 11 */
        {0x02389C00, 1*1024      },    /*Memory protection unit (MPU) 12 */
        {0x0238A000, 1*1024      },    /*Memory protection unit (MPU) 13 */
        {0x0238A400, 1*1024      },    /*Memory protection unit (MPU) 14 */
        {0x02440000, 16*1024     },    /*DSP trace formatter 0           */
        {0x02530000, 128         },    /*I2C 0                           */
        {0x02530400, 128         },    /*I2C 1                           */
        {0x02530800, 128         },    /*I2C 2                           */
        {0x02530C00, 64          },    /*UART0                           */
        {0x02531000, 64          },    /*UART1                           */
        {0x02560080, 128*1024    },    /*ARM CorePac INTC                */
        {0x02600000, 8*1024      },    /*Secondary interrupt controller 0*/
        {0x02608000, 8*1024      },    /*Secondary interrupt controller 2*/
        {0x0260BF00, 256         },    /*GPIO Config                     */
        {0x02620000, 4*1024      },    /*BOOTCFG chip-level registers    */
        {0x02630000, 64*1024     },    /*USB 0 PHY CFG                   */
        {0x02640000, 2*1024      },    /*Semaphore Config                */
        {0x02680000, 512*1024    },    /*USB 0 MMR CFG                   */
        {0x02700000, 32*1024     },    /*EDMA channel controller (TPCC) 0*/
        {0x02708000, 32*1024     },    /*EDMA channel controller (TPCC) 4*/
        {0x02720000, 32*1024     },    /*EDMA channel controller (TPCC) 1*/
        {0x02728000, 32*1024     },    /*EDMA channel controller (TPCC) 3*/
        {0x02740000, 32*1024     },    /*EDMA channel controller (TPCC) 2*/
        {0x02760000, 1*1024      },    /*EDMA TPCC0 transfer controller  */
        {0x02768000, 1*1024      },    /*EDMA TPCC0 transfer controller  */
        {0x02770000, 1*1024      },    /*EDMA TPCC1 transfer controller  */
        {0x02778000, 1*1024      },    /*EDMA TPCC1 transfer controller  */
        {0x02780000, 1*1024      },    /*EDMA TPCC1 transfer controller  */
        {0x02788000, 1*1024      },    /*EDMA TPCC1 transfer controller  */
        {0x02790000, 1*1024      },    /*EDMA TPCC2 transfer controller  */
        {0x02798000, 1*1024      },    /*EDMA TPCC2 transfer controller  */
        {0x027A0000, 1*1024      },    /*EDMA TPCC2 transfer controller  */
        {0x027A8000, 1*1024      },    /*EDMA TPCC2 transfer controller  */
        {0x027B0000, 1*1024      },    /*EDMA TPCC3 transfer controller  */
        {0x027B8000, 1*1024      },    /*EDMA TPCC3 transfer controller  */
        {0x027B8400, 1*1024      },    /*EDMA TPCC4 transfer controller  */
        {0x027B8800, 1*1024      },    /*EEDMA TPCC4 transfer controller */
        {0x027D0000, 16*1024     },    /*TI embedded trace buffer (TETB) */
        {0x027D4000, 16*1024     },    /*TBR_ARM CorePac - Trace buffer -*/
        {0x02850000, 32*1024     },    /*TBR_SYS- Trace buffer - System  */
        {0x02A00000, 1*1024*1024 },    /*Navigator configuration         */
        {0x02B00000, 1*1024*1024 },    /*Navigator linking RAM           */
        {0x02F00000, 1*1024*1024 },    /*10GbE Config                    */
        {0x03000000, 1*1024*1024 },    /*DBG Config                      */
        {0x08000000, 128*1024    },    /*Extended memory controller      */
        {0x0BC00000, 1*1024*1024 },    /*Multicore shared memory         */
        {0x0C000000, 2*1024*1024 },    /*Multicore shared memory (MSM)   */
        {0x10800000, 512*1024    },    /*CorePac0 L2 SRAM                */
        {0x10E00000, 32*1024     },    /*CorePac0 L1P SRAM               */
        {0x10F00000, 32*1024     },    /*CorePac0 L1D SRAM               */
        {0x20000000, 1*1024*1024 },    /*System trace manager (STM)      */
        {0x20600000, 1*1024*1024 },    /*Network Coprocessor 1(Packet    */
        {0x20700000, 512*1024    },    /*USB 1 MMR CFG                   */
        {0x20780000, 64*1024     },    /*USB 1 PHY CFG                   */
        {0x20B00000, 256*1024    },    /*Boot ROM                        */
        {0x21000400, 512         },    /*SPI0                            */
        {0x21000600, 512         },    /*SPI1                            */
        {0x21000800, 512         },    /*SPI2                            */
        {0x21000A00, 256         },    /*EMIF Config                     */
        {0x21010000, 512         },    /*DDR3A EMIF Config               */
        {0x21020000, 32*1024     },    /*PCIe 1config                    */
        {0x21400000, 256         },    /*HyperLink0 config               */
        {0x21800000, 32*1024     },    /*PCIe 0 config                   */
        {0x23A00000, 2*1024*1024 },    /*Navigator                       */
        {0x24000000, 16*1024*1024},    /*NETCP15 config                  */
        {0x25000000, 512*1024    },    /*USB1 MMR config                 */
        {0x25080000, 64*1024     }     /*USB1 PHY config                 */
};
#elif defined(DEVICE_K2L)
MMU_Memory_Segment MMU_default_flat_map[]=
{
        {0x00000000, 256*1024},         /*ARM ROM                         */
        {0x01000000, 64*1024},          /*ARM AXI2VBUSM Master            */
        {0x01100000, 64*1024},          /*ARM STM Stimulus Ports          */
        {0x01D00000, 128},              /*Tracer CFG0                     */
        {0x01D08000, 128},              /*Tracer CFG1                     */
        {0x01D10000, 128},              /*Tracer CFG2                     */
        {0x01D18000, 128},              /*Tracer CFG3                     */
        {0x01D20000, 128},              /*Tracer CFG23                    */
        {0x01D28000, 128},              /*Tracer CFG8                     */
        {0x01D30000, 128},              /*Tracer CFG20                    */
        {0x01D38000, 128},              /*Tracer CFG21                    */
        {0x01D40000, 128},              /*Tracer CFG25                    */
        {0x01D48000, 128},              /*Tracer CFG09                    */
        {0x01D50000, 128},              /*Tracer CFG10                    */
        {0x01D58000, 128},              /*Tracer CFG11                    */
        {0x01D60000, 128},              /*Tracer CFG12                    */
        {0x01D88000, 128},              /*Tracer CFG26                    */
        {0x01D90000, 128},              /*Tracer CFG27                    */
        {0x01D98000, 128},              /*Tracer CFG28                    */
        {0x01DA0000, 128},              /*Tracer CFG22                    */
        {0x01DB0000, 128},              /*Tracer CFG31                    */
        {0x01DC0000, 128},              /*Tracer CFG17                    */
        {0x01DC8000, 128},              /*Tracer CFG18                    */
        {0x01DD0000, 128},              /*Tracer CFG19                    */
        {0x01DD8000, 128},              /*Tracer CFG4                     */
        {0x01DE0000, 128},              /*Tracer CFG5                     */
        {0x01DE0400, 128},              /*Tracer CFG6                     */
        {0x01DE0800, 128},              /*Tracer CFG7                     */
        {0x01DE8000, 128},              /*Tracer CFG24                    */
        {0x01E80000, 16*1024},          /*ARM CorePac VBUSP Memory        */
        {0x02100000, 64*1024},          /*RAC - FEI configuration         */
        {0x02110000, 64*1024},          /*RAC - BEI configuration         */
        {0x02120000, 128*1024},         /*RAC - GCCP 0 configuration      */
        {0x02140000, 128*1024},         /*RAC - GCCP 1 configuration      */
        {0x021C0000, 1*1024},           /*TCP3d_0 configuration           */
        {0x021C8000, 1*1024},           /*TCP3d_1 configuration           */
        {0x021D0000, 256},              /*VCP2_0 configuration            */
        {0x021D4000, 256},              /*VCP2_1 configuration            */
        {0x021D8000, 256},              /*VCP2_2 configuration            */
        {0x021DC000, 256},              /*VCP2_3 configuration            */
        {0x021F0000, 2*1024},           /*FFTC_0 configuration            */
        {0x021F4000, 2*1024},           /*FFTC_1 configuration            */
        {0x02200000, 128},              /*Timer 0                         */
        {0x02210000, 128},              /*Timer 1                         */
        {0x02220000, 128},              /*Timer 2                         */
        {0x02230000, 128},              /*Timer 3                         */
        {0x02280000, 128},              /*Timer 8                         */
        {0x02290000, 128},              /*Timer 9                         */
        {0x022A0000, 128},              /*Timer 10                        */
        {0x022B0000, 128},              /*Timer 11                        */
        {0x022C0000, 128},              /*Timer 12                        */
        {0x022D0000, 128},              /*Timer 13                        */
        {0x022E0000, 128},              /*Timer 14                        */
        {0x022F0000, 128},              /*Timer 15                        */
        {0x022F0080, 128},              /*Timer 16                        */
        {0x022F0100, 128},              /*Timer 17                        */
        {0x02310000, 512},              /*PLL Controller                  */
        {0x02320000, 8*1024},           /*CSISC2 SerDes Config 3          */
        {0x02324000, 8*1024},           /*CSISC2 SerDes Config 0          */
        {0x02326000, 4*1024},           /*CSISC2 SerDes Config 1          */
        {0x02329000, 4*1024},           /*DDRA PHY Config                 */
        {0x0232A000, 8*1024},           /*CSISC2 SerDes Config 2          */
        {0x02330000, 1*1024},           /*SmartReflex0                    */
        {0x02340000, 1*1024},           /*Memory protection unit (MPU)    */
        {0x02340800, 128},              /*Tracer CFG30                    */
        {0x02348000, 256},              /*GPIO1 configuration             */
        {0x02348400, 64},               /*UART2 configuration             */
        {0x02348800, 64},               /*UART3 configuration             */
        {0x02348C00, 1*1024},           /*OSR configuration               */
        {0x02350000, 4*1024},           /*Power sleep controller (PSC)    */
        {0x02360000, 1*1024},           /*Memory protection unit (MPU) 0  */
        {0x02368000, 1*1024},           /*Memory protection unit (MPU) 1  */
        {0x02370000, 1*1024},           /*Memory protection unit (MPU) 2  */
        {0x02378000, 1*1024},           /*Memory protection unit (MPU) 3  */
        {0x02380000, 1*1024},           /*Memory protection unit (MPU) 4  */
        {0x02388000, 1*1024},           /*Memory protection unit (MPU) 5  */
        {0x02388400, 1*1024},           /*Memory protection unit (MPU) 6  */
        {0x02388800, 1*1024},           /*Memory protection unit (MPU) 7  */
        {0x02388C00, 1*1024},           /*Memory protection unit (MPU) 8  */
        {0x02389000, 1*1024},           /*Memory protection unit (MPU) 9  */
        {0x02389400, 1*1024},           /*Memory protection unit (MPU) 10 */
        {0x02389800, 1*1024},           /*Memory protection unit (MPU) 11 */
        {0x02389C00, 1*1024},           /*Memory protection unit (MPU) 12 */
        {0x0238A000, 1*1024},           /*Memory protection unit (MPU) 13 */
        {0x0238A400, 1*1024},           /*Memory protection unit (MPU) 14 */
        {0x02440000, 16*1024},          /*DSP trace formatter 0           */
        {0x02450000, 16*1024},          /*DSP trace formatter 1           */
        {0x02460000, 16*1024},          /*DSP trace formatter 2           */
        {0x02470000, 16*1024},          /*DSP trace formatter 3           */
        {0x02530000, 128},              /*I2C 0                           */
        {0x02530400, 128},              /*I2C 1                           */
        {0x02530800, 128},              /*I2D 2                           */
        {0x02530C00, 64},               /*UART0                           */
        {0x02531000, 64},               /*UART1                           */
        {0x02540000, 128*1024},         /*BCP                             */
        {0x02560000, 128*1024},         /*ARM CorePac INTC (GIC400)       */
        {0x02580000, 256*1024},         /*TAC                             */
        {0x02600000, 8*1024},           /*Secondary interrupt controller 0*/
        {0x02608000, 8*1024},           /*Secondary interrupt controller 2*/
        {0x0260BF00, 256},              /*GPIO Config                     */
        {0x02620000, 4*1024},           /*BOOTCFG chip-level registers    */
        {0x02630000, 64*1024},          /*USB PHY Config                  */
        {0x02640000, 2*1024},           /*Semaphore Config                */
        {0x02680000, 512*1024},         /*USB MMR Config                  */
        {0x02700000, 32*1024},          /*EDMA channel controller (TPCC)  */
        {0x02720000, 32*1024},          /*EDMA channel controller (TPCC)  */
        {0x02740000, 32*1024},          /*EDMA channel controller (TPCC)  */
        {0x02760000, 1*1024},           /*EDMA TPCC0 transfer controller  */
        {0x02768000, 1*1024},           /*EDMA TPCC0 transfer controller  */
        {0x02770000, 1*1024},           /*EDMA TPCC1 transfer controller  */
        {0x02778000, 1*1024},           /*EDMA TPCC1 transfer controller  */
        {0x02780000, 1*1024},           /*EDMA TPCC1 transfer controller  */
        {0x02788000, 1*1024},           /*EDMA TPCC1 transfer controller  */
        {0x02790000, 1*1024},           /*EDMA TPCC2 transfer controller  */
        {0x02798000, 1*1024},           /*EDMA TPCC2 transfer controller  */
        {0x027A0000, 1*1024},           /*EDMA TPCC2 transfer controller  */
        {0x027A8000, 1*1024},           /*EDMA TPCC2 transfer controller  */
        {0x027D0000, 16*1024},          /*TI embedded trace buffer (TETB) */
        {0x027D4000, 16*1024},          /*TBR ARM CorePac - Trace buffer -*/
        {0x027E0000, 16*1024},          /*TI embedded trace buffer (TETB) */
        {0x027F0000, 16*1024},          /*TI embedded trace buffer (TETB) */
        {0x02800000, 16*1024},          /*TI embedded trace buffer (TETB) */
        {0x02850000, 32*1024},          /*TBR_SYS-Trace Buffer -System    */
        {0x02A00000, 1*1024*1024},      /*Navigator configuration         */
        {0x02B00000, 1*1024*1024},      /*Navigator linking RAM           */
        {0x03000000, 1*1024*1024},      /*Debug_SS Configuration          */
        {0x08000000, 128*1024},         /*Extended memory controller      */
        {0x0BC00000, 1*1024*1024},      /*Multicore shared memory         */
        {0x0C000000, 2*1024*1024},      /*Multicore shared memory (MSM)   */
        {0x10800000, 1*1024*1024},      /*CorePac0 L2 SRAM                */
        {0x10E00000, 32*1024},          /*CorePac0 L1P SRAM               */
        {0x10F00000, 32*1024},          /*CorePac0 L1D SRAM               */
        {0x11800000, 1*1024*1024},      /*CorePac1 L2 SRAM                */
        {0x11E00000, 32*1024},          /*CorePac1 L1P SRAM               */
        {0x11F00000, 32*1024},          /*CorePac1 L1D SRAM               */
        {0x12800000, 1*1024*1024},      /*CorePac2 L2 SRAM                */
        {0x12E00000, 32*1024},          /*CorePac2 L1P SRAM               */
        {0x12F00000, 32*1024},          /*CorePac2 L1D SRAM               */
        {0x13800000, 1*1024*1024},      /*CorePac3 L2 SRAM                */
        {0x13E00000, 32*1024},          /*CorePac3 L1P SRAM               */
        {0x13F00000, 32*1024},          /*CorePac3 L1D SRAM               */
        {0x20000000, 1*1024*1024},      /*System trace manager (STM)      */
        {0x20600000, 1*1024*1024},      /*TCP3d_1 data                    */
        {0x20800000, 1*1024*1024},      /*TCP3d_0 data                    */
        {0x20B00000, 256*1024},         /*Boot ROM                        */
        {0x21000400, 512},              /*SPI0                            */
        {0x21000600, 512},              /*SPI1                            */
        {0x21000800, 512},              /*SPI2                            */
        {0x21000A00, 256},              /*AEMIF Config                    */
        {0x21010000, 512},              /*DDR3A EMIF                      */
        {0x21020000, 32*1024},          /*PCIe1 config                    */
        {0x21800000, 32*1024},          /*PCIe0 config                    */
        {0x22A00000, 64*1024},          /*VCP2_0 Data                     */
        {0x22B00000, 64*1024},          /*VCP2_1 Data                     */
        {0x22C00000, 64*1024},          /*VCP2_2 Data                     */
        {0x22D00000, 64*1024},          /*VCP2_3 Data                     */
        {0x23200000, 256*1024},         /*TAC BEI                         */
        {0x23A00000, 2*1024*1024},      /*Navigator                       */
        {0x24000000, 32*1024*1024},     /*DFE configuration               */
        {0x26000000, 16*1024*1024},     /*NetCP configuration             */
        {0x27000000, 4*1024*1024},      /*IQNet configuration             */
        {0x70000000, 1*1024*1024}       /*OSR data                        */
};
#elif defined(DEVICE_K2H) || defined(DEVICE_K2K)
MMU_Memory_Segment MMU_default_flat_map[]=
{
        {0x00000000, 256*1024},         /*ARM ROM                        */
        {0x01000000, 64*1024},          /*ARM AXI2VBUSM Master           */ 
        {0x01100000, 64*1024},          /*ARM STM Stimulus Ports         */ 
        {0x01D00000, 128},              /*Tracer_MSMC0_CFG               */ 
        {0x01D08000, 128},              /*Tracer_MSMC1_CFG               */ 
        {0x01D10000, 128},              /*Tracer_MSMC2_CFG               */ 
        {0x01D18000, 128},              /*Tracer_MSMC3_CFG               */ 
        {0x01D20000, 128},              /*Tracer_QM_M_CFG                */ 
        {0x01D28000, 128},              /*Tracer_DDR3A_CFG               */ 
        {0x01D30000, 128},              /*Tracer_SM_CFG                  */ 
        {0x01D38000, 128},              /*Tracer_QM_CFG1_CFG             */ 
        {0x01D40000, 128},              /*Tracer_CFG_CFG                 */ 
        {0x01D48000, 128},              /*Tracer_L2_0_CFG                */ 
        {0x01D50000, 128},              /*Tracer_L2_1_CFG                */ 
        {0x01D58000, 128},              /*Tracer_L2_2_CFG                */ 
        {0x01D60000, 128},              /*Tracer_L2_3_CFG                */ 
        {0x01D68000, 128},              /*Tracer_L2_4_CFG                */ 
        {0x01D70000, 128},              /*Tracer_L2_5_CFG                */ 
        {0x01D78000, 128},              /*Tracer_L2_6_CFG                */ 
        {0x01D80000, 128},              /*Tracer_L2_7_CFG                */ 
        {0x01D88000, 128},              /*Tracer_RAC_FEI_CFG             */ 
        {0x01D90000, 128},              /*Tracer_RAC_CFG1_CFG            */ 
        {0x01D98000, 128},              /*Tracer_TAC_BE_CFG              */ 
        {0x01DA0000, 128},              /*Tracer_QM_CFG2_CFG             */ 
        {0x01DA8000, 128},              /*Tracer_RAC_CFG2_CFG            */ 
        {0x01DB0000, 128},              /*Tracer_DDR3B_CFG               */ 
        {0x01DB8000, 128},              /*Tracer_BCR_CFG_CFG             */ 
        {0x01DC0000, 128},              /*Tracer_TPCC0_4_CFG             */ 
        {0x01DC8000, 128},              /*Tracer_TPCC1_2_3_CFG           */ 
        {0x01DD0000, 128},              /*Tracer_INTC_CFG                */ 
        {0x01DD8000, 128},              /*Tracer_MSMC4_CFG               */ 
        {0x01DE0000, 128},              /*Tracer_MSMC5_CFG               */ 
        {0x01DE0400, 128},              /*Tracer_MSMC6_CFG               */ 
        {0x01DE0800, 128},              /*Tracer_MSMC7_CFG               */ 
        {0x01DE8000, 128},              /*Tracer_SPI_ROM_EMIF16_CFG      */ 
        {0x01E80000, 16*1024},          /*ARM CorePac VBUSP Memory       */ 
        {0x01F00000, 512*1024},         /*AIF2 control                   */ 
        {0x01F80000, 64*1024},          /*RAC_1 - FEI control            */ 
        {0x01F90000, 64*1024},          /*RAC_1 - BEI control            */ 
        {0x01FA0000, 128*1024},         /*RAC_1 - GCCP 0 control         */ 
        {0x01FC0000, 128*1024},         /*RAC_1 - GCCP 1 control         */ 
        {0x02000000, 1*1024*1024},      /*Network Coprocessor (Packet    */ 
        {0x02100000, 64*1024},          /*RAC_0 - FEI control            */ 
        {0x02110000, 64*1024},          /*RAC_0 - BEI control            */ 
        {0x02120000, 128*1024},         /*RAC_0 - GCCP 0 control         */ 
        {0x02140000, 128*1024},         /*RAC_0 - GCCP 1 control         */ 
        {0x021C0000, 1*1024},           /*TCP3d_0                        */ 
        {0x021C4000, 1*1024},           /*TCP3d_2                        */ 
        {0x021C6000, 1*1024},           /*TCP3d_3                        */ 
        {0x021C8000, 1*1024},           /*TCP3d_1                        */ 
        {0x021D0000, 256},              /*VCP2_0 configuration           */ 
        {0x021D4000, 256},              /*VCP2_1 configuration           */ 
        {0x021D8000, 256},              /*VCP2_2 configuration           */ 
        {0x021DC000, 256},              /*VCP2_3 configuration           */ 
        {0x021DF000, 128},              /*USIM configuration             */ 
        {0x021F0000, 2*1024},           /*FFTC_0 configuration           */ 
        {0x021F0800, 2*1024},           /*FFTC_4 configuration           */ 
        {0x021F1000, 2*1024},           /*FFTC_5 configuration           */ 
        {0x021F4000, 2*1024},           /*FFTC_1 configuration           */ 
        {0x021F8000, 2*1024},           /*FFTC_2 configuration           */ 
        {0x021FC000, 2*1024},           /*FFTC_3 configuration           */ 
        {0x02200000, 128},              /*Timer0                         */ 
        {0x02210000, 128},              /*Timer1                         */ 
        {0x02220000, 128},              /*Timer2                         */ 
        {0x02230000, 128},              /*Timer3                         */ 
        {0x02240000, 128},              /*Timer4                         */ 
        {0x02250000, 128},              /*Timer5                         */ 
        {0x02260000, 128},              /*Timer6                         */ 
        {0x02270000, 128},              /*Timer7                         */ 
        {0x02280000, 128},              /*Timer8                         */ 
        {0x02290000, 128},              /*Timer9                         */ 
        {0x022A0000, 128},              /*Timer10                        */ 
        {0x022B0000, 128},              /*Timer11                        */ 
        {0x022C0000, 128},              /*Timer12                        */ 
        {0x022D0000, 128},              /*Timer13                        */ 
        {0x022E0000, 128},              /*Timer14                        */ 
        {0x022F0000, 128},              /*Timer15                        */ 
        {0x022F0080, 128},              /*Timer16                        */ 
        {0x022F0100, 128},              /*Timer17                        */ 
        {0x022F0180, 128},              /*Timer18                        */ 
        {0x022F0200, 128},              /*Timer19                        */ 
        {0x02310000, 512},              /*PLL Controller                 */ 
        {0x0231A000, 8*1024},           /*HyperLink0 SerDes Config       */ 
        {0x0231C000, 8*1024},           /*HyperLink1 SerDes Config       */ 
        {0x0231E000, 8*1024},           /*10GbE SerDes Config            */ 
        {0x02320000, 16*1024},          /*PCIE SerDes Config             */ 
        {0x02324000, 8*1024},           /*AIF2 SerDes B4 Config          */ 
        {0x02326000, 8*1024},           /*AIF2 SerDes B8 Config          */ 
        {0x02328000, 4*1024},           /*DDRB PHY Config                */ 
        {0x02329000, 4*1024},           /*DDRA PHY Config                */ 
        {0x0232A000, 8*1024},           /*SGMII SerDes Config            */ 
        {0x0232C000, 4*1024},           /*SRIO SerDes Config             */ 
        {0x02330000, 1*1024},           /*SmartReflex0                   */ 
        {0x02330400, 1*1024},           /*SmartReflex1                   */ 
        {0x02340000, 256},              /*VCP2_4 configuration           */ 
        {0x02344000, 256},              /*VCP2_5 configuration           */ 
        {0x02348000, 256},              /*VCP2_6 configuration           */ 
        {0x0234C000, 256},              /*VCP2_7 configuration           */ 
        {0x02350000, 4*1024},           /*Power sleep controller (PSC)   */ 
        {0x02360000, 1*1024},           /*Memory protection unit (MPU) 0 */ 
        {0x02368000, 1*1024},           /*Memory protection unit (MPU) 1 */ 
        {0x02370000, 1*1024},           /*Memory protection unit (MPU) 2 */ 
        {0x02378000, 1*1024},           /*Memory protection unit (MPU) 3 */ 
        {0x02380000, 1*1024},           /*Memory protection unit (MPU) 4 */ 
        {0x02388000, 1*1024},           /*Memory protection unit (MPU) 5 */ 
        {0x02388400, 1*1024},           /*Memory protection unit (MPU) 6 */ 
        {0x02388800, 1*1024},           /*Memory protection unit (MPU) 7 */ 
        {0x02388C00, 1*1024},           /*Memory protection unit (MPU) 8 */ 
        {0x02389000, 1*1024},           /*Memory protection unit (MPU) 9 */ 
        {0x02389400, 1*1024},           /*Memory protection unit (MPU) 10*/ 
        {0x02389800, 1*1024},           /*Memory protection unit (MPU) 11*/ 
        {0x02389C00, 1*1024},           /*Memory protection unit (MPU) 12*/ 
        {0x0238A000, 1*1024},           /*Memory protection unit (MPU) 13*/ 
        {0x0238A400, 1*1024},           /*Memory protection unit (MPU) 14*/ 
        {0x02440000, 16*1024},          /*DSP trace formatter 0          */ 
        {0x02450000, 16*1024},          /*DSP trace formatter 1          */ 
        {0x02460000, 16*1024},          /*DSP trace formatter 2          */ 
        {0x02470000, 16*1024},          /*DSP trace formatter 3          */ 
        {0x02480000, 16*1024},          /*DSP trace formatter 4          */ 
        {0x02490000, 16*1024},          /*DSP trace formatter 5          */ 
        {0x024A0000, 16*1024},          /*DSP trace formatter 6          */ 
        {0x024B0000, 16*1024},          /*DSP trace formatter 7          */ 
        {0x02530000, 128},              /*I2C 0                          */ 
        {0x02530400, 128},              /*I2C 1                          */ 
        {0x02530800, 128},              /*I2C 2                          */ 
        {0x02530C00, 64},               /*UART0                          */ 
        {0x02531000, 64},               /*UART1                          */ 
        {0x02540000, 128*1024},         /*BCP                            */ 
        {0x02560000, 128*1024},         /*ARM CorePac INTC (GIC400)      */ 
        {0x02580000, 512*1024},         /*TAC                            */ 
        {0x02600000, 8*1024},           /*Secondary interrupt controller0*/ 
        {0x02604000, 8*1024},           /*Secondary interrupt controller1*/ 
        {0x02608000, 8*1024},           /*Secondary interrupt controller2*/ 
        {0x0260BF00, 256},              /*GPIO Config                    */ 
        {0x02620000, 4*1024},           /*BOOTCFG chip-level registers   */ 
        {0x02630000, 64*1024},          /*USB PHY Config                 */ 
        {0x02640000, 2*1024},           /*Semaphore Config               */ 
        {0x02680000, 512*1024},         /*USB MMR Config                 */ 
        {0x02700000, 32*1024},          /*EDMA channel controller (TPCC) */ 
        {0x02708000, 32*1024},          /*EDMA channel controller (TPCC) */ 
        {0x02720000, 32*1024},          /*EDMA channel controller (TPCC) */ 
        {0x02728000, 32*1024},          /*EDMA channel controller (TPCC) */ 
        {0x02740000, 32*1024},          /*EDMA channel controller (TPCC) */ 
        {0x02760000, 1*1024},           /*EDMA TPCC0 transfer controller */ 
        {0x02768000, 1*1024},           /*EDMA TPCC0 transfer controller */ 
        {0x02770000, 1*1024},           /*EDMA TPCC1 transfer controller */ 
        {0x02778000, 1*1024},           /*EDMA TPCC1 transfer controller */ 
        {0x02780000, 1*1024},           /*EDMA TPCC1 transfer controller */ 
        {0x02788000, 1*1024},           /*EDMA TPCC1 transfer controller */ 
        {0x02790000, 1*1024},           /*EDMA TPCC2 transfer controller */ 
        {0x02798000, 1*1024},           /*EDMA TPCC2 transfer controller */ 
        {0x027A0000, 1*1024},           /*EDMA TPCC2 transfer controller */ 
        {0x027A8000, 1*1024},           /*EDMA TPCC2 transfer controller */ 
        {0x027B0000, 1*1024},           /*EDMA TPCC3 transfer controller */ 
        {0x027B8000, 1*1024},           /*EDMA TPCC3 transfer controller */ 
        {0x027B8400, 1*1024},           /*EDMA TPCC4 transfer controller */ 
        {0x027B8800, 1*1024},           /*EEDMA TPCC4 transfer controller*/ 
        {0x027C0000, 1*1024},           /*BCR config                     */ 
        {0x027D0000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x027D4000, 16*1024},          /*TBR ARM CorePac - Trace buffer */ 
        {0x027E0000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x027F0000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02800000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02810000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02820000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02830000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02840000, 16*1024},          /*TI embedded trace buffer (TETB)*/ 
        {0x02850000, 32*1024},          /*TBR_SYS-Trace Buffer -System   */ 
        {0x02900000, 256*1024},         /*Serial RapidIO configuration   */ 
        {0x02A00000, 1*1024*1024},      /*Navigator configuration        */ 
        {0x02B00000, 1*1024*1024},      /*Navigator linking RAM          */ 
        {0x02C00000, 64*1024},          /*RAC_2 - FEI control            */ 
        {0x02C10000, 64*1024},          /*RAC_2 - BEI control            */ 
        {0x02C20000, 128*1024},         /*RAC_2 - GCCP 0 control         */ 
        {0x02C40000, 128*1024},         /*RAC_2 - GCCP 1 control         */ 
        {0x02C80000, 64*1024},          /*RAC_3 - FEI control            */ 
        {0x02C90000, 64*1024},          /*RAC_3 - BEI control            */ 
        {0x02CA0000, 128*1024},         /*RAC_3 - GCCP 0 control         */ 
        {0x02CC0000, 128*1024},         /*RAC_3 - GCCP 1 control         */ 
        {0x02F00000, 1*1024*1024},      /*10GbE Config                   */ 
        {0x03000000, 1*1024*1024},      /*Debug_SS Configuration         */ 
        {0x08000000, 128*1024},         /*Extended memory controller     */ 
        {0x0BC00000, 1*1024*1024},      /*Multicore shared memory        */ 
        {0x0C000000, 6*1024*1024},      /*Multicore shared memory (MSM)  */ 
        {0x10800000, 1*1024*1024},      /*CorePac0 L2 SRAM               */ 
        {0x10E00000, 32*1024},          /*CorePac0 L1P SRAM              */ 
        {0x10F00000, 32*1024},          /*CorePac0 L1D SRAM              */ 
        {0x11800000, 1*1024*1024},      /*CorePac1 L2 SRAM               */ 
        {0x11E00000, 32*1024},          /*CorePac1 L1P SRAM              */ 
        {0x11F00000, 32*1024},          /*CorePac1 L1D SRAM              */ 
        {0x12800000, 1*1024*1024},      /*CorePac2 L2 SRAM               */ 
        {0x12E00000, 32*1024},          /*CorePac2 L1P SRAM              */ 
        {0x12F00000, 32*1024},          /*CorePac2 L1D SRAM              */ 
        {0x13800000, 1*1024*1024},      /*CorePac3 L2 SRAM               */ 
        {0x13E00000, 32*1024},          /*CorePac3 L1P SRAM              */ 
        {0x13F00000, 32*1024},          /*CorePac3 L1D SRAM              */ 
        {0x14800000, 1*1024*1024},      /*CorePac4 L2 SRAM               */ 
        {0x14E00000, 32*1024},          /*CorePac4 L1P SRAM              */ 
        {0x14F00000, 32*1024},          /*CorePac4 L1D SRAM              */ 
        {0x15800000, 1*1024*1024},      /*CorePac5 L2 SRAM               */ 
        {0x15E00000, 32*1024},          /*CorePac5 L1P SRAM              */ 
        {0x15F00000, 32*1024},          /*CorePac5 L1D SRAM              */ 
        {0x16800000, 1*1024*1024},      /*CorePac6 L2 SRAM               */ 
        {0x16E00000, 32*1024},          /*CorePac6 L1P SRAM              */ 
        {0x16F00000, 32*1024},          /*CorePac6 L1D SRAM              */ 
        {0x17800000, 1*1024*1024},      /*CorePac7 L2 SRAM               */ 
        {0x17E00000, 32*1024},          /*CorePac7 L1P SRAM              */ 
        {0x17F00000, 32*1024},          /*CorePac7 L1D SRAM              */ 
        {0x20000000, 1*1024*1024},      /*System trace manager (STM)     */ 
        {0x20600000, 1*1024*1024},      /*TCP3d_1 data                   */ 
        {0x20700000, 1*1024*1024},      /*TCP3d_2 data                   */ 
        {0x20800000, 1*1024*1024},      /*TCP3d_0 data                   */ 
        {0x20900000, 1*1024*1024},      /*TCP3d_3 data                   */ 
        {0x20B00000, 256*1024},         /*Boot ROM                       */ 
        {0x21000400, 512},              /*SPI0                           */ 
        {0x21000600, 512},              /*SPI1                           */ 
        {0x21000800, 512},              /*SPI2                           */ 
        {0x21000A00, 256},              /*AEMIF Config                   */ 
        {0x21010000, 512},              /*DDR3A EMIF Config              */ 
        {0x21020000, 128*1024},         /*DDR3B EMIF configuration       */ 
        {0x21400000, 256},              /*HyperLink0 config              */ 
        {0x21400100, 256},              /*HyperLink1 config              */ 
        {0x21800000, 32*1024},          /*PCIe config                    */ 
        {0x22A00000, 64*1024},          /*VCP2_0 Data                    */ 
        {0x22B00000, 64*1024},          /*VCP2_1 Data                    */ 
        {0x22C00000, 64*1024},          /*VCP2_2 Data                    */ 
        {0x22D00000, 64*1024},          /*VCP2_3 Data                    */ 
        {0x22E00000, 64*1024},          /*VCP2_4 Data                    */ 
        {0x22F00000, 64*1024},          /*VCP2_5 Data                    */ 
        {0x23000000, 64*1024},          /*VCP2_6 Data                    */ 
        {0x23100000, 64*1024},          /*VCP2_7 Data                    */ 
        {0x23200000, 384*1024},         /*TAC BEI                        */ 
        {0x23A00000, 2*1024*1024},      /*Navigator                      */ 
        {0x23C00000, 4*1024*1024}       /*BCR-RAC data                   */ 
};
#endif

/*first and second level MMU translation tables are allocated statically in driver,
third level translation table should be allocated in application level if needed*/
//second level MMU translation tables
unsigned long long gullaMMU2ndLevelTT[4][512] __attribute__ ((aligned (4096))); 
//first level MMU translation tables
unsigned long long gullaMMU1stLevelTT[4] __attribute__ ((aligned (32)));      	

//supported memory attributes
static Uint8 memAttrTable[8]= {
	MMU_MEM_ATTR_STRONG_ORDER           , /*strongly ordered*/
	MMU_MEM_ATTR_DEVICE                 , /*device*/
	MMU_MEM_ATTR_NORMAL_NON_CACHE       , /*normal non-cache memory*/
	MMU_MEM_ATTR_NORMAL_CACHE_RA_WT_NWA , /*normal, read-allocate, write-through, non-write-allocate*/
	MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_NWA , /*normal, read-allocate, write-back, non-write-allocate*/
	MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA  , /*normal, read-allocate, write-back, write-allocate*/
	0, 	//not used
	0   //not used
};

/*compose the attribute fields in 64-bit long descriptor entry*/
unsigned long long MMU_long_format_attribute_compose(MMU_Memory_Map_Range * memory_range)
{
 	unsigned long long ullEntryAttr;
	Uint8 attrIndex, numAttr= sizeof(memAttrTable);

	//find the index of attribute
 	for(attrIndex=0; attrIndex< numAttr; attrIndex++)
 	{
 		if(memAttrTable[attrIndex]==memory_range->attribute)
 			break;
 	}
 	if(attrIndex==numAttr) 
 	{
 		printf("memory attribute 0x%x for virtual address 0x%x is not supported\n", 
 			memory_range->attribute, memory_range->uiVirtualAddress);
 		return 0;
 	}
 	
 	ullEntryAttr= 
 		 ((unsigned long long)memory_range->exectuePermission<<MMU_MEM_ATTR_PL1_EXE_NEVER_SHIFT)
		|(attrIndex                      <<MMU_MEM_ATTR_INDEX_SHIFT)
		|(memory_range->accessPermission <<MMU_MEM_ATTR_ACCESS_PERM_SHIFT)
		|(memory_range->shareAttr        <<MMU_MEM_ATTR_SHARE_SHIFT)
		|(memory_range->isGlobal         <<MMU_MEM_ATTR_NOT_GLOBAL_SHIFT)
		|(memory_range->isSecure         <<MMU_MEM_ATTR_NON_SECURE_SHIFT)
		|(1                              <<MMU_MEM_ATTR_ACCESS_FLAG_SHIFT);

	return ullEntryAttr;
}

/*setup long format 1st level blocks for a memory range*/
void MMU_long_format_1st_level_blocks_setup(MMU_Memory_Map_Range * memory_range)
{
	int i;
	Uint32 uiVirtualAddress, uiByteCnt;
	unsigned long long ullPhysicalAddress;

	unsigned long long ullEntryAttr= MMU_long_format_attribute_compose(memory_range);
	
	uiVirtualAddress= memory_range->uiVirtualAddress&ALIGN_1G_MASK;
	ullPhysicalAddress= memory_range->ullPhysicalAddress&ALIGN_1G_LONG_MASK;
	uiByteCnt= memory_range->uiByteCnt&ALIGN_1G_MASK;
	if(0==uiByteCnt)
		return;

	//setup all 1GB blocks
	for(i=0; i< uiByteCnt; i += 1024*1024*1024)
	{
		//write the entry
		gullaMMU1stLevelTT[uiVirtualAddress>>30] = 
			ullPhysicalAddress|ullEntryAttr|MMU_LONG_DESC_TYPE_BLOCK;

		//increase address for next 1GB block
		uiVirtualAddress += 1024*1024*1024;
		ullPhysicalAddress += 1024*1024*1024;
	}
}

/*copy 1st level block attributes to corresponding 2nd level blocks, 
make 512 blocks of 2nd level equivalent to one block of 1st level*/
void copy_1st_level_attribute_to_2nd_level_blocks(Uint32 uiVirtualAddress)
{
	int j;
	unsigned long long ullEntryBase;

	ullEntryBase= gullaMMU1stLevelTT[uiVirtualAddress>>30] & 0xFFFFFFFFC0000FFFULL;
	for(j=0; j<512; j++)
	{
		gullaMMU2ndLevelTT[uiVirtualAddress>>30][j]= 
			ullEntryBase + j*2*1024*1024;
	}
}

/*setup long format 2nd level blocks for a memory range*/
void MMU_long_format_2nd_level_blocks_setup(MMU_Memory_Map_Range * memory_range)
{
	int i;
	Uint32 uiVirtualAddress, uiByteCnt;
	unsigned long long ullPhysicalAddress;
	unsigned long long * ullp1stLevelEntry;

	unsigned long long ullEntryAttr= MMU_long_format_attribute_compose(memory_range);
	
	uiVirtualAddress= memory_range->uiVirtualAddress&ALIGN_2M_MASK;
	ullPhysicalAddress= memory_range->ullPhysicalAddress&ALIGN_2M_LONG_MASK;
	uiByteCnt= memory_range->uiByteCnt&ALIGN_2M_MASK;
	if(0==uiByteCnt)
		return;

	//setup all 2MB blocks
	for(i=0; i< uiByteCnt; i += 2*1024*1024)
	{
		ullp1stLevelEntry = &gullaMMU1stLevelTT[uiVirtualAddress>>30];

		/*if high level entry is block entry, its maps will be copied to low level entries, 
		and then change the high level entry to a table entry*/
		if(MMU_LONG_DESC_TYPE_BLOCK == (*ullp1stLevelEntry&MMU_LONG_DESC_TYPE_MASK))
		{
			copy_1st_level_attribute_to_2nd_level_blocks(uiVirtualAddress);
		}

		/*if high level entry is not table entry, change the high level entry to a table entry*/
		if(MMU_LONG_DESC_TYPE_TABLE != (*ullp1stLevelEntry&MMU_LONG_DESC_TYPE_MASK))
		{
			*ullp1stLevelEntry = (unsigned long long)((Uint32)(&gullaMMU2ndLevelTT[uiVirtualAddress>>30][0])
				|MMU_LONG_DESC_TYPE_TABLE);
		}

		//write the entry
		gullaMMU2ndLevelTT[uiVirtualAddress>>30][(uiVirtualAddress>>21)&0x1FF] = 
			ullPhysicalAddress|ullEntryAttr|MMU_LONG_DESC_TYPE_BLOCK;

		//increase address for next 2MB block
		uiVirtualAddress += 2*1024*1024;
		ullPhysicalAddress += 2*1024*1024;
	}
}

/*setup long format 2nd level table for a third-level memory range*/
void MMU_long_format_2nd_level_table_setup(MMU_Memory_Map_Range * memory_range,
	Uint32 ui3rdLevelTableAddress)
{
	Uint32 uiVirtualAddress;
	unsigned long long * ullp1stLevelEntry;

	uiVirtualAddress= memory_range->uiVirtualAddress&ALIGN_2M_MASK;

	ullp1stLevelEntry = &gullaMMU1stLevelTT[uiVirtualAddress>>30];

	/*if high level entry is block entry, its maps will be copied to low level entries, 
	and then change the high level entry to a table entry*/
	if(MMU_LONG_DESC_TYPE_BLOCK == (*ullp1stLevelEntry&MMU_LONG_DESC_TYPE_MASK))
	{
		copy_1st_level_attribute_to_2nd_level_blocks(uiVirtualAddress);
	}

	/*if highe level entry is not table entry, change the high level entry to a table entry*/
	if(MMU_LONG_DESC_TYPE_TABLE != (*ullp1stLevelEntry&MMU_LONG_DESC_TYPE_MASK))
	{
		*ullp1stLevelEntry = (unsigned long long)((Uint32)(&gullaMMU2ndLevelTT[uiVirtualAddress>>30][0])
			|MMU_LONG_DESC_TYPE_TABLE);
	}

	//write the entry
	gullaMMU2ndLevelTT[uiVirtualAddress>>30][(uiVirtualAddress>>21)&0x1FF] = 
		(unsigned long long)ui3rdLevelTableAddress|MMU_LONG_DESC_TYPE_TABLE;
}

static Uint32 ui3rdLevelTableIndex=0;//allocation index of 3rd level table.
unsigned long long (*ullpMMU3rdLevelTT)[512]= NULL;

/*setup long format 3rd level blocks for a memory range*/
void MMU_long_format_3rd_level_blocks_setup(MMU_Memory_Map_Range * memory_range)
{
	int i;
	Uint32 uiVirtualAddress, uiByteCnt;
	unsigned long long ullPhysicalAddress;
	unsigned long long ullEntryBase;
	unsigned long long * ullp2ndLevelEntry;
	unsigned long long * ullp3rdLevelTT;

	unsigned long long ullEntryAttr= MMU_long_format_attribute_compose(memory_range);

	if(NULL==ullpMMU3rdLevelTT)
	{
		puts("memory map includes ranges less than 2MB, third level table need be provided throught MMU_Long_Format_Config.ullpMMU3rdLevelTT by caller");
		return;
	}
	
	uiVirtualAddress= memory_range->uiVirtualAddress&ALIGN_4K_MASK;
	ullPhysicalAddress= memory_range->ullPhysicalAddress&ALIGN_4K_LONG_MASK;
	uiByteCnt= memory_range->uiByteCnt&ALIGN_4K_MASK;
	if(0==uiByteCnt)
		return;

	ullp2ndLevelEntry = &gullaMMU2ndLevelTT[uiVirtualAddress>>30][(uiVirtualAddress>>21)&0x1FF];

	/*if high level entry is a block entry, allocate 3rd-level table, 
	high-level map will be copied to the 3rd-level table*/
	if(MMU_LONG_DESC_TYPE_BLOCK == (*ullp2ndLevelEntry&MMU_LONG_DESC_TYPE_MASK))
	{
		//allocate a 3rd-level table
		ullp3rdLevelTT= &ullpMMU3rdLevelTT[ui3rdLevelTableIndex][0]; 
		ui3rdLevelTableIndex++;

		//copy memory map to 3rd-level table
		ullEntryBase= (*ullp2ndLevelEntry & 0xFFFFFFFFFFE00FFCULL)|MMU_LONG_DESC_TYPE_PAGE;
		for(i=0; i<512; i++)
		{
			ullp3rdLevelTT[i]= ullEntryBase + i*4*1024;
		}
	}
	/*if high level entry is table entry, get the pointer of 3rd-level table*/
	else if(MMU_LONG_DESC_TYPE_TABLE== (*ullp2ndLevelEntry&MMU_LONG_DESC_TYPE_MASK))
	{
		ullp3rdLevelTT= (unsigned long long *)((Uint32)*ullp2ndLevelEntry & 0xFFFFF000);
	}
	else 	//high level entry is originally a invalid entry
	{
		//allocate a 3rd-level table
		ullp3rdLevelTT= &ullpMMU3rdLevelTT[ui3rdLevelTableIndex][0];
		ui3rdLevelTableIndex++;

		//clear MMU table entries, make them invalid.
		memset(ullp3rdLevelTT, 0, 512*8);
	}

	/*if high level entry is not table entry, change the high level entry to a table entry*/
	if(MMU_LONG_DESC_TYPE_TABLE != (*ullp2ndLevelEntry&MMU_LONG_DESC_TYPE_MASK))
	{
		MMU_long_format_2nd_level_table_setup(memory_range, (Uint32)ullp3rdLevelTT);
	}

	//setup all 4KB blocks
	for(i=0; i< uiByteCnt; i += 4*1024)
	{
		//write the entry
		ullp3rdLevelTT[(uiVirtualAddress>>12)&0x1FF] = 
			ullPhysicalAddress|ullEntryAttr|MMU_LONG_DESC_TYPE_PAGE;

		//increase address for next 2MB block
		uiVirtualAddress += 4*1024;
		ullPhysicalAddress += 4*1024;
	}
}

/*flat map all internal memories and registers as device type,
only use first and second level table*/
void MMU_long_format_table_flat_init()
{
	int i;
	Uint32 uiStartAddress, uiByteCnt;

	MMU_Memory_Map_Range defualt_memory_map_range;
	
	//clear all MMU table entries, make them invalid.
	memset(gullaMMU1stLevelTT, 0, sizeof(gullaMMU1stLevelTT));
	memset(gullaMMU2ndLevelTT, 0, sizeof(gullaMMU2ndLevelTT));

	defualt_memory_map_range.attribute= MMU_MEM_ATTR_STRONG_ORDER;
	defualt_memory_map_range.accessPermission= MMU_MEM_ATTR_RW;
	defualt_memory_map_range.exectuePermission= MMU_MEM_ATTR_XN;
	defualt_memory_map_range.shareAttr= MMU_MEM_ATTR_OUTER_SHARE;
	defualt_memory_map_range.isGlobal= MMU_MEM_ATTR_GLOBAL;
	defualt_memory_map_range.isSecure= MMU_MEM_ATTR_NON_SECURE;

	//map all internal memories and registers segments
	for(i=0; i< sizeof(MMU_default_flat_map)/sizeof(MMU_Memory_Segment); i++)
	{
	 	uiStartAddress= MMU_default_flat_map[i].uiStartAddress;
	 	uiByteCnt= MMU_default_flat_map[i].uiByteCnt;

	 	/*since only 2nd level table is used for default flat map,
	 	extend and align the address and size to 2MB boundary*/
		uiByteCnt = (uiByteCnt+ (uiStartAddress & MOD_2M_MASK) + 2*1024*1024-1) & ALIGN_2M_MASK;
	 	uiStartAddress &= ALIGN_2M_MASK;

	 	defualt_memory_map_range.uiVirtualAddress= uiStartAddress;
	 	defualt_memory_map_range.ullPhysicalAddress= uiStartAddress;
	 	defualt_memory_map_range.uiByteCnt= uiByteCnt;

		/*setup long format 2nd level blocks for a memory range*/
	 	MMU_long_format_2nd_level_blocks_setup(&defualt_memory_map_range);	 	
	}
#if 1 	/*enable boot ROM for execution*/
	defualt_memory_map_range.accessPermission= MMU_MEM_ATTR_PL1_RO;
	defualt_memory_map_range.exectuePermission= MMU_MEM_ATTR_X;
 	defualt_memory_map_range.uiVirtualAddress= 0;
 	defualt_memory_map_range.ullPhysicalAddress= 0;
 	defualt_memory_map_range.uiByteCnt= 2*1024*1024;

	/*setup long format 2nd level blocks for a memory range*/
 	MMU_long_format_2nd_level_blocks_setup(&defualt_memory_map_range);	 	
#endif
}

/*configure the long format tables based on the memory map ranges defined 
in "MMU_cfg", which may overwrite default flat map*/
void MMU_long_format_table_config(MMU_Long_Format_Config * MMU_cfg)
{
	int i;
	MMU_Memory_Map_Range memory_range;
	Uint32 uiVirtualAddress, uiByteCnt, uiHeadByteCnt, uiTailByteCnt;
	unsigned long long ullPhysicalAddress;

	/*3rd-level table, if used, should be provided by caller through MMU_cfg->ullpMMU3rdLevelTT*/
	ui3rdLevelTableIndex= 0;
	ullpMMU3rdLevelTT= MMU_cfg->ullpMMU3rdLevelTT;
	if(((Uint32)ullpMMU3rdLevelTT)&MOD_4K_MASK)
	{
		printf("Align 3rd-level table address 0x%x to 4KB boundary!\n", (Uint32)ullpMMU3rdLevelTT);
		ullpMMU3rdLevelTT = (unsigned long long (*)[512])(((Uint32)ullpMMU3rdLevelTT)&MOD_4K_MASK);
	}

	//setup table entries for all memory map ranges
	for(i=0; i< MMU_cfg->uiNumMemMapRanges; i++)
	{
		memory_range= MMU_cfg->memory_map[i];

	 	uiVirtualAddress= memory_range.uiVirtualAddress;
	 	uiByteCnt= memory_range.uiByteCnt;
	 	ullPhysicalAddress= memory_range.ullPhysicalAddress;

		if(0==uiByteCnt)
		{
			printf("Skip memory map range %d becasue its size is 0.\n", i);
			continue;
		}
		else if(uiByteCnt>(0x100000000ULL-uiVirtualAddress))
		{
			uiByteCnt= 0x100000000ULL-uiVirtualAddress;
			printf("Memory map range %d is too large (%u), which exceeds the maximum 32-bit address 0xFFFFFFFF, trim it to %d.\n",
				i, memory_range.uiByteCnt, uiByteCnt);
			memory_range.uiByteCnt= uiByteCnt;
		}
		
	 	/*align the address and size to 4KB boundary*/
	 	if(uiVirtualAddress & MOD_4K_MASK)
	 		printf("Align virtual address 0x%x to 4KB boundary!\n", uiVirtualAddress);
	 	if(ullPhysicalAddress& MOD_4K_MASK)
	 		printf("Align physical address 0x%llx to 4KB boundary!\n", ullPhysicalAddress);
	 	if(uiByteCnt & MOD_4K_MASK)
	 		printf("Align memory range size %d for virtual address 0x%x to multiple of 4KB!\n", 
	 			uiByteCnt, uiVirtualAddress);
		uiByteCnt = (uiByteCnt+ (uiVirtualAddress & MOD_4K_MASK) + 4*1024-1) & ALIGN_4K_MASK;
	 	uiVirtualAddress &= ALIGN_4K_MASK;
	 	ullPhysicalAddress &= ALIGN_4K_LONG_MASK;

		/*split a memory range into 5 smaller aligned ranges:
		3rd-level head range (aligned to 4KB boundary)
		2nd-level head range (aligned to 2MB boundary)
		1st-level      range (aligned to 1GB boundary)
		2nd-level tail range (aligned to 2MB boundary)
		3rd-level tail range (aligned to 4KB boundary),
		the size of some ranges may be 0*/
		if(uiVirtualAddress&MOD_2M_MASK) //is there 3rd-level head range?
		{
			uiHeadByteCnt= 2*1024*1024- (uiVirtualAddress&MOD_2M_MASK);
			if(uiHeadByteCnt>uiByteCnt)
				uiHeadByteCnt= uiByteCnt;
				
			memory_range.uiVirtualAddress= uiVirtualAddress;
			memory_range.uiByteCnt= uiHeadByteCnt;
			memory_range.ullPhysicalAddress= ullPhysicalAddress;
			/*setup long format 3rd level blocks for head range*/
		 	MMU_long_format_3rd_level_blocks_setup(&memory_range);	 	

			//skip this 3rd-level head range
			uiByteCnt -= uiHeadByteCnt;
			if(0==uiByteCnt)
				continue;
			uiVirtualAddress += uiHeadByteCnt;
			ullPhysicalAddress += uiHeadByteCnt;
		}

		if((uiVirtualAddress+uiByteCnt)&MOD_2M_MASK) //is there 3rd-level tail range?
		{
			uiTailByteCnt= (uiVirtualAddress+uiByteCnt)&MOD_2M_MASK;
			memory_range.uiVirtualAddress= (uiVirtualAddress+uiByteCnt)&ALIGN_2M_MASK;
			memory_range.uiByteCnt= uiTailByteCnt;
			memory_range.ullPhysicalAddress= (ullPhysicalAddress+uiByteCnt)&ALIGN_2M_LONG_MASK;
			/*setup long format 3rd level blocks for tail range*/
		 	MMU_long_format_3rd_level_blocks_setup(&memory_range);	 	

			//skip this 3rd-level tail range
			uiByteCnt -= uiTailByteCnt;
			if(0==uiByteCnt)
				continue;
		}

		if(uiVirtualAddress&MOD_1G_MASK) //is there 2nd-level head range?
		{
			uiHeadByteCnt= 1024*1024*1024- (uiVirtualAddress&MOD_1G_MASK);
			if(uiHeadByteCnt>uiByteCnt)
				uiHeadByteCnt= uiByteCnt;
				
			memory_range.uiVirtualAddress= uiVirtualAddress;
			memory_range.uiByteCnt= uiHeadByteCnt;
			memory_range.ullPhysicalAddress= ullPhysicalAddress;
			/*setup long format 2nd level blocks for head range*/
		 	MMU_long_format_2nd_level_blocks_setup(&memory_range);	 	

			//skip this 2nd-level head range
			uiByteCnt -= uiHeadByteCnt;
			if(0==uiByteCnt)
				continue;
			uiVirtualAddress += uiHeadByteCnt;
			ullPhysicalAddress += uiHeadByteCnt;
		}

		if((uiVirtualAddress+uiByteCnt)&MOD_1G_MASK) //is there 2nd-level tail range?
		{
			uiTailByteCnt= (uiVirtualAddress+uiByteCnt)&MOD_1G_MASK;
			memory_range.uiVirtualAddress= (uiVirtualAddress+uiByteCnt)&ALIGN_1G_MASK;
			memory_range.uiByteCnt= uiTailByteCnt;
			memory_range.ullPhysicalAddress= (ullPhysicalAddress+uiByteCnt)&ALIGN_1G_LONG_MASK;
			/*setup long format 2nd level blocks for tail range*/
		 	MMU_long_format_2nd_level_blocks_setup(&memory_range);	 	

			//skip the 2nd-level tail range
			uiByteCnt -= uiTailByteCnt;
			if(0==uiByteCnt)
				continue;
		}

		//the remaining is 1st-level memory range
		memory_range.uiVirtualAddress= uiVirtualAddress;
		memory_range.uiByteCnt= uiByteCnt;
		memory_range.ullPhysicalAddress= ullPhysicalAddress;
		/*setup long format 1st level blocks for remaining memory range*/
	 	MMU_long_format_1st_level_blocks_setup(&memory_range);	 	
	}
}

/*initialize long format MMU table according to "MMU_cfg".*/
void MMU_long_format_init(MMU_Long_Format_Config * MMU_cfg)
{
	//disable and Clear cache
	CP15_ICacheDisable();
	CP15_DCacheDisable();

	/*disable MMU globally*/
	CP15_MMUDisable();

	/*configure memory attributes register MAIR0/1*/
    CP15_MAIR0Config((memAttrTable[0]<<0)
		|(memAttrTable[1]<<8)
		|(memAttrTable[2]<<16)
		|(memAttrTable[3]<<24));
	CP15_MAIR1Config((memAttrTable[4]<<0)
		|(memAttrTable[5]<<8)
		|(memAttrTable[6]<<16)
		|(memAttrTable[7]<<24));

	if(TRUE==MMU_cfg->bAlignCheck)
	    CP15_SCTLRConfigBitField(CP15_SCTLR_ALIGN_CHECK_MASK, 0);
	else //disable alignment check
	    CP15_SCTLRConfigBitField(0, CP15_SCTLR_ALIGN_CHECK_MASK);

	/* Configure the TTB Control register to use only TTBR0 and enable LPAE*/	
	CP15_TTBCRLongConfig( CP15_TTBCR_LONG_EAE_LPAE	                   
		|(MMU_cfg->tableCacheAttr << CP15_TTBCR_LONG_IRGN0_SHIFT)	                   
		|(MMU_cfg->tableCacheAttr << CP15_TTBCR_LONG_ORGN0_SHIFT)	                   
		|(MMU_cfg->tableShareAttr << CP15_TTBCR_LONG_SH0_SHIFT));    

	/*flat map all internal memories and registers as device type*/
	MMU_long_format_table_flat_init();

	/*configure the long format tables according to the memory map ranges defined 
	in "MMU_cfg", which may overwrite default flag map*/
	MMU_long_format_table_config(MMU_cfg);

	/*Sets TTBR0 Register for long descriptor format*/
	CP15_64bitTtb0Set((unsigned long long)gullaMMU1stLevelTT);

	/*enable MMU globally*/
	CP15_MMUEnable();
}

/*======================device level memory protection=======================*/
/*delete one MPAX segment*/
void KeyStone_SES_MPAX_seg_delete(Uint32 segNum, Uint32 PrivID)
{
	if(	gpMSMC_regs->SES_MPAX_LCKSTAT&(1<<PrivID))
		CSL_MSMC_unlockSES(PrivID);
	
	gpMSMC_regs->SES_MPAX_PER_PRIVID[PrivID].SES[segNum].MPAXH= 0;
	gpMSMC_regs->SES_MPAX_PER_PRIVID[PrivID].SES[segNum].MPAXL= 0;

	CSL_MSMC_lockSES(PrivID);
}
void KeyStone_SMS_MPAX_seg_delete(Uint32 segNum, Uint32 PrivID)
{
	if(	gpMSMC_regs->SMS_MPAX_LCKSTAT&(1<<PrivID))
		CSL_MSMC_unlockSMS(PrivID);
	
	gpMSMC_regs->SMS_MPAX_PER_PRIVID[PrivID].SMS[segNum].MPAXH= 0;
	gpMSMC_regs->SMS_MPAX_PER_PRIVID[PrivID].SMS[segNum].MPAXL= 0;

	CSL_MSMC_lockSMS(PrivID);
}

/*****************************************************************************
 Prototype    : KeyStone_MPAX_seg_setup
 Description  : configure one MPAX segment
 Input        : MPAX_Regs * MPAX_regs       
                Uint32 BADDR                
                Uint32 RADDR                
                Uint32 SegementSize  
                K2_MSMC_Share share
                Uint32 AccessPermisionMask  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/7/15
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_MPAX_seg_setup(MPAX_Regs * MPAX_regs, Uint32 BADDR, 
	Uint32 RADDR, Uint32 SegementSize, K2_MSMC_Share share, Uint32 AccessPermisionMask)
{
	Uint32 SegSizeMask, SegSizeBits;

	if(SegementSize<4*1024)
	{
		printf("Segment size %d is less than 4KB. ", SegementSize);
		SegementSize = 4*1024;
		printf("Extended segment size to 4KB.\n");
	}
	
	SegSizeBits= 31 - _lmbd(1, SegementSize);
	SegSizeMask= (1<<SegSizeBits)-1;
	if(SegementSize&SegSizeMask)
	{
		printf("Segment size 0x%x is not power of 2. ", SegementSize);
		SegSizeBits += 1;
		SegementSize= (1<<SegSizeBits);
		SegSizeMask= (1<<SegSizeBits)-1;
		printf("Extended segment size to 0x%x.\n", SegementSize);
	}

	if(BADDR&SegSizeMask)
	{
		printf("Segment base address 0x%x does not start from power-of-2 boundary corresponds to segment size 0x%x.\n", 
			BADDR, SegementSize);
		BADDR &= (~SegSizeMask);
		printf("Extended base address to 0x%x.\n", BADDR);
	}
	if(RADDR&(SegSizeMask>>4))
	{
		printf("Segment replacement address 0x%x does not start from power-of-2 boundary corresponds to segment size 0x%x.\n", 
			RADDR, SegementSize);
		RADDR &= (~(SegSizeMask>>4));
		printf("Extended replacement address to 0x%x.\n", RADDR);
	}
	
	MPAX_regs->MPAXH= BADDR|(share<<MSMC_MPAXH_US_SHIFT)|(SegSizeBits-1); 
	MPAX_regs->MPAXL= RADDR|AccessPermisionMask; 

}

/*****************************************************************************
 Prototype    : KeyStone_SMS_MPAX_setup
 Description  : configure multiple MPAX segments in SMS of MSMC with a conf-
                iguration table
 Input        : MPAX_Config MPAX_cfg[]  
                Uint32 firstSeg         
                Uint32 numSegs          
                Uint32 PrivID           
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/7/15
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_SMS_MPAX_setup(MPAX_Config MPAX_cfg[], 
	Uint32 firstSeg, Uint32 numSegs, Uint32 PrivID)
{
	int i;

	if(	gpMSMC_regs->SMS_MPAX_LCKSTAT&(1<<PrivID))
		CSL_MSMC_unlockSMS(PrivID);

	/*CAUTION:
	A MPAX segment can only be modified when there is no access to this segment. 
	It is recommended to configure the MPAX at the very beginning of application
	software before any shared memory is used. 
	If a MPAX segment must be modified on-the-fly, the safer way is, to write 
	the new configuration to a unused higher segment, and then clear the old 
	segment. This is based on the fact that higher numbered segments take 
	precedence over lower numbered segments.	*/
	for(i=numSegs-1; i>=0 ; i--)
		KeyStone_MPAX_seg_setup(
			(MPAX_Regs *)&gpMSMC_regs->SMS_MPAX_PER_PRIVID[PrivID].SMS[firstSeg+i], 
			MPAX_cfg[i].BADDR, MPAX_cfg[i].RADDR, MPAX_cfg[i].SegementSize, 
			MPAX_cfg[i].share, MPAX_cfg[i].AccessPermisionMask);

	CSL_MSMC_lockSMS(PrivID);
}

/*****************************************************************************
 Prototype    : KeyStone_SES_MPAX_setup
 Description  : configure multiple MPAX segments in SES of MSMC with a conf-
                iguration table
 Input        : MPAX_Config MPAX_cfg[]  
                Uint32 firstSeg         
                Uint32 numSegs          
                Uint32 PrivID           
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/7/15
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_SES_MPAX_setup(MPAX_Config MPAX_cfg[], 
	Uint32 firstSeg, Uint32 numSegs, Uint32 PrivID)
{
	int i;

	if(	gpMSMC_regs->SES_MPAX_LCKSTAT&(1<<PrivID))
		CSL_MSMC_unlockSES(PrivID);

	/*CAUTION:
	A MPAX segment can only be modified when there is no access to this segment. 
	It is recommended to configure the MPAX at the very beginning of application
	software before any shared memory is used. 
	If a MPAX segment must be modified on-the-fly, the safer way is, to write 
	the new configuration to a unused higher segment, and then clear the old 
	segment. This is based on the fact that higher numbered segments take 
	precedence over lower numbered segments.	*/
	for(i=numSegs-1; i>=0 ; i--)
		KeyStone_MPAX_seg_setup(
			(MPAX_Regs *)&gpMSMC_regs->SES_MPAX_PER_PRIVID[PrivID].SES[firstSeg+i], 
			MPAX_cfg[i].BADDR, MPAX_cfg[i].RADDR, MPAX_cfg[i].SegementSize, 
			MPAX_cfg[i].share, MPAX_cfg[i].AccessPermisionMask);

	CSL_MSMC_lockSES(PrivID);
}

/*****************************************************************************
 Prototype    : K2_SMS_MPAX_init
 Description  : Initialize SMS MPAX for SOC DMA access MSMC RAM
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2014/7/30
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void K2_SMS_MPAX_init(K2_PrivID privID, K2_MSMC_Share share)
{
	MPAX_Config MPAX_cfg;

	/*memory address extension/mapping and memory protection for DMA masters*/
	MPAX_cfg.AccessPermisionMask= MP_SR|MP_SW|MP_UR|MP_UW;
	MPAX_cfg.share = share; //share (coherent) between DMA and ARM core
	MPAX_cfg.BADDR =  0x0C000000;
	MPAX_cfg.RADDR = 0x00C000000>>4;
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	/*K2K/K2H MSMC RAM size is 6MB, but the MPAX segment size must be power of 2, 
	so set the first segment to 4MB here*/
	MPAX_cfg.SegementSize= 4*1024*1024;
#else
	MPAX_cfg.SegementSize= 2*1024*1024;
#endif
	KeyStone_SMS_MPAX_setup(&MPAX_cfg, 0, 1, privID);

#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	/*K2K/K2H MSMC RAM size is 6MB, but the MPAX segment size must be power of 2, 
	so set the second segment to 2MB here*/
	MPAX_cfg.BADDR =  0x0C400000;
	MPAX_cfg.RADDR = 0x00C400000>>4;
	MPAX_cfg.SegementSize= 2*1024*1024;
	KeyStone_SMS_MPAX_setup(&MPAX_cfg, 1, 1, privID);
#endif
}

/*****************************************************************************
 Prototype    : KeyStone_MSMC_MP_interrupt_en
 Description  : Enable MSMC Memory protection error interrupt for all PrivIDs
*****************************************************************************/
void KeyStone_MSMC_MP_interrupt_en()
{
	if(gpMSMC_regs->CFGLCKSTAT&CSL_MSMC_CFGLCKSTAT_WSTAT_MASK)
		CSL_MSMC_unlockNonMPAX();

    /*clear MP fault record*/
    gpMSMC_regs->SMPFCR = 1; 

    /*clear interrupt error status flag*/
	gpMSMC_regs->SMIRC  = 0xFFFF<<CSL_MSMC_SMIRC_PFIC_SHIFT;

	//enable the interrupt
	gpMSMC_regs->SMIESTAT |= 0xFFFF<<CSL_MSMC_SMIESTAT_PFIESTAT_SHIFT;

	CSL_MSMC_lockNonMPAX();
}

/*****************************************************************************
 Prototype    : KeyStone_MSMC_protection_exception_handler
 Description  : MSMC memory protection processing
 Input        : None
 Output       : None
 Return Value : 
*****************************************************************************/
void KeyStone_MSMC_protection_exception_handler()
{
	unsigned int master_id;
    unsigned int priv_id;
    unsigned int address;
    unsigned int NM; 	//address Not Matching

	address = gpMSMC_regs->SMPFAR;
	
	master_id = (gpMSMC_regs->SMPFR&CSL_MSMC_SMPFR_FMSTID_MASK)>>
		CSL_MSMC_SMPFR_FMSTID_SHIFT;
    priv_id = (gpMSMC_regs->SMPFR&CSL_MSMC_SMPFR_FPID_MASK)>>
		CSL_MSMC_SMPFR_FPID_SHIFT;

    NM = (gpMSMC_regs->SMPFXR & CSL_MSMC_SMPFXR_NM_MASK) >> CSL_MSMC_SMPFXR_NM_SHIFT;

	printf("  memory protection exception caused by master %d (PrivID= %d) accessing address 0x%x\n", 
		master_id, priv_id, address);

    if(1 == NM)
    {
        printf("  Fault is caused by the address not matching any of the segment BADDR\n");        
    }

	if(gpMSMC_regs->CFGLCKSTAT&CSL_MSMC_CFGLCKSTAT_WSTAT_MASK)
	    CSL_MSMC_unlockNonMPAX();
    /*clear fault record*/
    gpMSMC_regs->SMPFCR = 1;
    /*clear interrupt error status flag*/
	gpMSMC_regs->SMIRC  = (1<<priv_id)<<CSL_MSMC_SMIRC_PFIC_SHIFT;
    CSL_MSMC_lockNonMPAX();            
}

/*==========Peripherals registers and internal data buffer MPU=============*/
MPU_Addr gstruMpuAddrRange[] = 
{/* refer to the device data manual MPU section */
        {0x01D00000, 0x01E7FFFF},  /* Main CFG SCR */
        {0x23A00000, 0x23BFFFFF},   /* QM_SS_DATA PORT */
        {0x02A00000, 0x02AFFFFF},  /* QM_SS_CFG1 PORT */
        {0x027C0000, 0x027C03FF},  /* BCR */
        {0x02100000, 0x0215FFFF},  /* RAC 0/1 */
        {0x02A04000, 0x02BFFFFF},  /* QM_SS_CFG1 PORT */
        {0x02C00000, 0x02CDFFFF},  /* RAC 2/3 */
        {0x21010000, 0xFFFFFFFF},  /* DDR3B, OSR, PCIE1*/
        {0x20B00000, 0x3FFFFFFF},  /* SPIROM/EMIF16 */
        {0x02640000, 0x026407FF},  /* INTC/AINTC */
        {0x02600000, 0x02609FFF},  /* Semaphore */
        {0x02200000, 0x03FFFFFF},  /* SCR_6 and CPU/6 CFG SCR */
        {0x21000400, 0x210007FF},  /* SPI0 */
        {0x21000400, 0x210007FF},  /* SPI1 */
        {0x21000800, 0x21000AFF}  /* SPI2 */
#ifdef CSL_MPU_15_REGS
        ,{0x24000000, 0x25FFFFFF}  /* DFE, IQNet, NetCP */
#endif
};
/*****************************************************************************
 Prototype    : KeyStone_MPU_range_setup
 Description  : configure one range in peripheral MPU
 Input        : CSL_MpuProg_regionRegs *MPPA_regs  
                Uint32 uiStartAddress              
                Uint32 uiEndAddress                
                Uint32 AccessPermisionMask         
 Output       : None
 Return Value : 
*****************************************************************************/
void KeyStone_MPU_range_setup(CSL_MpuProg_regionRegs *MPPA_regs, 
	Uint32 uiStartAddress, Uint32 uiEndAddress, Uint32 AccessPermisionMask)
{
    unsigned int boundaryMask; 

	//the address must align to 1KB boundary on KeyStone devices
	boundaryMask= 0x3FF; 
	
    if(0 != (uiStartAddress&boundaryMask))
    {
    	printf("aligned start address 0x%x to 0x%x\n",
    		uiStartAddress,	uiStartAddress&(~boundaryMask));
    	uiStartAddress= uiStartAddress&(~boundaryMask);
    }

    MPPA_regs->PROG_START_ADDRESS = uiStartAddress;
    MPPA_regs->PROG_END_ADDRESS = uiEndAddress;   
    MPPA_regs->PROG_MPPA = AccessPermisionMask;
}

/*****************************************************************************
 Prototype    : KeyStone_MPU_setup
 Description  : peripherals MPU ranges configuration
 Input        : Uint32 uiMPU_num: number of the MPU to be setup
                MPU_Range_Config MPU_cfg[]: MPU ranges configuration table
                Uint32 numRangeCfg: number of ranges to be configured          
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/12/15
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void KeyStone_MPU_setup(Uint32 uiMPU_num, 
	MPU_Range_Config MPU_cfg[], Uint32 numRangeCfg)
{
    int i;
    unsigned int mpuNumProgmableRange;
    CSL_MpuRegs * mpuRegs;
	mpuRegs= gpMPU_regs[uiMPU_num];

    mpuNumProgmableRange = (mpuRegs->CONFIG & CSL_MPU_CONFIG_NUM_PROG_MASK)>>CSL_MPU_CONFIG_NUM_PROG_SHIFT;
    if(mpuNumProgmableRange == 0)
    {   
        mpuNumProgmableRange = 16;
    }

	if(numRangeCfg>mpuNumProgmableRange)
    {
        printf("MPU %d programmable ranges %d < %d.\n", 
        	uiMPU_num, mpuNumProgmableRange, numRangeCfg);
        numRangeCfg=mpuNumProgmableRange;            
    }
    else if(numRangeCfg<mpuNumProgmableRange)
    {
        printf("MPU %d setup %d of %d ranges.\n", 
        	uiMPU_num, numRangeCfg, mpuNumProgmableRange);
    }

    for(i=0; i<numRangeCfg; i++)
    {
	    if((MPU_cfg[i].StartAddr < gstruMpuAddrRange[uiMPU_num].StartAddr) 
	      ||(MPU_cfg[i].EndAddr > gstruMpuAddrRange[uiMPU_num].EndAddr) )
	    {
	        printf("The configuration address is out of MPU %d protection range\n", 
	        	uiMPU_num);
	        continue;
	    }

        KeyStone_MPU_range_setup(&mpuRegs->PROG_REGION[i], 
            MPU_cfg[i].StartAddr, MPU_cfg[i].EndAddr, 
            MPU_cfg[i].AccessPermisionMask); 

    }

    //clear unused ranges
	for( ;i<mpuNumProgmableRange; i++)
	{
		mpuRegs->PROG_REGION[i].PROG_MPPA = 0; 	//eanble access to other range by default.
	}

	//clear status
	mpuRegs->FAULT_CLEAR = 1;
	mpuRegs->INT_ENABLED_STATUS_CLEAR = 
		CSL_MPU_INT_ENABLED_STATUS_CLEAR_ENABLED_ADDR_ERR_MASK
		|CSL_MPU_INT_ENABLED_STATUS_CLEAR_ENABLED_PROT_ERR_MASK;

	/* enable the interrupt */
	mpuRegs->INT_ENABLE = CSL_MPU_INT_ENABLE_ADDR_ERR_EN_MASK 
		| CSL_MPU_INT_ENABLE_PROT_ERR_EN_MASK;                

    return;
}

/*****************************************************************************
 Prototype    : KeyStone_MPU_MPPA_modify
 Description  : search the range which match a address and then modify
                the access permission of that range.
 Input        : Uint32 uiMPU_num: number of the MPU to be modifed  
                Uint32 uiAddress: address which need modify permision              
                Uint32 AccessPermisionMask: permission mask for that range         
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/12/13
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void KeyStone_MPU_MPPA_modify(Uint32 uiMPU_num, 
	Uint32 uiAddress, Uint32 AccessPermisionMask)
{
    int i;
    unsigned int mpuNumProgmableRange;
    CSL_MpuRegs * mpuRegs;
	mpuRegs= gpMPU_regs[uiMPU_num];

    mpuNumProgmableRange = (mpuRegs->CONFIG & CSL_MPU_CONFIG_NUM_PROG_MASK)>>CSL_MPU_CONFIG_NUM_PROG_SHIFT;
    if(mpuNumProgmableRange == 0)
    {   
        mpuNumProgmableRange = 16;
    }

	/*search through all ranges*/
	for(i=0; i< mpuNumProgmableRange; i++)
	{
		/*match with one range*/
		if((uiAddress >= mpuRegs->PROG_REGION[i].PROG_START_ADDRESS) 
      		&&(uiAddress <= mpuRegs->PROG_REGION[i].PROG_END_ADDRESS))
      	{
      		mpuRegs->PROG_REGION[i].PROG_MPPA = AccessPermisionMask;
      		return;
      	}
	}

	printf("address 0x%08x does not match any range in MPU %d\n", 
		uiAddress, uiMPU_num);
    
    return;
}

/*****************************************************************************
 Prototype    : KeyStone_MPU_interrupts_enable
 Description  : enable the all MPU interrupts
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/28
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void KeyStone_MPU_interrupt_enable(Uint32 uiMPU_num)
{
	if(NULL==gpMPU_regs[uiMPU_num])
	{
		//printf("Invalid MPU number %d\n", uiMPU_num);
		return;
	}
	if((gpMPU_regs[uiMPU_num]->REVISION&0xFFFF0000)!=
		(CSL_MPU_REVISION_RESETVAL&0xFFFF0000))
	{	
		printf("Can't read MPU%d ID register, make sure corresponding power domain is enabled.\n", uiMPU_num);
		return;
	}
	
    gpMPU_regs[uiMPU_num]->FAULT_CLEAR = 1;
    gpMPU_regs[uiMPU_num]->INT_ENABLED_STATUS_CLEAR = 
    	CSL_MPU_INT_ENABLED_STATUS_CLEAR_ENABLED_ADDR_ERR_MASK
    	|CSL_MPU_INT_ENABLED_STATUS_CLEAR_ENABLED_PROT_ERR_MASK;
	gpMPU_regs[uiMPU_num]->INT_ENABLE = CSL_MPU_INT_ENABLE_ADDR_ERR_EN_MASK 
    	|CSL_MPU_INT_ENABLE_PROT_ERR_EN_MASK;                

}
void KeyStone_MPU_interrupts_enable()
{
	int i;
	Uint32 uiNumMPU=15;
	
#ifdef CSL_MPU_15_REGS
	uiNumMPU= 16;
#endif

	for(i=0; i<uiNumMPU; i++)
	{
		KeyStone_MPU_interrupt_enable(i);
	}
    return;
}

char * Peri_MPU_err_type_str[]=
{
    "User execution fault!",
    "User write fault!",
    "User read fault!",
    "Supervisor execution fault!",
    "Supervisor write fault!",
    "Supervisor read fault!"
};

char * Ns_str[]=
{
    "secure",
    "non-secure"
};
/*****************************************************************************
 Prototype    : KeyStone_peripherals_MPU_fault_status
 Description  : Print the MPU error information
 Input        : unsigned int uwFltStatus: Fault status register value  
                unsigned int uwFltAddr  : Fault address  
 Output       : None
 Return Value : 
*****************************************************************************/
void KeyStone_peripherals_MPU_fault_status(unsigned int uwFltStatus, 
    unsigned int uwFltAddr)
{
    unsigned int MSTID;
    unsigned int PRIVID;
    unsigned int NS;
    unsigned int FaultType;
    unsigned int BitsCnt;
    
    MSTID = (uwFltStatus & CSL_MPU_FAULT_STATUS_MSTID_MASK)>>CSL_MPU_FAULT_STATUS_MSTID_SHIFT;
    PRIVID = (uwFltStatus & CSL_MPU_FAULT_STATUS_PRIVID_MASK)>>CSL_MPU_FAULT_STATUS_PRIVID_SHIFT;
    NS = (uwFltStatus & CSL_MPU_FAULT_STATUS_NS_MASK)>>CSL_MPU_FAULT_STATUS_NS_SHIFT;        
    printf("  The MSTID %d (PRIVID %d) triggered MPU error at 0x%x with %s access\n", 
    	MSTID, PRIVID, uwFltAddr, Ns_str[NS]);  

    FaultType = (uwFltStatus & CSL_MPU_FAULT_STATUS_FAULT_TYPE_MASK) >> CSL_MPU_FAULT_STATUS_FAULT_TYPE_SHIFT;
    if(1==(_dotpu4(_bitc4(FaultType), 0x01010101)))
    {
    	BitsCnt= 31 - _lmbd(1, FaultType);
        printf("  %s\n",Peri_MPU_err_type_str[BitsCnt]);
    }
    else if(0x3F == FaultType)
    {
        puts("  Relaxed cache line fill fault!");            
    }
    else if(0x12 == FaultType)
    {
        puts("  Relaxed cache write back fault!");                
    }    
}
/*****************************************************************************
 Prototype    : KeyStone_peripherals_MPU_excepiton_handler
 Description  : peripheral MPU processing
 Input        : Uint32 uiMpuNum: number of the MPU be handled 
 Output       : None
 Return Value : 
*****************************************************************************/
void KeyStone_peripherals_MPU_excepiton_handler(Uint32 uiMpuNum)
{
    Uint32 uwStatus;
    Uint32 uwFltAddr;
    Uint32 uwFltStatus;
	CSL_MpuRegs *pstruMpuRegs= gpMPU_regs[uiMpuNum];
	
    uwStatus = pstruMpuRegs->INT_ENABLED_STATUS_CLEAR;
    if(uwStatus & 0x2)
    {   
        printf("  MPU %d address violation error\n", uiMpuNum);
        pstruMpuRegs->INT_ENABLED_STATUS_CLEAR = 2;
    }        

    if(uwStatus & 0x1)
    {   
        printf("  MPU %d protection violation error\n", uiMpuNum);
        pstruMpuRegs->INT_ENABLED_STATUS_CLEAR = 1;
    }
      
    uwFltAddr = pstruMpuRegs->FAULT_ADDRESS;
    uwFltStatus = pstruMpuRegs->FAULT_STATUS;
    
    KeyStone_peripherals_MPU_fault_status(uwFltStatus,uwFltAddr);        
    pstruMpuRegs->FAULT_CLEAR = 1;

    pstruMpuRegs->EOI = 0;     
}


/*================internal shared memory EDC============================*/
/*****************************************************************************
 Prototype    : KeyStone_MSMC_RAM_EDC_enable
 Description  : Enable MSMC EDC
 Input        : scrubCnt, number of MSMC clock cycles between scrubbing
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/15
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_MSMC_RAM_EDC_enable(Uint32 scrubCnt)
{
	if(gpMSMC_regs->CFGLCKSTAT&CSL_MSMC_CFGLCKSTAT_WSTAT_MASK)
		CSL_MSMC_unlockNonMPAX();

	/*Software must wait for the PRR (Parity RAM Ready) bit before making 
	the first read access to MSMC RAM after reset.*/
	while(0==(gpMSMC_regs->SMEDCC&CSL_MSMC_SMEDCC_PRR_MASK));

	/* set scrubbing period value */
	if(scrubCnt>255)
		scrubCnt= 255;
	CSL_MSMC_setCounterBankRefreshRead(scrubCnt); //the scrubbing engine works every scrubCnt*1024 cycle*/

	/* clear EDC errors and enable EDC event*/
	gpMSMC_regs->SMIRC = 0xf;
	gpMSMC_regs->SMIESTAT |= (CSL_MSMC_SMIESTAT_NCSIE_MASK
			           | CSL_MSMC_SMIESTAT_CSIE_MASK
			           | CSL_MSMC_SMIESTAT_NCEIE_MASK
			           | CSL_MSMC_SMIESTAT_CEIE_MASK);

	//enable MSMC_RAM EDC
	CSL_MSMC_setECM(1);

	CSL_MSMC_lockNonMPAX();
}

/*****************************************************************************
 Prototype    : KeyStone_MSMC_RAM_EDC_interrupt_en
 Description  : Enable MSMC EDC error interrupt
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/15
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_MSMC_RAM_EDC_interrupt_en()
{
	if(gpMSMC_regs->CFGLCKSTAT&CSL_MSMC_CFGLCKSTAT_WSTAT_MASK)
		CSL_MSMC_unlockNonMPAX();

	/* clear EDC errors*/
	gpMSMC_regs->SMIRC = 0xf;

	/* Enable EDC error interrupt */
	gpMSMC_regs->SMIESTAT |= (CSL_MSMC_SMIESTAT_NCSIE_MASK
			           | CSL_MSMC_SMIESTAT_CSIE_MASK
			           | CSL_MSMC_SMIESTAT_NCEIE_MASK
			           | CSL_MSMC_SMIESTAT_CEIE_MASK);

	CSL_MSMC_lockNonMPAX();
}

/*****************************************************************************
 Prototype    : KeyStone_MSMC_RAM_EDC_handler
 Description  : MSMC_RAM EDC error handler
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/28
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void KeyStone_MSMC_RAM_EDC_handler()
{
	/* EDC correctable error during scrubbing cycle */
    Uint8  cses;
	/* EDC non-correctable error during scrubbing cycle */
    Uint8  ncses;
    /* EDC correctable error during SRAM access*/
    Uint8  cees;
    /* EDC non-correctable error during SRAM access*/
    Uint8  ncees;
    /* protection fault status*/
    Uint16  pfeStat;

    /*  error address  */
    Uint32 errAddr, bitPos, PrivID;

	if(gpMSMC_regs->CFGLCKSTAT&CSL_MSMC_CFGLCKSTAT_WSTAT_MASK)
		CSL_MSMC_unlockNonMPAX();

    CSL_MSMC_getPendingInterrupts(&pfeStat, &cees, &ncees, &cses, &ncses);

	if((cses == 1)||(ncses == 1))
	{
		if(cses == 1)
		{
			/*scrubbing engine report address offset from 0,
			convert it to normal address start from 0xc000000*/
			errAddr = (gpMSMC_regs->SMCEA&0xFFFFFF)+0xc000000;
			
			bitPos = (gpMSMC_regs->SMCEA&CSL_MSMC_SMCEA_ESYN_MASK)
				>>CSL_MSMC_SMCEA_ESYN_SHIFT;
			printf("MSMC_RAM Correctable error occurred at bit %d of address 0x%x by scrubbing\n", 
				bitPos, errAddr);
		}
		 if(ncses == 1)
		{
			/*scrubbing engine report address offset from 0*/
			errAddr = gpMSMC_regs->SMNCEA+0xc000000;
			
			printf("MSMC_RAM Non-correctable error occurred at address 0x%x during scrubbing\n", errAddr);
		}
		printf("%d correctable errors, %d non-correctable errors occurred during scrubbing.\n",
			(gpMSMC_regs->SMSECC&CSL_MSMC_SMSECC_SCEC_MASK)
				>>CSL_MSMC_SMSECC_SCEC_SHIFT,
			(gpMSMC_regs->SMSECC&CSL_MSMC_SMSECC_SNCEC_MASK)
				>>CSL_MSMC_SMSECC_SNCEC_SHIFT);
	}
	if(cees == 1)
	{
		volatile Uint32 scrubValue;
		
		errAddr =  gpMSMC_regs->SMCERRAR;

		//scrub the address to correct the error
#if 0
		//EDMA_copy(errAddr, errAddr, 32, EDMA_CC0_CH0, DMA_WAIT);
#else
		scrubValue= *(volatile Uint32 *)errAddr; //touch to cach
		*(volatile Uint32 *)errAddr= scrubValue; //make cache dirty
		CP15_DCacheCleanInvalidateBuff(errAddr, 32);
#endif
		__asm__(" DSB");
		__asm__(" ISB");
		
		bitPos = (gpMSMC_regs->SMCERRXR&CSL_MSMC_SMCERRXR_ESYN_MASK)
			>>CSL_MSMC_SMCERRXR_ESYN_SHIFT;
		PrivID = (gpMSMC_regs->SMCERRXR&CSL_MSMC_SMCERRXR_SEPID_MASK)
			>>CSL_MSMC_SMCERRXR_SEPID_SHIFT;
		printf("MSMC_RAM Correctable error occurred at bit %d of address 0x%x by PrivID %d ", 
			bitPos, errAddr, PrivID);
		if(gpMSMC_regs->SMCERRXR&CSL_MSMC_SMCERRXR_SER_MASK)
			printf("(not from CorePacs)\n");
		else
			printf("(from CorePacs)\n");
	}
	if(ncees ==1)
	{
		errAddr = gpMSMC_regs->SMNCERRAR;
		
		PrivID = (gpMSMC_regs->SMNCERRXR&CSL_MSMC_SMNCERRXR_SEPID_MASK)
			>>CSL_MSMC_SMNCERRXR_SEPID_SHIFT;
		printf("MSMC_RAM Non-correctable error occurred at address 0x%x by PrivID %d ", 
			errAddr, PrivID);
		if(gpMSMC_regs->SMNCERRXR&CSL_MSMC_SMNCERRXR_SER_MASK)
			printf("(not from CorePacs)\n");
		else
			printf("(from CorePacs)\n");
	}

	/* clear EDC error status  */
	CSL_MSMC_clearRawInterruptStatus(0, cees,ncees, cses, ncses);

	CSL_MSMC_lockNonMPAX();
}

/*===============================Exception=============================*/
/*some exception events routed from CIC2 to GIC and then to core,
all these events are routed to one input of GIC*/
Uint32 gCIC_EXC_out_num = 92; 	//CIC2 output event number
#define CIC2_ERROR_INT_ID CSL_ARM_GIC_CIC_2_OUT92 /*GIC input ID for the CIC2 output*/
Uint32 gCIC_EXC_EN_MASK[16]= {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
/*list all the exception events routed throught CIC2 to GIC*/
Uint16 gCIC_exception_events[]=
{
	CSL_CIC2_EDMACC_0_ERRINT     
	,CSL_CIC2_EDMACC_0_TC_0_ERRINT
	,CSL_CIC2_EDMACC_0_TC_1_ERRINT
	,CSL_CIC2_EDMACC_1_ERRINT     
	,CSL_CIC2_EDMACC_1_TC_0_ERRINT
	,CSL_CIC2_EDMACC_1_TC_1_ERRINT
	,CSL_CIC2_EDMACC_1_TC_2_ERRINT
	,CSL_CIC2_EDMACC_1_TC_3_ERRINT
	,CSL_CIC2_EDMACC_2_ERRINT     
	,CSL_CIC2_EDMACC_2_TC_0_ERRINT
	,CSL_CIC2_EDMACC_2_TC_1_ERRINT
	,CSL_CIC2_EDMACC_2_TC_2_ERRINT
	,CSL_CIC2_EDMACC_2_TC_3_ERRINT
#ifdef CSL_EDMACC_3
	,CSL_CIC2_EDMACC_3_ERRINT     
	,CSL_CIC2_EDMACC_3_TC_0_ERRINT
	,CSL_CIC2_EDMACC_3_TC_1_ERRINT
#endif
#ifdef CSL_EDMACC_4
	,CSL_CIC2_EDMACC_4_ERRINT     
	,CSL_CIC2_EDMACC_4_TC_0_ERRINT
	,CSL_CIC2_EDMACC_4_TC_1_ERRINT
#endif
	,CSL_CIC2_MSMC_SCRUB_CERROR 
	,CSL_CIC2_MSMC_DEDC_CERROR 
	,CSL_CIC2_MSMC_DEDC_NC_ERROR 
	,CSL_CIC2_MSMC_SCRUB_NC_ERROR
	,CSL_CIC2_MSMC_MPF_ERROR0 
	,CSL_CIC2_MSMC_MPF_ERROR1 
	,CSL_CIC2_MSMC_MPF_ERROR2 
	,CSL_CIC2_MSMC_MPF_ERROR3 
	,CSL_CIC2_MSMC_MPF_ERROR4 
	,CSL_CIC2_MSMC_MPF_ERROR5 
	,CSL_CIC2_MSMC_MPF_ERROR6 
	,CSL_CIC2_MSMC_MPF_ERROR7 
	,CSL_CIC2_MSMC_MPF_ERROR8    
	,CSL_CIC2_MSMC_MPF_ERROR9    
	,CSL_CIC2_MSMC_MPF_ERROR10   
	,CSL_CIC2_MSMC_MPF_ERROR11   
	,CSL_CIC2_MSMC_MPF_ERROR12   
	,CSL_CIC2_MSMC_MPF_ERROR13   
	,CSL_CIC2_MSMC_MPF_ERROR14   
	,CSL_CIC2_MSMC_MPF_ERROR15   
	,CSL_CIC2_DDR3_0_ERR  
#ifdef CSL_CIC2_DDR3_1_ERR
	,CSL_CIC2_DDR3_1_ERR 
#endif
	,CSL_CIC2_MPU_0_INT      
	,CSL_CIC2_MPU_1_INT      
	,CSL_CIC2_MPU_2_INT      
#ifdef CSL_CIC2_MPU_3_INT
	,CSL_CIC2_MPU_3_INT      
#endif
#ifdef CSL_CIC2_MPU_4_INT
	,CSL_CIC2_MPU_4_INT      
#endif
	,CSL_CIC2_MPU_5_INT      
#ifdef CSL_CIC2_MPU_6_INT
	,CSL_CIC2_MPU_6_INT      
#endif
	,CSL_CIC2_MPU_7_INT      
	,CSL_CIC2_MPU_8_INT      
	,CSL_CIC2_MPU_9_INT      
	,CSL_CIC2_MPU_10_INT      
	,CSL_CIC2_MPU_11_INT      
	,CSL_CIC2_MPU_12_INT      
	,CSL_CIC2_MPU_13_INT      
	,CSL_CIC2_MPU_14_INT      
#ifdef CSL_CIC2_MPU_15_INT
	,CSL_CIC2_MPU_15_INT      
#endif
};

/*****************************************************************************
 Prototype    : KeyStone_CIC_exception_events_mapping
 Description  : CIC exception event mapping to the ARM GIC
 Input        : void  
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/10/5
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void KeyStone_CIC_exception_events_mapping(void)
{
	int i;
	
	/* Disable Global host interrupts. */
	gpCIC_regs->GLOBAL_ENABLE_HINT_REG= 0;

	for(i=0; i< sizeof(gCIC_exception_events)/2; i++)
	{
		KeyStone_CIC_event_map(gpCIC_regs, gCIC_exception_events[i], gCIC_EXC_out_num);

		//record the enabled events, exception handler will check error according to this records
		gCIC_EXC_EN_MASK[gCIC_exception_events[i]>>5] |= (1<<(gCIC_exception_events[i]&0x1F));	
	}

	/* Enable Global host interrupts. */
	gpCIC_regs->GLOBAL_ENABLE_HINT_REG= 1;

}

void DDR3_IRQ_handler(Uint32 uiDDR3_num)
{
	int i;
	Uint32 uiStatus, uiOneBitErrorCnt;
	unsigned long long ullErrorAddress;
	CSL_Emif4fvRegs * DDR3ControlRegs;
#if (2==CSL_DDR3_PER_CNT)
	/*for Device has two DDR3 interfaces*/
	DDR3ControlRegs= gpDDR3ControlRegs[uiDDR3_num];

	printf("  DDR3_%c error happened.\n", 'A'+uiDDR3_num);
#else
	/*for Device has one DDR3 interface*/
	DDR3ControlRegs= gpDDR3ControlRegs;

	printf("  DDR3 error happened.\n");
#endif

	uiOneBitErrorCnt= DDR3ControlRegs->ONE_BIT_ECC_ERR_CNT;
	if(uiOneBitErrorCnt)
		printf("   1-bit ECC error happend %d times. Error distribution: 0x%08x%08x\n", 
			uiOneBitErrorCnt,
			DDR3ControlRegs->ONE_BIT_ECC_ERR_DIST_2,
			DDR3ControlRegs->ONE_BIT_ECC_ERR_DIST_1);

	uiStatus= DDR3ControlRegs->IRQSTATUS_SYS;

	if(uiStatus&CSL_EMIF4FV_IRQSTATUS_SYS_REG_2B_ECC_ERR_SYS_MASK)
	{
		ullErrorAddress= DDR3ControlRegs->TWO_BIT_ECC_ERR_ADDR_LOG;
		printf("   2-bit ECC error happened at DDR internal address 0x%llx\n", ullErrorAddress<<1);
		DDR3ControlRegs->TWO_BIT_ECC_ERR_ADDR_LOG= 1; 	//clear the log
	}
	if(uiStatus&CSL_EMIF4FV_IRQSTATUS_SYS_REG_1B_ECC_ERR_SYS_MASK)
	{
		DDR3ControlRegs->ONE_BIT_ECC_ERR_CNT= uiOneBitErrorCnt; 	//decrement the count

		//check error address
		if(uiOneBitErrorCnt>2)
			uiOneBitErrorCnt= 2; //only have two address record
		for(i=0; i<uiOneBitErrorCnt; i++)
		{
			ullErrorAddress= DDR3ControlRegs->ONE_BIT_ECC_ERR_ADDR_LOG;
			printf("   1-bit ECC error happened at DDR internal address 0x%llx\n", ullErrorAddress<<1);
			DDR3ControlRegs->ONE_BIT_ECC_ERR_ADDR_LOG= 1; 	//POP the next
		}
	}
	if(uiStatus&CSL_EMIF4FV_IRQSTATUS_SYS_REG_WR_ECC_ERR_SYS_MASK)
	{
		printf("   unaligned write to ECC range.\n");
	}
	if(uiStatus&CSL_EMIF4FV_IRQSTATUS_SYS_REG_ERR_SYS_MASK)
	{
		printf("   VBUSM command or address error.\n");
	}

	//clear the status
	DDR3ControlRegs->IRQSTATUS_SYS= CSL_EMIF4FV_IRQSTATUS_SYS_REG_1B_ECC_ERR_SYS_MASK
		|CSL_EMIF4FV_IRQSTATUS_SYS_REG_2B_ECC_ERR_SYS_MASK
		|CSL_EMIF4FV_IRQSTATUS_SYS_REG_WR_ECC_ERR_SYS_MASK
		|CSL_EMIF4FV_IRQSTATUS_SYS_REG_ERR_SYS_MASK;

}

/*****************************************************************************
 Prototype    : KeyStone_CIC_EXC_handler
 Description  : This function handle the exception events from CIC
 Input        : void
 Output       : None
 Return Value : void
 
  History        :
  1.Date         : 2012/10/28
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void KeyStone_CIC_EXC_handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	int i;
	Uint32 status[15], uiTempStatus;
	Uint16 MPU_events[16]=
	{
		CSL_CIC2_MPU_0_INT      
		,CSL_CIC2_MPU_1_INT      
		,CSL_CIC2_MPU_2_INT      
#ifdef CSL_CIC2_MPU_3_INT
		,CSL_CIC2_MPU_3_INT      
#else
		,0xFFFF
#endif
#ifdef CSL_CIC2_MPU_4_INT
		,CSL_CIC2_MPU_4_INT      
#else
		,0xFFFF
#endif
		,CSL_CIC2_MPU_5_INT      
#ifdef CSL_CIC2_MPU_6_INT
		,CSL_CIC2_MPU_6_INT      
#else
		,0xFFFF
#endif
		,CSL_CIC2_MPU_7_INT      
		,CSL_CIC2_MPU_8_INT      
		,CSL_CIC2_MPU_9_INT      
		,CSL_CIC2_MPU_10_INT      
		,CSL_CIC2_MPU_11_INT      
		,CSL_CIC2_MPU_12_INT      
		,CSL_CIC2_MPU_13_INT      
		,CSL_CIC2_MPU_14_INT      
#ifdef CSL_CIC2_MPU_15_INT
		,CSL_CIC2_MPU_15_INT      
#else
		,0xFFFF
#endif
	};

	printf("External exception happened at program address 0x%x!\n", uiIntAddress);

	/*Step1: Disable CIC host interrupt*/
	KeyStone_CIC_disable_host_int(gpCIC_regs, gCIC_EXC_out_num);

	for(i=0; i<sizeof(gCIC_EXC_EN_MASK)/4; i++)
	{
		status[i]  = gpCIC_regs->ENA_STATUS_REG[i]&gCIC_EXC_EN_MASK[i];

		/*Step2: clear system events*/
		gpCIC_regs->ENA_STATUS_REG[i]= status[i];
	}
	
	/*----------------------------EDMA error-----------------------------*/      
	/*                                                                           
	CIC: 0xD5 EDMA3CC0 EDMACC_ERRINT EDMA3CC0 error interrupt                       
	CIC: 0xD7 EDMA3CC0 EDMATC_ERRINT0 EDMA3CC0 EDMA3TC0 error interrupt             
	CIC: 0xD8 EDMA3CC0 EDMATC_ERRINT1 EDMA3CC0 EDMA3TC1 error interrupt*/  
	uiTempStatus= (status[CSL_CIC2_EDMACC_0_ERRINT/32]>>(CSL_CIC2_EDMACC_0_ERRINT%32))&0xD;
	if(uiTempStatus) 
		EDMA_error_handler(0, uiTempStatus);                                      
                                                                               
	/*                                                                           
	CIC: 0xD9 EDMA3CC1 EDMACC_ERRINT EDMA3CC1 error interrupt                       
	CIC: 0xDB EDMA3CC1 EDMATC_ERRINT0 EDMA3CC1 EDMA3TC0 error interrupt             
	CIC: 0xDC EDMA3CC1 EDMATC_ERRINT1 EDMA3CC1 EDMA3TC1 error interrupt             
	CIC: 0xDD EDMA3CC1 EDMATC_ERRINT2 EDMA3CC1 EDMA3TC2 error interrupt             
	CIC: 0xDE EDMA3CC1 EDMATC_ERRINT3 EDMA3CC1 EDMA3TC3 error interrupt*/           
	uiTempStatus= (status[CSL_CIC2_EDMACC_1_ERRINT/32]>>(CSL_CIC2_EDMACC_1_ERRINT%32))&0x3D;
	if(uiTempStatus)
		EDMA_error_handler(1, uiTempStatus);                                     
                                                                               
    /*                                                                         
	CIC: 0xDF EDMA3CC2 EDMACC_ERRINT EDMA3CC2 error interrupt                       
	CIC: 0xE1 EDMA3CC2 EDMATC_ERRINT0 EDMA3CC2 EDMA3TC0 error interrupt             
	CIC: 0xE2 EDMA3CC2 EDMATC_ERRINT1 EDMA3CC2 EDMA3TC1 error interrupt             
	CIC: 0xE3 EDMA3CC2 EDMATC_ERRINT2 EDMA3CC2 EDMA3TC2 error interrupt             
	CIC: 0xE4 EDMA3CC2 EDMATC_ERRINT3 EDMA3CC2 EDMA3TC3 error interrupt*/           
	uiTempStatus= ((status[CSL_CIC2_EDMACC_2_ERRINT/32]>>(CSL_CIC2_EDMACC_2_ERRINT%32))&1)
		|(((status[CSL_CIC2_EDMACC_2_TC_0_ERRINT/32]>>(CSL_CIC2_EDMACC_2_TC_0_ERRINT%32))&0xF)<<2);
	if(uiTempStatus)
		EDMA_error_handler(2, uiTempStatus);                               
                                                                               
#ifdef CSL_EDMACC_3                                                            
	/*                                                                           
	CIC: 0xE5 EDMA3CC3 EDMACC_ERRINT EDMA3CC3 error interrupt                       
	CIC: 0xE7 EDMA3CC3 EDMATC_ERRINT0 EDMA3C3 EDMA3TC0 error interrupt              
	CIC: 0xE8 EDMA3CC3 EDMATC_ERRINT1 EDMA3CC3 EDMA3TC1 error interrupt*/           
	uiTempStatus= (status[CSL_CIC2_EDMACC_3_ERRINT/32]>>(CSL_CIC2_EDMACC_3_ERRINT%32))&0xD;
	if(uiTempStatus)                           
		EDMA_error_handler(3, uiTempStatus);                                
#endif

#ifdef CSL_EDMACC_4                                                            
	/*                                                                           
	CIC: 0xE9 EDMA3CC4 EDMACC_ERRINT EDMA3CC4 error interrupt                       
	CIC: 0xEB EDMA3CC4 EDMATC_ERRINT0 EDMA3C4 EDMA3TC0 error interrupt              
	CIC: 0xEC EDMA3CC4 EDMATC_ERRINT1 EDMA3CC4 EDMA3TC1 error interrupt*/           
	uiTempStatus= (status[CSL_CIC2_EDMACC_4_ERRINT/32]>>(CSL_CIC2_EDMACC_4_ERRINT%32))&0xD;
	if(uiTempStatus)                           
		EDMA_error_handler(4, uiTempStatus);                                
#endif                                                                         
	/*----------------------------MPU error-----------------------------*/
	for(i=0; i<16; i++)
	{
		if(0xFFFF==MPU_events[i]) 	//MPU not availible
			continue;
			
		if(status[MPU_events[i]>>5]&(1<<(MPU_events[i]&0x1F)))
		{
			KeyStone_peripherals_MPU_excepiton_handler(i);
		}
	}
    
	/*--------------------------MSMC EDC error--------------------------*/
	if((status[CSL_CIC2_MSMC_DEDC_NC_ERROR/32]&(1<<(CSL_CIC2_MSMC_DEDC_NC_ERROR%32)))
		||(status[CSL_CIC2_MSMC_SCRUB_NC_ERROR/32]&(1<<(CSL_CIC2_MSMC_SCRUB_NC_ERROR%32)))
		||(status[CSL_CIC2_MSMC_SCRUB_CERROR/32]&(1<<(CSL_CIC2_MSMC_SCRUB_CERROR%32)))
		||(status[CSL_CIC2_MSMC_DEDC_CERROR/32]&(1<<(CSL_CIC2_MSMC_DEDC_CERROR%32))))
	{
		KeyStone_MSMC_RAM_EDC_handler();
	}

	/*------------------------MSMC protection error---------------------*/
	if((status[CSL_CIC2_MSMC_MPF_ERROR0/32]>>(CSL_CIC2_MSMC_MPF_ERROR0%32))&0xFFFF)
		KeyStone_MSMC_protection_exception_handler();

	/*----------------------------DDR ECC error-------------------------*/
	//CIC: DDR3_0_ERR DDR3_A_EMIF Error Interrupt
	if(status[CSL_CIC2_DDR3_0_ERR/32]&(1<<(CSL_CIC2_DDR3_0_ERR%32)))
	{
		DDR3_IRQ_handler(CSL_DDR3_0);
	}

#ifdef CSL_DDR3_1
	//CIC: DDR3_1_ERR DDR3_B_EMIF Error Interrupt
	if(status[CSL_CIC2_DDR3_1_ERR/32]&(1<<(CSL_CIC2_DDR3_1_ERR%32)))
	{
		DDR3_IRQ_handler(CSL_DDR3_1);
	}
#endif

    /*Step3: Enable the CIC host interrupt */
    KeyStone_CIC_enable_host_int(gpCIC_regs, gCIC_EXC_out_num);    

}

/*exception handler for watchdog timer*/
void Watchdog_Timer_Handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiInterruptID;
	uiInterruptID= GIC_GET_INT_ID(uiIAR_value);

	printf("Watch dog timer for ARM core %d expired at program address 0x%x!\n", 
		uiInterruptID-32, uiIntAddress);
}

/*exception handler for bus error*/
void ARM_bus_error_Handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	CPU_securely_execute(CP15_clear_AXI_bus_error); /*the error could not be cleared???*/
	printf("ARM AXI bus error happened at program address 0x%x!\n", uiIntAddress);
}

/*parser the higer 32-bit of the emory Error Syndrome Register*/
void ARM_memory_error_parser(Uint32 uiError)
{
	if(uiError&CP15_MEMORY_FATAL_ERROR_MASK)
		printf(" Non-fatal error, ");
	else
		printf(" Fatal error, ");
	printf("repeat error count= %d, random error count= %d\n",
		(uiError&CP15_MEMORY_REPEAT_ERROR_CNT_MASK)>>CP15_MEMORY_REPEAT_ERROR_CNT_SHIFT,
		(uiError&CP15_MEMORY_RANDOM_ERROR_CNT_MASK)>>CP15_MEMORY_RANDOM_ERROR_CNT_SHIFT);
}

/*check ARM CorePac memory error*/
void ARM_memory_error_check()
{
	Uint32 uiError;

	uiError= CP15_get_CPU_memory_error_count();
	if(uiError)
	{
		puts("CPU memory (L1 cache or TLB) error happened:");
		ARM_memory_error_parser(uiError);
	}
	uiError= CP15_get_L2_memory_error_count();
	if(uiError)
	{
		puts("L2 memory error happened:");
		ARM_memory_error_parser(uiError);
	}
}

/*exception handler for ECC of internal RAM*/
void ARM_internal_ECC_error_Handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	ARM_memory_error_check();
	CPU_securely_execute(CP15_clear_L2_async_error);
	printf("ARM internal ECC error happened at program address 0x%x!\n", uiIntAddress);
}

/*****************************************************************************
 Prototype    : KeyStone_Exception_cfg
 Description  : Config the system error and external exception.
                Call this function as last step after all 
                configuration/initialization complete
 Input        : Bool bGlobalExceptionMaster. If TRUE, the global exception events 
                from CIC will be routed to exception model of this CPU core.
 Output       : None
 Return Value : 
*****************************************************************************/
void KeyStone_Exception_cfg(Bool bGlobalExceptionMaster)
{
	GIC_INT_Config int_cfg;
	Uint32 uiCoreNum;

	puts("Enable Exception handling...");

	int_cfg.ucGroupNum= 0; 	//exception route to group 0, FIQ
	int_cfg.ucPriority= GIC400_PRIORITY_HIGHER;

	int_cfg.trigger_type= GIC_TRIGGER_TYPE_LEVEL;

	//hook ARM internal ECC interrupt
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_ARM_NINTERRIRQ), 
		&int_cfg, ARM_internal_ECC_error_Handler);
	CP15_clear_L2_async_error();

#if 0	/*this error always happens???*/
	//hook ARM AXI bus error interrupt
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_ARM_NAXIERRIRQ), 
		&int_cfg, ARM_bus_error_Handler);
	CP15_clear_AXI_bus_error();
#endif
	uiCoreNum= CP15_get_CPU_ID();

	int_cfg.trigger_type= GIC_TRIGGER_TYPE_EDGE;

	//hook watch dog timer interrupt
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_RSTMUX_INT8+uiCoreNum), 
		&int_cfg, Watchdog_Timer_Handler);

	if(bGlobalExceptionMaster)
	{
		/*enable exception events routed from CIC,
		please note, this should be only configured for one ARM core*/
		KeyStone_CIC_exception_events_mapping();

		//hook error interrupt from CIC2
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CIC2_ERROR_INT_ID), 
			&int_cfg, KeyStone_CIC_EXC_handler);
	}

	/*Eanble external exception, global exception enable*/
	//CPU_FIQ_enable();
}


//array of interrupt handling function pointers
INT_Handler_t INT_Handlers[NUM_GIC_INTERRUPTS];

void GIC_handler(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiInterruptID;
	uiInterruptID= GIC_GET_INT_ID(uiIAR_value);

	if(uiInterruptID>=NUM_GIC_INTERRUPTS)
		printf("spurious interrupt %d happened at program address 0x%x!\n", 
			uiInterruptID, uiIntAddress);
	else if(INT_Handlers[uiInterruptID])
		INT_Handlers[uiInterruptID](uiIAR_value, uiIntAddress);
	else
		printf("unhooked interrupt %d happened at program address 0x%x!\n", 
			uiInterruptID, uiIntAddress);
}

/*
 * NOTE:
 * =====
 * On a Keystone2 device all transactions recieved 
 * by GIC-400 are marked as secure transactions.
 */

/*interrupt handler for GIC group 0*/
void FIQ_Handler(Uint32 uiIntAddress)
{
	Uint32 uiIAR;

	//acknowledge interrupt, read interrupt ID
	uiIAR = gpGIC_regs->GICC.GICC_IAR;

	GIC_handler(uiIAR, uiIntAddress);

	//end of interrupt
	gpGIC_regs->GICC.GICC_EOIR = uiIAR;
}

/*interrupt handler for GIC group 1*/
void IRQ_Handler(Uint32 uiIntAddress)
{
	Uint32 uiIAR;

	//enable FIQ during IRQ, that is, enable FIQ to preempt IRQ
	CPU_FIQ_enable();	

	//acknowledge interrupt, read interrupt ID
	uiIAR = gpGIC_regs->GICC.GICC_AIAR;

	GIC_handler(uiIAR, uiIntAddress);

	//end of interrupt
	gpGIC_regs->GICC.GICC_AEOIR = uiIAR;
}

void Undefined_Handler(Uint32 uiExceptionAddress)
{
	printf("Undefined instruction exception happened at program address 0x%x!\n", uiExceptionAddress);

	while(1); //trap
}

/*fault status for long descriptor format*/
char * fault_status_str[]=
{
	"",
	"",
	"",
	"",
	"",
	"Translation fault on first level translation",
	"Translation fault on second level translation", 
	"Translation fault on third level translation",
	"",
	"Access flag fault on first level translation",
	"Access flag fault on second level translation", 
	"Access flag fault on third level translation",
	"",
	"Permission fault on first level translation",
	"Permission fault on second level translation", 
	"Permission fault on third level translation",
	"Synchronous external abort",
	"Asynchronous external abort", 
	"",
	"",
	"",
	"Synchronous external abort on first level translation table walk",
	"Synchronous external abort on second level translation table walk", 
	"Synchronous external abort on third level translation table walk",
	"Synchronous parity error on memory access",
	"Asynchronous parity error on memory access", 
	"",
	"",
	"",
	"Synchronous parity error on memory access on first level translation table walk",
	"Synchronous parity error on memory access on second level translation table walk", 
	"Synchronous parity error on memory access on third level translation table walk",
	"",
	"Alignment fault", 
	"Debug event"
};
void Abort_Status(Uint32 FSR, Uint32 FAR)
{
	Uint32 status_id= (FSR&CP15_FSR_STATUS_MASKT)>>CP15_FSR_STATUS_SHIFT;

	if((status_id>34)||(NULL==fault_status_str[status_id]))
		puts("Reserved abort status happened.");
	else
	{
		printf(" %s happened ", fault_status_str[status_id]);
		if((status_id==17)||(status_id==25)||(status_id==34))
			printf("\n"); 	//FAR is invalid
		else
			printf("at address 0x%x.\n", FAR);
	}
}

void Prefetch_Abort_Handler(Uint32 uiExceptionAddress,
	Uint32 IFSR, Uint32 IFAR)
{
	printf("Instruction prefetch abort happened at program address 0x%x!\n", uiExceptionAddress);
	Abort_Status(IFSR, IFAR);

	exit(1);
	//while(1); //trap
}

void Data_Abort_Handler(Uint32 uiExceptionAddress, 
	Uint32 DFSR, Uint32 DFAR, Uint32 ADFSR)
{
	Uint32 uiRAM_ID;
	printf("Data abort exception happened at program address 0x%x!\n", uiExceptionAddress);
	Abort_Status(DFSR, DFAR);

	if(ADFSR&CP15_ADFSR_VALID_MASK)	//error valid
	{
		ARM_memory_error_check();
		if(ADFSR&CP15_ADFSR_L2_ERROR_MASK)
		{
			puts("An L2 ECC double-bit error occurred.");
		}
		uiRAM_ID= (ADFSR&CP15_ADFSR_RAM_ID_MASK)>>CP15_ADFSR_RAM_ID_SHIFT;
		if((8==uiRAM_ID)||(9==uiRAM_ID))
		{
			if(8==uiRAM_ID)
				printf("L1 tag RAM double-bit error occurred. ");
			else
				printf("L1 data RAM double-bit error occurred. ");
			printf("Bank/Way=%d, Index=%d\n",
				(ADFSR&CP15_ADFSR_BANK_WAY_MASK)>>CP15_ADFSR_BANK_WAY_SHIFT,
				(ADFSR&CP15_ADFSR_INDEX_MASK)>>CP15_ADFSR_INDEX_SHIFT);
 		}
	}

	//while(1); //trap
}

/*===================interrupt configure based on GIC-400=====================*/
/*initialize GIC global parameters, must be called before all other GIC-400 operations.
Please note, in K2 devices, all transaction made to GIC are treated as secure transaction*/
void GIC_global_init(GIC_Config * gic_cfg)
{
	int i;

	//clear interrupt handler function pointer table
	for(i=0; i< NUM_GIC_INTERRUPTS; i++)
		INT_Handlers[i]= 0;

	//enable GICD
	if(gic_cfg->bEnableGrp0)
	{
		gpGIC_regs->DISTRIBUTOR.GICD_CTLR |=  GIC_CTLR_ENABLEGRP0_MASK;
	}
	if(gic_cfg->bEnableGrp1)
	{
		gpGIC_regs->DISTRIBUTOR.GICD_CTLR |=  GIC_CTLR_ENABLEGRP1_MASK;
	}

}

/*initialize GIC CPU interface parameters, must be called before all other GIC-400 operations.
Please note, in K2 devices, all transaction made to GIC are treated as secure transaction*/
void GIC_CPU_init(GIC_Config * gic_cfg)
{
	int i;
	Uint32 uiCoreNum, uiClearMask;
	volatile Uint32 *  GICD_ITARGETSR;

	/*enable/disable GICC for current CPU*/
	gpGIC_regs->GICC.GICC_CTLR =  
		 ((gic_cfg->bEnableGrp0<<GIC_CTLR_ENABLEGRP0_SHIFT)&GIC_CTLR_ENABLEGRP0_MASK)
		|((gic_cfg->bEnableGrp1<<GIC_CTLR_ENABLEGRP1_SHIFT)&GIC_CTLR_ENABLEGRP1_MASK)
		|((gic_cfg->bEnableFIQ <<GIC_CTLR_FIQEN_SHIFT     )&GIC_CTLR_FIQEN_MASK     );

	GIC_priority_mask(GIC400_PRIORITY_MASK);

	/*clear all target enable bits for current CPU, 
	actually disable all SPI interrupts to current CPU*/
	uiCoreNum= CP15_get_CPU_ID();
	uiClearMask= ~(0x01010101<<uiCoreNum);
	GICD_ITARGETSR= &gpGIC_regs->DISTRIBUTOR.GICD_ITARGETSR0;
	for(i=8; i<NUM_GIC_INTERRUPTS/4; i++) //GICD_ITARGETSR[7:0] are read only
		GICD_ITARGETSR[i] &= uiClearMask;
	
}

/*configure an interrupt and hook handler for it.
Please note, in K2 devices, all transaction made to GIC are treated as secure transaction*/
void GIC_interrupt_hook(Uint32 uiINT_num, 
	GIC_INT_Config * int_cfg, INT_Handler_t handler)
{
	Uint32 uiPriority, uiTriggerType;
	volatile Uint32 * GICD_ITARGETSR;
	volatile Uint32 * GICD_ISENABLER;
	volatile Uint32 * GICD_ICFGR;
	volatile Uint32 * GICD_IPRIORITYR;
	volatile Uint32 * GICD_IGROUPR;
	volatile Uint32 * GICD_ICPENDR;

	if(uiINT_num> NUM_GIC_INTERRUPTS)
		return;
	if(NULL==handler)
		return;
	if(NULL==int_cfg)
		return;

	GICD_IGROUPR   = &gpGIC_regs->DISTRIBUTOR.GICD_IGROUPR0;
	GICD_IPRIORITYR= &gpGIC_regs->DISTRIBUTOR.GICD_IPRIORITYR0;
	GICD_ICFGR     = &gpGIC_regs->DISTRIBUTOR.GICD_ICFGR0;
	GICD_ITARGETSR = &gpGIC_regs->DISTRIBUTOR.GICD_ITARGETSR0;
	GICD_ISENABLER = &gpGIC_regs->DISTRIBUTOR.GICD_ISENABLER0;
	GICD_ICPENDR   = &gpGIC_regs->DISTRIBUTOR.GICD_ICPENDR0;

	if(0==int_cfg->ucGroupNum) //route to group 0
		GICD_IGROUPR[uiINT_num/32] &= ~(1<<(uiINT_num&31));
	else 	//route to group 1
		GICD_IGROUPR[uiINT_num/32] |= 1<<(uiINT_num&31);

	//clear priority field for this CPU
	uiPriority= GICD_IPRIORITYR[uiINT_num/4] & (~(0xFF<<((uiINT_num&3)*8)));
	//set priority field for this CPU
	GICD_IPRIORITYR[uiINT_num/4] = uiPriority | (int_cfg->ucPriority<<((uiINT_num&3)*8));

	//clear trigger type field for this CPU
	uiTriggerType= GICD_ICFGR[uiINT_num/16] & (~(0x3<<((uiINT_num&15)*2)));
	//set trigger type field for this CPU
	GICD_ICFGR[uiINT_num/16] = uiTriggerType | (int_cfg->trigger_type<<((uiINT_num&15)*2));

	//hook the interrupt handler
	INT_Handlers[uiINT_num] = handler;

	//clear pending interrupt
	GICD_ICPENDR[uiINT_num/32] |= 1<<(uiINT_num&31);

	//enable the interrupt
	GICD_ISENABLER[uiINT_num/32] |= 1<<(uiINT_num&31);

	//enable target bit for current CPU
	GICD_ITARGETSR[uiINT_num/4] |= 1<<((uiINT_num&3)*8+CP15_get_CPU_ID());

}

/*mask out the interrupts with priority lower or equal than the mask_priority_level.
Please note, lower priority vale means higher priority*/
void GIC_priority_mask(GIC_Priority mask_priority_level)
{
 	gpGIC_regs->GICC.GICC_PMR = mask_priority_level;
}

void GIC_interupt_enable(Uint32 uiINT_num)
{
	volatile Uint32 * GICD_ISENABLER;
	GICD_ISENABLER = &gpGIC_regs->DISTRIBUTOR.GICD_ISENABLER0;

	//eanble the interrupt
	GICD_ISENABLER[uiINT_num/32] |= 1<<(uiINT_num&31);
}

void GIC_interupt_disable(Uint32 uiINT_num)
{
	volatile Uint32 * GICD_ICENABLER;
	GICD_ICENABLER = &gpGIC_regs->DISTRIBUTOR.GICD_ICENABLER0;

	//disable the interrupt
	GICD_ICENABLER[uiINT_num/32] |= 1<<(uiINT_num&31);
}

/*generate a software interrupt*/
void GIC_SGI_generate(Uint32 uiSGI_ID, 
	GIC_SGI_Target_Mode_t target_mode, Uint8 ucTargetList)
{
	Uint32 uiGroup;
	volatile Uint32 * GICD_IGROUPR;

	GICD_IGROUPR = &gpGIC_regs->DISTRIBUTOR.GICD_IGROUPR0;
	uiGroup = (GICD_IGROUPR[uiSGI_ID/32]>>(uiSGI_ID&31))&1;
	
	/*SGI is triggered only if SATT field matches the group configuration of this SGI*/
	gpGIC_regs->DISTRIBUTOR.GICD_SGIR =
		 (uiSGI_ID&CSL_GIC400_GICD_SGIR_SGIINTID_MASK)
		|(target_mode&CSL_GIC400_GICD_SGIR_TARGETLISTFILTER_SHIFT)
		|(ucTargetList&CSL_GIC400_GICD_SGIR_CPUTARGETLIST_SHIFT)
		|(uiGroup&CSL_GIC400_GICD_SGIR_SATT_SHIFT);
}

/*poll interrupt status and execute interrupt handler accordingly*/
void ARM_poll_interrupts()
{
#ifdef ARM_POLL_INTERRUPT
	if(CP15_get_interrupt_status()&CP15_ISR_I_MASK)
	{
		IRQ_Handler((Uint32)ARM_poll_interrupts);
	}
	if(CP15_get_interrupt_status()&CP15_ISR_F_MASK)
		FIQ_Handler((Uint32)ARM_poll_interrupts);
#endif
}

/*=========================other utility functions==========================*/
/*****************************************************************************
 Prototype    : K2_get_device_info
 Description  : Get device information
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2010/12/12
    Author       : Brighton Feng
    Modification : Created function
  2.Date         : 2014/7/11
    Author       : Brighton Feng
    Modification : Update to parser device type, boot mode, endian information,
                   speed grade, required voltage...

*****************************************************************************/
Uint32 K2_lookup_device_speed_grade(Uint32 uiSpeedCode)
{
	if(uiSpeedCode&DEVSPEED_800_MHZ_MASK_H)       return 800;
	else if(uiSpeedCode&DEVSPEED_1000_MHZ_MASK_H) return 1000;
	else if(uiSpeedCode&DEVSPEED_1200_MHZ_MASK_H) return 1200;
	else if(uiSpeedCode&DEVSPEED_1350_MHZ_MASK_H) return 1350;
	else if(uiSpeedCode&DEVSPEED_1400_MHZ_MASK_H) return 1400;
	else if(uiSpeedCode&DEVSPEED_1500_MHZ_MASK  ) return 1500;
	else if(uiSpeedCode&DEVSPEED_1400_MHZ_MASK_L) return 1400;
	else if(uiSpeedCode&DEVSPEED_1350_MHZ_MASK_L) return 1350;
	else if(uiSpeedCode&DEVSPEED_1200_MHZ_MASK_L) return 1200;
	else if(uiSpeedCode&DEVSPEED_1000_MHZ_MASK_L) return 1000;
	else                                          return 800;
}

//get device speed grade from the EFUSE register
void K2_get_device_speed_grade()
{
	Uint32 uiDevSpeed;

#ifdef DEVICE_K2L
	uiDevSpeed= gpBootCfgRegs->EFUSE_RSVD0;
#else
	uiDevSpeed= gpBootCfgRegs->EFUSE_RSVD2;
#endif

	printf("DSP speed grade = %dMHz, ARM speed grade= %dMHz\n", 
		K2_lookup_device_speed_grade((uiDevSpeed&DEVSPEED_DSP_SPEED_MASK)>>DEVSPEED_DSP_SPEED_SHIFT),
		K2_lookup_device_speed_grade((uiDevSpeed&DEVSPEED_ARM_SPEED_MASK)>>DEVSPEED_ARM_SPEED_SHIFT));
}
char * device_type_str[]=
{
	"K2H/K2K",
	"K2E",
	"K2L",
	"unknown"
};
char * endian_str[]=
{
	"big",
	"little"
};
char * K2L_boot_mode_str[]=
{
	"no boot or I2C slave",
	"PCIE",
	"I2C master",
	"SPI",
	"EMIF(NOR FLASH)",
	"NAND FLASH",
	"Ethernet",
	"UART"
};
char * K2E_boot_mode_str[]=
{
	"no boot or I2C slave",
	"I2C master",
	"SPI",
	"EMIF(NOR FLASH) or NAND FLASH",
	"no",
	"Ethernet",
	"PCIE or HyperLink",
	"UART"
};
char * K2H_K2K_boot_mode_str[]=
{
	"no boot or I2C slave",
	"I2C master",
	"SPI",
	"EMIF(NOR FLASH) or NAND FLASH",
	"SRIO",
	"Ethernet",
	"PCIE or HyperLink",
	"UART"
};
char * boot_master_str[]=
{
	"ARM",
	"DSP"
};
char * input_clk_str[]=
{
	"50MHz",
	"66.67MHz",
	"80MHz",
	"100MHz",
	"156.25MHz",
	"250MHz",
	"312.5MHz",
	"122.88MHz",
	"bypassed"
};
void K2_get_device_info()
{
	K2_Device_Type device_type;
	char * boot_mode;
	Uint8 ucBootMode, ucBootMaster;
	Uint32 * DieID= (Uint32 *)&gpBootCfgRegs->DIE_ID_REG0;
	Uint32 uiVID;
	Uint32 uiJTAG_ID = gpBootCfgRegs->JTAG_ID_REG0;
	Uint32 uiDevStat = gpBootCfgRegs->DEVSTAT;
	Uint8 ucPLL_cfg= 8; //8 means bypassed

	ucBootMode= (uiDevStat&DEVSTAT_BOOTMODE_MASK)>>DEVSTAT_BOOTMODE_SHIFT; 
	ucBootMaster= (uiDevStat&DEVSTAT_BOOTMASTER_MASK)>>DEVSTAT_BOOTMASTER_SHIFT;
	if(0xB9A602F==(uiJTAG_ID&0xFFFFFFF))
	{
		device_type= K2E;
		boot_mode= K2E_boot_mode_str[ucBootMode];

		//PLL is not configured with SPI and I2C master boot mode
		if((1!=ucBootMode)&&(2!=ucBootMode)) 	
			ucPLL_cfg= (uiDevStat&DEVSTAT_SYSPLL_MASK)>>DEVSTAT_SYSPLL_SHIFT;

#ifndef DEVICE_K2E
		printf("Error: this is a K2E device, please define the DEVICE_K2E in compiler option and rebuild the program!\n");
#endif
	}
	else if(0xB9A702F==(uiJTAG_ID&0xFFFFFFF))
	{
		device_type= K2L;
		boot_mode= K2L_boot_mode_str[ucBootMode];

		//PLL is not configured with SPI and I2C master boot mode
		if((3!=ucBootMode)&&(2!=ucBootMode))
		{
			if(0==ucBootMaster) 	//boot master is ARM
				ucPLL_cfg= (uiDevStat&DEVSTAT_ARMPLL_MASK)>>DEVSTAT_ARMPLL_SHIFT;
			else 	//boot master is DSP
				ucPLL_cfg= (uiDevStat&DEVSTAT_SYSPLL_MASK)>>DEVSTAT_SYSPLL_SHIFT;
		}

#ifndef DEVICE_K2L
		printf("Error: this is a K2L device, please define the DEVICE_K2L in compiler option and rebuild the program!\n");
#endif
	}
	else if(0xB98102F==(uiJTAG_ID&0xFFFFFFF))
	{
		device_type= K2H_K2K;
		boot_mode= K2H_K2K_boot_mode_str[ucBootMode];

		//PLL is not configured with SPI and I2C master boot mode
		if((1!=ucBootMode)&&(2!=ucBootMode))
		{
			if(0==ucBootMaster) 	//boot master is ARM
				ucPLL_cfg= (uiDevStat&DEVSTAT_ARMPLL_MASK)>>DEVSTAT_ARMPLL_SHIFT;
			else 	//boot master is DSP
				ucPLL_cfg= (uiDevStat&DEVSTAT_SYSPLL_MASK)>>DEVSTAT_SYSPLL_SHIFT;
		}

#if (!defined(DEVICE_K2H) && !defined(DEVICE_K2K))
		printf("Error: this is a K2H or K2K device, please define the DEVICE_K2E or DEVICE_K2K in compiler option and rebuild the program!\n");
#endif
	}
	else
	{
		device_type= UNKNOWN;
		boot_mode= "unknown";
	}

	printf("JTAG ID= 0x%08x. This is a %s device, version variant = %d\n", 
		uiJTAG_ID, device_type_str[device_type], uiJTAG_ID>>28);

	printf("DEVSTAT= 0x%08x. %s endian, %s boot, boot master is %s core, PLL configuration implies the input clock for core is %s\n", 
		uiDevStat, endian_str[uiDevStat&DEVSTAT_LENDIAN_MASK], boot_mode, 
		boot_master_str[ucBootMaster], input_clk_str[ucPLL_cfg]);

	if(ucBootMaster)
	{
		puts("Please change boot master to ARM, this program relies on the SMC severice routine supported by the ARM BOOT ROM!");
		while(1);
	}

	uiVID= (gpPSC_regs->VCNTLID&CSL_PSC_VCNTLID_VCNTL_MASK)>>CSL_PSC_VCNTLID_VCNTL_SHIFT;
	printf("SmartReflex VID= %d, required core voltage= %.3fV.\n", uiVID, 0.7+(float)uiVID*0.41/64.f);
	
	printf("Die ID= 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", DieID[0], DieID[1], DieID[2], DieID[3]);

	K2_get_device_speed_grade();
}

/*****************************************************************************
 Prototype    : K2_common_device_init
 Description  : common initialization for internal modules in K2 device 
          enable GIC, memory protection interrupts, EDC for MSMC RAM 
  History        :
  1.Date         : July 11, 2014
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void K2_common_device_init()
{
	GIC_Config gic_cfg;

	K2_get_device_info();

	//initialize GIC400, must be called before all other GIC400 operations
	gic_cfg.bEnableFIQ= TRUE;
	gic_cfg.bEnableGrp0= TRUE;
	gic_cfg.bEnableGrp1= TRUE;
	GIC_global_init(&gic_cfg);

	KeyStone_MPU_interrupt_enable(0); 	//for CFG
	KeyStone_MPU_interrupt_enable(1); 	//for QMSS
	KeyStone_MPU_interrupt_enable(2); 	//for QMSS
	KeyStone_MPU_interrupt_enable(5); 	//for QMSS
	KeyStone_MPU_interrupt_enable(9); 	//for interrupt controllers
	KeyStone_MPU_interrupt_enable(10); 	//for semaphore
	KeyStone_MPU_interrupt_enable(11); 	//for CFG
	KeyStone_MPU_interrupt_enable(12); 	//for SPI0
	KeyStone_MPU_interrupt_enable(13); 	//for SPI1
	KeyStone_MPU_interrupt_enable(14); 	//for SPI2
	
	KeyStone_MSMC_MP_interrupt_en();

	/*Enable MSMC EDC and setup scrubbing cycle counter= 255*1024*/
	KeyStone_MSMC_RAM_EDC_enable(255);
}

/*****************************************************************************
 Prototype    : K2_common_CPU_init
 Description  : common initialization for ARM CPU, should be called after 
                K2_common_device_init()
  History        :
  1.Date         : September 1, 2014
    Author       : Brighton Feng
    Modification : Created function
*****************************************************************************/
void K2_common_CPU_init()
{
	GIC_Config gic_cfg;

	CP15_BranchPredictionEnable();
	
	//initialize GIC400 interface for CPU
	gic_cfg.bEnableFIQ= TRUE;
	gic_cfg.bEnableGrp0= TRUE;
	gic_cfg.bEnableGrp1= TRUE;
	GIC_CPU_init(&gic_cfg);

	//enabel PMU
	CP15_enable_PMU();
	CP15_enable_PMU_user_access();
	CP15_enable_CCNT();
	calc_cycle_measure_overhead();

	PMU_CCNT_overflow_INT_setup();

	puts("Enable IRQ and FIQ.");
	CPU_IRQ_enable();
	CPU_FIQ_enable();
}

