/* SPDX-License-Identifier: BSD-3-Clause */

#include "dramc_top.h"

#include "dramc_actiming.h"
#include "dramc_common.h"
#include "dramc_dv_init.h"
#include "dramc_int_global.h"
#include <emi.h>
#include "x_hal_io.h"
#include "sv_c_data_traffic.h"
#include "dramc_pi_api.h"
#include <soc/dramc_param.h>
#include <soc/emi.h>
#include <types.h>

DRAMC_CTX_T dram_ctx_chb;

#if (FOR_DV_SIMULATION_USED == 1)
U8 gu1BroadcastIsLP4 = TRUE;
#endif

bool gAndroid_DVFS_en = TRUE;
bool gUpdateHighestFreq = FALSE;

#define DV_SIMULATION_BYTEMODE 0
#define DV_SIMULATION_LP5_TRAINING_MODE1 1
#define DV_SIMULATION_LP5_CBT_PHASH_R 1

#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
   SAVE_TIME_FOR_CALIBRATION_T SavetimeData;
#endif

U8 gHQA_Test_Freq_Vcore_Level = 0;	// 0: only 1 freq  , others are multi freq	1: low vcore 2: high vcore

#define ENABLE_DRAM_SINGLE_FREQ_SELECT 0xFF  // 0xFF=all freq by gFreqTbl. The 0x"X" != 0xFF for single freq by gFreqTbl index, ex: 0x3 for DDR3733

DRAM_DFS_FREQUENCY_TABLE_T gFreqTbl[DRAM_DFS_SHUFFLE_MAX] = {
	{LP4_DDR3200 /*0*/, DIV8_MODE, SRAM_SHU1, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of term group (3733) must k first.
	{LP4_DDR4266 /*1*/, DIV8_MODE, SRAM_SHU0, DUTY_NEED_K,	VREF_CALI_ON,	CLOSE_LOOP_MODE},  // highest freq of term group (3733) must k first.
	{LP4_DDR800  /*2*/, DIV4_MODE, SRAM_SHU6, DUTY_DEFAULT, VREF_CALI_OFF,	SEMI_OPEN_LOOP_MODE},  //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
	{LP4_DDR1866 /*3*/, DIV8_MODE, SRAM_SHU3, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR1200 /*4*/, DIV8_MODE, SRAM_SHU5, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR2400 /*5*/, DIV8_MODE, SRAM_SHU2, DUTY_NEED_K,	VREF_CALI_ON,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR1600 /*6*/, DIV8_MODE, SRAM_SHU4, DUTY_DEFAULT, VREF_CALI_ON,  CLOSE_LOOP_MODE},  //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
};


DRAMC_CTX_T DramCtx_LPDDR4 =
{
	CHANNEL_SINGLE, // Channel number
	CHANNEL_A,			// DRAM_CHANNEL
	RANK_DUAL,		  //DRAM_RANK_NUMBER_T
	RANK_0, 			  //DRAM_RANK_T

#ifdef MTK_FIXDDR1600_SUPPORT
	LP4_DDR1600,
#else
#if __FLASH_TOOL_DA__
	LP4_DDR1600,
#else
#if (DV_SIMULATION_LP4 == 1)
	LP4_DDR1600,
#else
	LP5_DDR3200,
#endif
#endif
#endif
	DRAM_DFS_SHUFFLE_1,
#if DV_SIMULATION_LP4
	TYPE_LPDDR4X,		 // DRAM_DRAM_TYPE_T
#else
	TYPE_LPDDR5,
#endif
	FSP_0 , //// DRAM Fast switch point type, only for LP4, useless in LP3
	ODT_OFF,
	{CBT_NORMAL_MODE, CBT_NORMAL_MODE},  // bring up LP4X rank0 & rank1 use normal mode
#if ENABLE_READ_DBI
	{DBI_OFF,DBI_ON},  //read DBI
#else
	{DBI_OFF,DBI_OFF}, //read DBI
#endif
#if ENABLE_WRITE_DBI
	{DBI_OFF,DBI_ON},  // write DBI
#else
	{DBI_OFF,DBI_OFF},	// write DBI
#endif
	DATA_WIDTH_16BIT,	  // DRAM_DATA_WIDTH_T
	DEFAULT_TEST2_1_CAL,	// test2_1;
	DEFAULT_TEST2_2_CAL,	// test2_2;
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
	TEST_WORST_SI_PATTERN,	  // test_pattern;
#else
	TEST_XTALK_PATTERN,
#endif
#if (DV_SIMULATION_LP4 == 1)
	800,				  // frequency
	800,				  // freqGroup
#else
	1600,
	1600,
#endif
	0x88, //vendor_id initial value
	REVISION_ID_MAGIC,
	0xff, //density
	{0,0},
	0,	// u2num_dlycell_perT;
	270,  // u2DelayCellTimex100;

#if PRINT_CALIBRATION_SUMMARY
	//aru4CalResultFlag[CHANNEL_NUM][RANK_MAX]
	{{0,}},
	//aru4CalExecuteFlag[CHANNEL_NUM][RANK_MAX]
	{{0,}},
	1,
	0,
#endif
	{0}, //BOOL arfgWriteLevelingInitShif;
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	FALSE, //femmc_Ready
	0,
	0,
	0,
	&SavetimeData,
#endif
	&gFreqTbl[DRAM_DFS_SHUFFLE_MAX-1], // default is DDR1600 1:8 mode
	DRAM_DFS_REG_SHU0,
	TRAINING_MODE2,
	CBT_PHASE_RISING,
	0,	//new CBT pattern
	PHYPLL_MODE,
	DBI_OFF,
	FSP_MAX,
	PINMUX_EMCP,
	{DISABLE,DISABLE},	// disable 10GB
	0,
};



#if defined(DDR_INIT_TIME_PROFILING) || (__ETT__ && SUPPORT_SAVE_TIME_FOR_CALIBRATION)
DRAMC_CTX_T gTimeProfilingDramCtx;
U8 gtime_profiling_flag = 0;
#endif

void vSetVcoreByFreq(DRAMC_CTX_T *p)
{
#if 1//def MTK_PMIC_MT6359
#if (FOR_DV_SIMULATION_USED==0 && SW_CHANGE_FOR_SIMULATION==0)
#if __FLASH_TOOL_DA__
	dramc_set_vcore_voltage(725000);
#else
	unsigned int vio18, vcore, vdram, vddq, vmddr;

	vio18 = vcore = vdram = vddq = vmddr = 0;
	(void)vio18;

#if __ETT__
	hqa_set_voltage_by_freq(p, &vio18, &vcore, &vdram, &vddq, &vmddr);
#elif 0//defined(VCORE_BIN)
	switch (vGet_Current_ShuLevel(p)) {
	case SRAM_SHU0:  //4266
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU0);
		if (!vcore)
	#endif
		vcore = get_vcore_uv_table(0);
		break;
	case SRAM_SHU1:   //3200
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU1);
		if (!vcore)
	#endif
		vcore = (get_vcore_uv_table(0) + get_vcore_uv_table(1)) >> 1;
		break;
	case SRAM_SHU2:  //2400
	case SRAM_SHU3:  //1866
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU2);
		if (!vcore)
	#endif
		vcore = (get_vcore_uv_table(0) + get_vcore_uv_table(2)) >> 1;
		break;
	case SRAM_SHU4:  //1600
	case SRAM_SHU5:  //1200
	case SRAM_SHU6:  //800
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU4);
		if (!vcore)
	#endif
		vcore = (get_vcore_uv_table(0) + get_vcore_uv_table(3)) >> 1;
		break;
	}
#else
	switch (vGet_Current_ShuLevel(p)) {
	case SRAM_SHU0: // 4266
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU0);
	#else
		vcore = SEL_PREFIX_VCORE(LP4, KSHU0);
	#endif
		break;
	case SRAM_SHU1: // 3200
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU1);
	#else
		vcore = SEL_PREFIX_VCORE(LP4, KSHU1);
	#endif
		break;
	case SRAM_SHU2: // 2400
	case SRAM_SHU3: //1866
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU2);
	#else
		vcore = SEL_PREFIX_VCORE(LP4, KSHU2);
	#endif
		break;
	case SRAM_SHU4: //1600
	case SRAM_SHU5: //1200
	case SRAM_SHU6: //800
	#ifdef VOLTAGE_SEL
		vcore = vcore_voltage_select(KSHU4);
	#else
		vcore = SEL_PREFIX_VCORE(LP4, KSHU4);
	#endif
		break;
	default:
		return;
	}
#endif

	if (vcore)
		dramc_set_vcore_voltage(vcore);

#if defined(DRAM_HQA)
	vio18 = SEL_VIO18;
	if (vio18)
		dramc_set_vio18_voltage(vio18);

	vdram = SEL_PREFIX_VDRAM(LP4);
	if (vdram)
		dramc_set_vdram_voltage(p->dram_type, vdram);

	vddq = SEL_PREFIX_VDDQ;
	if (vddq)
		dramc_set_vddq_voltage(p->dram_type, vddq);

	vmddr = SEL_PREFIX_VMDDR;
	if (vmddr)
		dramc_set_vmddr_voltage(vmddr);
#endif

#ifdef FOR_HQA_REPORT_USED
	switch (vGet_Current_ShuLevel(p)) {
		case SRAM_SHU0: //3733
		case SRAM_SHU1: //3200
	case SRAM_SHU2: //2400
	case SRAM_SHU3: //1866
	case SRAM_SHU4: //1600
	case SRAM_SHU5: //1200
	case SRAM_SHU6: //800
		gHQA_Test_Freq_Vcore_Level = 0; //only 1 freq
			break;
		default:
			print("[HQA] undefined shuffle level for Vcore (SHU%d)\r\n", vGet_Current_ShuLevel(p));
#if __ETT__
			while(1);
#endif
			break;
	}
#endif

#ifndef DDR_INIT_TIME_PROFILING
	print("Read voltage for %d, %d\n", p->frequency, vGet_Current_ShuLevel(p));
	print("Vio18 = %d\n", dramc_get_vio18_voltage());
	print("Vcore = %d\n", dramc_get_vcore_voltage());
	print("Vdram = %d\n", dramc_get_vdram_voltage(p->dram_type));
	print("Vddq = %d\n", dramc_get_vddq_voltage(p->dram_type));
	print("Vmddr = %d\n", dramc_get_vmddr_voltage());
#endif
#endif
#endif
#endif
}

U32 vGetVoltage(DRAMC_CTX_T *p, U32 get_voltage_type)
{
#if (defined(DRAM_HQA) || __ETT__) && (FOR_DV_SIMULATION_USED == 0)
	if (get_voltage_type==0)
		return dramc_get_vcore_voltage();

	if (get_voltage_type==1)
		return dramc_get_vdram_voltage(p->dram_type);

	if (get_voltage_type==2)
		return dramc_get_vddq_voltage(p->dram_type);

	if (get_voltage_type==3)
		   return dramc_get_vio18_voltage();
	if (get_voltage_type==4)
			 return dramc_get_vmddr_voltage();

#endif

	return 0;
}

#ifdef FOR_HQA_TEST_USED
VCORE_DELAYCELL_T gVcoreDelayCellTable[49]={	{500000, 512},
												{506250, 496},
												{512500, 482},
												{518750, 469},
												{525000, 457},
												{531250, 445},
												{537500, 434},
												{543750, 423},
												{550000, 412},
												{556250, 402},
												{562500, 393},
												{568750, 384},
												{575000, 377},
												{581250, 369},
												{587500, 362},
												{593750, 355},
												{600000, 348},
												{606250, 341},
												{612500, 335},
												{618750, 328},
												{625000, 322},
												{631250, 317},
												{637500, 312},
												{643750, 307},
												{650000, 302},
												{656250, 297},
												{662500, 292},
												{668750, 288},
												{675000, 284},
												{681250, 280},
												{687500, 276},
												{693750, 272},
												{700000, 269},
												{706250, 265},
												{712500, 262},
												{718750, 258},
												{725000, 255},
												{731250, 252},
												{737500, 249},
												{743750, 246},
												{750000, 243},
												{756250, 241},
												{762500, 238},
												{768750, 236},
												{775000, 233},
												{781250, 231},
												{787500, 229},
												{793750, 227},
												{800000, 225},
												//{825000, 718},
												//{831250, 717},
												//{837500, 715},
												//{843750, 713},
												//{850000, 708},
												//{856250, 705},
												//{862500, 702},
												//{868750, 700},
												//{875000, 698}
												};

void GetVcoreDelayCellTimeFromTable(DRAMC_CTX_T *p)
{
	U32 channel_i, i;
	U32 get_vcore = 0;
	U16 u2gdelay_cell_ps = 0;
	U8 u1delay_cell_cnt = 0;
	VCORE_DELAYCELL_T *pVcoreDelayCellTable;

#if (defined(DRAM_HQA) || __ETT__) && (FOR_DV_SIMULATION_USED == 0)
	#if 1//__Petrus_TO_BE_PORTING__
	get_vcore = dramc_get_vcore_voltage();
	#endif
#endif

	pVcoreDelayCellTable = (VCORE_DELAYCELL_T *)gVcoreDelayCellTable;
	u1delay_cell_cnt = sizeof(gVcoreDelayCellTable)/sizeof(gVcoreDelayCellTable[0]);

	for(i=0; i<u1delay_cell_cnt; i++)
	{
		if (get_vcore >= pVcoreDelayCellTable[i].u2Vcore)
		{
			u2gdelay_cell_ps = pVcoreDelayCellTable[i].u2DelayCell;
		}
	}

	msg("[GetVcoreDelayCellTimeFromTable(%d)] VCore=%d(x100), DelayCell=%d(x100)\n", u1delay_cell_cnt, get_vcore, u2gdelay_cell_ps);

	for(channel_i=CHANNEL_A; channel_i < p->support_channel_num; channel_i++)
	{
		u2gdelay_cell_ps_all[get_shuffleIndex_by_Freq(p)][channel_i] = u2gdelay_cell_ps;
		u4gVcore[get_shuffleIndex_by_Freq(p)] = get_vcore/1000;
	}
}
#endif

///TODO: wait for porting +++
#ifdef FIRST_BRING_UP
void Test_Broadcast_Feature(DRAMC_CTX_T *p)
{
	U32 u4RegBackupAddress[] =
	{
		(DRAMC_REG_SHURK_SELPH_DQ2),
		(DRAMC_REG_SHURK_SELPH_DQ2 + SHIFT_TO_CHB_ADDR),

		(DDRPHY_REG_SHU_RK_B0_DQ0),
		(DDRPHY_REG_SHU_RK_B0_DQ0 + SHIFT_TO_CHB_ADDR),
	};
	U32 read_value;
	U32 backup_broadcast;

	backup_broadcast = GetDramcBroadcast();

	DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);

	DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));

	DramcBroadcastOnOff(DRAMC_BROADCAST_ON);

	vIO32Write4B(DRAMC_REG_SHURK_SELPH_DQ2, 0xA55A00FF);
	vIO32Write4B(DDRPHY_REG_SHU_RK_B0_DQ0, 0xA55A00FF);

	read_value = u4IO32Read4B(DRAMC_REG_SHURK_SELPH_DQ2 + SHIFT_TO_CHB_ADDR);
	if (read_value != 0xA55A00FF)
	{
		err("Check Erro! Broad Cast CHA RG to CHB Fail!!\n");
		while (1);
	}

	read_value = u4IO32Read4B(DDRPHY_REG_SHU_RK_B0_DQ0 + SHIFT_TO_CHB_ADDR);
	if (read_value != 0xA55A00FF)
	{
		err("Check Erro! Broad Cast CHA RG to CHB Fail!!\n");
		while (1);
	}

	DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);

	DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));

	DramcBroadcastOnOff(backup_broadcast);
}
#endif

#ifdef ENABLE_MIOCK_JMETER
U8 gPRE_MIOCK_JMETER_HQA_USED_flag=0;

static void Set_PRE_MIOCK_JMETER_HQA_USED_flag(U8 value)
{
	gPRE_MIOCK_JMETER_HQA_USED_flag = value;
}

void Get_RX_DelayCell(DRAMC_CTX_T *p)
{
#if defined(FOR_HQA_REPORT_USED) && (FOR_DV_SIMULATION_USED==0) && (SW_CHANGE_FOR_SIMULATION==0)
		if (gHQALOG_RX_delay_cell_ps_075V == 0)
		{
#if __ETT__
			msg("RX delay cell calibration (%d):\n", hqa_vmddr_class);

			switch (hqa_vmddr_class)
			{
				case 1:
					dramc_set_vcore_voltage(_SEL_PREFIX(VMDDR, HV, LP4));
					break;
				case 2:
					dramc_set_vcore_voltage(_SEL_PREFIX(VMDDR, NV, LP4));
					break;
				case 3:
					dramc_set_vcore_voltage(_SEL_PREFIX(VMDDR, LV, LP4));
					break;
			}
#else
			// set vcore to RX used 0.75V
			dramc_set_vcore_voltage(SEL_PREFIX_VMDDR);	//set vmddr voltage to vcore to K RX delay cell
#endif

			DramcMiockJmeter(p);

			gHQALOG_RX_delay_cell_ps_075V = u2gdelay_cell_ps;

			// set vocre back
			vSetVcoreByFreq(p);
		}
#endif
}

void PRE_MIOCK_JMETER_HQA_USED(DRAMC_CTX_T *p)
{
	U32 backup_freq_sel, backup_channel;
	U32 channel_idx;

#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	if(p->femmc_Ready==1)
	{
		for(channel_idx=CHANNEL_A; channel_idx<p->support_channel_num; channel_idx++)
		{
			//for (shuffleIdx = DRAM_DFS_SHUFFLE_1; shuffleIdx < DRAM_DFS_SHUFFLE_MAX; shuffleIdx++)
			{
				u2g_num_dlycell_perT_all[p->shu_type][channel_idx] = p->pSavetimeData->u2num_dlycell_perT;
				u2gdelay_cell_ps_all[p->shu_type][channel_idx] = p->pSavetimeData->u2DelayCellTimex100;
			}
		}

		p->u2num_dlycell_perT = p->pSavetimeData->u2num_dlycell_perT;
		p->u2DelayCellTimex100 = p->pSavetimeData->u2DelayCellTimex100;
		return;
	}
#endif


	backup_freq_sel = vGet_PLL_FreqSel(p);
	backup_channel = p->channel;

	msg3("[JMETER_HQA]\n");
	Set_PRE_MIOCK_JMETER_HQA_USED_flag(1);

	vSetPHY2ChannelMapping(p, CHANNEL_A);

	DramcMiockJmeterHQA(p);

	vSetPHY2ChannelMapping(p, backup_channel);

	Set_PRE_MIOCK_JMETER_HQA_USED_flag(0);

	vSet_PLL_FreqSel(p, backup_freq_sel);
}
#endif


#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
#if !EMMC_READY
u32 g_dram_save_time_init_done[DRAM_DFS_SHUFFLE_MAX] = {0};
SAVE_TIME_FOR_CALIBRATION_T SaveTimeDataByShuffle[DRAM_DFS_SHUFFLE_MAX];
#endif
static DRAM_STATUS_T DramcSave_Time_For_Cal_End(DRAMC_CTX_T *p)
{
	if (!u1IsLP4Family(p->dram_type))
		return DRAM_FAIL;

	if (p->femmc_Ready == 0)
	{
		#if EMMC_READY
		write_offline_dram_calibration_data(p->shu_type, p->pSavetimeData);
		msg("[FAST_K] Save calibration result to emmc\n");
		#else
		g_dram_save_time_init_done[p->shu_type] = 1;
		memcpy(&(SaveTimeDataByShuffle[p->shu_type]), p->pSavetimeData, sizeof(SAVE_TIME_FOR_CALIBRATION_T));
		msg("[FAST_K] Save calibration result to SW memory\n");
		#endif
	}
	else
	{
		msg("[FAST_K] Bypass saving calibration result to emmc\n");
	}

	return DRAM_OK;
}

static DRAM_STATUS_T DramcSave_Time_For_Cal_Init(DRAMC_CTX_T *p)
{
	if (!u1IsLP4Family(p->dram_type))
		return DRAM_FAIL;

	if (doe_get_config("fullk"))
	return DRAM_FAIL;

	// Parepare fask k data
	#if EMMC_READY
	// scy: only need to read emmc one time for each boot-up
	//if (g_dram_save_time_init_done == 1)
	//	  return DRAM_OK;
	//else
	//	  g_dram_save_time_init_done = 1;
	if (read_offline_dram_calibration_data(p->shu_type, p->pSavetimeData) < 0)
		{
		p->femmc_Ready = 0;
		memset(p->pSavetimeData, 0, sizeof(SAVE_TIME_FOR_CALIBRATION_T));
		}
		else
		{
		p->femmc_Ready = 1;
		}

	#else //EMMC is not avaliable, load off-line data

	if (g_dram_save_time_init_done[p->shu_type] == 0)
	{
		p->femmc_Ready = 0;
		memset(p->pSavetimeData, 0, sizeof(SAVE_TIME_FOR_CALIBRATION_T));
	}
	else
	{
		memcpy(p->pSavetimeData, &(SaveTimeDataByShuffle[p->shu_type]), sizeof(SAVE_TIME_FOR_CALIBRATION_T));
		p->femmc_Ready = 1;
	}
	#endif

	if (p->femmc_Ready == 1)
	{
		if (p->frequency < 1600)
		{	// freq < 1600, TX and RX tracking are disable. Therefore, bypass calibration.
			p->Bypass_RDDQC = 1;
			p->Bypass_RXWINDOW = 1;
			p->Bypass_TXWINDOW = 1;
	}
	else
	{
			p->Bypass_RDDQC = 1;
			p->Bypass_RXWINDOW = !ENABLE_RX_TRACKING;
			p->Bypass_TXWINDOW = 0;
	}

#if RUNTIME_SHMOO_RELEATED_FUNCTION
		p->Bypass_RDDQC = 1;
		p->Bypass_RXWINDOW = 1;
		p->Bypass_TXWINDOW = 1;
#endif
	}

#if EMMC_READY
	msg("[FAST_K] DramcSave_Time_For_Cal_Init SHU%d, femmc_Ready=%d\n", p->shu_type, p->femmc_Ready);
#else
	msg("[FAST_K] DramcSave_Time_For_Cal_Init SHU%d, Init_done=%d, femmc_Ready=%d\n", p->shu_type, g_dram_save_time_init_done[p->shu_type], p->femmc_Ready);
#endif
	msg("[FAST_K] Bypass_RDDQC %d, Bypass_RXWINDOW=%d, Bypass_TXWINDOW=%d\n", p->Bypass_RDDQC, p->Bypass_RXWINDOW, p->Bypass_TXWINDOW);

	return DRAM_OK;
}
#endif

#if ENABLE_RANK_NUMBER_AUTO_DETECTION
static void DramRankNumberDetection(DRAMC_CTX_T *p)
{
	U8 u1RankBak;

	u1RankBak = u1GetRank(p);  // backup current rank setting

	vSetPHY2ChannelMapping(p, CHANNEL_A); // when switching channel, must update PHY to Channel Mapping
	vSetRank(p, RANK_1);

	if (DramcWriteLeveling(p, AUTOK_ON, PI_BASED) == DRAM_OK)
	{
		p->support_rank_num = RANK_DUAL;
		vIO32WriteFldAlign(DRAMC_REG_SA_RESERVE, 0, SA_RESERVE_SINGLE_RANK);  //keep support_rank_num to reserved rg
	}
	else
	{
		p->support_rank_num = RANK_SINGLE;
		vIO32WriteFldAlign(DRAMC_REG_SA_RESERVE, 1, SA_RESERVE_SINGLE_RANK);  //keep support_rank_num to reserved rg
	}
	msg("[RankNumberDetection] %d\n", p->support_rank_num);

	vSetRank(p, u1RankBak);  // restore rank setting
}
#endif

static void UpdateGlobal10GBEnVariables(DRAMC_CTX_T *p)
{
	p->u110GBEn[RANK_0] = (get_row_width_by_emi(RANK_0) >= 18) ? ENABLE : DISABLE;
	p->u110GBEn[RANK_1] = (get_row_width_by_emi(RANK_1) >= 18) ? ENABLE : DISABLE;
	//msg("[10GBEn] RANK0=%d, RANK1=%d\n", p->u110GBEn[RANK_0], p->u110GBEn[RANK_1]);
}

void vCalibration_Flow_For_MDL(DRAMC_CTX_T *p)
{
	U8 u1RankMax;
	S8 s1RankIdx;

#if GATING_ADJUST_TXDLY_FOR_TRACKING
	DramcRxdqsGatingPreProcess(p);
#endif

	if (p->support_rank_num == RANK_DUAL)
		u1RankMax = RANK_MAX;
	else
		u1RankMax = RANK_1;

	for (s1RankIdx = RANK_0; s1RankIdx < u1RankMax; s1RankIdx++)
	{
		vSetRank(p, s1RankIdx);

		vAutoRefreshSwitch(p, ENABLE); //when doing gating, RX and TX calibration, auto refresh should be enable
		dramc_rx_dqs_gating_cal(p, AUTOK_OFF, 0);
		DramcRxWindowPerbitCal(p, PATTERN_RDDQC, NULL, AUTOK_OFF);

#if MRW_CHECK_ONLY
		mcSHOW_MRW_MSG("\n==[MR Dump] %s==\n", __func__);
#endif
		vAutoRefreshSwitch(p, DISABLE); //After gating, Rx and Tx calibration, auto refresh should be disable
	}

	vSetRank(p, RANK_0); // Set p's rank back to 0 (Avoids unexpected auto-rank offset calculation in u4RegBaseAddrTraslate())

#if GATING_ADJUST_TXDLY_FOR_TRACKING
	DramcRxdqsGatingPostProcess(p);
#endif
}

static int GetDramInforAfterCalByMRR(DRAMC_CTX_T *p, DRAM_INFO_BY_MRR_T *DramInfo)
{
	U8 u1RankIdx, u1DieNumber = 0;
	U16 u2Density;
	U16 u2MR7;
	U16 u2MR8 = 0;
	U64 u8Size = 0, u8Size_backup = 0;

	if (p->revision_id != REVISION_ID_MAGIC)
		return 0;

	vSetPHY2ChannelMapping(p, CHANNEL_A);

	// Read MR5 for Vendor ID
	DramcModeRegReadByRank(p, RANK_0, 5, &(p->vendor_id));// for byte mode, don't show value of another die.
	p->vendor_id &= 0xFF;
	msg("[GetDramInforAfterCalByMRR] Vendor %x.\n", p->vendor_id);
	// Read MR6 for Revision ID
	DramcModeRegReadByRank(p, RANK_0, 6, &(p->revision_id));// for byte mode, don't show value of another die.
	msg("[GetDramInforAfterCalByMRR] Revision %x.\n", p->revision_id);
	// Read MR6 for Revision ID2
	DramcModeRegReadByRank(p, RANK_0, 7, &u2MR7);// for byte mode, don't show value of another die.
	msg("[GetDramInforAfterCalByMRR] Revision 2 %x.\n", u2MR7);
#if (!__ETT__) && (FOR_DV_SIMULATION_USED==0)
	set_dram_mr(5, p->vendor_id);
	set_dram_mr(6, p->revision_id);
	set_dram_mr(7, u2MR7);
#endif
	if (DramInfo != NULL)
	{
		DramInfo->u2MR5VendorID = p->vendor_id;
		DramInfo->u2MR6RevisionID = p->revision_id;

		for (u1RankIdx = 0; u1RankIdx < RANK_MAX; u1RankIdx++)
			DramInfo->u8MR8RankSize[u1RankIdx] = 0;
	}

	// Read MR8 for dram density
	for (u1RankIdx = 0; u1RankIdx < (p->support_rank_num); u1RankIdx++)
	{
		#if 0//PRINT_CALIBRATION_SUMMARY
		if ((p->aru4CalExecuteFlag[u1ChannelIdx][u1RankIdx] != 0) && \
			(p->aru4CalResultFlag[u1ChannelIdx][u1RankIdx] == 0))
		#endif
		{
			DramcModeRegReadByRank(p, u1RankIdx, 0, &(gu2MR0_Value[u1RankIdx]));
			msg("MR0 0x%x\n", gu2MR0_Value[u1RankIdx]);

			DramcModeRegReadByRank(p, u1RankIdx, 8, &u2Density);
			msg("MR8 0x%x\n", u2Density);
			u2MR8 |= (u2Density & 0xFF) << (u1RankIdx * 8);

			u1DieNumber = 1;
			if (((u2Density >> 6) & 0x3) == 1) //OP[7:6] =0, x16 (normal mode)
				u1DieNumber = 2;

			u2Density = (u2Density >> 2) & 0xf;

			switch (u2Density)
			{
				///TODO: Darren, please check the value of u8Size.
				case 0x0:
					u8Size = 0x20000000;  //4Gb = 512MB
					//msg("[EMI]DRAM density = 4Gb\n");
					break;
				case 0x1:
					u8Size = 0x30000000;  //6Gb = 768MB
					//msg("[EMI]DRAM density = 6Gb\n");
					break;
				case 0x2:
					u8Size = 0x40000000;  //8Gb = 1GB = 2^30 bytes = 0x40000000 bytes
					//msg("[EMI]DRAM density = 8Gb\n");
					break;
				case 0x3:
					u8Size = 0x60000000;  //12Gb = 1.5GB = 3^30 bytes = 0x60000000 bytes
					//msg("[EMI]DRAM density = 12Gb\n");
					break;
				case 0x4:
					u8Size = 0x80000000;  //16Gb = 2GB = 4^30 bytes = 0x80000000 bytes
					//msg("[EMI]DRAM density = 16Gb\n");
					break;
				case 0x5:
					u8Size = 0xc0000000; //24Gb = 3GB = 6^30 bytes = 0xc0000000 bytes
					//msg("[EMI]DRAM density = 24Gb\n");
					break;
				case 0x6:
					u8Size = 0x100000000L; //32Gb = 4GB = 8^30 bytes = 0x10000000 bytes
					//msg("[EMI]DRAM density = 32Gb\n");
					break;
				default:
					u8Size = 0; //reserved
			}

			if (u8Size_backup < u8Size) // find max dram size for vDramcACTimingOptimize
			{
				u8Size_backup = u8Size;
				p->density = u2Density;
			}

			p->ranksize[u1RankIdx] = u8Size * u1DieNumber;	//dram rank size = density * DieNumber

			if (DramInfo != NULL)
			{
				DramInfo->u8MR8RankSize[u1RankIdx] = p->ranksize[u1RankIdx];
			}
		}
		// 1GB = 2^30 bytes
		// u8Size * (2^3) / (2^30)	==>Gb
		msg("RK%d, DieNum %d, Density %dGb, RKsize %dGb.\n\n", u1RankIdx, u1DieNumber, (U32)(u8Size >> 27), (U32)(p->ranksize[u1RankIdx] >> 27));
	}
#if (!__ETT__) && (FOR_DV_SIMULATION_USED==0)
	set_dram_mr(8, u2MR8);
#endif
	return 0;
}

static void vCalibration_Flow_LP4(DRAMC_CTX_T *p)
{
	U8 u1RankMax;
	S8 s1RankIdx;
	//DRAM_STATUS_T VrefStatus;

#ifdef DDR_INIT_TIME_PROFILING
	U32 CPU_Cycle;
	TimeProfileBegin();
#endif

#if __Petrus_TO_BE_PORTING__
#if ENABLE_PHY_RX_INPUT_OFFSET	// skip when bring up
	///TODO: no shuffle, only need to do once under highest freq.
	if(p->frequency == u2DFSGetHighestFreq(p))
	DramcRXInputBufferOffsetCal(p);

#ifdef DDR_INIT_TIME_PROFILING
	CPU_Cycle=TimeProfileEnd();
	time_msg("\tRX input cal takes %d us\n", CPU_Cycle);
	TimeProfileBegin();
#endif
#endif
#endif


#if GATING_ADJUST_TXDLY_FOR_TRACKING
	DramcRxdqsGatingPreProcess(p);
#endif

	if (p->support_rank_num==RANK_DUAL)
		u1RankMax = RANK_MAX;
	else
		u1RankMax = RANK_1;

	//vAutoRefreshSwitch(p, DISABLE); //auto refresh is set as disable in LP4_DramcSetting, so don't need to disable again
	vAutoRefreshSwitch(p, DISABLE);

#if 1//(SIMUILATION_CBT == 1)
	for(s1RankIdx=RANK_0; s1RankIdx<u1RankMax; s1RankIdx++)
	{
		vSetRank(p, s1RankIdx);
		#if PINMUX_AUTO_TEST_PER_BIT_CA
		CheckCAPinMux(p);
		#endif

		CmdBusTrainingLP45(p, AUTOK_OFF);

			#if ENABLE_EYESCAN_GRAPH
			print_EYESCAN_LOG_message(p, 0); //draw CBT eyescan
			#endif

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d CBT takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif
	}
	vSetRank(p, RANK_0);

#if __Petrus_TO_BE_PORTING__
	No_Parking_On_CLRPLL(p);
#endif

	// The patch must to do after cbt training
	ShuffleDfsToFSP1(p);
#endif

#if 0//(SIMULATION_WRITE_LEVELING == 1)
	for(s1RankIdx=RANK_0; s1RankIdx<u1RankMax; s1RankIdx++)
	{
		vSetRank(p, s1RankIdx);

		vAutoRefreshSwitch(p, DISABLE); //When doing WriteLeveling, should make sure that auto refresh is disable

#if (!WCK_LEVELING_FM_WORKAROUND)
		if (u1IsLP4Family(p->dram_type))
#endif
		{
			if (!(u1IsLP4Div4DDR800(p) && (p->rank == RANK_1))) // skip for DDR800 rank1
			{
				msg("\n----->DramcWriteLeveling(PI) begin...\n");

				DramcWriteLeveling(p, AUTOK_OFF, PI_BASED);

				msg("DramcWriteLeveling(PI) end<-----\n\n");
			}
		}

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d Write leveling takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif
	}
	vSetRank(p, RANK_0);

	#if ENABLE_WDQS_MODE_2 // <=DDR1600 reduce PI change code time
	if (!(u1IsLP4Div4DDR800(p)) && (p->frequency <= 800) && (p->support_rank_num == RANK_DUAL)) // skip DDR800semi, for DDR1200/DDR1600 only
		WriteLevelingPosCal(p, PI_BASED);
	#elif ENABLE_TX_WDQS // for WDQS mode 1 to avoid dual rank PI code incorrect
	if (!(u1IsLP4Div4DDR800(p)) && (p->support_rank_num == RANK_DUAL))
		WriteLevelingPosCal(p, PI_BASED);
	#endif
#endif /* (SIMULATION_WRITE_LEVELING == 1) */

	for(s1RankIdx=RANK_0; s1RankIdx<u1RankMax; s1RankIdx++)
	{
		vSetRank(p, s1RankIdx);

#if 1//(SIMULATION_WRITE_LEVELING == 1)
		vAutoRefreshSwitch(p, DISABLE); //When doing WriteLeveling, should make sure that auto refresh is disable

#if (!WCK_LEVELING_FM_WORKAROUND)
		if (u1IsLP4Family(p->dram_type))
#endif
		{
			if (!(u1IsLP4Div4DDR800(p) && (p->rank == RANK_1))) // skip for DDR800 rank1
			{
				msg("\n----->DramcWriteLeveling(PI) begin...\n");

				DramcWriteLeveling(p, AUTOK_ON, PI_BASED);

				msg("DramcWriteLeveling(PI) end<-----\n\n");
			}
			#ifdef DDR_INIT_TIME_PROFILING
			CPU_Cycle=TimeProfileEnd();
			time_msg("\tRank %d Write leveling takes %d us\n", s1RankIdx, CPU_Cycle);
			TimeProfileBegin();
			#endif
		}
#endif /* (SIMULATION_WRITE_LEVELING == 1) */

		vAutoRefreshSwitch(p, ENABLE); //when doing gating, RX and TX calibration, auto refresh should be enable

		dramc_rx_dqs_gating_cal(p, AUTOK_OFF, 0);

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d Gating takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif

		DramcRxWindowPerbitCal(p, PATTERN_RDDQC, NULL, AUTOK_OFF);

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d RX RDDQC takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif

#if MRW_CHECK_ONLY
		mcSHOW_MRW_MSG("\n==[MR Dump] %s==\n", __func__);
#endif

		DramcTxWindowPerbitCal(p, TX_DQ_DQS_MOVE_DQ_DQM, FALSE, AUTOK_OFF);

		if (Get_Vref_Calibration_OnOff(p)==VREF_CALI_ON)
		{
			DramcTxWindowPerbitCal(p, TX_DQ_DQS_MOVE_DQ_ONLY, TRUE, AUTOK_OFF);
		}

#if PINMUX_AUTO_TEST_PER_BIT_TX
		CheckTxPinMux(p);
#endif
		DramcTxWindowPerbitCal(p, TX_DQ_DQS_MOVE_DQ_ONLY, FALSE, AUTOK_OFF);

#if TX_K_DQM_WITH_WDBI
		if (p->DBI_W_onoff[p->dram_fsp]==DBI_ON)
		{
			// K DQM with DBI_ON, and check DQM window spec.
			//msg("[TX_K_DQM_WITH_WDBI] Step1: K DQM with DBI_ON, and check DQM window spec.\n\n");
			vSwitchWriteDBISettings(p, DBI_ON);
			DramcTxWindowPerbitCal((DRAMC_CTX_T *) p, TX_DQ_DQS_MOVE_DQM_ONLY, FALSE, AUTOK_OFF);
			vSwitchWriteDBISettings(p, DBI_OFF);
		}
#endif

	#if ENABLE_EYESCAN_GRAPH
		Dramc_K_TX_EyeScan_Log(p);
		print_EYESCAN_LOG_message(p, 2); //draw TX eyescan
	#endif

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d TX calibration takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif

		DramcRxdatlatCal(p);

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d Datlat takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif

#if PINMUX_AUTO_TEST_PER_BIT_RX
		CheckRxPinMux(p);
#endif
		DramcRxWindowPerbitCal(p, PATTERN_TEST_ENGINE, NULL /*Set Vref = 0 to test*/, AUTOK_OFF);

		#ifdef DDR_INIT_TIME_PROFILING
		CPU_Cycle=TimeProfileEnd();
		time_msg("\tRank %d RX calibration takes %d us\n", s1RankIdx, CPU_Cycle);
		TimeProfileBegin();
		#endif
	   // DramcRxdqsGatingCal(p);

#if ENABLE_EYESCAN_GRAPH
		print_EYESCAN_LOG_message(p, 1); //draw RX eyescan
#endif

#if (SIMULATION_RX_DVS == 1)
	if (p->frequency >=2133)
		DramcRxDVSWindowCal(p);
#endif

#if TX_OE_CALIBATION && !ENABLE_WDQS_MODE_2
		if(p->frequency >= 1600)
		{
			DramcTxOECalibration(p);
		}
#endif

		vAutoRefreshSwitch(p, DISABLE);

		#if ENABLE_TX_TRACKING
		DramcDQSOSCSetMR18MR19(p);
		DramcDQSOSCMR23(p);
		#endif

	}

#if __Petrus_TO_BE_PORTING__
	#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	if(p->femmc_Ready==0)
	#endif
	{
		if(p->frequency >= RX_VREF_DUAL_RANK_K_FREQ)  // for 3733/4266
		{
			U8 u1ByteIdx, u1HighFreqRXVref[2];
			for(u1ByteIdx =0 ; u1ByteIdx<(p->data_width/DQS_BIT_NUMBER); u1ByteIdx++)
			{
				u1HighFreqRXVref[u1ByteIdx] = (gFinalRXVrefDQ[p->channel][RANK_0][u1ByteIdx] + gFinalRXVrefDQ[p->channel][RANK_1][u1ByteIdx]) >> 1;
				msg("RX Vref Byte%d (u1HighFreqRXVref) = %d = (%d+ %d)>>1\n", u1ByteIdx, u1HighFreqRXVref[u1ByteIdx], gFinalRXVrefDQ[p->channel][RANK_0][u1ByteIdx], gFinalRXVrefDQ[p->channel][RANK_1][u1ByteIdx]);
			}

			for(s1RankIdx=RANK_0; s1RankIdx < u1RankMax; s1RankIdx++)
			{
				vSetRank(p, s1RankIdx);
				DramcRxWindowPerbitCal((DRAMC_CTX_T *) p, 1, u1HighFreqRXVref);
			}
		}
	}
#endif

	vSetRank(p, RANK_0); // Set p's rank back to 0 (Avoids unexpected auto-rank offset calculation in u4RegBaseAddrTraslate())

	#if ENABLE_TX_TRACKING
	DramcDQSOSCShuSettings(p);
	#endif

#if (SIMULATION_GATING && GATING_ADJUST_TXDLY_FOR_TRACKING)
	DramcRxdqsGatingPostProcess(p);
#endif

#if TDQSCK_PRECALCULATION_FOR_DVFS
	DramcDQSPrecalculation_preset(p);
#endif

#if SIMULATION_RX_DVS
	if (p->frequency >=2133)
		DramcDramcRxDVSCalPostProcess(p);
#endif

	DramcDualRankRxdatlatCal(p);

#if RDSEL_TRACKING_EN
	if (p->frequency >= 1866)
		RDSELRunTimeTracking_preset(p);
#endif

#if XRTWTW_NEW_CROSS_RK_MODE
	if(p->support_rank_num == RANK_DUAL)
	{
		XRTWTW_SHU_Setting(p);
	}
#endif

#if __Petrus_TO_BE_PORTING__
#if LJPLL_FREQ_DEBUG_LOG
	DDRPhyFreqMeter();
#endif
#endif

	#ifdef DDR_INIT_TIME_PROFILING
	CPU_Cycle=TimeProfileEnd();
	time_msg("\tMisc takes %d us\n\n", s1RankIdx, CPU_Cycle);
	#endif
}

static void vDramCalibrationSingleChannel(DRAMC_CTX_T *p)
{
#if 0//!__ETT__
	/*
	 * Since DRAM calibration will cost much time,
	 * kick wdt here to prevent watchdog timeout.
	 */
#if (FOR_DV_SIMULATION_USED == 0 && SW_CHANGE_FOR_SIMULATION == 0)
	mtk_wdt_restart();
#endif
#endif

	vCalibration_Flow_LP4(p);
}

void vDramCalibrationAllChannel(DRAMC_CTX_T *p)
{
	U8 channel_idx, rank_idx;

#ifdef DDR_INIT_TIME_PROFILING
	U32 u4low_tick0, u4high_tick0, u4low_tick1, u4high_tick1;
#if __ETT__
	u4low_tick0 = GPT_GetTickCount(&u4high_tick0);
#else
	u4low_tick0 = get_timer(0);
#endif
#endif

	vIO32WriteFldMulti_All(DDRPHY_REG_CA_CMD2, P_Fld(1, CA_CMD2_RG_TX_ARCMD_OE_DIS_CA)
											| P_Fld(0, CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA)
											| P_Fld(0xff, CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA));
	for (channel_idx = CHANNEL_A; channel_idx < p->support_channel_num; channel_idx++)
	{
		vSetPHY2ChannelMapping(p, channel_idx);// when switching channel, must update PHY to Channel Mapping
		vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_CA_CMD2), P_Fld(0, CA_CMD2_RG_TX_ARCMD_OE_DIS_CA)
											| P_Fld(1, CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA)
											| P_Fld(0xff, CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA));
		vDramCalibrationSingleChannel(p);
	}

	vSetPHY2ChannelMapping(p, CHANNEL_A);

#if PRINT_CALIBRATION_SUMMARY
	vPrintCalibrationResult(p);
#endif

#ifdef FOR_HQA_TEST_USED
	#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	if (p->femmc_Ready == 1)
	{
		msg("\nCalibration fast K is enable, cannot show HQA measurement information\n");
	}
	else
	#endif
	print_HQA_measure_message(p);
#endif

	/* Enable/Disable calibrated rank's DBI function accordingly */
#if ENABLE_READ_DBI
	//Read DBI ON
	vSetRank(p, RANK_0);
	vSetPHY2ChannelMapping(p, CHANNEL_A);

	DramcReadDBIOnOff(p, p->DBI_R_onoff[p->dram_fsp]);
#endif

#if ENABLE_WRITE_DBI
	// Just settle the DBI parameters which would be stored into shuffle space.
	if (p->DBI_W_onoff[p->dram_fsp])
	{
		for (channel_idx = CHANNEL_A; channel_idx < p->support_channel_num; channel_idx++)
		{
			vSetPHY2ChannelMapping(p, channel_idx);

			for (rank_idx = RANK_0; rank_idx < RANK_MAX; rank_idx++)
			{
				vSetRank(p, rank_idx);
				DramcWriteShiftMCKForWriteDBI(p, -1); //Tx DQ/DQM -1 MCK for write DBI ON
			}
			vSetRank(p, RANK_0);
		}
		vSetPHY2ChannelMapping(p, CHANNEL_A);

		// Improve Write DBI Power
		ApplyWriteDBIPowerImprove(p, ENABLE);

		#if ENABLE_WRITE_DBI_Protect
		ApplyWriteDBIProtect(p, ENABLE);
		#endif
	}

	DramcWriteDBIOnOff(p, p->DBI_W_onoff[p->dram_fsp]);
#endif

#if TX_PICG_NEW_MODE
	TXPICGSetting(p);
#endif

#if XRTRTR_NEW_CROSS_RK_MODE
	if (p->support_rank_num == RANK_DUAL)
	{
		XRTRTR_SHU_Setting(p);
	}
#endif

#if (ENABLE_TX_TRACKING || TDQSCK_PRECALCULATION_FOR_DVFS)
	FreqJumpRatioCalculation(p);
#endif

#ifdef TEMP_SENSOR_ENABLE
	DramcHMR4_Presetting(p);
#endif

#if (ENABLE_PER_BANK_REFRESH == 1)
	DramcEnablePerBankRefresh(p, ON);
#else
	DramcEnablePerBankRefresh(p, OFF);
#endif

#if DRAMC_MODIFIED_REFRESH_MODE
	DramcModifiedRefreshMode(p);
#endif

#if DRAMC_CKE_DEBOUNCE
	DramcCKEDebounce(p);
#endif

#if ENABLE_TX_TRACKING
	U8 backup_channel = p->channel;
	U8 channelIdx;

	for (channelIdx = CHANNEL_A; channelIdx < p->support_channel_num; channelIdx++)
	{
		vSetPHY2ChannelMapping(p, channelIdx);
		DramcHwDQSOSC(p);
	}

	vSetPHY2ChannelMapping(p, backup_channel);
	msg("TX_TRACKING: ON\n");
#else
	msg("TX_TRACKING: OFF\n");
#endif


#if ENABLE_DFS_RUNTIME_MRW
	DFSRuntimeMRW_preset(p, vGet_Current_ShuLevel(p));
#endif

#ifdef DDR_INIT_TIME_PROFILING
#if __ETT__
	u4low_tick1 = GPT_GetTickCount(&u4high_tick1);
	time_msg("	(4) vDramCalibrationAllChannel() take %d ms\n\r", ((u4low_tick1 - u4low_tick0) * 76) / 1000000);
#else
	u4low_tick1 = get_timer(u4low_tick0);
	time_msg("	(4) vDramCalibrationAllChannel() take %d ms\n\r", u4low_tick1);
#endif
#endif
}

U8 gGet_MDL_Used_Flag = 0;
void Set_MDL_Used_Flag(U8 value)
{
	gGet_MDL_Used_Flag = value;
}

U8 Get_MDL_Used_Flag(void)
{
	return gGet_MDL_Used_Flag;
}

DRAMC_CTX_T *psCurrDramCtx;
U8 gfirst_init_flag = 0;
int Init_DRAM(DRAM_DRAM_TYPE_T dram_type, DRAM_CBT_MODE_EXTERN_T dram_cbt_mode_extern,
		  DRAM_INFO_BY_MRR_T *DramInfo, U8 get_mdl_used)
{
	#if !SW_CHANGE_FOR_SIMULATION

	DRAMC_CTX_T * p;
	U8 final_shu;
	DRAM_DFS_FREQUENCY_TABLE_T *first_cali_freq_tbl;

#ifdef DDR_INIT_TIME_PROFILING
	U32 CPU_Cycle;
	TimeProfileBegin();
#endif

	psCurrDramCtx = &DramCtx_LPDDR4;

#if defined(DDR_INIT_TIME_PROFILING) || (__ETT__ && SUPPORT_SAVE_TIME_FOR_CALIBRATION)
	if (gtime_profiling_flag == 0)
	{
		memcpy(&gTimeProfilingDramCtx, psCurrDramCtx, sizeof(DRAMC_CTX_T));
		gtime_profiling_flag = 1;
	}

	p = &gTimeProfilingDramCtx;
	gfirst_init_flag = 0;

	//DramcConfInfraReset(p);  //No need when DDR_INIT_TIME_PROFILING_TEST_CNT=1
#else
	p = psCurrDramCtx;
#endif

	p->new_cbt_mode = 1;

	Set_MDL_Used_Flag(get_mdl_used);

	p->dram_type = dram_type;

	/* Convert DRAM_CBT_MODE_EXTERN_T to DRAM_CBT_MODE_T */
	switch ((int)dram_cbt_mode_extern)
	{
		case CBT_R0_R1_NORMAL:
			p->dram_cbt_mode[RANK_0] = CBT_NORMAL_MODE;
			p->dram_cbt_mode[RANK_1] = CBT_NORMAL_MODE;
			break;
		case CBT_R0_R1_BYTE:
			p->dram_cbt_mode[RANK_0] = CBT_BYTE_MODE1;
			p->dram_cbt_mode[RANK_1] = CBT_BYTE_MODE1;
			break;
		case CBT_R0_NORMAL_R1_BYTE:
			p->dram_cbt_mode[RANK_0] = CBT_NORMAL_MODE;
			p->dram_cbt_mode[RANK_1] = CBT_BYTE_MODE1;
			break;
		case CBT_R0_BYTE_R1_NORMAL:
			p->dram_cbt_mode[RANK_0] = CBT_BYTE_MODE1;
			p->dram_cbt_mode[RANK_1] = CBT_NORMAL_MODE;
			break;
		default:
			err("Error!");
			break;
	}
	msg2("dram_cbt_mode_extern: %d\n"
					  "dram_cbt_mode [RK0]: %d, [RK1]: %d\n",
					  (int)dram_cbt_mode_extern, p->dram_cbt_mode[RANK_0], p->dram_cbt_mode[RANK_1]);

#if ENABLE_APB_MASK_WRITE
	U32 u4GPTTickCnt;
	TimeProfileBegin();

	EnableDramcAPBMaskWrite(p);
	DramcRegAPBWriteMask(p);

	u4GPTTickCnt = TimeProfileEnd();
	time_msg("[DramcRegAPBWriteMask] take %d ms\n", u4GPTTickCnt / 1000);

	TestAPBMaskWriteFunc(p);

	while (1);
#endif

	DramcBroadcastOnOff(DRAMC_BROADCAST_ON);   //LP4 broadcast on

	if (gfirst_init_flag == 0)
	{
		MPLLInit();
		Global_Option_Init(p);
		gfirst_init_flag = 1;
	}

#ifdef FIRST_BRING_UP
	Test_Broadcast_Feature(p);
#endif

#if (FOR_DV_SIMULATION_USED == 0 && SW_CHANGE_FOR_SIMULATION == 0)
	{
		U32 backup_broadcast;
		backup_broadcast = GetDramcBroadcast();
		DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);
		mdl_setting(p);
		UpdateGlobal10GBEnVariables(p); // @Darren, for 10GB
		TA2_Test_Run_Time_HW_Set_Column_Num(p);
		DramcBroadcastOnOff(backup_broadcast);
	}
#endif

	info("\n\n[Bian_co] ETT version 0.0.0.1\n dram_type %d, R0 cbt_mode %d, R1 cbt_mode %d VENDOR=%d\n\n", p->dram_type, p->dram_cbt_mode[RANK_0], p->dram_cbt_mode[RANK_1], p->vendor_id);

#if __Petrus_TO_BE_PORTING__
	vDramcInit_PreSettings(p);
#endif

	// DramC & PHY init for all channels
	//===  First frequency ======
	first_cali_freq_tbl = &gFreqTbl[DRAM_DFS_SHUFFLE_MAX-1];

#if defined(DUMP_INIT_RG_LOG_TO_DE)
	vSetDFSFreqSelByTable(p, &gFreqTbl[1]); //0:3200 1:4266, 2:800, 3:1866, 4:1200, 5:2400, 6:1600
#else
	vSetDFSFreqSelByTable(p, first_cali_freq_tbl);
	//vSetDFSFreqSelByTable(p, &gFreqTbl[1]);
#endif
	//#if (ENABLE_DRAM_SINGLE_FREQ_SELECT != 0xFF) || defined(FIRST_BRING_UP) || (__FLASH_TOOL_DA__)
	if (is_dvfs_enabled())
		gAndroid_DVFS_en = TRUE;
	else
		gAndroid_DVFS_en = FALSE;

#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	DramcSave_Time_For_Cal_Init(p);
#endif
#ifndef LOOPBACK_TEST
	if (p->dram_type == TYPE_LPDDR4X) // LP4/LP4P need confirm
	{
		// LP4 IMP_LOW_FREQ <= DDR3733, IMP_HIGH_FREQ >= DDR4266
		// LP5 IMP_LOW_FREQ <= DDR3733, IMP_HIGH_FREQ >= DDR4266
		DramcSwImpedanceCal(p, 1, IMP_LOW_FREQ);
		DramcSwImpedanceCal(p, 1, IMP_HIGH_FREQ);
		#if ENABLE_SAMSUNG_NT_ODT
		DramcSwImpedanceCal(p, 1, IMP_NT_ODTN); // for Samsung NT ODTN
		#endif
	}
	else
	{
		err("[DramcSwImpedanceCal] Warnning: Need confirm DRAM type for SW IMP Calibration !!!\n");
		#if __ETT__
		while (1);
		#endif
	}
#endif

#ifdef DDR_INIT_TIME_PROFILING
	CPU_Cycle = TimeProfileEnd();
	time_msg("(0)Pre_Init + SwImdepance takes %d ms\n\r", CPU_Cycle / 1000);
#endif

#ifdef DUMP_INIT_RG_LOG_TO_DE
	gDUMP_INIT_RG_LOG_TO_DE_RG_log_flag = 1;
	mcSHOW_DUMP_INIT_RG_MSG("\n\n//=== DDR\033[1;32m%d\033[m\n",p->frequency<<1);
#endif

	//Clk free run
	//EnableDramcPhyDCM(p, 0);

	DFSInitForCalibration(p);

#ifdef TEST_MODE_MRS
	if (global_which_test == 0)
		TestModeTestMenu();
#endif


#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	if (p->femmc_Ready==1)
	{
		p->support_rank_num = p->pSavetimeData->support_rank_num;
	}
#endif

	#if (FOR_DV_SIMULATION_USED == 0 && SW_CHANGE_FOR_SIMULATION == 0)
	U32 backup_broadcast;
	backup_broadcast = GetDramcBroadcast();
	DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);
	emi_init2();
	DramcBroadcastOnOff(backup_broadcast);
	#endif

	if (Get_MDL_Used_Flag()==GET_MDL_USED)
	{
		// only K CHA to save time
		vSetPHY2ChannelMapping(p, CHANNEL_A);
		vCalibration_Flow_For_MDL(p); // currently for LP4
		GetDramInforAfterCalByMRR(p, DramInfo);
		return 0;
	}
	else //NORMAL_USED
	{
		#if (fcFOR_CHIP_ID == fcMargaux) // @Darren, new chip need double confirm
		if (p->DRAMPinmux == PINMUX_DSC)
			UpdateDFSTbltoDDR3200(p);
		#endif
		vDramCalibrationAllChannel(p);
		GetDramInforAfterCalByMRR(p, DramInfo);
		vDramcACTimingOptimize(p);
	}

	#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	DramcSave_Time_For_Cal_End(p);
	#endif

#if ((!defined(FIRST_BRING_UP)) || (ENABLE_DRAM_SINGLE_FREQ_SELECT != 0xFF)) && (!__FLASH_TOOL_DA__)
	DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, (DRAM_DFS_SHUFFLE_TYPE_T)p->pDFSTable->shuffleIdx);
	#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	DramcSave_Time_For_Cal_End(p);
	#endif
	LoadShuffleSRAMtoDramc(p, (DRAM_DFS_SHUFFLE_TYPE_T)p->pDFSTable->shuffleIdx, DRAM_DFS_SHUFFLE_2); //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
	#if ENABLE_SRAM_DMA_WA
	DPHYSRAMShuWAToSHU1(p); //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
	#endif

	S8 u1ShuIdx;
	S8 allCaliShuIdx = 0xFF;

	if (CONFIG(MEDIATEK_DRAM_DVFS_LIMIT_FREQ_CNT)) {
		if (p->DRAMPinmux == PINMUX_DSC)
			allCaliShuIdx = 0x61;	// 3200, 2400, 1600
		else
			allCaliShuIdx = 0x43;	// 3200, 4266, 1600
	}
	dramc_debug("all cali shu idx: 0x%x\n", allCaliShuIdx);

//#if (ENABLE_DRAM_SINGLE_FREQ_SELECT == 0xFF)
	if (is_dvfs_enabled()) {
		for (u1ShuIdx = DRAM_DFS_SHUFFLE_MAX - 2; u1ShuIdx >= DRAM_DFS_SHUFFLE_1; u1ShuIdx--)
		{
			#if (fcFOR_CHIP_ID == fcMargaux) && (ENABLE_DRAM_SINGLE_FREQ_SELECT == 0xFF) // @Darren, new chip need double confirm
			if ((p->DRAMPinmux == PINMUX_DSC) && (gFreqTbl[u1ShuIdx].shuffleIdx == SRAM_SHU0))
				continue;
			#endif

			// ignore the calibration for shuffle which is not in allCaliShuIdx, just copy first cali shuffle data
			if (!(allCaliShuIdx & BIT(u1ShuIdx))) {
				// copy first calibration shuffle to this shuffle (if DVFS, need double confirm)
				DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, (DRAM_DFS_SHUFFLE_TYPE_T)gFreqTbl[u1ShuIdx].shuffleIdx);
				continue;
			}

			vSetDFSFreqSelByTable(p, &gFreqTbl[u1ShuIdx]);
			#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
			DramcSave_Time_For_Cal_Init(p);
			#endif
			DFSInitForCalibration(p);
			vDramCalibrationAllChannel(p);
			vDramcACTimingOptimize(p);

			#if RUNTIME_SHMOO_RELEATED_FUNCTION && SUPPORT_SAVE_TIME_FOR_CALIBRATION
			if (p->frequency == u2DFSGetHighestFreq(p))
			{
				DramcRunTimeShmooRG_BackupRestore(p);

				RunTime_Shmoo_update_parameters(p);
			}
#endif
			DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, (DRAM_DFS_SHUFFLE_TYPE_T)gFreqTbl[u1ShuIdx].shuffleIdx);
			#if (fcFOR_CHIP_ID == fcMargaux) && (ENABLE_DRAM_SINGLE_FREQ_SELECT == 0xFF) // @Darren, new chip need double confirm
			if ((p->DRAMPinmux == PINMUX_DSC) && (gFreqTbl[u1ShuIdx].shuffleIdx == SRAM_SHU1))
				DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, (DRAM_DFS_SHUFFLE_TYPE_T)gFreqTbl[u1ShuIdx + 1].shuffleIdx); // Copy SRAM_SHU1 to SRAM_SHU0
			#endif

			#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
			DramcSave_Time_For_Cal_End(p);
			#endif
		}
	}
#endif //((!defined(FIRST_BRING_UP)) || (ENABLE_DRAM_SINGLE_FREQ_SELECT != 0xFF)) && (!__FLASH_TOOL_DA__)

#ifdef DDR_INIT_TIME_PROFILING
	TimeProfileBegin();
#endif

	vAfterCalibration(p);

#ifdef ENABLE_POST_PACKAGE_REPAIR
	PostPackageRepair();
#endif

#if __Petrus_TO_BE_PORTING__

#if 0//TX_OE_CALIBATION, for DMA test
	U8 u1ChannelIdx, u1RankIdx;
	for (u1ChannelIdx = 0; u1ChannelIdx < (p->support_channel_num); u1ChannelIdx++)
		for (u1RankIdx = 0; u1RankIdx < (p->support_rank_num); u1RankIdx++)
		{
			vSetPHY2ChannelMapping(p, u1ChannelIdx);
			vSetRank(p, u1RankIdx);
			DramcTxOECalibration(p);
		}

	vSetPHY2ChannelMapping(p, CHANNEL_A);
	vSetRank(p, RANK_0);

	U32 u4err_value;
	DramcDmaEngine((DRAMC_CTX_T *)p, 0x50000000, 0x60000000, 0xff00, 8, DMA_PREPARE_DATA_ONLY, p->support_channel_num);
	u4err_value = DramcDmaEngine((DRAMC_CTX_T *)p, 0x50000000, 0x60000000, 0xff00, 8, DMA_CHECK_DATA_ACCESS_AND_COMPARE, p->support_channel_num);
	msg("DramC_TX_OE_Calibration  0x%X\n", u4err_value);
#endif

#if !LCPLL_IC_SCAN
#if (FOR_DV_SIMULATION_USED == 0 && SW_CHANGE_FOR_SIMULATION == 0)
	print_DBG_info(p);
	Dump_EMIRegisters(p);
#endif
#endif

#if 0
	DramcRegDump(p, SRAM_SHU0);
#endif

// ETT_NO_DRAM #endif

#if ETT_NO_DRAM
	//NoDramDramcRegDump(p);
	NoDramRegFill();
#endif
#endif //#if __Petrus_TO_BE_PORTING__

	#if DRAMC_MODEREG_CHECK
	DramcModeReg_Check(p);
	#endif

	#if __FLASH_TOOL_DA__
	vPrintPinInfoResult(p);
	vGetErrorTypeResult(p);
	#endif
	#if CPU_RW_TEST_AFTER_K
	msg("\n[MEM_TEST] 02: After DFS, before run time config\n");
	vDramCPUReadWriteTestAfterCalibration(p);
#endif

	#if TA2_RW_TEST_AFTER_K
	msg("\n[TA2_TEST]\n");
	TA2_Test_Run_Time_HW(p);
	#endif

#if __ETT__
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
	if (!(p->femmc_Ready == 0))
#elif defined(DDR_INIT_TIME_PROFILING)
if (u2TimeProfileCnt == (DDR_INIT_TIME_PROFILING_TEST_CNT - 1)) //last time of loop
#endif
#endif
	{
		EnableDFSHwModeClk(p);
		msg("DFS_SHUFFLE_HW_MODE: ON\n");
		if (gAndroid_DVFS_en == TRUE) // shuffle to DDR3733 boot
		{
#if defined(SLT)
			final_shu = SRAM_SHU1;	//DDR3200
#else
			final_shu = SRAM_SHU0;	//DDR4266
#endif

			vSetDFSFreqSelByTable(p, get_FreqTbl_by_shuffleIndex(p, final_shu));
			DramcDFSDirectJump_SRAMShuRGMode(p, SRAM_SHU1);
			DramcDFSDirectJump_SRAMShuRGMode(p, final_shu);
			print("switch to %d Mbps bootup\n", p->frequency * 2);
		}


#if __Petrus_TO_BE_PORTING__
		#if (DVT_TEST_DUMMY_RD_SIDEBAND_FROM_SPM && defined(DUMMY_READ_FOR_TRACKING))
		DramcDummyReadForSPMSideBand(p); // SPM dummy read 1us <-> 4us for DVT only (it must call after TransferPLLToSPMControl)
		#endif

		EnableDramcTrackingBySPMControl(p);

		msg("\n\nSettings after calibration\n\n");
		reg_msg("\n\nSettings after calibration\n\n");
#endif

		DramcRunTimeConfig(p);
	}

	#if CPU_RW_TEST_AFTER_K
	msg("\n[MEM_TEST] 03: After run time config\n");
	vDramCPUReadWriteTestAfterCalibration(p);
	#endif

	#if TA2_RW_TEST_AFTER_K
	msg("\n[TA2_TEST]\n");
	TA2_Test_Run_Time_HW(p);
	#endif


#if (__ETT__ && CPU_RW_TEST_AFTER_K)
	/* 0x46000000 is LK base addr */
	//while(1)
	{
		//if ((s4value = dramc_complex_mem_test (0x46000000, 0x2000)) == 0)
		if ((s4value = dramc_complex_mem_test (0x40024000, 0x20000)) == 0)
		{
			msg("1st complex R/W mem test pass\n");
		}
		else
		{
			msg("1st complex R/W mem test fail :-%d\n", -s4value);
#if defined(SLT)
			err("[dramc] DRAM_FATAL_ERR_FLAG = 0x80000000\n");
			while (1);
#endif
		}
	}
#endif

#if MRW_CHECK_ONLY
	vPrintFinalModeRegisterSetting(p);
#endif

#ifdef DDR_INIT_TIME_PROFILING
	CPU_Cycle = TimeProfileEnd();
	time_msg("	(5) After calibration takes %d ms\n\r", CPU_Cycle / 1000);
#endif	// end of DDR_INIT_TIME_PROFILING

#endif//SW_CHANGE_FOR_SIMULATION
	//Low_Power_Scenarios_Test(p);

	//vSetDFSFreqSelByTable(p, get_FreqTbl_by_shuffleIndex(p, SRAM_SHU1));
	//DramcDFSDirectJump(p, SRAM_SHU1);//Switch to CLRPLL

	//ETT_DRM(p);
	return 0;
}
///TODO: wait for porting ---


///TODO: wait for porting +++
static void DPI_vDramCalibrationSingleChannel(DRAMC_CTX_T *DramConfig, cal_sv_rand_args_t *psra)
{
	U8 ii;

	///TODO: wait for porting +++
#if GATING_ADJUST_TXDLY_FOR_TRACKING
	DramcRxdqsGatingPreProcess(DramConfig);
#endif
	///TODO: wait for porting ---

	vAutoRefreshSwitch(DramConfig, DISABLE);

#if 1//(SIMUILATION_CBT == 1)
	for (ii = RANK_0; ii < DramConfig->support_rank_num; ii++)
	{
		vSetRank(DramConfig, ii);

		if (!psra || psra->cbt) {
			msg("\n----->DramcCBT begin...\n");
			timestamp_show();
		#if CBT_O1_PINMUX_WORKAROUND
			CmdBusTrainingLP45(DramConfig, AUTOK_OFF); //Cannot use aito-k in A60868
		#else
			if (psra)
				CmdBusTrainingLP45(DramConfig, psra->cbt_autok);
			else
				CmdBusTrainingLP45(DramConfig, AUTOK_OFF);
		#endif
			timestamp_show();
			msg("DramcCBT end<-----\n\n");
		}
	#if ENABLE_EYESCAN_GRAPH
	   msg("CBT EYESCAN start<-----\n\n");
	   print_EYESCAN_LOG_message(DramConfig, 0); //draw CBT eyescan
	   msg("CBT EYESCAN end<-----\n\n");
	   #endif
	}

	vSetRank(DramConfig, RANK_0);

	///TODO: wait for porting +++
#if __A60868_TO_BE_PORTING__
	No_Parking_On_CLRPLL(DramConfig);
#endif // __A60868_TO_BE_PORTING__
	///TODO: wait for porting ---
#endif /* (SIMUILATION_CBT == 1) */

	for (ii = RANK_0; ii < DramConfig->support_rank_num; ii++)
	{
		vSetRank(DramConfig, ii);

		vAutoRefreshSwitch(DramConfig, DISABLE); //When doing WriteLeveling, should make sure that auto refresh is disable

#if 1//(SIMULATION_WRITE_LEVELING == 1)
#if (!WCK_LEVELING_FM_WORKAROUND)
	if (u1IsLP4Family(DramConfig->dram_type))
#endif
	{
		if (!(u1IsLP4Div4DDR800(DramConfig) && (DramConfig->rank == RANK_1))) // skip for DDR800 rank1
		{
			if (!psra || psra->wl) {
				msg("\n----->DramcWriteLeveling(PI) begin...\n");
				timestamp_show();
				if (psra)
				{
					DramcWriteLeveling(DramConfig, psra->wl_autok, PI_BASED);
				}
				else
					DramcWriteLeveling(DramConfig, AUTOK_OFF, PI_BASED);

				timestamp_show();
				msg("DramcWriteLeveling(PI) end<-----\n\n");
			}
		}
	}
#endif /* (SIMULATION_WRITE_LEVELING == 1) */

		vAutoRefreshSwitch(DramConfig, ENABLE);

#if 1//(SIMULATION_GATING == 1)
		if (!psra || psra->gating) {
			msg("\n----->DramcGating begin...\n");
			timestamp_show();
			if (psra)
				dramc_rx_dqs_gating_cal(DramConfig, psra->gating_autok, 0);
			else
				dramc_rx_dqs_gating_cal(DramConfig, AUTOK_OFF, 0);
			timestamp_show();
			msg("DramcGating end < -----\n\n");
		}
#endif

#if 1//(SIMULATION_RX_RDDQC == 1)
		if (!psra || psra->rddqc) {
			msg("\n----->DramcRxWindowPerbitCal RDDQC begin...\n");
			timestamp_show();

			#if 0 // Used when testing LP5 RK1 WCK2CK in high efficiency mode and differential mode.
			p->rank = 1;
			// For test HEFF = 1 / WCKDUAL = 0
			vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_WCKCTRL), 0, SHU_WCKCTRL_WCKDUAL);
			vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHU_COMMON0),
					P_Fld(1, SHU_COMMON0_LP5WCKON) |
					P_Fld(1, SHU_COMMON0_LP5HEFF_MODE));
			vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL), 0, CKECTRL_CKE2RANK_OPT8);
			#endif
			DramcRxWindowPerbitCal(DramConfig, PATTERN_RDDQC, NULL, AUTOK_OFF);
			timestamp_show();
			msg("DramcRxWindowPerbitCal end<-----\n\n");
		}
#endif // (SIMULATION_RX_RDDQC == 1)

#if (__LP5_COMBO__ == TRUE)
#if (SIMULATION_DUTY_CYC_MONITOR == 1)
		if (is_lp5_family(DramConfig) && DramConfig->frequency >= GetFreqBySel(DramConfig,LP5_DDR4266))
		{
			if (!psra) {
				msg("\n----->DramcDutyCycleMonitor begin...\n");
				timestamp_show();
				DramcDutyCycleMonitor(DramConfig);
				timestamp_show();
				msg("DramcDutyCycleMonitor end<-----\n\n");

				msg("\n----->DramcWriteLeveling(DLY) begin...\n");
				timestamp_show();
				DramcWriteLeveling(DramConfig, psra->wl_autok, DLY_BASED);
				timestamp_show();
				msg("DramcWriteLeveling(DLY)end<-----\n\n");
			}
		}
#endif /* (SIMULATION_DUTY_CYC_MONITOR == 1) */
#endif // (__LP5_COMBO__ == TRUE)

#if 1//(SIMULATION_TX_PERBIT == 1)
		if (!psra || psra->tx_perbit) {
			msg("\n----->DramcTxWindowPerbitCal begin...\n");
			timestamp_show();
			if (psra)
				DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_DQM,
						FALSE, psra->tx_auto_cal);
			else
				DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_DQM,
						FALSE, AUTOK_OFF);
			if (Get_Vref_Calibration_OnOff(DramConfig) == VREF_CALI_ON) {
				if (psra)
					DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_ONLY,
							TRUE, psra->tx_auto_cal);
				else
					DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_ONLY,
							TRUE, AUTOK_OFF);
			}
			if (psra)
				DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_ONLY,
						FALSE, psra->tx_auto_cal);
			else
				DramcTxWindowPerbitCal(DramConfig, TX_DQ_DQS_MOVE_DQ_ONLY,
						FALSE, AUTOK_OFF);
			timestamp_show();
			msg("DramcTxWindowPerbitCal end<-----\n\n");

		#if ENABLE_EYESCAN_GRAPH
			   msg("\n----->DramcTxEYESCAN begin...\n");
			   Dramc_K_TX_EyeScan_Log(DramConfig);
			   print_EYESCAN_LOG_message(DramConfig, 2); //draw TX eyescan
			   msg("\n----->DramcTxEYESCAN end...\n");
			   #endif
		}
#endif // (SIMULATION_TX_PERBIT == 1)

#if 1//(SIMULATION_DATLAT == 1)
		if (1) { // No parameter in correspondence with by now
			msg("\n----->DramcRxdatlatCal begin...\n");
			timestamp_show();

			DramcRxdatlatCal(DramConfig);

			timestamp_show();
			msg("DramcRxdatlatCal end<-----\n\n");
		}
#endif // (SIMULATION_DATLAT == 1)

#if 1//(SIMULATION_RX_PERBIT == 1)
		if (!psra || psra->rx_perbit) {
			msg("\n----->DramcRxWindowPerbitCal begin...\n");
			timestamp_show();
			if (psra)
				DramcRxWindowPerbitCal(DramConfig, PATTERN_TEST_ENGINE,
						NULL /*Set Vref = 0 to test*/, psra->rx_auto_cal);
			else
				DramcRxWindowPerbitCal(DramConfig, PATTERN_TEST_ENGINE,
						NULL /*Set Vref = 0 to test*/, AUTOK_OFF);
			timestamp_show();
			msg("DramcRxWindowPerbitCal end<-----\n\n");

			#if ENABLE_EYESCAN_GRAPH
			   msg("DramcRxWindowPerbitCal EYESCAN start<-----\n\n");
			   print_EYESCAN_LOG_message(DramConfig, 1); //draw RX eyescan
			   msg("DramcRxWindowPerbitCal EYESCAN end<-----\n\n");
			#endif
		}
#endif // (SIMULATION_RX_PERBIT == 1)

#if (SIMULATION_RX_DVS == 1)
	if (DramConfig->frequency >=2133)
		DramcRxDVSWindowCal(DramConfig);
#endif

#if TX_OE_CALIBATION
		if (DramConfig->frequency >= 1600)
		{
			DramcTxOECalibration(DramConfig);
		}
#endif // TX_OE_CALIBATION

		#if ENABLE_TX_TRACKING
		#if 0 /* Starting from Vinson, no need to pre-calculate MR23 for different freqs */
		if (gu1MR23Done == FALSE)
		{
			DramcDQSOSCAuto(p);
		}
		#endif
		DramcDQSOSCAuto(DramConfig);
		DramcDQSOSCMR23(DramConfig);
		DramcDQSOSCSetMR18MR19(DramConfig);
		#endif
	}

	vSetRank(DramConfig, RANK_0);

	#if ENABLE_TX_TRACKING
	DramcDQSOSCShuSettings(DramConfig);
	#endif

///TODO: wait for porting +++
#if GATING_ADJUST_TXDLY_FOR_TRACKING
	DramcRxdqsGatingPostProcess(DramConfig);
#endif

#if TDQSCK_PRECALCULATION_FOR_DVFS
	DramcDQSPrecalculation_preset(DramConfig);
#endif

#if SIMULATION_RX_DVS
	if (DramConfig->frequency >=2133)
		DramcDramcRxDVSCalPostProcess(DramConfig);
#endif

#if XRTWTW_NEW_CROSS_RK_MODE
	if (DramConfig->support_rank_num == RANK_DUAL)
	{
		XRTWTW_SHU_Setting(DramConfig);
	}
#endif

#if DV_SIMULATION_DATLAT
	DramcDualRankRxdatlatCal(DramConfig);
#endif

#if RDSEL_TRACKING_EN
	if (DramConfig->frequency != 400)
		RDSELRunTimeTracking_preset(DramConfig);
#endif

///TODO: wait for porting ---

}

static void DPI_vDramCalibrationAllChannel(DRAMC_CTX_T *DramConfig, cal_sv_rand_args_t *psra)
{
	U8 channel_idx, rank_idx;

	CKEFixOnOff(DramConfig, CKE_WRITE_TO_ALL_RANK, CKE_FIXOFF, CKE_WRITE_TO_ALL_CHANNEL);
	for (channel_idx = CHANNEL_A; channel_idx < DramConfig->support_channel_num; channel_idx++)
	{
		vSetPHY2ChannelMapping(DramConfig, channel_idx);// when switching channel, must update PHY to Channel Mapping
		CKEFixOnOff(DramConfig, CKE_WRITE_TO_ALL_RANK, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
		DPI_vDramCalibrationSingleChannel(DramConfig, psra);
	}

	vSetPHY2ChannelMapping(DramConfig, CHANNEL_A);

///TODO: wait for porting +++
#if ENABLE_READ_DBI
	DramcReadDBIOnOff(DramConfig, DramConfig->DBI_R_onoff[DramConfig->dram_fsp]);
#endif

#if ENABLE_WRITE_DBI
	// Just settle the DBI parameters which would be stored into shuffle space.
	if (DramConfig->DBI_W_onoff[DramConfig->dram_fsp])
	{
		for (channel_idx = CHANNEL_A; channel_idx < DramConfig->support_channel_num; channel_idx++)
		{
			vSetPHY2ChannelMapping(DramConfig, channel_idx);

			for (rank_idx = RANK_0; rank_idx < DramConfig->support_rank_num; rank_idx++)
			{
				vSetRank(DramConfig, rank_idx);
				DramcWriteShiftMCKForWriteDBI(DramConfig, -1); //Tx DQ/DQM -1 MCK for write DBI ON
			}
			vSetRank(DramConfig, RANK_0);
		}
		vSetPHY2ChannelMapping(DramConfig, CHANNEL_A);

		// Improve Write DBI Power
		ApplyWriteDBIPowerImprove(DramConfig, ENABLE);

		#if ENABLE_WRITE_DBI_Protect
		ApplyWriteDBIProtect(DramConfig, ENABLE);
		#endif
	}
	DramcWriteDBIOnOff(DramConfig, DramConfig->DBI_W_onoff[DramConfig->dram_fsp]);


#endif

#if XRTRTR_NEW_CROSS_RK_MODE
	if (DramConfig->support_rank_num == RANK_DUAL)
	{
		XRTRTR_SHU_Setting(DramConfig);
	}
#endif

#if DV_SIMULATION_DFS
#if (ENABLE_TX_TRACKING || TDQSCK_PRECALCULATION_FOR_DVFS)
	FreqJumpRatioCalculation(DramConfig);
#endif
#endif

#ifdef TEMP_SENSOR_ENABLE
	DramcHMR4_Presetting(DramConfig);
#endif

#if (ENABLE_PER_BANK_REFRESH == 1)
	DramcEnablePerBankRefresh(DramConfig, ON);
#else
	DramcEnablePerBankRefresh(DramConfig, OFF);
#endif

#if ENABLE_TX_TRACKING
	U8 backup_channel = DramConfig->channel;
	U8 channelIdx;

	for (channelIdx = CHANNEL_A; channelIdx < DramConfig->support_channel_num; channelIdx++)
	{
		vSetPHY2ChannelMapping(DramConfig, channelIdx);
		DramcHwDQSOSC(DramConfig);
	}

	vSetPHY2ChannelMapping(DramConfig, backup_channel);
	msg("TX_TRACKING: ON\n");
#else
	msg("TX_TRACKING: OFF\n");
#endif

///TODO: wait for porting ---

}

///TODO: wait for porting +++
#if __A60868_TO_BE_PORTING__
void RG_dummy_write(DRAMC_CTX_T *p, U32 pattern)
{
	unsigned int ii;
	for (ii = 0; ii < 20; ii++)
		vIO32WriteFldAlign(DDRPHY_RFU_0X1D4, pattern, RFU_0X1D4_RESERVED_0X1D4);
}

void EnablePLLtoSPMControl(DRAMC_CTX_T *p)
{
	vIO32WriteFldAlign_All(DDRPHY_MISC_SPM_CTRL1, 0, MISC_SPM_CTRL1_SPM_DVFS_CONTROL_SEL); // DFS SPM mode for calibration
}
#endif // __A60868_TO_BE_PORTING__
///TODO: wait for porting ---

void dump_dramc_ctx(DRAMC_CTX_T *p)
{
	msg("== DRAMC_CTX_T ==\n");
	msg("support_channel_num:	 %d\n", p->support_channel_num);
	msg("channel:				 %d\n", p->channel);
	msg("support_rank_num:		 %d\n", p->support_rank_num);
	msg("rank:					 %d\n", p->rank);
	msg("freq_sel:				 %d\n", p->freq_sel);
	msg("shu_type:				 %d\n", p->shu_type);
	msg("dram_type: 			 %d\n", p->dram_type);
	msg("dram_fsp:				 %d\n", p->dram_fsp);
	msg("odt_onoff: 			 %d\n", p->odt_onoff);
	msg("dram_cbt_mode: 		 %d, %d\n", (int)p->dram_cbt_mode[0], (int)p->dram_cbt_mode[1]);
	msg("DBI_R_onoff:			 %d, %d\n", (int)p->DBI_R_onoff[0], (int)p->DBI_R_onoff[1]);
	msg("DBI_W_onoff:			 %d, %d\n", (int)p->DBI_W_onoff[0], (int)p->DBI_W_onoff[1]);
	msg("data_width:			 %d\n", p->data_width);
	msg("test2_1:			  0x%x\n", p->test2_1);
	msg("test2_2:			  0x%x\n", p->test2_2);
	msg("frequency: 			 %d\n", p->frequency);
	msg("freqGroup: 			 %d\n", p->freqGroup);
	msg("lp5_training_mode: 			 %d\n", p->lp5_training_mode);
	msg("lp5_cbt_phase: 			 %d\n", p->lp5_cbt_phase);
	msg("new_cbt_mode:				%d\n", p->new_cbt_mode);
	msg("u1PLLMode: 			 %d\n", p->u1PLLMode);
	msg("curDBIState:			   %d\n", p->curDBIState);
}


void DPI_SW_main_LP4(DRAMC_CTX_T *ExtConfig, cal_sv_rand_args_t *psra)
{
	u32 value;
#if DV_SIMULATION_DFS
	S8 s1ShuIdx;
#endif

	DRAMC_CTX_T *p = &DramCtx_LPDDR4; //default;

	p->dram_type = ExtConfig->dram_type;
	if(p->dram_type==TYPE_LPDDR5)
	{
		MEM_TYPE = LPDDR5;
	}
	else
	{
		MEM_TYPE = LPDDR4;
	}

	p->dram_cbt_mode[0] = ExtConfig->dram_cbt_mode[0];
	p->dram_cbt_mode[1] = ExtConfig->dram_cbt_mode[1];
	p->freq_sel = ExtConfig->freq_sel;
	p->frequency = ExtConfig->frequency;
	p->freqGroup = ExtConfig->freqGroup;
	p->new_cbt_mode = ExtConfig->new_cbt_mode;

#if 0 // for Refs
DRAM_DFS_FREQUENCY_TABLE_T gFreqTbl[DRAM_DFS_SHUFFLE_MAX] = {
	{LP4_DDR3200 /*0*/, DIV8_MODE, SRAM_SHU1, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of term group (3733) must k first.
	{LP4_DDR4266 /*1*/, DIV8_MODE, SRAM_SHU0, DUTY_NEED_K,	VREF_CALI_ON,	CLOSE_LOOP_MODE},  // highest freq of term group (3733) must k first.
	{LP4_DDR800  /*2*/, DIV4_MODE, SRAM_SHU6, DUTY_DEFAULT, VREF_CALI_OFF,	SEMI_OPEN_LOOP_MODE},  //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
	{LP4_DDR1866 /*3*/, DIV8_MODE, SRAM_SHU3, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR1200 /*4*/, DIV8_MODE, SRAM_SHU5, DUTY_LAST_K,	VREF_CALI_OFF,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR2400 /*5*/, DIV8_MODE, SRAM_SHU2, DUTY_NEED_K,	VREF_CALI_ON,	CLOSE_LOOP_MODE},  // highest freq of unterm group (2400) must k first.
	{LP4_DDR1600 /*6*/, DIV8_MODE, SRAM_SHU4, DUTY_DEFAULT, VREF_CALI_ON,  CLOSE_LOOP_MODE},  //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
};
#endif
	if (u1IsLP4Family(p->dram_type))
	{
		if((ExtConfig->freq_sel==LP4_DDR3733) || (ExtConfig->freq_sel==LP4_DDR4266))
		{
			p->pDFSTable = &gFreqTbl[1];
		}
		else if(ExtConfig->freq_sel==LP4_DDR1600)
		{
			p->pDFSTable = &gFreqTbl[6];
		}
		else if(ExtConfig->freq_sel==LP4_DDR800)
		{
			p->pDFSTable = &gFreqTbl[2];
		}
		/*else if(ExtConfig->freq_sel==LP4_DDR400)
		{
			p->pDFSTable = &gFreqTbl[2];
		}*/
	}

	enter_function();

	if (!psra) {
		/*
		 * for SA's simulation
		 */
		msg("enter SA's simulation flow.\n");
		p->support_channel_num = CHANNEL_SINGLE;
		p->channel = CHANNEL_A;
		p->support_rank_num = RANK_DUAL;
		/* DramRank */
		p->rank = RANK_0;
		/* DRAMC operation clock frequency in MHz */
		#if (fcFOR_CHIP_ID == fcA60868)
		#if DV_SIMULATION_DFS
		p->pDFSTable = &gFreqTbl[DRAM_DFS_SHUFFLE_2];
		p->shu_type = DRAM_DFS_SHUFFLE_2;
		#endif
		#endif
#if 0
		/* DRAM type */
		#if DV_SIMULATION_LP4
		p->dram_type = TYPE_LPDDR4X;
		//p->freq_sel = LP4_DDR3200;//DV_SIMULATION_RUN_FREQ_SEL;
		//p->frequency = 1600;//DV_SIMULATION_RUN_FREQ;
		p->freq_sel = LP4_DDR1600;//DV_SIMULATION_RUN_FREQ_SEL;
		p->frequency = 800;//DV_SIMULATION_RUN_FREQ;
		#else
		p->dram_type = TYPE_LPDDR5;
		p->freq_sel = LP5_DDR3200;//DV_SIMULATION_RUN_FREQ_SEL;
		p->frequency = 1600;//DV_SIMULATION_RUN_FREQ;
		#endif
#endif
		/* DRAM Fast switch point type, only for LP4, useless in LP3 */
		p->dram_fsp = FSP_0;

#if 0
		#if DV_SIMULATION_BYTEMODE
		p->dram_cbt_mode[RANK_0] = CBT_BYTE_MODE1;
		p->dram_cbt_mode[RANK_1] = CBT_BYTE_MODE1;
		#else
		p->dram_cbt_mode[RANK_0] = CBT_NORMAL_MODE;
		p->dram_cbt_mode[RANK_1] = CBT_NORMAL_MODE;
		#endif
#endif
		/* IC and DRAM read DBI */
		p->DBI_R_onoff[FSP_0] = DBI_OFF; /* only for LP4, uesless in LP3 */
		p->DBI_R_onoff[FSP_1] = DBI_OFF; /* only for LP4, uesless in LP3 */
		#if ENABLE_READ_DBI
		p->DBI_R_onoff[FSP_1] = DBI_ON; /* only for LP4, uesless in LP3 */
		#else
		p->DBI_R_onoff[FSP_1] = DBI_OFF; /* only for LP4, uesless in LP3 */
		#endif
		/* IC and DRAM write DBI */
		p->DBI_W_onoff[FSP_0] = DBI_OFF; /* only for LP4, uesless in LP3 */
		p->DBI_W_onoff[FSP_1] = DBI_OFF; /* only for LP4, uesless in LP3 */
		#if ENABLE_WRITE_DBI
		p->DBI_W_onoff[FSP_1] = DBI_ON; /* only for LP4, uesless in LP3 */
		#else
		p->DBI_W_onoff[FSP_1] = DBI_OFF; /* only for LP4, uesless in LP3 */
		#endif
		/* bus width */
		p->data_width = DATA_WIDTH_16BIT;
		/* DRAMC internal test engine-2 parameters in calibration */
		p->test2_1 = DEFAULT_TEST2_1_CAL;
		p->test2_2 = DEFAULT_TEST2_2_CAL;
		/* DRAMC test pattern in calibration */
		p->test_pattern = TEST_XTALK_PATTERN;
		/* u2DelayCellTimex100 */
		p->u2DelayCellTimex100 = 250; // @Darren, 2.5ps
		p->vendor_id = 0x1;
		p->density = 0;
		/* p->ranksize = {0,0}; */
		p->ShuRGAccessIdx = DRAM_DFS_REG_SHU0;
		#if DV_SIMULATION_LP5_TRAINING_MODE1
		p->lp5_training_mode = TRAINING_MODE1;
		#else
		p->lp5_training_mode = TRAINING_MODE2;
		#endif

		#if DV_SIMULATION_LP5_CBT_PHASH_R
		p->lp5_cbt_phase = CBT_PHASE_RISING;
		#else
		p->lp5_cbt_phase = CBT_PHASE_FALLING;
		#endif
	} else {
		/*
		 * for DV's regression
		 */
		msg("enter DV's regression flow.\n");
		p->support_channel_num = CHANNEL_SINGLE;
		p->channel = psra->calibration_channel;
		p->support_rank_num = RANK_DUAL;
		/* DramRank */
		p->rank = psra->calibration_rank;
		/* DRAMC operation clock frequency in MHz */
		#if (fcFOR_CHIP_ID == fcA60868)
		#if DV_SIMULATION_DFS
		p->pDFSTable = &gFreqTbl[DRAM_DFS_SHUFFLE_2];
		p->shu_type = DRAM_DFS_SHUFFLE_2;
		#endif
		#endif

		/* DRAM type */
		//p->dram_type = psra->dram_type;
		//p->freq_sel = LP5_DDR4266;//DV_SIMULATION_RUN_FREQ_SEL;
		//p->frequency = 2133;//DV_SIMULATION_RUN_FREQ;
		//set_type_freq_by_svargs(p, psra);

		/* DRAM Fast switch point type, only for LP4, useless in LP3 */
		p->dram_fsp = FSP_0;

		p->dram_cbt_mode[RANK_0] = psra->rk0_cbt_mode;
		p->dram_cbt_mode[RANK_1] = psra->rk1_cbt_mode;

		/* IC and DRAM read DBI */
		p->DBI_R_onoff[FSP_0] = (psra->mr3_value >> 6) & 0x1; /* only for LP4, uesless in LP3 */
		p->DBI_R_onoff[FSP_1] = (psra->mr3_value >> 6) & 0x1; /* only for LP4, uesless in LP3 */
		p->DBI_R_onoff[FSP_2] = (psra->mr3_value >> 6) & 0x1;
		/* IC and DRAM write DBI */
		p->DBI_W_onoff[FSP_0] = (psra->mr3_value >> 7) & 0x1; /* only for LP4, uesless in LP3 */
		p->DBI_W_onoff[FSP_1] = (psra->mr3_value >> 7) & 0x1; /* only for LP4, uesless in LP3 */
		p->DBI_W_onoff[FSP_2] = (psra->mr3_value >> 7) & 0x1;
		/* bus width */
		p->data_width = DATA_WIDTH_16BIT;
		/* DRAMC internal test engine-2 parameters in calibration */
		p->test2_1 = DEFAULT_TEST2_1_CAL;
		p->test2_2 = DEFAULT_TEST2_2_CAL;
		/* DRAMC test pattern in calibration */
		p->test_pattern = TEST_XTALK_PATTERN;
		/* u2DelayCellTimex100 */
		p->u2DelayCellTimex100 = 0;
		p->vendor_id = 0x1;
		p->density = 0;
		/* p->ranksize = {0,0}; */
		p->ShuRGAccessIdx = DRAM_DFS_REG_SHU0;
		p->lp5_training_mode = psra->cbt_training_mode;
		p->lp5_cbt_phase = psra->cbt_phase;
		p->new_cbt_mode = psra->new_cbt_mode;
	}

#if QT_GUI_Tool
	p->lp5_training_mode = ExtConfig->lp5_training_mode;
#endif

	if (psra && is_lp5_family(p)) {
		p->dram_fsp = (psra->mr16_value >> 2) & 0x3;
	} else if (psra && u1IsLP4Family(p->dram_type)) {
		p->dram_fsp = (psra->mr13_value >> 7) & 0x1;
	}

//	  p->dram_type = TYPE_LPDDR5;
//	  #define __FW_VER__ "WCK leveling with DLY +16! and MRinit for FSP1 -- 777"
	#define __FW_VER__ "All struct move done, new RX range -- 444"

	if (u1IsLP4Family(p->dram_type)) {
		msg("%s enter == LP4 == ...%s\n", __FUNCTION__, __FW_VER__);
	} else {
		msg("%s enter == LP5 == ...%s\n", __FUNCTION__, __FW_VER__);
	}
	msg(CHK_INCLUDE_LOCAL_HEADER);

	msg("SIMULATION_LP4_ZQ			 ... %d\n", SIMULATION_LP4_ZQ);
	msg("SIMULATION_SW_IMPED		 ... %d\n", SIMULATION_SW_IMPED);
	msg("SIMULATION_MIOCK_JMETER	 ... %d\n", SIMULATION_MIOCK_JMETER);
	msg("SIMULATION_8PHASE			 ... %d\n", SIMULATION_8PHASE);
	msg("SIMULATION_RX_INPUT_BUF	 ... %d\n", SIMULATION_RX_INPUT_BUF);
	msg("SIMUILATION_CBT			 ... %d\n", SIMUILATION_CBT);
	msg("SIMULATION_WRITE_LEVELING	 ... %d\n", SIMULATION_WRITE_LEVELING);
	msg("SIMULATION_DUTY_CYC_MONITOR ... %d\n", SIMULATION_DUTY_CYC_MONITOR);
	msg("SIMULATION_GATING			 ... %d\n", SIMULATION_GATING);
	msg("SIMULATION_DATLAT			 ... %d\n", SIMULATION_DATLAT);
	msg("SIMULATION_RX_RDDQC		 ... %d\n", SIMULATION_RX_RDDQC);
	msg("SIMULATION_RX_PERBIT		 ... %d\n", SIMULATION_RX_PERBIT);
	msg("SIMULATION_TX_PERBIT		 ... %d\n", SIMULATION_TX_PERBIT);
	msg("\n\n");

	msg("============== CTX before calibration ================\n");
	dump_dramc_ctx(p);

	DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);

	//vIO32Write4B_All2(p, DDRPHY_SHU_RK_CA_CMD1, 0x0FFF);
	value = u4Dram_Register_Read(p, DRAMC_REG_DDRCOMMON0);
	msg("Get Addr:0x%x, Value:0x%x\n", DRAMC_REG_DDRCOMMON0, value);

	value = u4Dram_Register_Read(p, DDRPHY_REG_SHU_RK_CA_CMD1);
	msg("Get Addr:0x%x, Value:0x%x\n", DDRPHY_REG_SHU_RK_CA_CMD1, value);

	value = u4Dram_Register_Read(p, DDRPHY_REG_MISC_DQO1);
	msg("Get Addr:0x%x, Value:0x%x\n", DDRPHY_REG_MISC_DQO1, value);

	value = u4Dram_Register_Read(p, DDRPHY_MD32_REG_SSPM_TIMER0_RESET_VAL );
	msg("Get Addr:0x%x, Value:0x%x\n", DDRPHY_MD32_REG_SSPM_TIMER0_RESET_VAL, value);

	DramcBroadcastOnOff(DRAMC_BROADCAST_ON); //LP4 broadcast on

	Global_Option_Init(p);

#if __A60868_TO_BE_PORTING__
	vDramcInit_PreSettings(p);

	DDRPhyFreqSel(p, p->pDFSTable->freq_sel);

	vSetPHY2ChannelMapping(p, p->channel);
#endif // __A60868_TO_BE_PORTING__
	///TODO: wait for porting ---


	if (u1IsLP4Family(p->dram_type))
	{
		vSetDFSFreqSelByTable(p, p->pDFSTable); // for LP4x
	}
	else ///TODO: Jeremy, modify this when LP5 gFreqtbl ready
	{
		DDRPhyFreqSel(p, p->freq_sel);
	}

#if (SIMULATION_SW_IMPED == 1)
	msg("\n----->DramcSwImpedanceCal begin...\n");
	timestamp_show();
	// LP4 IMP_LOW_FREQ <= DDR3733, IMP_HIGH_FREQ >= DDR4266
	// LP5 IMP_LOW_FREQ <= DDR3733, IMP_HIGH_FREQ >= DDR4266
	DramcSwImpedanceCal(p, 1, IMP_LOW_FREQ);
	DramcSwImpedanceCal(p, 1, IMP_HIGH_FREQ);
	timestamp_show();
	msg("DramcSwImpedanceCal end<-----\n\n");
#endif /* (SIMULATION_SW_IMPED == 1) */

#if DV_SIMULATION_INIT_C
	///TODO: wait for porting +++
	DramcInit(p);

	// Before calibration setting
	vBeforeCalibration(p);
#if __A60868_TO_BE_PORTING__
	#if DV_SIMULATION_BEFORE_K
	vApplyConfigBeforeCalibration(p);
	//vMR2InitForSimulationTest(p);
	#endif

#ifdef DUMP_INIT_RG_LOG_TO_DE
	#if 0 //Dump RG to other shuffle for FT used, don't delete
		mcSHOW_DUMP_INIT_RG_MSG("\n\n\n\n\n\n===== Save to Shuffle RG ======\n");
		DramcSaveToShuffleReg(p, DRAM_DFS_SHUFFLE_1, DRAM_DFS_SHUFFLE_3);
	#endif
		while (1);
#endif
#endif
#endif // __A60868_TO_BE_PORTING__
	///TODO: wait for porting ---


#if (SIMULATION_MIOCK_JMETER == 1)
	msg("\n----->DramcMiockJmeter begin...\n");
	timestamp_show();
	PRE_MIOCK_JMETER_HQA_USED(p);
	timestamp_show();
	msg("DramcMiockJmeter end<-----\n\n");
#endif /* (SIMULATION_MIOCK_JMETER == 1) */

#if (SIMULATION_8PHASE == 1)
	if(is_lp5_family(p) && (p->frequency >= 2133)) {
		msg("\n----->Dramc8PhaseCal begin...\n");
		timestamp_show();
		Dramc8PhaseCal(p); // it must set before duty calib
		timestamp_show();
		msg("Dramc8PhaseCal end<-----\n\n");
	}
#endif /* (SIMULATION_8PHASE == 1) */

	///TODO: wait for porting +++
	#if !DV_SIMULATION_DFS // No calib will use legacy mode init settings
	DPI_vDramCalibrationAllChannel(p, psra); // for DDR1600 1:8 mode
	#endif

#if DV_SIMULATION_DFS
	DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, p->pDFSTable->shuffleIdx);
	LoadShuffleSRAMtoDramc(p, p->pDFSTable->shuffleIdx, DRAM_DFS_SHUFFLE_2); //Darren: DDR1600 for MRW (DramcModeRegInit_LP4 and CBT)
	#if ENABLE_SRAM_DMA_WA
	DPHYSaveToSRAMShuWA(p, p->pDFSTable->shuffleIdx);
	#endif

	#if (fcFOR_CHIP_ID == fcA60868)
	for (s1ShuIdx = DRAM_DFS_SHUFFLE_MAX - 10; s1ShuIdx >= DRAM_DFS_SHUFFLE_1; s1ShuIdx--)
	#else
	for (s1ShuIdx = DRAM_DFS_SHUFFLE_MAX - 2; s1ShuIdx >= DRAM_DFS_SHUFFLE_1; s1ShuIdx--)
	#endif
	{
		vSetDFSFreqSelByTable(p, &gFreqTbl[s1ShuIdx]);
		DramcInit(p);
		// Before calibration setting
		vBeforeCalibration(p);

		#if DV_SIMULATION_BEFORE_K
		vApplyConfigBeforeCalibration(p);
		#endif

		#if (SIMULATION_8PHASE == 1)
		if(is_lp5_family(p) && (p->frequency >= 2133)) {
			msg("\n----->Dramc8PhaseCal begin...\n");
			timestamp_show();
			Dramc8PhaseCal(p); // it must set before duty calib
			timestamp_show();
			msg("Dramc8PhaseCal end<-----\n\n");
		}
		#endif /* (SIMULATION_8PHASE == 1) */

		#if !DV_SIMULATION_DFS // No calib will use legacy mode init settings
		DPI_vDramCalibrationAllChannel(p, psra); // for gDVDFSTbl
		#endif
		DramcSaveToShuffleSRAM(p, DRAM_DFS_SHUFFLE_1, gFreqTbl[s1ShuIdx].shuffleIdx);
		#if ENABLE_SRAM_DMA_WA
		DPHYSaveToSRAMShuWA(p, gFreqTbl[s1ShuIdx].shuffleIdx);
		#endif
	}
#endif
	///TODO: wait for porting ---




	///TODO: wait for porting +++
	vAfterCalibration(p);

#if SIMULATION_RUNTIME_CONFIG
	DramcRunTimeConfig(p);
#endif

#if __A60868_TO_BE_PORTING__
#if DV_SIMULATION_AFTER_K
	vApplyConfigAfterCalibration(p);
#endif

#if DV_SIMULATION_RUN_TIME_MRW
	enter_pasr_dpd_config(0, 0xFF);
#endif

#if DV_SIMULATION_RUN_TIME_MRR
	DramcModeRegReadByRank(p, RANK_0, 4, &u2val1);
	DramcModeRegReadByRank(p, RANK_0, 5, &u2val2);
	DramcModeRegReadByRank(p, RANK_0, 8, &u2val3);
	msg("[Runtime time MRR] MR4 = 0x%x, MR5 = 0x%x, MR8 = 0x%x\n", u2val1, u2val2, u2val3);
#endif

#if 0//DV_SIMULATION_DFS // NOTE: Don't use DramcDFSDirectJump_SPMMode. it will cause NULL object access.
	// high freq -> low freq
	for (s1ShuIdx = 0; s1ShuIdx < DV_SIMULATION_DFS_SHU_MAX; s1ShuIdx++)
			DramcDFSDirectJump_SRAMShuRGMode(p, gDVDFSTbl[s1ShuIdx].shuffleIdx);
	// low freq -> high freq
	for (s1ShuIdx = DV_SIMULATION_DFS_SHU_MAX - 1; s1ShuIdx >= DRAM_DFS_SHUFFLE_1; s1ShuIdx--)
			DramcDFSDirectJump_SRAMShuRGMode(p, gDVDFSTbl[s1ShuIdx].shuffleIdx);
#endif

#if DV_SIMULATION_SPM_CONTROL
	EnablePLLtoSPMControl(p);
#endif

	RG_dummy_write(p, 0xAAAAAAAA);
#endif // __A60868_TO_BE_PORTING__
	///TODO: wait for porting ---

	//Temp_TA2_Test_After_K(p);

	//Ett_Mini_Strss_Test(p);
#if MRW_CHECK_ONLY
	vPrintFinalModeRegisterSetting(p);
#endif
#if PRINT_CALIBRATION_SUMMARY
	vPrintCalibrationResult(p);
#endif

	exit_function();
}

///TODO: wait for porting +++
#if __A60868_TO_BE_PORTING__
#if SW_CHANGE_FOR_SIMULATION
void main(void)
{

	DRAMC_CTX_T DramConfig;
	DramConfig.channel = CHANNEL_A;
	DramConfig.support_rank_num = RANK_DUAL;
	// DramRank
	DramConfig.rank = RANK_0;
	// DRAM type
	DramConfig.dram_type = TYPE_LPDDR4X;
	// DRAM Fast switch point type, only for LP4, useless in LP3
	DramConfig.dram_fsp = FSP_0;
	// DRAM CBT mode, only for LP4, useless in LP3
	DramConfig.dram_cbt_mode[RANK_0] = CBT_NORMAL_MODE;
	DramConfig.dram_cbt_mode[RANK_1] = CBT_NORMAL_MODE;
	// IC and DRAM read DBI
	DramConfig.DBI_R_onoff[FSP_0] = DBI_OFF;			 // only for LP4, uesless in LP3
	#if ENABLE_READ_DBI
	DramConfig.DBI_R_onoff[FSP_1] = DBI_ON; 			 // only for LP4, uesless in LP3
	#else
	DramConfig.DBI_R_onoff[FSP_1] = DBI_OFF;		// only for LP4, uesless in LP3
	#endif
	// IC and DRAM write DBI
	DramConfig.DBI_W_onoff[FSP_0] = DBI_OFF;			 // only for LP4, uesless in LP3
	#if ENABLE_WRITE_DBI
	DramConfig.DBI_W_onoff[FSP_1] = DBI_ON; 			 // only for LP4, uesless in LP3
	#else
	DramConfig.DBI_W_onoff[FSP_1] = DBI_OFF;		 // only for LP4, uesless in LP3
	#endif
	// bus width
	DramConfig.data_width = DATA_WIDTH_32BIT;
	// DRAMC internal test engine-2 parameters in calibration
	DramConfig.test2_1 = DEFAULT_TEST2_1_CAL;
	DramConfig.test2_2 = DEFAULT_TEST2_2_CAL;
	// DRAMC test pattern in calibration
	DramConfig.test_pattern = TEST_XTALK_PATTERN;
	// DRAMC operation clock frequency in MHz
	DramConfig.frequency = 800;

	//DramConfig.enable_rx_scan_vref =DISABLE;
	//DramConfig.enable_tx_scan_vref =DISABLE;
	//DramConfig.dynamicODT = DISABLE;

	MPLLInit();

	Global_Option_Init(&DramConfig);

	// DramC & PHY init for all channels
	DDRPhyFreqSel(&DramConfig, LP4_DDR1600);


#if WRITE_LEVELING_MOVE_DQS_INSTEAD_OF_CLK
	memset(DramConfig.arfgWriteLevelingInitShif, FALSE, sizeof(DramConfig.arfgWriteLevelingInitShif));
	//>fgWriteLevelingInitShif= FALSE;
#endif

	DramcInit(&DramConfig);

	vApplyConfigBeforeCalibration(&DramConfig);
	vMR2InitForSimulationTest(&DramConfig);

	vSetPHY2ChannelMapping(&DramConfig, DramConfig.channel);

	#if SIMULATION_SW_IMPED
	DramcSwImpedanceCal(&DramConfig, 1, LOW_FREQ);	//for DRVN/P and ODTN
	//DramcSwImpedanceCal(&DramConfig, 1, HIGH_FREQ);  //for DRVN/P and ODTN
	#endif


#if SIMULATION_LP4_ZQ
	 if (DramConfig.dram_type == TYPE_LPDDR4 || DramConfig.dram_type == TYPE_LPDDR4X || DramConfig.dram_type == TYPE_LPDDR4P)
	 {
		 DramcZQCalibration(&DramConfig);
	 }
#endif

	#if SIMUILATION_LP4_CBT
	CmdBusTrainingLP4(&DramConfig);
	#endif

#if SIMULATION_WRITE_LEVELING
	DramcWriteLeveling(&DramConfig);
#endif

	#if SIMULATION_GATING
	// Gating calibration of single rank
	DramcRxdqsGatingCal(&DramConfig);

	// Gating calibration of both rank
	//DualRankDramcRxdqsGatingCal(&DramConfig);
	#endif

#if SIMUILATION_LP4_RDDQC
	DramcRxWindowPerbitCal(&DramConfig, 0, NULL);
#endif

	#if SIMULATION_DATLAT
	// RX Datlat calibration of single rank
	DramcRxdatlatCal(&DramConfig);

	// RX Datlat calibration of two rank
	//DramcDualRankRxdatlatCal(&DramConfig);
	#endif

	#if SIMULATION_RX_PERBIT
	DramcRxWindowPerbitCal(&DramConfig, 1, NULL);
	#endif

	#if SIMULATION_TX_PERBIT
	DramcTxWindowPerbitCal(&DramConfig, TX_DQ_DQS_MOVE_DQ_DQM);
	DramcTxWindowPerbitCal(&DramConfig, TX_DQ_DQS_MOVE_DQ_ONLY);
	#endif

	#if ENABLE_READ_DBI
	//Read DBI ON
	SetDramModeRegForReadDBIOnOff(&DramConfig, DramConfig.dram_fsp, DramConfig.DBI_R_onoff[DramConfig.dram_fsp]);
	#endif

	#if ENABLE_WRITE_DBI
	//Write DBI ON
	DramcWriteShiftMCKForWriteDBI(&DramConfig, -1);
	SetDramModeRegForWriteDBIOnOff(&DramConfig, DramConfig.dram_fsp, DramConfig.DBI_W_onoff[DramConfig.dram_fsp]);
	#endif

	#if ENABLE_READ_DBI
	DramcReadDBIOnOff(&DramConfig, DramConfig.DBI_R_onoff[DramConfig.dram_fsp]);
	#endif

	#if ENABLE_WRITE_DBI
	DramcWriteDBIOnOff(&DramConfig, DramConfig.DBI_W_onoff[DramConfig.dram_fsp]);
	#endif
}
#endif //SW_CHANGE_FOR_SIMULATION
#endif // __A60868_TO_BE_PORTING__
///TODO: wait for porting ---
