/******************************************************************************
  Copyright (C), 2013, Texas Instrument.
 ******************************************************************************
  File Name     : K2_DDR_Init.c
  Version       : Initial Draft
  Author        : Brighton Feng
  Created       : May 18, 2013
  Last Modified :
  Description   : KeyStone 2 DDR configuration
  History       :
  1.Date        : May 18, 2013
    Author      : Brighton Feng
    Modification: Created file
******************************************************************************/
#include <stdio.h>
#include <csl_bootcfgaux.h>
#include "K2_DDR_Init.h"
/*----------------------------------------------*
 * project-wide global variables                *
 *----------------------------------------------*/
#if (2==CSL_DDR3_PER_CNT)
/*for Device has two DDR3 interfaces*/
DDR3_PHY_Regs * gDDR3_PHY_Regs[CSL_DDR3_PER_CNT] = 
{
	(DDR3_PHY_Regs *)CSL_DDR3_0_PHY_CFG_REGS,
	(DDR3_PHY_Regs *)CSL_DDR3_1_PHY_CFG_REGS
};
#else
/*for Device has one DDR3 interface*/
DDR3_PHY_Regs * gDDR3_PHY_Regs = (DDR3_PHY_Regs *)CSL_DDR3_0_PHY_CFG_REGS;
#endif


/*----------------------------------------------*
 * module-wide global variables                 *
 *----------------------------------------------*/
/*look up table for the WR field in the PHY MR0 register*/
unsigned char DDR3_PHY_MR0_WR_LUT[32]=
{
	1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 
	5, 6, 6, 7, 7, 0, 0, 0, 0, 0, 
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
	0, 0 
};
/*----------------------------------------------*
 * macros                                       *
 *----------------------------------------------*/
/*covert DDR timing value in nanosecond to number of clocks (round up)*/
#define DDR_NS_TO_CLK(ns, clkMHz) ((unsigned int)((ns)*(clkMHz)/1000.f+0.99999f))
#define DDR_NS_TO_CLK_MINUS_1(ns, clkMHz) (DDR_NS_TO_CLK(ns, clkMHz)-1)

/*some DDR3 timing are specified as maximum of nanosecond and number of clock,
this function compare two values and select the maximum one*/
#define DDR_MAX_CLK(time, clkMHz) MAX(time.nCK, (unsigned int)(time.ns*clkMHz/1000.f+0.99999f))
#define DDR_MAX_CLK_MINUS_1(time, clkMHz) (DDR_MAX_CLK(time, clkMHz)-1)

/*****************************************************************************
 Prototype    : K2_DDR_PHY_status_check
 Description  : check the status of DDR PHY
 Input        : DDR3_PHY_Regs * PHY_Regs    
 Output       : error information if any
 Return Value : 0 if all done without error; PGSR0 register value if any error
 
  History        :
  1.Date         : November 22, 2013
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
/*bit 20~27 of PGSR0 register*/
char * DDR_PHY_error_str[]=
{
	"Impedance Calibration",
	"Write Leveling",
	"DQS Gate Training",
	"Write Leveling Adjustment",
	"Read Bit Deskew",
	"Write Bit Deskew",
	"Read Eye Training",
	"Write Eye Training"
};
/*bit 0~11 of PGSR0 register*/
char * DDR_PHY_done_str[]=
{
	"All initialization routines",
	"PLL Lock",
	"Digital Delay Line (DDL) Calibration",
	"Impedance Calibration",
	"DRAM Initialization",
	"Write Leveling",
	"DQS Gate Training",
	"Write Leveling Adjustment",
	"Read Bit Deskew",
	"Write Bit Deskew",
	"Read Eye Training",
	"Write Eye Training"
};
int K2_DDR_PHY_status_check(DDR3_PHY_Regs * PHY_Regs)
{
	int i;
	volatile Uint32 PGSR0= PHY_Regs->PGSR0;
	
	if(0x80000FFF==PGSR0)
		return 0;

	printf("DDR PHY status PGSR0=0x%x.\n", PGSR0);

	if(DDR3_PHY_PGSR0_APLOCK_MASK!= (PGSR0&DDR3_PHY_PGSR0_APLOCK_MASK))
		puts("DDR PHY ERROR: AC PLL is NOT locked!");
	
	/*bit 20~27 should be "0", which means no error*/
	for(i=20; i<=27; i++)
	{
		if(0 != (PGSR0&(1<<i)))
			printf("DDR PHY %s error!\n", DDR_PHY_error_str[i-20]);
	}

	/*bit 0~11 should be "1", which means all done*/
	for(i=0; i<=11; i++)
	{
		if(0==(PGSR0&(1<<i)))
			printf("DDR PHY %s is NOT done!\n", DDR_PHY_done_str[i]);
	}

	return PGSR0;
}

void K2_DDR_PHY_wait_stauts(DDR3_PHY_Regs * PHY_Regs,
	Uint32 status_mask)
{
	Uint32 uiRetryTimes=0;
	volatile Uint32 PGSR0;
	do{
		TSC_delay_us(1);
		PGSR0= PHY_Regs->PGSR0;
		uiRetryTimes++;
		if(uiRetryTimes>1000000)
		{
			puts("wait DDR3 PHY status in PGSR0 register timeout!");
			return;
		}
	}while ((PGSR0&status_mask) != status_mask);

}

/*****************************************************************************
 Prototype    : K2_DDR_Init
 Description  : setup the DDR3
 Input        : DDR3_Config * DDR_cfg    
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : May 19, 2013
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void K2_DDR_Init(DDR3_Config * DDR_cfg)
{
	int i;
	float data_rate_MTS, clock_MHz;
	unsigned int FRQSEL, refresh_period_clocks, num_bytes, T_RTW;

	Uint32 ECC_EN= 0;
	Uint32 ECC_RANGE_PROT= 0;
	Uint32 ADDR_RNG_EN[2]= {0, 0};
	Uint32 START_ADDR[2]= {0, 0};
	Uint32 END_ADDR[2]= {0, 0};

	CSL_Emif4fvRegs * ControlRegs= DDR_cfg->ControlRegs;
	DDR3_PHY_Regs * PHY_Regs= DDR_cfg->PHY_Regs;
	DDR3_ECC_Config * ecc_cfg= DDR_cfg->ecc_cfg;
	DDR3_Arbitration_Config * arbitration_cfg= DDR_cfg->arbitration_cfg;

	/*The DDR3 Controller and PHY control registers are located in a memory 
	space that is protected from erroneous writes by errant software. Therefore, 
	before these registers can be written an unlock sequence must have been 
	completed. This requires writes of specific key words to the KICK1 and KICK2
	registers if these have not already been left unlocked by the PLL 
	programming routines.*/
	CSL_BootCfgUnlockKicker();

	/*the Main PLL and the DDR3 PLL for this interface must be configured
	and allowed to lock. They must be stable before beginning this DDR3 interface 
	configuration sequence.*/

	data_rate_MTS= DDR_cfg->ref_clock_MHz/DDR_cfg->PLL_input_divisor*
		DDR_cfg->PLL_multiplier/DDR_cfg->PLL_output_divisor*4;
	clock_MHz= data_rate_MTS/2; 	//data speed is double of clock speed

	refresh_period_clocks= (unsigned int)64000.f*clock_MHz/8192.f;
	//if the DDR operating temperatue exceeds 85C, refresh rate should be double
	if(DDR_TEMP_OVER_85C==DDR_cfg->temperature)
		refresh_period_clocks /= 2;

	/*Note that the DDR3 PLL on KeyStone-II devices will need to output half of 
	the DDR3 clock frequency.  The DDR3 PLL output frequency will be a quarter 
	of the DDR3 data rate.*/
	if(KeyStone_PLL_init(DDR_cfg->PLL_Regs, DDR_cfg->PLL_input_divisor, 
		DDR_cfg->PLL_multiplier, DDR_cfg->PLL_output_divisor))
		return;

	printf("Initialize DDR data rate = %.3f/%d*%d/%d*4= %.1f MTS, bus width = %d bits.\n", 
		DDR_cfg->ref_clock_MHz, DDR_cfg->PLL_input_divisor, DDR_cfg->PLL_multiplier, 
		DDR_cfg->PLL_output_divisor, data_rate_MTS, 64>>(DDR_cfg->busWidth));

	/*Drives CKE low. (not required on K2)
	This is a JEDEC requirement that we have 500us delay between reset de-assert 
	and cke assert and then program the correct refresh rate
	The DDR internal clock is divide by 16 before SDCFG write*/
	//ControlRegs->SDRAM_REF_CTRL = CSL_EMIF4FV_SDRAM_REF_CTRL_REG_INITREF_DIS_MASK
		//|(unsigned int)(500.f*clock_MHz/16.f);

	/*1. Poll the IDONE bit in the PHY General Status Register 0 (address offset 
	0x010). The DDR3 controller and PHY execute an initialization sequence after 
	reset release that must complete before programming. The IDONE bit will be 
	set to a ˇ°1ˇ± once this initialization is complete. Do not proceed until 
	the IDONE bit is set.*/
	K2_DDR_PHY_wait_stauts(PHY_Regs, DDR3_PHY_PGSR0_IDONE_MASK);

	/*2a. Program FRQSEL in the PHY PLL Control Register (address offset 0x018). 
	The FRQSEL value is based on the DDR3 output clock frequency.*/
	if(clock_MHz/2<166)
	{
		puts("Error: data rate lower than 666");
		return;
	}
	else if(clock_MHz/2<(225+275)/2)
		FRQSEL= 3;
	else if(clock_MHz/2<(335+385)/2)
		FRQSEL= 1;
	else 
		FRQSEL= 0;
	PHY_Regs->PLLCR = (PHY_Regs->PLLCR&(~DDR3_PHY_PLLCR_FRQSEL_MASK))
		|(FRQSEL<<DDR3_PHY_PLLCR_FRQSEL_SHIFT);

	/*2b. Program WLSTEP (bit 2) =1, IODDRM (bits 7 and 8) =1, and ZCKSEL (bits 
	24 and 23) in the PHY General Configuration Register 1 (address offset 
	0x00C). All other fields must be left at their default values. We recommend 
	using a read©\modify©\write sequence to preserve the other bits.*/
	PHY_Regs->PGCR1 = (PHY_Regs->PGCR1
		&(~(DDR3_PHY_PGCR1_IODDRM_MASK|DDR3_PHY_PGCR1_ZCKSEL_MASK
		|DDR3_PHY_PGCR1_WLSTEP_MASK)))
		|(1<<DDR3_PHY_PGCR1_WLSTEP_SHIFT)
		|(1<<DDR3_PHY_PGCR1_IODDRM_SHIFT)
		|(1<<DDR3_PHY_PGCR1_ZCKSEL_SHIFT);/*(vbusp_clk(main_clk/6)/ZCKSEL_div)<=33MHz*/

	/*2c. Program PHY Timing Parameters Register 3,4. 
	The default values of PTR0/1/2 are conservative, it is safe to use default value.*/
	//PHY_Regs->PTR0 =
	//PHY_Regs->PTR1 =
	//PHY_Regs->PTR2 =
	PHY_Regs->PTR3 = 
		 (DDR_MAX_CLK(DDR_cfg->tXS, clock_MHz)<<DDR3_PHY_PTR3_TDINIT1_SHIFT)
		|(DDR_NS_TO_CLK(500000, clock_MHz)<<DDR3_PHY_PTR3_TDINIT0_SHIFT);

	PHY_Regs->PTR4 =
		 (DDR_NS_TO_CLK(1000  , clock_MHz)<<DDR3_PHY_PTR4_TDINIT3_SHIFT)
		|(DDR_NS_TO_CLK(200000, clock_MHz)<<DDR3_PHY_PTR4_TDINIT2_SHIFT);

	/*2d. Program PDQ (bits 4, 5 and 6) =0, MPRDQ (bit 7) =0, BYTEMASK (bits 10 
	through 15) =1, NOSRA (bit 27) =1 in the DRAM 
	Configuration Register (address offset 0x044). All other fields must be 
	left at their default values. We recommend using a read©\modify©\write 
	sequence to preserve the other bits.*/
	PHY_Regs->DCR= (PHY_Regs->DCR
		&(~(DDR3_PHY_DCR_PDQ_MASK|DDR3_PHY_DCR_MPRDQ_MASK|DDR3_PHY_DCR_BYTEMASK_MASK
		|DDR3_PHY_DCR_NOSRA_MASK|DDR3_PHY_DCR_UDIMM_MASK)))
		|(1<<DDR3_PHY_DCR_BYTEMASK_SHIFT)
		|((Uint32)(DDR_cfg->bUDIMM_address_mirror)<<DDR3_PHY_DCR_NOSRA_SHIFT)
		|((Uint32)(DDR_cfg->bUDIMM_address_mirror)<<DDR3_PHY_DCR_UDIMM_SHIFT);

	/*2e. Program DRAM Timing Parameters Register 0©\2 (address offset 0x048 ©\ 
	0x050) based on the timing parameters extracted from the DRAM datasheet.*/
	PHY_Regs->DTPR0 = 
		 (DDR_NS_TO_CLK(DDR_cfg->tRC , clock_MHz)<<DDR3_PHY_DTPR0_TRC_SHIFT   )
		|(DDR_MAX_CLK  (DDR_cfg->tRRD, clock_MHz)<<DDR3_PHY_DTPR0_TRRD_SHIFT  )
		|(DDR_NS_TO_CLK(DDR_cfg->tRAS, clock_MHz)<<DDR3_PHY_DTPR0_TRAS_SHIFT  )
		|(DDR_NS_TO_CLK(DDR_cfg->tRCD, clock_MHz)<<DDR3_PHY_DTPR0_TRCD_SHIFT  )
		|(DDR_NS_TO_CLK(DDR_cfg->tRP , clock_MHz)<<DDR3_PHY_DTPR0_TRP_SHIFT   )
		|(DDR_MAX_CLK  (DDR_cfg->tWTR, clock_MHz)<<DDR3_PHY_DTPR0_TWTR_SHIFT  )
		|(DDR_MAX_CLK  (DDR_cfg->tRTP, clock_MHz)<<DDR3_PHY_DTPR0_TRTP_SHIFT  );
	PHY_Regs->DTPR1 = 
		 (DDR_NS_TO_CLK(DDR_cfg->tWLO+DDR_cfg->round_trip_delay_ns, clock_MHz)<<DDR3_PHY_DTPR1_TWLO_SHIFT  )
		|(DDR_cfg->tWLMRD<<DDR3_PHY_DTPR1_TWLMRD_SHIFT)
		|(DDR_NS_TO_CLK(DDR_cfg->tRFC, clock_MHz)<<DDR3_PHY_DTPR1_TRFC_SHIFT  )
		|(DDR_NS_TO_CLK(DDR_cfg->tFAW, clock_MHz)<<DDR3_PHY_DTPR1_TFAW_SHIFT  )
		|((DDR_MAX_CLK(DDR_cfg->tMOD, clock_MHz)-12)<<DDR3_PHY_DTPR1_TMOD_SHIFT  )
		|((DDR_cfg->tMRD-4) <<DDR3_PHY_DTPR1_TMRD_SHIFT  );
	PHY_Regs->DTPR2 = 
		 (DDR_cfg->tCCD <<DDR3_PHY_DTPR2_TCCD_SHIFT  )
		|(1<<DDR3_PHY_DTPR2_TRTW_SHIFT  ) /*add 1 clock to standard bus turn around delay*/
		|(0<<DDR3_PHY_DTPR2_TRTODT_SHIFT) /*ODT may be turned on immediately after read post-amble*/
		|(DDR_cfg->tDLLK<<DDR3_PHY_DTPR2_TDLLK_SHIFT )
		|((DDR_MAX_CLK(DDR_cfg->tCKE, clock_MHz)+1)<<DDR3_PHY_DTPR2_TCKE_SHIFT  )
		|(MAX(DDR_MAX_CLK(DDR_cfg->tXPDLL, clock_MHz),DDR_MAX_CLK(DDR_cfg->tXP, clock_MHz))<<DDR3_PHY_DTPR2_TXP_SHIFT )
		|(MAX(DDR_cfg->tDLLK, DDR_MAX_CLK(DDR_cfg->tXS, clock_MHz))<<DDR3_PHY_DTPR2_TXS_SHIFT );

	/*2f. Program BL=0, CL, WR, and PD=1 in the Mode Register 0 (address offset 
	0x054). All other fields will be programmed to their default values.*/
	PHY_Regs->MR0 = (PHY_Regs->MR0&(~(DDR3_PHY_MR0_BL_MASK
		|DDR3_PHY_MR0_CL0_MASK|DDR3_PHY_MR0_CL123_MASK|DDR3_PHY_MR0_WR_MASK
		|DDR3_PHY_MR0_PD_MASK)))
		|((DDR_cfg->CL&1)<<DDR3_PHY_MR0_CL0_SHIFT)
		|((DDR_cfg->CL>>1)<<DDR3_PHY_MR0_CL123_SHIFT)
		|(DDR3_PHY_MR0_WR_LUT[DDR_NS_TO_CLK(DDR_cfg->tWR, clock_MHz)]<<DDR3_PHY_MR0_WR_SHIFT)
		|(1<<DDR3_PHY_MR0_PD_SHIFT);

	/*2g. Program DIC, RTT, and TDQS in the Mode Register 1 (address offset 
	0x058). All other fields will be programmed to their default values.*/
	PHY_Regs->MR1 = (PHY_Regs->MR1&(~(DDR3_PHY_MR1_DIC0_MASK
		|DDR3_PHY_MR1_DIC1_MASK|DDR3_PHY_MR1_RTT0_MASK|DDR3_PHY_MR1_RTT1_MASK
		|DDR3_PHY_MR1_RTT2_MASK|DDR3_PHY_MR1_TDQS_MASK)))
		|((DDR_cfg->drive&1)<<DDR3_PHY_MR1_DIC0_SHIFT)
		|((DDR_cfg->drive>>1)<<DDR3_PHY_MR1_DIC1_SHIFT)
		|((DDR_cfg->DDR_TERM&1)<<DDR3_PHY_MR1_RTT0_SHIFT)
		|(((DDR_cfg->DDR_TERM>>1)&1)<<DDR3_PHY_MR1_RTT1_SHIFT)
		|(((DDR_cfg->DDR_TERM>>2)&1)<<DDR3_PHY_MR1_RTT2_SHIFT)
		|((0)<<DDR3_PHY_MR1_TDQS_SHIFT); /*TDQS function is disabled to enable the DM function*/

	/*2h. Program Mode Register 2 (address offset 0x05C).*/ 
	PHY_Regs->MR2 = (PHY_Regs->MR2&(~(DDR3_PHY_MR2_RTTWR_MASK
		|DDR3_PHY_MR2_CWL_MASK|DDR3_PHY_MR2_PASR_MASK
		|DDR3_PHY_MR2_SRT_MASK|DDR3_PHY_MR2_ASR_MASK)))
		|((DDR_cfg->DYN_ODT)<<DDR3_PHY_MR2_RTTWR_SHIFT)
		|((DDR_cfg->CWL)<<DDR3_PHY_MR2_CWL_SHIFT)
		|((DDR_cfg->temperature)<<DDR3_PHY_MR2_SRT_SHIFT)
		|((0)<<DDR3_PHY_MR2_ASR_SHIFT);

	/*2i. Program DTMPR=1, DTEXD, DTEXG, RANKEN=1 or 3, and RFSHDT=7 in the Data 
	Training Configuration Register (address offset 0x068). All other fields 
	will be programmed to their default values.*/
	PHY_Regs->DTCR = (PHY_Regs->DTCR&(~(DDR3_PHY_DTCR_DTMPR_MASK
		|DDR3_PHY_DTCR_DTEXG_MASK|DDR3_PHY_DTCR_DTEXD_MASK
		|DDR3_PHY_DTCR_RFSHDT_MASK|DDR3_PHY_DTCR_RANKEN_MASK)))
		|(1<<DDR3_PHY_DTCR_DTMPR_SHIFT)
		|((DDR_cfg->num_CE*2+1)<<DDR3_PHY_DTCR_RANKEN_SHIFT)
		|((7)<<DDR3_PHY_DTCR_RFSHDT_SHIFT);

	/*2j. Program tREFPRD in the PHY General Configuration Register 2 (address 
	offset 0x08C). All other fields must be left at their default values. */
	PHY_Regs->PGCR2 = (PHY_Regs->PGCR2&(~DDR3_PHY_PGCR2_TREFPRD_MASK))
		|((refresh_period_clocks*9-400)<<DDR3_PHY_PGCR2_TREFPRD_SHIFT);

	/*2k. Program the ZQ Calibration Registers (address offsets 0x184, 0x194, 
	0x1A4 and 0x1B4) with the calculated values.*/
	PHY_Regs->ZQ[0].CR1= 0x5D; /*for Address / Control / Command*/
	PHY_Regs->ZQ[1].CR1= 0x5B; /*for Data 0 to Data 3*/
	PHY_Regs->ZQ[2].CR1= 0x5B; /*for Data 4 to Data 7*/

	/*3. Re©\trigger PHY initialization which steps the SDRAM through its wake 
	sequence and writes to the mode registers:
	a. Program 0x0000_0033 to the PHY Initialization Register (address offset 0x004).
	b. Poll for IDONE=1 in the PHY General Status Register 0 (address offset 0x010). 
	Do not proceed until the IDONE bit is set.*/
	PHY_Regs->PIR= 0x33;
	K2_DDR_PHY_wait_stauts(PHY_Regs, 
			DDR3_PHY_PGSR0_ZCDONE_MASK | 
			DDR3_PHY_PGSR0_DCDONE_MASK | 
			DDR3_PHY_PGSR0_PLDONE_MASK | 
			DDR3_PHY_PGSR0_IDONE_MASK);

	/*Software must trigger PHY initialization and full leveling/calibration 
	after enabling ECC for the first time. The ECC can then be disabled/re-enabled 
	for test purposes without re-triggering full leveling.*/
	if(ecc_cfg)
	{
		ECC_RANGE_PROT= (Uint32)ecc_cfg->rangeMode;

		for(i= 0; i<2; i++)
		{
			if(ecc_cfg->addressRange[i].byteCnt)
			{
				ADDR_RNG_EN[i]= 1;
				START_ADDR[i]= (ecc_cfg->addressRange[i].startAddr>>17)&0xFFFF;
				END_ADDR[i]= ((ecc_cfg->addressRange[i].startAddr
					+ ecc_cfg->addressRange[i].byteCnt-1)>>17)&0xFFFF;
			}
		}

		if(ecc_cfg->addressRange[0].byteCnt+
			ecc_cfg->addressRange[1].byteCnt)
		{
			ECC_EN= 1;

			ControlRegs->ONE_BIT_ECC_ERR_THRSH= 
				(ecc_cfg->one_bit_ECC_INT_threshold<<CSL_EMIF4FV_ONE_BIT_ECC_ERR_THRSH_REG_1B_ECC_ERR_THRSH_SHIFT)
				|(ecc_cfg->one_bit_ECC_INT_window<<CSL_EMIF4FV_ONE_BIT_ECC_ERR_THRSH_REG_1B_ECC_ERR_WIN_SHIFT);

			//clear the status
			ControlRegs->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;

			//enable error interrupt
			ControlRegs->IRQENABLE_SET_SYS= 
				 CSL_EMIF4FV_IRQENABLE_SET_SYS_REG_EN_1B_ECC_ERR_SYS_MASK
				|CSL_EMIF4FV_IRQENABLE_SET_SYS_REG_EN_2B_ECC_ERR_SYS_MASK
				|CSL_EMIF4FV_IRQENABLE_SET_SYS_REG_EN_WR_ECC_ERR_SYS_MASK
				|CSL_EMIF4FV_IRQENABLE_SET_SYS_REG_EN_ERR_SYS_MASK;
		}
	}

	ControlRegs->ECC_CTRL = 
		((ECC_EN)<<CSL_EMIF4FV_ECC_CTRL_REG_ECC_EN_SHIFT)|
		((ECC_RANGE_PROT)<<CSL_EMIF4FV_ECC_CTRL_REG_ECC_ADDR_RNG_PROT_SHIFT)|
#ifdef CSL_EMIF4FV_ECC_CTRL_REG_RMW_EN_SHIFT
		((ECC_EN)<<CSL_EMIF4FV_ECC_CTRL_REG_RMW_EN_SHIFT)|
#else
		((ECC_EN)<<DDR3_ECC_CTRL_REG_RMW_EN_SHIFT)|
#endif
#ifdef CSL_EMIF4FV_ECC_CTRL_REG_ECC_VERIFY_EN_SHIFT
		((ECC_EN)<<CSL_EMIF4FV_ECC_CTRL_REG_ECC_VERIFY_EN_SHIFT)|
#else
		((ECC_EN)<<DDR3_ECC_CTRL_REG_ECC_VERIFY_EN_SHIFT)|
#endif
		((ADDR_RNG_EN[1])<<CSL_EMIF4FV_ECC_CTRL_REG_ECC_ADDR_RNG_2_EN_SHIFT)|
		((ADDR_RNG_EN[0])<<CSL_EMIF4FV_ECC_CTRL_REG_ECC_ADDR_RNG_1_EN_SHIFT);

	ControlRegs->ECC_ADDR_RNG_1= 
		((START_ADDR[0])<<CSL_EMIF4FV_ECC_ADDR_RNG_1_REG_ECC_STRT_ADDR_1_SHIFT)|
		((END_ADDR[0])<<CSL_EMIF4FV_ECC_ADDR_RNG_1_REG_ECC_END_ADDR_1_SHIFT);

	ControlRegs->ECC_ADDR_RNG_2= 
		((START_ADDR[1])<<CSL_EMIF4FV_ECC_ADDR_RNG_2_REG_ECC_STRT_ADDR_2_SHIFT)|
		((END_ADDR[1])<<CSL_EMIF4FV_ECC_ADDR_RNG_2_REG_ECC_END_ADDR_2_SHIFT);

	/*4. Setup the data lanes for the proper width (64©\bit, 32©\bit or 16©\bit) 
	and with ECC enabled or disabled and then re©\trigger PHY initialization to 
	cause the write leveling and the read training to complete (note that the 
	setup supports all 9 byte lanes enabled ¨C 64 bits of data plus ECC byte lane)*/
	/*4a. If using a 16©\bit wide DDR interface, program DXEN=0 in the DATX8 
	2©\7 General Configuration Registers (address offsets 0x240, 0x280, 
	0x2C0, 0x300, 0x340, and 0x380) to disable the leveling/training for 
	the upper byte lanes.*/
	/*4b. If using a 32©\bit wide DDR interface, program DXEN=0 in the DATX8 
	4©\7 General Configuration Registers (address offsets 0x2C0, 0x300, 0x340, 
	and 0x380) to disable the leveling/training for the upper byte lanes.*/
	if(DDR_BUS_WIDTH_16==DDR_cfg->busWidth)
		num_bytes= 2;
	else if(DDR_BUS_WIDTH_32==DDR_cfg->busWidth)
		num_bytes= 4;
	else
		num_bytes= 8;
	for(i=0; i< num_bytes; i++)
		PHY_Regs->DAT[i].GCR |= DDR3_PHY_DAT_GCR_DXEN_MASK;
	for(i=num_bytes; i< 8; i++)
		PHY_Regs->DAT[i].GCR &= (~DDR3_PHY_DAT_GCR_DXEN_MASK);	

	/*4c. If ECC is not required, program DXEN=0 in the DATX8 8 General 
	Configuration Register (address offset 0x3C0) to disable the 
	leveling/training for the ECC byte lane.*/
	if(ECC_EN) 
		PHY_Regs->DAT[8].GCR |= DDR3_PHY_DAT_GCR_DXEN_MASK;
	else
		PHY_Regs->DAT[8].GCR &= (~DDR3_PHY_DAT_GCR_DXEN_MASK);	

	/*4d. Program 0x0000_FF81 to the PHY Initialization Register (address 
	offset 0x004) to trigger the leveling and training sequences.*/
	/*4e. Poll for IDONE=1 in the PHY General Status Register 0 (address 
	offset 0x010). Do not proceed until the IDONE bit is set.*/
	PHY_Regs->PIR= 0xFF81;
	K2_DDR_PHY_wait_stauts(PHY_Regs, 
			DDR3_PHY_PGSR0_WEDONE_MASK | 
			DDR3_PHY_PGSR0_REDONE_MASK | 
			DDR3_PHY_PGSR0_WDDONE_MASK | 
			DDR3_PHY_PGSR0_RDDONE_MASK | 
			DDR3_PHY_PGSR0_WLADONE_MASK| 
			DDR3_PHY_PGSR0_QSGDONE_MASK| 
			DDR3_PHY_PGSR0_WLDONE_MASK | 
			DDR3_PHY_PGSR0_DIDONE_MASK | 
			DDR3_PHY_PGSR0_ZCDONE_MASK | 
			DDR3_PHY_PGSR0_DCDONE_MASK | 
			DDR3_PHY_PGSR0_PLDONE_MASK | 
			DDR3_PHY_PGSR0_IDONE_MASK);

	/*DDR3 controller arbitration configuration*/
	if(arbitration_cfg)
	{
		ControlRegs->PRI_COS_MAP= CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_COS_MAP_EN_MASK
			|(arbitration_cfg->priority_to_COS_map[7]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_7_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[6]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_6_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[5]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_5_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[4]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_4_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[3]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_3_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[2]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_2_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[1]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_1_COS_SHIFT)
			|(arbitration_cfg->priority_to_COS_map[0]<<CSL_EMIF4FV_PRI_COS_MAP_REG_PRI_0_COS_SHIFT);

		if(arbitration_cfg->COS1_request_max_wait_cycles>4080)
			arbitration_cfg->COS1_request_max_wait_cycles=4080;
		if(arbitration_cfg->COS2_request_max_wait_cycles>4080)
			arbitration_cfg->COS2_request_max_wait_cycles=4080;
		if(arbitration_cfg->old_request_max_wait_cycles>4080)
			arbitration_cfg->old_request_max_wait_cycles=4080;
		ControlRegs->VBUSM_CONFIG= 
			((arbitration_cfg->COS1_request_max_wait_cycles/16)<<CSL_EMIF4FV_VBUSM_CONFIG_REG_COS_COUNT_1_SHIFT)
			|((arbitration_cfg->COS2_request_max_wait_cycles/16)<<CSL_EMIF4FV_VBUSM_CONFIG_REG_COS_COUNT_2_SHIFT)
			|((arbitration_cfg->old_request_max_wait_cycles/16)<<CSL_EMIF4FV_VBUSM_CONFIG_REG_PR_OLD_COUNT_SHIFT);
	}
	else
		/*maximum wait clock (up to 255*16=4080)*/
		ControlRegs->VBUSM_CONFIG= 
			CSL_EMIF4FV_VBUSM_CONFIG_REG_COS_COUNT_1_MASK
			|CSL_EMIF4FV_VBUSM_CONFIG_REG_COS_COUNT_2_MASK
			|CSL_EMIF4FV_VBUSM_CONFIG_REG_PR_OLD_COUNT_MASK;

	/*maximum the read write switch threshold (up to 32*8*8=2048 bytes)*/
	ControlRegs->RD_WR_EXEC_THRSH= 
		CSL_EMIF4FV_RD_WR_EXEC_THRSH_REG_WR_THRSH_MASK
		|CSL_EMIF4FV_RD_WR_EXEC_THRSH_REG_RD_THRSH_MASK;

	/*5. Configure the DDR3 Controller registers to complete the 
	initialization sequence (note that the DDR3 controller registers 
	have a different base address from the PHY registers):*/
	/*5a. Program the SDCFG register (address offset 0x8) based on the 
	interface configuration parameters.*/
	ControlRegs->SDRAM_CONFIG= 
		(3<<CSL_EMIF4FV_SDRAM_CONFIG_REG_SDRAM_TYPE_SHIFT)| 	/*Set to 3 for DDR3. All other values reserved.*/
		(DDR_cfg->DDR_TERM<<CSL_EMIF4FV_SDRAM_CONFIG_REG_DDR_TERM_SHIFT)|
		(DDR_cfg->DYN_ODT<<CSL_EMIF4FV_SDRAM_CONFIG_REG_DYN_ODT_SHIFT)|
		(DDR_cfg->CWL<<CSL_EMIF4FV_SDRAM_CONFIG_REG_CWL_SHIFT)|
		(DDR_cfg->busWidth<<CSL_EMIF4FV_SDRAM_CONFIG_REG_NARROW_MODE_SHIFT)|
		(DDR_cfg->CL<<CSL_EMIF4FV_SDRAM_CONFIG_REG_CL_SHIFT)|
		(DDR_cfg->num_bank<<CSL_EMIF4FV_SDRAM_CONFIG_REG_IBANK_SHIFT)|
		(DDR_cfg->num_CE<<CSL_EMIF4FV_SDRAM_CONFIG_REG_EBANK_SHIFT)|
		(DDR_cfg->pageSize<<CSL_EMIF4FV_SDRAM_CONFIG_REG_PAGESIZE_SHIFT);

	/*5b. Program the four timing parameter registers SDTIM1, SDTIM2, 
	SDTIM3 and SDTIM4 (address offsets 0x18, 0x1C, 0x20 and 0x28) based on 
	the timing parameters taken from the SDRAM data sheet.*/
	ControlRegs->SDRAM_TIM_1 = 
		 (DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tWR,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_1_REG_T_WR_SHIFT     )
		|(DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tRAS, clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_1_REG_T_RAS_SHIFT    )
		|(DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tRC,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_1_REG_T_RC_SHIFT     )
		|(DDR_NS_TO_CLK_MINUS_1((DDR_cfg->tFAW/4), clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_1_REG_T_RRD_SHIFT    )
		|(DDR_MAX_CLK_MINUS_1  (DDR_cfg->tWTR, clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_1_REG_T_WTR_SHIFT    );

	if(DDR_1_CE==DDR_cfg->num_CE)
		/*For single rank: T_RTW = (((2*DQS delay for CS0) 
		+ tDQSCK + write leveling tolerance)/tCK)-1*/
		T_RTW= 3;
	else
		/*For dual rank: T_RTW = (((DQS delay for CS0 + DQS delay for CS1) 
		+ absolute (command delay for CS0 - command delay for CS1) 
		+ tDQSCK + write leveling tolerance)/tCK)-1*/
		T_RTW= 7;
		
	ControlRegs->SDRAM_TIM_2 = 
		 ((T_RTW)<<CSL_EMIF4FV_SDRAM_TIM_2_REG_T_RTW_SHIFT    )
		|(DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tRP,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_2_REG_T_RP_SHIFT     )
		|(DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tRCD, clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_2_REG_T_RCD_SHIFT    );

	ControlRegs->SDRAM_TIM_3 = 
		 (DDR_MAX_CLK_MINUS_1  (DDR_cfg->tXP,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_3_REG_T_XP_SHIFT     )
		|(DDR_MAX_CLK_MINUS_1  (DDR_cfg->tXS,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_3_REG_T_XSNR_SHIFT   )
		|((DDR_cfg->tDLLK-1)<<CSL_EMIF4FV_SDRAM_TIM_3_REG_T_XSRD_SHIFT   )
		|(DDR_MAX_CLK_MINUS_1  (DDR_cfg->tRTP, clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_3_REG_T_RTP_SHIFT    )
		|(DDR_MAX_CLK_MINUS_1  (DDR_cfg->tCKE, clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_3_REG_T_CKE_SHIFT    );

	ControlRegs->SDRAM_TIM_4 = 
		 ((5)<<CSL_EMIF4FV_SDRAM_TIM_4_REG_T_CSTA_SHIFT   )
		|(DDR_MAX_CLK(DDR_cfg->tCKE,clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_4_REG_T_CKESR_SHIFT  )
		|((DDR_cfg->tZQCS-1)<<CSL_EMIF4FV_SDRAM_TIM_4_REG_ZQ_ZQCS_SHIFT  )
		|(DDR_NS_TO_CLK_MINUS_1(DDR_cfg->tRFC,  clock_MHz)<<CSL_EMIF4FV_SDRAM_TIM_4_REG_T_RFC_SHIFT    )
		|((0xF)<<CSL_EMIF4FV_SDRAM_TIM_4_REG_T_RAS_MAX_SHIFT);

	/*5c. Program the ZQCFG Register (address offset 0xC8) with the timing 
	parameters for periodic impedance calibration.*/
	ControlRegs->ZQ_CONFIG = 
		((DDR_cfg->num_CE)<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_CS1EN_SHIFT)|
		((1)<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_CS0EN_SHIFT)|
		((1)<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_DUALCALEN_SHIFT)| 	/*This bit should always be set to 1.*/
		((1)<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_SFEXITEN_SHIFT)|
		((DDR_cfg->tZQOPER/DDR_cfg->tZQCS-1)<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_ZQCL_MULT_SHIFT)| 	/*T_ZQ_ZQCL_MULT = (tZQoper/tZQCS ¨C 1)*/
		/*interval between ZQCS commands = 0.5%/((TSens x Tdriftrate) + (VSens x Vdriftrate))
		=0.5%/((max (dRTTdT, dRONdTM) x Tdriftrate in C/second) + (max(dRTTdV, dRONdVM) x Vdriftrate in mV/second))
		this time need be converted to refresh period number*/
		(((unsigned int)(1000000000*0.5/(1.5*1.2+0.15*15))/(64000000/8192))
			<<CSL_EMIF4FV_ZQ_CONFIG_REG_ZQ_REFINTERVAL_SHIFT);

	/*5d. Program the refresh period and clear reg_initref_dis to 0 in the 
	SDRAM Refresh Control Register (address offset 0x10).*/
	ControlRegs->SDRAM_REF_CTRL = refresh_period_clocks;

	TSC_delay_us(1);
	K2_DDR_PHY_status_check(PHY_Regs); //check status of DDR PHY for debug
}


/*get DDR ECC ranges accoridng to "ecc_cfg", return number of valid ranges*/
Uint32 get_DDR_ECC_ranges(DDR3_ECC_Config * ecc_cfg, 
	DDR3_ECC_Addr_Range addressRanges[], unsigned long long ullTotalByteCount)
{
	Uint32 uiRangeCount=0;
	unsigned long long ullECC_start_offset;

	if(NULL==ecc_cfg)
		return 0;
	
	/*Note: 36-bit DDR3 internal address need be translated into 32-bit EDMA virtul address.
	if the ECC range is larger than 2GB, SES MPAX need be reconfigured.*/
	if(EN_ECC_WITHIN_DEFINED_RANGES==ecc_cfg->rangeMode)
	{
		if(ecc_cfg->addressRange[0].byteCnt)
		{
			addressRanges[uiRangeCount].startAddr= ecc_cfg->addressRange[0].startAddr;
			addressRanges[uiRangeCount].byteCnt= ecc_cfg->addressRange[0].byteCnt;
			uiRangeCount++;
		}
		if(ecc_cfg->addressRange[1].byteCnt)
		{
			addressRanges[uiRangeCount].startAddr= ecc_cfg->addressRange[1].startAddr;
			addressRanges[uiRangeCount].byteCnt= ecc_cfg->addressRange[1].byteCnt;
			uiRangeCount++;
		}
	}
	else if((ecc_cfg->addressRange[0].byteCnt)&&
		(ecc_cfg->addressRange[1].byteCnt)) 	//EN_ECC_OUT_OF_DEFINED_RANGES, 3 ranges
	{
		addressRanges[uiRangeCount].startAddr= 0;
		addressRanges[uiRangeCount].byteCnt= ecc_cfg->addressRange[0].startAddr;
		uiRangeCount++;

		ullECC_start_offset= ecc_cfg->addressRange[0].startAddr+ecc_cfg->addressRange[0].byteCnt;
		addressRanges[uiRangeCount].startAddr= ullECC_start_offset;
		addressRanges[uiRangeCount].byteCnt= ecc_cfg->addressRange[1].startAddr- ullECC_start_offset;
		uiRangeCount++;

		ullECC_start_offset= ecc_cfg->addressRange[1].startAddr+ecc_cfg->addressRange[1].byteCnt;
		if(ullTotalByteCount>ullECC_start_offset)
		{
			addressRanges[uiRangeCount].startAddr= ullECC_start_offset;
			addressRanges[uiRangeCount].byteCnt= ullTotalByteCount- ullECC_start_offset;
			uiRangeCount++;
		}
	}
	return uiRangeCount;
}

