blob: 15407700723cf28d938fb127d6f20c6d56b2ec29 [file] [log] [blame]
/* SPDX-License-Identifier: BSD-3-Clause */
//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include "dramc_common.h"
#include "dramc_int_global.h"
#include "x_hal_io.h"
#include "sv_c_data_traffic.h"
#define BITMAP_BITS_MAX 128
#if CBT_MOVE_CA_INSTEAD_OF_CLK
#define MAX_CA_PI_DELAY 95
#else
#define MAX_CA_PI_DELAY 63
#endif
#define MAX_CS_PI_DELAY 63
#define MAX_CLK_PI_DELAY 31
#define PASS_RANGE_NA 0x7fff
#define DIE_NUM_MAX 1 //LP4 only
static U8 fgwrlevel_done = 0;
#if __ETT__
U8 gETT_WHILE_1_flag = 1;
#endif
U8 u1MR01Value[FSP_MAX];
U8 u1MR02Value[FSP_MAX];
U8 u1MR03Value[FSP_MAX];
U8 u1MR11Value[FSP_MAX];
U8 u1MR18Value[FSP_MAX];
U8 u1MR19Value[FSP_MAX];
U8 u1MR20Value[FSP_MAX];
U8 u1MR21Value[FSP_MAX];
U8 u1MR22Value[FSP_MAX];
U8 u1MR51Value[FSP_MAX];
U8 u1MR04Value[RANK_MAX];
U8 u1MR13Value[RANK_MAX];
U8 u1MR26Value[RANK_MAX];
U8 u1MR30Value[RANK_MAX];
U8 u1MR12Value[CHANNEL_NUM][RANK_MAX][FSP_MAX];
U8 u1MR14Value[CHANNEL_NUM][RANK_MAX][FSP_MAX];
U16 gu2MR0_Value[RANK_MAX] = {0xffff, 0xffff};
#if PINMUX_AUTO_TEST_PER_BIT_RX
S16 gFinalRXPerbitFirstPass[CHANNEL_NUM][DQ_DATA_WIDTH];
#endif
#if PINMUX_AUTO_TEST_PER_BIT_TX
S16 gFinalTXPerbitFirstPass[CHANNEL_NUM][DQ_DATA_WIDTH];
#endif
#if PINMUX_AUTO_TEST_PER_BIT_CA
S16 gFinalCAPerbitFirstPass[CHANNEL_NUM][RANK_MAX][CATRAINING_NUM_LP4];
#endif
#ifdef FOR_HQA_TEST_USED
U16 gFinalCBTVrefCA[CHANNEL_NUM][RANK_MAX];
U16 gFinalCBTCA[CHANNEL_NUM][RANK_MAX][10];
U16 gFinalRXPerbitWin[CHANNEL_NUM][RANK_MAX][DQ_DATA_WIDTH];
U16 gFinalTXPerbitWin[CHANNEL_NUM][RANK_MAX][DQ_DATA_WIDTH];
U16 gFinalTXPerbitWin_min_max[CHANNEL_NUM][RANK_MAX];
U16 gFinalTXPerbitWin_min_margin[CHANNEL_NUM][RANK_MAX];
U16 gFinalTXPerbitWin_min_margin_bit[CHANNEL_NUM][RANK_MAX];
S8 gFinalClkDuty[CHANNEL_NUM];
U32 gFinalClkDutyMinMax[CHANNEL_NUM][2];
S8 gFinalDQSDuty[CHANNEL_NUM][DQS_NUMBER];
U32 gFinalDQSDutyMinMax[CHANNEL_NUM][DQS_NUMBER][2];
#endif
U8 gFinalCBTVrefDQ[CHANNEL_NUM][RANK_MAX];
U8 gFinalRXVrefDQ[CHANNEL_NUM][RANK_MAX][2];
U8 gFinalTXVrefDQ[CHANNEL_NUM][RANK_MAX];
#if defined(RELEASE)
U8 gEye_Scan_color_flag = 0;
U8 gCBT_EYE_Scan_flag = 0;
U8 gCBT_EYE_Scan_only_higheset_freq_flag = 1;
U8 gRX_EYE_Scan_flag = 0;
U8 gRX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gTX_EYE_Scan_flag = 1;
U8 gTX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gEye_Scan_unterm_highest_flag = 0;
#elif (CFG_DRAM_LOG_TO_STORAGE)
U8 gEye_Scan_color_flag = 0;
U8 gCBT_EYE_Scan_flag = 0;
U8 gCBT_EYE_Scan_only_higheset_freq_flag = 1;
U8 gRX_EYE_Scan_flag = 1;
U8 gRX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gTX_EYE_Scan_flag = 1;
U8 gTX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gEye_Scan_unterm_highest_flag = 0;
#else
U8 gEye_Scan_color_flag = 1;
U8 gCBT_EYE_Scan_flag = 0;
U8 gCBT_EYE_Scan_only_higheset_freq_flag = 1;
U8 gRX_EYE_Scan_flag = 0;
U8 gRX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gTX_EYE_Scan_flag = 0;
U8 gTX_EYE_Scan_only_higheset_freq_flag = 1;
U8 gEye_Scan_unterm_highest_flag = 0;
#endif
#ifdef FOR_HQA_REPORT_USED
#if CFG_DRAM_LOG_TO_STORAGE
U8 gHQALog_flag = 1;
#else
U8 gHQALog_flag = 0;
#endif
U16 gHQALOG_RX_delay_cell_ps_075V = 0;
#endif
#if (TX_AUTO_K_ENABLE && TX_AUTO_K_WORKAROUND)
U32 u4DQM_MCK_RK1_backup;
U32 u4DQM_UI_RK1_backup;
U32 u4DQM_PI_RK1_backup[2];
U32 u4DQ_MCK_RK1_backup;
U32 u4DQ_UI_RK1_backup;
U32 u4DQ_PI_RK1_backup[2];
#endif
#if SIMULATION_RX_DVS
U8 u1DVS_increase[RANK_MAX][DQS_NUMBER_LP4];
#endif
static S32 CATrain_CmdDelay[CHANNEL_NUM][RANK_MAX];
static U32 CATrain_CsDelay[CHANNEL_NUM][RANK_MAX];
static S32 wrlevel_dqs_final_delay[RANK_MAX][DQS_NUMBER]; // 3 is channel number
static U16 u2g_num_dlycell_perT = 49;
U16 u2gdelay_cell_ps;
U16 u2g_num_dlycell_perT_all[DRAM_DFS_SHUFFLE_MAX][CHANNEL_NUM];///TODO: to be removed by Francis
U16 u2gdelay_cell_ps_all[DRAM_DFS_SHUFFLE_MAX][CHANNEL_NUM];///TODO: to be removed by Francis
U32 u4gVcore[DRAM_DFS_SHUFFLE_MAX];
U8 gFinalRXVrefDQForSpeedUp[CHANNEL_NUM][RANK_MAX][2/*ODT_onoff*/][2/*2bytes*/] = {0};
U32 gDramcSwImpedanceResult[IMP_VREF_MAX][IMP_DRV_MAX] = {{0,0,0,0},{0,0,0,0},{0,0,0,0}};//ODT_ON/OFF x DRVP/DRVN/ODTP/ODTN
S16 gu2RX_DQS_Duty_Offset[DQS_NUMBER][2];
#define RX_DELAY_PRE_CAL 1
#if RX_DELAY_PRE_CAL
S16 s2RxDelayPreCal=PASS_RANGE_NA;
#endif
#if MRW_CHECK_ONLY
U16 u2MRRecord[CHANNEL_NUM][RANK_MAX][FSP_MAX][MR_NUM];
#endif
#if MRW_CHECK_ONLY || MRW_BACKUP
U8 gFSPWR_Flag[RANK_MAX]={FSP_0};
#endif
#define IN_CBT (0)
#define OUT_CBT (1)
#if PRINT_CALIBRATION_SUMMARY
static void vSetCalibrationResult(DRAMC_CTX_T *p, U8 ucCalType, U8 ucResult)
{
U32 *Pointer_CalExecute,*Pointer_CalResult;
if (ucCalType == DRAM_CALIBRATION_SW_IMPEDANCE)
{
Pointer_CalExecute = &p->SWImpCalExecute;
Pointer_CalResult = &p->SWImpCalResult;
}
else
{
Pointer_CalExecute = &p->aru4CalExecuteFlag[p->channel][p->rank];
Pointer_CalResult = &p->aru4CalResultFlag[p->channel][p->rank];
}
if (ucResult == DRAM_FAIL) // Calibration FAIL
{
*Pointer_CalExecute |= (1<<ucCalType); // ececution done
*Pointer_CalResult |= (1<<ucCalType); // no result found
}
else if(ucResult == DRAM_OK) // Calibration OK
{
*Pointer_CalExecute |= (1<<ucCalType); // ececution done
*Pointer_CalResult &= (~(1<<ucCalType)); // result found
}
else if(ucResult == DRAM_FAST_K) // FAST K
{
*Pointer_CalExecute &= (~(1<<ucCalType)); // no ececution
*Pointer_CalResult &= (~(1<<ucCalType)); // result found
}
else // NO K
{
*Pointer_CalExecute &= (~(1<<ucCalType)); // no ececution
*Pointer_CalResult |= (1<<ucCalType); // no result found
}
}
#if PRINT_CALIBRATION_SUMMARY_FASTK_CHECK
void Fast_K_CheckResult(DRAMC_CTX_T *p, U8 ucCalType)
{
U32 CheckResult=0xFFFFFFFF;
U32 debug_cnt[2], u4all_result_R, u4all_result_F;
BOOL FastK_Check_flag=0;
U32 *Pointer_FastKExecute,*Pointer_FastKResult;
Pointer_FastKExecute = &p->FastKExecuteFlag[p->channel][p->rank];
Pointer_FastKResult = &p->FastKResultFlag[p->channel][p->rank];
if ((ucCalType==DRAM_CALIBRATION_TX_PERBIT)||(ucCalType==DRAM_CALIBRATION_DATLAT)||(ucCalType==DRAM_CALIBRATION_RX_PERBIT))
{
DramcEngine2Init(p, p->test2_1, p->test2_2, TEST_XTALK_PATTERN, 0, TE_NO_UI_SHIFT);
CheckResult = DramcEngine2Run(p,TE_OP_WRITE_READ_CHECK , TEST_XTALK_PATTERN);
DramcEngine2End(p);
FastK_Check_flag=1;
}
else if (ucCalType==DRAM_CALIBRATION_RX_RDDQC)
{
DramcRxWinRDDQCInit(p);
CheckResult = DramcRxWinRDDQCRun(p);
DramcRxWinRDDQCEnd(p);
FastK_Check_flag=1;
}
else if (ucCalType==DRAM_CALIBRATION_GATING)
{
DramcEngine2Init(p, 0x55000000, 0xaa000000 |0x23, TEST_AUDIO_PATTERN, 0, TE_NO_UI_SHIFT);
//Gating Counter Reset
DramPhyReset(p);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
MISC_STBCAL2_DQSG_CNT_RST);
mcDELAY_US(1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 0,
MISC_STBCAL2_DQSG_CNT_RST);
DramcEngine2Run(p, TE_OP_READ_CHECK, TEST_AUDIO_PATTERN);
debug_cnt[0] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_CAL_DQSG_CNT_B0));
debug_cnt[1] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_CAL_DQSG_CNT_B1));
//mcSHOW_DBG_MSG((" 0x%X ",u4DebugCnt))
if (debug_cnt[0]==0x4646 && debug_cnt[1]==0x4646)
CheckResult=0;
DramcEngine2End(p);
FastK_Check_flag=1;
}
if ((FastK_Check_flag==1)&&(CheckResult==0))
{
//mcSHOW_DBG_MSG((" [FAST K CHECK]->PASS\n"))
*Pointer_FastKResult &= (~(1<<ucCalType)); // result PASS
*Pointer_FastKExecute |= (1<<ucCalType);; // Excuted
}
else if ((FastK_Check_flag==1)&&(CheckResult !=0))
{
//mcSHOW_DBG_MSG((" [FAST K CHECK]->FAIL\n"))
*Pointer_FastKResult |= (1<<ucCalType); // result FAIL
*Pointer_FastKExecute |= (1<<ucCalType);; // Excuted
}
}
#endif
const char *szCalibStatusName[DRAM_CALIBRATION_MAX]=
{
"SW Impedance ",
"DUTY Scan ",
"ZQ Calibration ",
"Jitter Meter ",
"CBT Training ",
"Write leveling ",
"RX DQS gating ",
"RX DQ/DQS(RDDQC) ",
"TX DQ/DQS ",
"RX DATLAT ",
"RX DQ/DQS(Engine)",
"TX OE ",
};
void vPrintCalibrationResult(DRAMC_CTX_T *p)
{
U8 ucCHIdx, ucRankIdx, ucCalIdx;
U32 ucCalResult_All, ucCalExecute_All;
U8 ucCalResult, ucCalExecute;
U8 u1CalibrationFail;
mcSHOW_DBG_MSG(("\n\n[Calibration Summary] %d Mbps\n", p->frequency * 2));
//for(ucFreqIdx=0; ucFreqIdx<DRAM_DFS_SHUFFLE_MAX; ucFreqIdx++)
{
//mcSHOW_DBG_MSG(("==Freqency = %d==\n", get_FreqTbl_by_shuffleIndex(p,ucFreqIdx)->frequency));
for(ucCHIdx=0; ucCHIdx<p->support_channel_num; ucCHIdx++)
{
for(ucRankIdx=0; ucRankIdx<p->support_rank_num; ucRankIdx++)
{
u1CalibrationFail =0;
ucCalExecute_All = p->aru4CalExecuteFlag[ucCHIdx][ucRankIdx];
ucCalResult_All = p->aru4CalResultFlag[ucCHIdx][ucRankIdx];
mcSHOW_DBG_MSG(("CH %d, Rank %d\n", ucCHIdx, ucRankIdx));
//mcSHOW_DBG_MSG(("[vPrintCalibrationResult] Channel = %d, Rank= %d, Freq.= %d, (ucCalExecute_All 0x%x, ucCalResult_All 0x%x)\n", ucCHIdx, ucRankIdx, ucFreqIdx, ucCalExecute_All, ucCalResult_All));
for(ucCalIdx =0; ucCalIdx<DRAM_CALIBRATION_MAX; ucCalIdx++)
{
if(ucCalIdx==0)
{
ucCalExecute = (U8)p->SWImpCalExecute; //for SW Impedence
ucCalResult = (U8)p->SWImpCalResult; //for SW Impedence
}
else
{
ucCalExecute = (U8)((ucCalExecute_All >>ucCalIdx) & 0x1);
ucCalResult = (U8)((ucCalResult_All >>ucCalIdx) & 0x1);
}
#if PRINT_CALIBRATION_SUMMARY_DETAIL
mcSHOW_DBG_MSG(("%s: ", szCalibStatusName[ucCalIdx]))
if(ucCalExecute==1 && ucCalResult ==1) // excuted and fail
{
u1CalibrationFail =1;
mcSHOW_DBG_MSG(("%s\n", "@_@FAIL@_@"))
}
else if (ucCalExecute==1 && ucCalResult ==0) // DRAM_OK
{
mcSHOW_DBG_MSG(("%s\n", "PASS"))
}
else if (ucCalExecute==0 && ucCalResult ==0) // DRAM_FAST K
{
mcSHOW_DBG_MSG(("%s\n", "FAST K"))
}
else //DRAM_NO K
{
mcSHOW_DBG_MSG(("%s\n", "NO K"))
}
#else
if(ucCalExecute==1 && ucCalResult ==1) // excuted and fail
{
u1CalibrationFail =1;
mcSHOW_DBG_MSG(("%s: %s\n", szCalibStatusName[ucCalIdx],"@_@FAIL@_@"))
}
#endif
}
if(u1CalibrationFail ==0)
{
mcSHOW_DBG_MSG(("All Pass.\n"));
}
mcSHOW_DBG_MSG(("\n"));
}
}
}
}
#endif
#if __FLASH_TOOL_DA__
#define CA_THRESHOLD 20
#define RX_THRESHOLD 150
#define TX_THRESHOLD 20
#define PERCENTAGE_THRESHOLD 50
#define PRINT_WIN_SIZE 0
U8* print_Impedence_LOG_type(U8 print_type)
{
switch (print_type)
{
case 0: return "DRVP";
case 1: return "DRVN";
case 2: return "ODTP";
case 3: return "ODTN";
default: return "ERROR";
}
}
void vPrintPinInfoResult(DRAMC_CTX_T *p)
{
U8 u1CHIdx, u1RankIdx, u1CAIdx, u1ByteIdx, u1ByteIdx_DQ, u1BitIdx, u1BitIdx_DQ, u1FreqRegionIdx, u1ImpIdx;
U8 u1PinError=0;
mcSHOW_DBG_MSG(("\n\n[Pin Info Summary] Freqency %d\n", p->frequency));
for (u1FreqRegionIdx=0;u1FreqRegionIdx<2/*IMP_VREF_MAX*/;u1FreqRegionIdx++)
{
for (u1ImpIdx=0;u1ImpIdx<IMP_DRV_MAX;u1ImpIdx++)
{
mcSHOW_DBG_MSG(("IMP %s type:%s %s\n", u1FreqRegionIdx?"Region1":"Region0", print_Impedence_LOG_type(u1ImpIdx), ((PINInfo_flashtool.IMP_ERR_FLAG>>(u1FreqRegionIdx*4+u1ImpIdx)&0x1)?"ERROR":"PASS")));
}
}
{
for(u1CHIdx=0; u1CHIdx<p->support_channel_num; u1CHIdx++)
{
for(u1RankIdx=0; u1RankIdx<p->support_rank_num; u1RankIdx++)
{
mcSHOW_DBG_MSG(("CH %d, Rank %d\n", u1CHIdx, u1RankIdx));
for (u1CAIdx =0; u1CAIdx <CATRAINING_NUM_LP4; u1CAIdx++)
{
#if 1//Transfer to Percentage
PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]= (PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]* 100 + 63) /64;
if ((PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]==0)||(PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]<=PERCENTAGE_THRESHOLD))
#else
if ((PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]==0)||(PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx]<=CA_THRESHOLD))
#endif
{
PINInfo_flashtool.CA_ERR_FLAG[u1CHIdx][u1RankIdx] |= (1<<u1CAIdx);
PINInfo_flashtool.TOTAL_ERR |= (0x1<<(u1CHIdx*4+u1RankIdx*2));
}
mcSHOW_DBG_MSG(("CA %d: %s ", u1CAIdx, ((PINInfo_flashtool.CA_ERR_FLAG[u1CHIdx][u1RankIdx]>>u1CAIdx)&0x1)?"ERROR":"PASS"));
#if PRINT_WIN_SIZE
mcSHOW_DBG_MSG(("(WIN_SIZE: %d %% )", (PINInfo_flashtool.CA_WIN_SIZE[u1CHIdx][u1RankIdx][u1CAIdx])));
#endif
mcSHOW_DBG_MSG(("\n"));
}
for (u1BitIdx =0; u1BitIdx <DQ_DATA_WIDTH_LP4; u1BitIdx++)
{
u1ByteIdx = (u1BitIdx>=8?1:0);
u1BitIdx_DQ = uiLPDDR4_O1_Mapping_POP[p->channel][u1BitIdx];
u1ByteIdx_DQ = (u1BitIdx_DQ>=8?1:0);
#if 1//Transfer to Percentage
PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx] = ((PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]* gHQALOG_RX_delay_cell_ps_075V * p->frequency * 2)+ (1000000 - 1)) / 1000000;
if (PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=PERCENTAGE_THRESHOLD)
#else
if ((PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]==0)||(PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=RX_THRESHOLD)\
||(PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]==0)||(PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=TX_THRESHOLD))
#endif
{
PINInfo_flashtool.DQ_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] |= (1<<(u1BitIdx-(u1ByteIdx==1?8:0)));
PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx_DQ] |= (1<<(u1BitIdx_DQ-(u1ByteIdx_DQ==1?8:0)));
PINInfo_flashtool.TOTAL_ERR |= (0x1<<(u1CHIdx*4+u1RankIdx*2+1));
}
#if 1//Transfer to Percentage
PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx] = (PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]* 100+ (vGet_DDR_Loop_Mode(p) == DDR800_CLOSE_LOOP? 63: 31)) / (vGet_DDR_Loop_Mode(p) == DDR800_CLOSE_LOOP? 64: 32);
if (PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=PERCENTAGE_THRESHOLD)
#else
if ((PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]==0)||(PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=RX_THRESHOLD)\
||(PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]==0)||(PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][u1BitIdx]<=TX_THRESHOLD))
#endif
{
PINInfo_flashtool.DQ_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] |= (1<<(u1BitIdx-(u1ByteIdx==1?8:0)));
PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx_DQ] |= (1<<(u1BitIdx_DQ-(u1ByteIdx_DQ==1?8:0)));
PINInfo_flashtool.TOTAL_ERR |= (0x1<<(u1CHIdx*4+u1RankIdx*2+1));
}
}
for (u1BitIdx_DQ=0; u1BitIdx_DQ<DQ_DATA_WIDTH_LP4; u1BitIdx_DQ++)
{
u1ByteIdx_DQ = (u1BitIdx_DQ>=8?1:0);
mcSHOW_DBG_MSG(("DRAM DQ %d: RX %s, TX %s ", u1BitIdx_DQ, (((PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx_DQ]>>(u1BitIdx_DQ-(u1ByteIdx_DQ==1?8:0)))&0x1)?"ERROR":"PASS"),\
(((PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx_DQ]>>(u1BitIdx_DQ-(u1ByteIdx_DQ==1?8:0)))&0x1)?"ERROR":"PASS")));
#if PRINT_WIN_SIZE
mcSHOW_DBG_MSG(("(RX WIN SIZE: %d %%, TX WIN SIZE: %d %% )", PINInfo_flashtool.DQ_RX_WIN_SIZE[u1CHIdx][u1RankIdx][uiLPDDR4_O1_Mapping_POP[u1CHIdx][u1BitIdx_DQ]], PINInfo_flashtool.DQ_TX_WIN_SIZE[u1CHIdx][u1RankIdx][uiLPDDR4_O1_Mapping_POP[u1CHIdx][u1BitIdx_DQ]]));
#endif
mcSHOW_DBG_MSG(("\n"));
}
}
}
}
}
void vGetErrorTypeResult(DRAMC_CTX_T *p)
{
U8 u1CHIdx, u1CHIdx_EMI, u1RankIdx, u1CAIdx, u1ByteIdx, u1BitIdx, u1FreqRegionIdx, u1ImpIdx;
mcSHOW_DBG_MSG(("\n[Get Pin Error Type Result]\n"));
if (PINInfo_flashtool.TOTAL_ERR==0 && PINInfo_flashtool.IMP_ERR_FLAG==0)//ALL PASS
{
mcSHOW_DBG_MSG(("ALL PASS\n"));
}
if (PINInfo_flashtool.IMP_ERR_FLAG)
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: Impedance calibration fail\n"));
mcSHOW_DBG_MSG(("Suspect EXTR contact issue\n"));
mcSHOW_DBG_MSG(("Suspect EXTR related resistor contact issue\n"));
}
if ((PINInfo_flashtool.TOTAL_ERR == 0xffff) && (PINInfo_flashtool.WL_ERR_FLAG== 0xff))
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: ALL calibration fail\n"));
mcSHOW_DBG_MSG(("Suspect RESET_N contact issue\n"));
mcSHOW_DBG_MSG(("Suspect DRAM Power (VDD1/VDD2/VDDQ) contact issue\n"));
}
else
{
for (u1CHIdx = 0; u1CHIdx < p->support_channel_num; u1CHIdx++)
{
#if (CHANNEL_NUM > 2)
if(u1CHIdx == CHANNEL_B)
u1CHIdx_EMI = CHANNEL_C;
else if(u1CHIdx == CHANNEL_C)
u1CHIdx_EMI = CHANNEL_B;
else //CHANNEL_A,CHANNEL_D
#endif
u1CHIdx_EMI = u1CHIdx;
if ((PINInfo_flashtool.TOTAL_ERR>>(u1CHIdx*4) & 0xf) == 0xf)
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: CH%d all calibration fail\n",u1CHIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_CK_T contact issue\n",u1CHIdx_EMI));
mcSHOW_DBG_MSG(("Suspect EMI%d_CK_C contact issue\n",u1CHIdx_EMI));
for (u1CAIdx =0; u1CAIdx <CATRAINING_NUM_LP4; u1CAIdx++)
{
mcSHOW_DBG_MSG(("Suspect EMI%d_CA%d contact issue\n",u1CHIdx_EMI,u1CAIdx));
}
}
else
{
for(u1RankIdx = 0; u1RankIdx < p->support_rank_num; u1RankIdx++)
{
if ((((PINInfo_flashtool.TOTAL_ERR>>(u1CHIdx*4+u1RankIdx*2)) & 0x3)==0x3) && \
(PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][BYTE_0] == 0xff) && \
(PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][BYTE_1] == 0xff)&& \
(PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][BYTE_0] == 0xff) && \
(PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][BYTE_1] == 0xff))
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: CH%d RK%d all calibration fail\n",u1CHIdx,u1RankIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_CKE_%d contact issue\n",u1CHIdx_EMI,u1RankIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_CS_%d contact issue\n",u1CHIdx_EMI,u1RankIdx));
}
else
{
for (u1ByteIdx = 0; u1ByteIdx < DQS_NUMBER_LP4; u1ByteIdx++)
{
if((PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] == 0xff) &&\
(PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] == 0xff))
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: CH%d RK%d Byte%d WL/Read/Write calibration fail\n",u1CHIdx,u1RankIdx,u1ByteIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_DQS%d_T contact issue\n",u1CHIdx_EMI,u1ByteIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_DQS%d_C contact issue\n",u1CHIdx_EMI,u1ByteIdx));
}
else if (PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx]&&\
PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx])
{
for (u1BitIdx = 0; u1BitIdx < DQS_BIT_NUMBER; u1BitIdx++)
{
if (((PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx]>>u1BitIdx)&0x1)&&\
((PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx]>>u1BitIdx)&0x1))
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: CH%d RK%d DRAM DQ%d Read/Write fail\n",u1CHIdx,u1RankIdx,u1ByteIdx*8+u1BitIdx));
mcSHOW_DBG_MSG(("Suspect EMI%d_DQ%d contact issue\n",u1CHIdx_EMI,u1ByteIdx*8+u1BitIdx));
}
}
}
else if((PINInfo_flashtool.DRAM_PIN_RX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] == 0xff) ||\
(PINInfo_flashtool.DRAM_PIN_TX_ERR_FLAG[u1CHIdx][u1RankIdx][u1ByteIdx] == 0xff))
{
mcSHOW_DBG_MSG(("[CHECK RESULT] FAIL: CH%d RK%d Byte%d Suspect other special contact or calibration issue\n",u1CHIdx_EMI,u1RankIdx,u1ByteIdx));
}
}
}
}
}
}
}
mcSHOW_DBG_MSG(("\n"));
return;
}
#endif
void vInitGlobalVariablesByCondition(DRAMC_CTX_T *p)
{
U8 u1CHIdx, u1RankIdx, u1FSPIdx;
u1MR01Value[FSP_0] = 0x26;
u1MR01Value[FSP_1] = 0x56;
u1MR03Value[FSP_0] = 0x31; //Set write post-amble as 0.5 tck
u1MR03Value[FSP_1] = 0x31; //Set write post-amble as 0.5 tck
#ifndef ENABLE_POST_PACKAGE_REPAIR
u1MR03Value[FSP_0] |= 0x4; //MR3 OP[2]=1 for PPR protection enabled
u1MR03Value[FSP_1] |= 0x4; //MR3 OP[2]=1 for PPR protection enabled
#endif
#if ENABLE_WRITE_POST_AMBLE_1_POINT_5_TCK
u1MR03Value[FSP_1] |= 0x2; //MR3 OP[1]=1 for Set write post-amble as 1.5 tck, support after Eig_er E2
#endif
u1MR04Value[RANK_0] = 0x3;
u1MR04Value[RANK_1] = 0x3;
// @Darren, for LP4Y single-end mode
u1MR21Value[FSP_0] = 0x0;
u1MR21Value[FSP_1] = 0x0;
u1MR51Value[FSP_0] = 0x0;
u1MR51Value[FSP_1] = 0x0;
for (u1FSPIdx = 0; u1FSPIdx < p->support_fsp_num; u1FSPIdx++)
{
u1MR02Value[u1FSPIdx] = 0x1a;
}
for (u1CHIdx = 0; u1CHIdx < CHANNEL_NUM; u1CHIdx++)
for (u1RankIdx = 0; u1RankIdx < RANK_MAX; u1RankIdx++)
for (u1FSPIdx = 0; u1FSPIdx < p->support_fsp_num; u1FSPIdx++)
{
// MR14 default value, LP4 default 0x4d, LP4X 0x5d
u1MR14Value[u1CHIdx][u1RankIdx][u1FSPIdx] = (u1FSPIdx == FSP_0)? 0x5d: 0x18; //0x18: customize for Eig_er
#if FSP1_CLKCA_TERM
u1MR12Value[u1CHIdx][u1RankIdx][u1FSPIdx] = (u1FSPIdx == FSP_0)? 0x5d: 0x1b;
#else
u1MR12Value[u1CHIdx][u1RankIdx][u1FSPIdx] = 0x5d;
#endif
#if MRW_CHECK_ONLY
for (u1MRIdx = 0; u1MRIdx < MR_NUM; u1MRIdx++)
u2MRRecord[u1CHIdx][u1RankIdx][u1FSPIdx][u1MRIdx] = 0xffff;
#endif
}
memset(gu2RX_DQS_Duty_Offset, 0, sizeof(gu2RX_DQS_Duty_Offset));
}
const U8 uiLPDDR4_CA_DRAM_Pinmux[PINMUX_MAX][CHANNEL_NUM][6] =
{
{
// for DSC
//CH-A
{
1, 4, 5, 3, 2, 0
},
#if (CHANNEL_NUM>1)
//CH-B
{
3, 5, 0, 2, 4, 1
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
5, 0, 4, 3, 1, 2
},
//CH-D
{
2, 5, 3, 0, 4, 1
},
#endif
},
{
// for LPBK
// TODO: need porting
},
{
// for EMCP
//CH-A
{
2, 4, 3, 5, 1, 0
},
#if (CHANNEL_NUM>1)
//CH-B
{
4, 5, 2, 0, 3, 1
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
5, 4, 0, 2, 1, 3
},
//CH-D
{
3, 5, 2, 4, 0, 1
},
#endif
}
};
//O1 DRAM->APHY
const U8 uiLPDDR4_O1_DRAM_Pinmux[PINMUX_MAX][CHANNEL_NUM][16] =
{
{
// for DSC
//CH-A
{
0, 1, 7, 6, 4, 5, 2, 3,
9, 8, 11, 10, 14, 15, 13, 12
},
#if (CHANNEL_NUM>1)
//CH-B
{
1, 0, 5, 6, 3, 2, 7, 4,
8, 9, 11, 10, 12, 14, 13, 15
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
0, 1, 7, 6, 4, 5, 2, 3,
9, 8, 11, 10, 14, 15, 13, 12
},
//CH-D
{
1, 0, 5, 6, 3, 2, 7, 4,
8, 9, 11, 10, 12, 14, 13, 15
},
#endif
},
{
// for LPBK
// TODO: need porting
},
{
// for EMCP
//CH-A
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 14, 11, 15, 13, 12
},
#if (CHANNEL_NUM>1)
//CH-B
{
0, 1, 4, 7, 3, 5, 6, 2,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 14, 11, 15, 13, 12
},
//CH-D
{
0, 1, 4, 7, 3, 5, 6, 2,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
}
};
//CA APHY->DRAM
#if (CA_PER_BIT_DELAY_CELL || PINMUX_AUTO_TEST_PER_BIT_CA)
const U8 uiLPDDR5_CA_Mapping_POP[CHANNEL_NUM][7] =
{
//CH-A
{
0, 1, 2, 3, 4, 5, 6
},
#if (CHANNEL_NUM>1)
//CH-B
{
0, 4, 2, 3, 1, 5, 6
}
#endif
};
U8 uiLPDDR4_CA_Mapping_POP[CHANNEL_NUM][6] =
{
//CH-A
{
5, 4, 0, 2, 1, 3
},
#if (CHANNEL_NUM>1)
//CH-B
{
3, 5, 2, 4, 0, 1
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
5, 4, 0, 2, 1, 3
},
//CH-D
{
3, 5, 2, 4, 0, 1
},
#endif
};
#endif
#if (__LP5_COMBO__)
const U8 uiLPDDR5_O1_Mapping_POP[CHANNEL_NUM][16] =
{
{
8, 9, 10, 11, 12, 15, 14, 13,
0, 1, 2, 3, 4, 7, 6, 5,
},
#if (CHANNEL_NUM>1)
{
8, 9, 10, 11, 12, 15, 14, 13,
0, 1, 2, 3, 4, 7, 6, 5,
},
#endif
};
#endif
//O1 DRAM->APHY
U8 uiLPDDR4_O1_Mapping_POP[CHANNEL_NUM][16] =
{
//CH-A
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 14, 11, 15, 13, 12
},
#if (CHANNEL_NUM>1)
//CH-B
{
0, 1, 4, 7, 3, 5, 6, 2,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 14, 11, 15, 13, 12
},
//CH-D
{
0, 1, 4, 7, 3, 5, 6, 2,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
};
void vBeforeCalibration(DRAMC_CTX_T *p)
{
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
DramcMRInit_LP5(p);
}
else
#endif
{
//DramcMRInit_LP4(p);
}
#if SIMULATION_RX_DVS || ENABLE_RX_TRACKING
DramcRxInputDelayTrackingInit_byFreq(p);
#endif
DramcHWGatingOnOff(p, 0); //disable gating tracking
CKEFixOnOff(p, CKE_WRITE_TO_ALL_RANK, CKE_FIXON, CKE_WRITE_TO_ALL_CHANNEL); //Let CLK always on during calibration
#if ENABLE_TMRRI_NEW_MODE
SetCKE2RankIndependent(p); //CKE should be controlled independently
#endif
//WDBI-OFF
vIO32WriteFldAlign_All(DRAMC_REG_SHU_TX_SET0, 0x0, SHU_TX_SET0_DBIWR);
#ifdef IMPEDANCE_TRACKING_ENABLE
// set correct setting to control IMPCAL HW Tracking in shuffle RG
// if p->freq >= 1333, enable IMP HW tracking(SHU_DRVING1_DIS_IMPCAL_HW=0), else SHU_DRVING1_DIS_IMPCAL_HW = 1
U8 u1DisImpHw;
U32 u4TermFreq;
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
u4TermFreq = LP5_MRFSP_TERM_FREQ;
else
#endif
u4TermFreq = LP4_MRFSP_TERM_FREQ;
u1DisImpHw = (p->frequency >= u4TermFreq)? 0: 1;
vIO32WriteFldMulti_All(DDRPHY_REG_MISC_SHU_IMPEDAMCE_UPD_DIS1, P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_ODTN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DRVN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DRVP_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_ODTN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_DRVN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_DRVP_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQ_ODTN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQ_DRVN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQ_DRVP_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQS_ODTN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQS_DRVN_UPD_DIS)
| P_Fld(u1DisImpHw, MISC_SHU_IMPEDAMCE_UPD_DIS1_DQS_DRVP_UPD_DIS)
| P_Fld(1, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_DRVP_UPD_DIS)
| P_Fld(1, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_DRVN_UPD_DIS)
| P_Fld(1, MISC_SHU_IMPEDAMCE_UPD_DIS1_WCK_ODTN_UPD_DIS));
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_MISC_IMPCAL1, (u1DisImpHw? 0x0:0x40), SHU_MISC_IMPCAL1_IMPCALCNT);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_MISC_DRVING1, u1DisImpHw, SHU_MISC_DRVING1_DIS_IMPCAL_HW);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_MISC_DRVING1, u1DisImpHw, SHU_MISC_DRVING1_DIS_IMP_ODTN_TRACK);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_MISC_DRVING2, u1DisImpHw, SHU_MISC_DRVING2_DIS_IMPCAL_ODT_EN);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_CA_CMD12, u1DisImpHw, SHU_CA_CMD12_RG_RIMP_UNTERM_EN);
#endif
vIO32WriteFldMulti_All(DDRPHY_REG_MISC_CLK_CTRL, P_Fld(0, MISC_CLK_CTRL_DVFS_CLK_MEM_SEL)
| P_Fld(0, MISC_CLK_CTRL_DVFS_MEM_CK_MUX_UPDATE_EN));
vIO32WriteFldMulti_All(DRAMC_REG_SHU_ZQ_SET0,
P_Fld(0x1ff, SHU_ZQ_SET0_ZQCSCNT) | //Every refresh number to issue ZQCS commands, only for DDR3/LPDDR2/LPDDR3/LPDDR4
P_Fld(0x1b, SHU_ZQ_SET0_TZQLAT));
if (p->support_channel_num == CHANNEL_SINGLE)
{
//single channel, ZQCSDUAL=0, ZQCSMASK=0
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_ZQ_SET0), P_Fld(0, ZQ_SET0_ZQCSDUAL) | P_Fld(0x0, ZQ_SET0_ZQCSMASK));
}
else if (p->support_channel_num == CHANNEL_DUAL)
{
// HW ZQ command is channel interleaving since 2 channel share the same ZQ pin.
#ifdef ZQCS_ENABLE_LP4
// dual channel, ZQCSDUAL =1, and CHA ZQCSMASK=0, CHB ZQCSMASK=1
vIO32WriteFldMulti_All(DRAMC_REG_ZQ_SET0, P_Fld(1, ZQ_SET0_ZQCSDUAL) |
P_Fld(0, ZQ_SET0_ZQCSMASK_OPT) |
P_Fld(0, ZQ_SET0_ZQMASK_CGAR) |
P_Fld(0, ZQ_SET0_ZQCS_MASK_SEL_CGAR));
// DRAMC CHA(CHN0):ZQCSMASK=1, DRAMC CHB(CHN1):ZQCSMASK=0.
// ZQCSMASK setting: (Ch A, Ch B) = (1,0) or (0,1)
// if CHA.ZQCSMASK=1, and then set CHA.ZQCALDISB=1 first, else set CHB.ZQCALDISB=1 first
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + (CHANNEL_A << POS_BANK_NUM), 1, ZQ_SET0_ZQCSMASK);
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + SHIFT_TO_CHB_ADDR, 0, ZQ_SET0_ZQCSMASK);
// DRAMC CHA(CHN0):ZQ_SET0_ZQCS_MASK_SEL=0, DRAMC CHB(CHN1):ZQ_SET0_ZQCS_MASK_SEL=0.
vIO32WriteFldAlign_All(DRAMC_REG_ZQ_SET0, 0, ZQ_SET0_ZQCS_MASK_SEL);
#endif
}
#if (CHANNEL_NUM > 2)
else if (p->support_channel_num == CHANNEL_FOURTH)
{
// HW ZQ command is channel interleaving since 2 channel share the same ZQ pin.
#ifdef ZQCS_ENABLE_LP4
// dual channel, ZQCSDUAL =1, and CHA ZQCSMASK=0, CHB ZQCSMASK=1
vIO32WriteFldMulti_All(DRAMC_REG_ZQ_SET0, P_Fld(1, ZQ_SET0_ZQCSDUAL) |
P_Fld(0, ZQ_SET0_ZQCALL) |
P_Fld(0, ZQ_SET0_ZQ_SRF_OPT) |
P_Fld(0, ZQ_SET0_ZQCSMASK_OPT) |
P_Fld(0, ZQ_SET0_ZQMASK_CGAR) |
P_Fld(0, ZQ_SET0_ZQCS_MASK_SEL_CGAR));
// DRAMC CHA(CHN0):ZQCSMASK=1, DRAMC CHB(CHN1):ZQCSMASK=0.
// ZQCSMASK setting: (Ch A, Ch C) = (1,0) or (0,1), (Ch B, Ch D) = (1,0) or (0,1)
// if CHA.ZQCSMASK=1, and then set CHA.ZQCALDISB=1 first, else set CHB.ZQCALDISB=1 first
#if fcFOR_CHIP_ID == fcPetrus
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + (CHANNEL_A << POS_BANK_NUM), 1, ZQ_SET0_ZQCSMASK);
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + (CHANNEL_B << POS_BANK_NUM), 0, ZQ_SET0_ZQCSMASK);
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + (CHANNEL_C << POS_BANK_NUM), 0, ZQ_SET0_ZQCSMASK);
vIO32WriteFldAlign(DRAMC_REG_ZQ_SET0 + (CHANNEL_D << POS_BANK_NUM), 1, ZQ_SET0_ZQCSMASK);
#endif
// DRAMC CHA(CHN0):ZQ_SET0_ZQCS_MASK_SEL=0, DRAMC CHB(CHN1):ZQ_SET0_ZQCS_MASK_SEL=0.
vIO32WriteFldAlign_All(DRAMC_REG_ZQ_SET0, 0, ZQ_SET0_ZQCS_MASK_SEL);
#endif
}
#endif
// Set 0 to be able to adjust TX DQS/DQ/DQM PI during calibration, for new cross rank mode.
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_B0_DQ2, 0, SHU_B0_DQ2_RG_ARPI_OFFSET_LAT_EN_B0);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_B1_DQ2, 0, SHU_B1_DQ2_RG_ARPI_OFFSET_LAT_EN_B1);
#if ENABLE_PA_IMPRO_FOR_TX_AUTOK
vIO32WriteFldAlign_All(DRAMC_REG_DCM_SUB_CTRL, 0x0, DCM_SUB_CTRL_SUBCLK_CTRL_TX_AUTOK);
#endif
// ARPI_DQ SW mode mux, TX DQ use 1: PHY Reg 0: DRAMC Reg
#if ENABLE_PA_IMPRO_FOR_TX_TRACKING
vIO32WriteFldAlign_All(DRAMC_REG_DCM_SUB_CTRL, 0, DCM_SUB_CTRL_SUBCLK_CTRL_TX_TRACKING);
#endif
//Darren-vIO32WriteFldAlign_All(DDRPHY_REG_MISC_CTRL1, 1, MISC_CTRL1_R_DMARPIDQ_SW); @Darren, remove to LP4_UpdateInitialSettings
//Disable HW MR18/19 to prevent fail case when doing SW MR18/19 in DQSOSCAuto
vIO32WriteFldAlign_All(DRAMC_REG_DQSOSCR, 0x1, DQSOSCR_DQSOSCRDIS);
vIO32WriteFldAlign_All(DRAMC_REG_REFCTRL0, 0x1, REFCTRL0_REFDIS); //disable refresh
vIO32WriteFldAlign_All(DRAMC_REG_SHU_MATYPE, u1MaType, SHU_MATYPE_MATYPE);
TX_Path_Algorithm(p);
}
void vAfterCalibration(DRAMC_CTX_T *p)
{
#if ENABLE_READ_DBI
EnableDRAMModeRegReadDBIAfterCalibration(p);
#endif
#if ENABLE_WRITE_DBI
EnableDRAMModeRegWriteDBIAfterCalibration(p);
#endif
SetMr13VrcgToNormalOperation(p);// Set VRCG{MR13[3]} to 0
CKEFixOnOff(p, CKE_WRITE_TO_ALL_RANK, CKE_DYNAMIC, CKE_WRITE_TO_ALL_CHANNEL); //After CKE FIX on/off, CKE should be returned to dynamic (control by HW)
vIO32WriteFldAlign_All(DRAMC_REG_DUMMY_RD, p->support_rank_num, DUMMY_RD_RANK_NUM);
#if FOR_DV_SIMULATION_USED == 1
cal_sv_rand_args_t *psra = get_psra();
if (psra) {
u1MR03Value[p->dram_fsp] = psra->mr3_value;
}
#endif
vIO32WriteFldAlign_All(DDRPHY_REG_MISC_CG_CTRL7, 0, MISC_CG_CTRL7_CK_BFE_DCM_EN);
vIO32WriteFldAlign_All(DRAMC_REG_TEST2_A4, 4, TEST2_A4_TESTAGENTRKSEL); // Rank selection is controlled by Test Agent
vIO32WriteFldAlign_All(DRAMC_REG_TEST2_A2, 0x20, TEST2_A2_TEST2_OFF); //@Chris, MP setting for runtime TA2 Length
vIO32WriteFldAlign_All(DDRPHY_REG_MISC_DUTYSCAN1, 0, MISC_DUTYSCAN1_DQSERRCNT_DIS);
vIO32WriteFldAlign_All(DDRPHY_REG_MISC_CTRL1, 0, MISC_CTRL1_R_DMSTBENCMP_RK_OPT);
}
static void O1PathOnOff(DRAMC_CTX_T *p, U8 u1OnOff)
{
#if 0//O1_SETTING_RESTORE
const U32 u4O1RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_VREF)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_VREF)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_PHY_VREF_SEL)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_PHY_VREF_SEL)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5))
};
#endif
U8 u1VrefSel;
if (u1OnOff == ON)
{
// These RG will be restored when leaving each calibration flow
// -------------------------------------------------------
// VREF_UNTERM_EN
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_VREF), 1, SHU_B0_VREF_RG_RX_ARDQ_VREF_UNTERM_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_VREF), 1, SHU_B1_VREF_RG_RX_ARDQ_VREF_UNTERM_EN_B1);
#if (__LP5_COMBO__ == TRUE)
if (p->dram_type==TYPE_LPDDR5)
u1VrefSel = 0x37;//unterm LP5
else
#endif
u1VrefSel = 0x37;//unterm LP4
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_PHY_VREF_SEL),
P_Fld(u1VrefSel, SHU_B0_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_LB_B0) |
P_Fld(u1VrefSel, SHU_B0_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_UB_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_PHY_VREF_SEL),
P_Fld(u1VrefSel, SHU_B1_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_LB_B1) |
P_Fld(u1VrefSel, SHU_B1_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_UB_B1));
}
// DQ_O1 enable/release
// -------------------------------------------------------
// Actually this RG naming is O1_EN in APHY
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6), u1OnOff, B0_DQ6_RG_RX_ARDQ_O1_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6), u1OnOff, B1_DQ6_RG_RX_ARDQ_O1_SEL_B1);
// DQ_IN_BUFF_EN
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ3),
P_Fld(u1OnOff, B0_DQ3_RG_RX_ARDQ_IN_BUFF_EN_B0) |
P_Fld(u1OnOff, B0_DQ3_RG_RX_ARDQS0_IN_BUFF_EN_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ3),
P_Fld(u1OnOff, B1_DQ3_RG_RX_ARDQ_IN_BUFF_EN_B1) |
P_Fld(u1OnOff, B1_DQ3_RG_RX_ARDQS0_IN_BUFF_EN_B1));
// DQ_BUFF_EN_SEL
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY3), u1OnOff, B0_PHY3_RG_RX_ARDQ_BUFF_EN_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY3), u1OnOff, B1_PHY3_RG_RX_ARDQ_BUFF_EN_SEL_B1);
// Gating always ON
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_RX_IN_GATE_EN_CTRL),(u1OnOff << 1) | u1OnOff, MISC_RX_IN_GATE_EN_CTRL_FIX_IN_GATE_EN);
mcDELAY_US(1);
}
/*
* set_cbt_intv -- set interval related rg according to speed.
*
* TODO, move these to ACTimingTable ????!!!
*/
struct cbt_intv {
DRAM_PLL_FREQ_SEL_T freq_sel;
DIV_MODE_T divmode;
u8 tcmdo1lat;
u8 catrain_intv;
u8 new_cbt_pat_intv;
u8 wlev_dqspat_lat;
};
static void set_cbt_intv_rg(DRAMC_CTX_T *p, struct cbt_intv *pintv)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL1),
P_Fld(pintv->tcmdo1lat, CBT_WLEV_CTRL1_TCMDO1LAT) |
P_Fld(pintv->catrain_intv, CBT_WLEV_CTRL1_CATRAIN_INTV));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL5),
P_Fld(pintv->new_cbt_pat_intv, CBT_WLEV_CTRL5_NEW_CBT_PAT_INTV));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(pintv->wlev_dqspat_lat, CBT_WLEV_CTRL0_WLEV_DQSPAT_LAT));
}
static struct cbt_intv *lookup_cbt_intv(struct cbt_intv *intv, int cnt,
DRAM_PLL_FREQ_SEL_T fsel, DIV_MODE_T dmode)
{
struct cbt_intv *pintv = NULL;
int i;
for (i = 0; i < cnt; i++) {
if (intv[i].freq_sel == fsel && intv[i].divmode == dmode) {
pintv = &intv[i];
break;
}
}
return pintv;
}
static void set_cbt_wlev_intv_lp4(DRAMC_CTX_T *p)
{
struct cbt_intv intv[] = {
{
LP4_DDR4266,
DIV8_MODE,
17, /*tcmdo1lat*/
14, /* catrain_intv */
19, /* new_cbt_pat_intv */
19, /* wlev_dqspat_lat */
}, {
LP4_DDR3733,
DIV8_MODE,
16, /*tcmdo1lat*/
13, /* catrain_intv */
18, /* new_cbt_pat_intv */
18, /* wlev_dqspat_lat */
}, {
LP4_DDR3200,
DIV8_MODE,
14, /*tcmdo1lat*/
11, /* catrain_intv */
16, /* new_cbt_pat_intv */
16, /* wlev_dqspat_lat */
}, {
LP4_DDR2667,
DIV8_MODE,
13, /*tcmdo1lat*/
10, /* catrain_intv */
15, /* new_cbt_pat_intv */
15, /* wlev_dqspat_lat */
}, {
LP4_DDR2400,
DIV8_MODE,
12, /*tcmdo1lat*/
9, /* catrain_intv */
14, /* new_cbt_pat_intv */
14, /* wlev_dqspat_lat */
}, {
LP4_DDR1866,
DIV8_MODE,
11, /*tcmdo1lat*/
9, /* catrain_intv */
13, /* new_cbt_pat_intv */
13, /* wlev_dqspat_lat */
}, {
LP4_DDR1600,
DIV8_MODE,
10, /*tcmdo1lat*/
8, /* catrain_intv */
12, /* new_cbt_pat_intv */
12, /* wlev_dqspat_lat */
}, {
LP4_DDR1200,
DIV8_MODE,
9, /*tcmdo1lat*/
8, /* catrain_intv */
11, /* new_cbt_pat_intv */
11, /* wlev_dqspat_lat */
}, {
LP4_DDR800,
DIV8_MODE,
8, /*tcmdo1lat*/
8, /* catrain_intv */
10, /* new_cbt_pat_intv */
10, /* wlev_dqspat_lat */
}, {
LP4_DDR1600,
DIV4_MODE,
16, /*tcmdo1lat*/
13, /* catrain_intv */
16, /* new_cbt_pat_intv */
16, /* wlev_dqspat_lat */
}, {
LP4_DDR1200,
DIV4_MODE,
14, /*tcmdo1lat*/
13, /* catrain_intv */
14, /* new_cbt_pat_intv */
14, /* wlev_dqspat_lat */
}, {
LP4_DDR800,
DIV4_MODE,
12, /*tcmdo1lat*/
13, /* catrain_intv */
12, /* new_cbt_pat_intv */
12, /* wlev_dqspat_lat */
}, {
LP4_DDR400,
DIV4_MODE,
12, /*tcmdo1lat*/
13, /* catrain_intv */
12, /* new_cbt_pat_intv */
12, /* wlev_dqspat_lat */
},
};
struct cbt_intv *pintv;
pintv = lookup_cbt_intv(intv, ARRAY_SIZE(intv),
p->freq_sel, vGet_Div_Mode(p));
if (!pintv) {
mcSHOW_DBG_MSG(("not found entry!\n"));
return;
}
set_cbt_intv_rg(p, pintv);
}
#if __LP5_COMBO__
static void set_cbt_wlev_intv_lp5(DRAMC_CTX_T *p)
{
struct cbt_intv intv[] = {
{
LP5_DDR6400,
UNKNOWN_MODE,
15, /*tcmdo1lat*/
15, /* catrain_intv */
17, /* new_cbt_pat_intv */
17, /* wlev_dqspat_lat */
}, {
LP5_DDR6000,
UNKNOWN_MODE,
15, /*tcmdo1lat*/
15, /* catrain_intv */
17, /* new_cbt_pat_intv */
17, /* wlev_dqspat_lat */
}, {
LP5_DDR5500,
UNKNOWN_MODE,
14, /*tcmdo1lat*/
14, /* catrain_intv */
16, /* new_cbt_pat_intv */
16, /* wlev_dqspat_lat */
}, {
LP5_DDR4800,
UNKNOWN_MODE,
13, /*tcmdo1lat*/
13, /* catrain_intv */
15, /* new_cbt_pat_intv */
15, /* wlev_dqspat_lat */
}, {
LP5_DDR4266,
UNKNOWN_MODE,
20, /*tcmdo1lat*/
20, /* catrain_intv */
22, /* new_cbt_pat_intv */
20, /* wlev_dqspat_lat */
}, {
LP5_DDR3733,
UNKNOWN_MODE,
19, /*tcmdo1lat*/
19, /* catrain_intv */
21, /* new_cbt_pat_intv */
19, /* wlev_dqspat_lat */
}, {
LP5_DDR3200,
UNKNOWN_MODE,
15, /*tcmdo1lat*/
15, /* catrain_intv */
17, /* new_cbt_pat_intv */
17, /* wlev_dqspat_lat */
}, {
LP5_DDR2400,
UNKNOWN_MODE,
13, /*tcmdo1lat*/
13, /* catrain_intv */
15, /* new_cbt_pat_intv */
15, /* wlev_dqspat_lat */
}, {
LP5_DDR1600,
UNKNOWN_MODE,
17, /*tcmdo1lat*/
17, /* catrain_intv */
19, /* new_cbt_pat_intv */
17, /* wlev_dqspat_lat */
}, {
LP5_DDR1200,
UNKNOWN_MODE,
15, /*tcmdo1lat*/
15, /* catrain_intv */
17, /* new_cbt_pat_intv */
15, /* wlev_dqspat_lat */
}, {
LP5_DDR800,
UNKNOWN_MODE,
13, /*tcmdo1lat*/
13, /* catrain_intv */
15, /* new_cbt_pat_intv */
13, /* wlev_dqspat_lat */
},
};
struct cbt_intv *pintv;
pintv = lookup_cbt_intv(intv, ARRAY_SIZE(intv), p->freq_sel, UNKNOWN_MODE);
if (!pintv) {
mcSHOW_DBG_MSG(("not found entry!\n"));
return;
}
set_cbt_intv_rg(p, pintv);
}
#endif /* __LP5_COMBO__ */
static void set_cbt_wlev_intv(DRAMC_CTX_T *p)
{
#if __LP5_COMBO__
if (is_lp5_family(p))
set_cbt_wlev_intv_lp5(p);
else
#endif
set_cbt_wlev_intv_lp4(p);
}
#if SIMUILATION_CBT == 1
/* To process LPDDR5 Pinmux */
struct cbt_pinmux {
u8 dram_dq_b0; /* EMI_B0 is mapped to which DRAMC byte ?? */
u8 dram_dq_b1;
u8 dram_dmi_b0; /* EMI_DMI0 is mapped to which DRAMC DMI ?? */
u8 dram_dmi_b1;
u8 dram_dq7_b0; /* EMI_DQ7 is mapped to which DRAMC DQ ?? */
u8 dram_dq7_b1; /* EMI_DQ15 is mapped to which DRAMC DQ ?? */
};
/* Per-project definition */
static struct cbt_pinmux lp4_cp[CHANNEL_NUM] = {
{
/* CHA */
.dram_dq_b0 = 0,
.dram_dq_b1 = 1,
.dram_dmi_b0 = 0,
.dram_dmi_b1 = 1,
},
#if (CHANNEL_NUM>1)
{
/* CHB */
.dram_dq_b0 = 0,
.dram_dq_b1 = 1,
.dram_dmi_b0 = 0,
.dram_dmi_b1 = 1,
},
#endif
#if (CHANNEL_NUM>2)
{
/* CHC */
.dram_dq_b0 = 0,
.dram_dq_b1 = 1,
.dram_dmi_b0 = 0,
.dram_dmi_b1 = 1,
},
{
/* CHD */
.dram_dq_b0 = 0,
.dram_dq_b1 = 1,
.dram_dmi_b0 = 0,
.dram_dmi_b1 = 1,
},
#endif
};
static inline u8 is_byte_mode(DRAMC_CTX_T *p)
{
return p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1? 1: 0;
}
static void vSetDramMRCBTOnOff(DRAMC_CTX_T *p, U8 u1OnOff, U8 operating_fsp)
{
if (u1OnOff)
{
// op[7] = !(p->dram_fsp), dram will switch to another FSP_OP automatically
if (operating_fsp)
{
MRWriteFldMulti(p, 13, P_Fld(0, MR13_FSP_OP) |
P_Fld(1, MR13_FSP_WR) |
P_Fld(1, MR13_CBT),
TO_MR);
}
else
{
MRWriteFldMulti(p, 13, P_Fld(1, MR13_FSP_OP) |
P_Fld(0, MR13_FSP_WR) |
P_Fld(1, MR13_CBT),
TO_MR);
}
if (p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), P_Fld(1, CBT_WLEV_CTRL0_BYTEMODECBTEN) |
P_Fld(1, CBT_WLEV_CTRL0_CBT_CMP_BYTEMODE)); //BYTEMODECBTEN=1
}
}
else
{
if (operating_fsp)
{
// !! Remain MR13_FSP_OP = 0, because of system is at low frequency now.
MRWriteFldMulti(p, 13, P_Fld(0, MR13_FSP_OP) |
P_Fld(1, MR13_FSP_WR) |
P_Fld(0, MR13_CBT),
TO_MR);
}
else
{
MRWriteFldMulti(p, 13, P_Fld(0, MR13_FSP_OP) |
P_Fld(0, MR13_FSP_WR) |
P_Fld(0, MR13_CBT),
TO_MR);
}
}
}
static void CBTEntryLP4(DRAMC_CTX_T *p, U8 operating_fsp, U16 operation_frequency)
{
struct cbt_pinmux *cp = &lp4_cp[p->channel];
#if MR_CBT_SWITCH_FREQ
if (p->dram_fsp == FSP_1)
DramcModeRegInit_CATerm(p, 1);
#endif
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL),
0, MISC_STBCAL_DQSIENCG_NORMAL_EN);
CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
// yr: CA train old mode and CS traing need to check MRSRK at this point
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), u1GetRank(p), SWCMD_CTRL0_MRSRK);
//Step 0: MRW MR13 OP[0]=1 to enable CBT
vSetDramMRCBTOnOff(p, ENABLE, operating_fsp);
//Step 0.1: before CKE low, Let DQS=0 by R_DMwrite_level_en=1, spec: DQS_t has to retain a low level during tDQSCKE period
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
1, CBT_WLEV_CTRL0_WRITE_LEVEL_EN);
//TODO, pinmux
//force byte0 tx
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
0x1, CBT_WLEV_CTRL0_DQSOEAOEN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
(1 << cp->dram_dq_b0), CBT_WLEV_CTRL0_CBT_DQBYTE_OEAO_EN);
}
mcDELAY_US(1);
//Step 1.0: let CKE go low
CKEFixOnOff(p, p->rank, CKE_FIXOFF, CKE_WRITE_TO_ONE_CHANNEL);
// Adjust u1MR13Value
(operating_fsp == FSP_1)?
DramcMRWriteFldAlign(p, 13, 1, MR13_FSP_OP, JUST_TO_GLOBAL_VALUE):
DramcMRWriteFldAlign(p, 13, 0, MR13_FSP_OP, JUST_TO_GLOBAL_VALUE);
// Step 1.1 : let IO to O1 path valid
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
// Let R_DMFIXDQIEN1=1 (byte1), 0xd8[13] ==> Note: Do not enable again.
//Currently set in O1PathOnOff
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_PADCTRL), 0x3, PADCTRL_FIXDQIEN);
// Let DDRPHY RG_RX_ARDQ_SMT_EN_B1=1 (byte1)
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_B1_DQ3), 1, B1_DQ3_RG_RX_ARDQ_SMT_EN_B1);
O1PathOnOff(p, ON);
}
if (p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
// let IO to O1 path valid by DDRPHY RG_RX_ARDQ_SMT_EN_B0=1
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_B0_DQ3), 1, B0_DQ3_RG_RX_ARDQ_SMT_EN_B0);
O1PathOnOff(p, ON);
}
// Wait tCAENT
mcDELAY_US(1);
}
static void CBTExitLP4(DRAMC_CTX_T *p, U8 operating_fsp, U8 operation_frequency)
{
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE || p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
//Step 1: CKE go high (Release R_DMCKEFIXOFF, R_DMCKEFIXON=1)
CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
//Step 2:wait tCATX, wait tFC
mcDELAY_US(1);
//Step 3: MRW to command bus training exit (MR13 OP[0]=0 to disable CBT)
vSetDramMRCBTOnOff(p, DISABLE, operating_fsp);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
0, CBT_WLEV_CTRL0_WRITE_LEVEL_EN);
}
//Step 4:
//Disable O1 path output
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
//Let DDRPHY RG_RX_ARDQ_SMT_EN_B1=0
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_B1_DQ3), 0, B1_DQ3_RG_RX_ARDQ_SMT_EN_B1);
O1PathOnOff(p, OFF);
//Let FIXDQIEN1=0 ==> Note: Do not enable again.
//Moved into O1PathOnOff
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_PADCTRL), 0, PADCTRL_FIXDQIEN);
}
if (p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
//Let DDRPHY RG_RX_ARDQ_SMT_EN_B0=0
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_B0_DQ3), 0, B0_DQ3_RG_RX_ARDQ_SMT_EN_B0);
O1PathOnOff(p, OFF);
//Disable Byte mode CBT enable bit
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), P_Fld(0, CBT_WLEV_CTRL0_BYTEMODECBTEN) |
P_Fld(0, CBT_WLEV_CTRL0_CBT_CMP_BYTEMODE)); //BYTEMODECBTEN=1
}
// Wait tCAENT
mcDELAY_US(1);
}
/*
* get_mck_ck_ratio -- get ratio of mck:ck
*
* TODO, remove later, get the ratio from dram ctx dfs table!!!!
*
*
* return 1 means 1:1
* return 0 means 1:2
*/
static u8 get_mck_ck_ratio(DRAMC_CTX_T *p)
{
/*
* as per DE's comments, LP5 mck:ck has only 1:1 and 1:2.
* read SHU_LP5_CMD.LP5_CMD1TO2EN to decide which one.
*/
u32 ratio;
ratio = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_LP5_CMD),
SHU_LP5_CMD_LP5_CMD1TO2EN);
mcSHOW_DBG_MSG5(("LP5 MCK:CK=%s\n", ratio == 1 ? "1:1" : "1:2"));
return ratio;
}
static u8 get_cbtui_adjustable_maxvalue(DRAMC_CTX_T *p)
{
u8 ratio;
/*
* MCK:CK=1:1,
* ther are only 0~1 for ui adjust, if ui value is larger than 1, adjust MCK.
*
* MCK:CK=1:2,
* ther are only 0~3 for ui adjust, if ui value is larger than 3, adjust MCK.
*
* MCK:CK=1:4, (for LP4)
* ther are only 0~7 for ui adjust, if ui value is larger than 7, adjust MCK.
*
*/
ratio = get_mck_ck_ratio(p);
/* here just for LP5 */
return ratio == 1? 1: 3;
}
static inline u32 get_ca_mck(DRAMC_CTX_T *p)
{
u32 dly;
dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA3));
return dly & 0x0FFFFFFFU;
}
static inline void put_ca_mck(DRAMC_CTX_T *p, u32 ca_mck)
{
u32 dly;
dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA3));
dly &= 0xF0000000U;
ca_mck &= 0x0FFFFFFFU;
dly |= ca_mck;
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA3), dly);
}
static inline u32 get_ca_ui(DRAMC_CTX_T *p)
{
u32 dly;
dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA7));
return dly & 0x0FFFFFFFU;
}
static inline void put_ca_ui(DRAMC_CTX_T *p, u32 ca_ui)
{
u32 dly;
dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA7));
dly &= 0xF0000000U;
ca_ui &= 0x0FFFFFFFU;
dly |= ca_ui;
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA7), dly);
// Note: CKE UI must sync CA UI (CA and CKE delay circuit are same) @Lin-Yi
// To avoid tXP timing margin issue
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA5), ca_ui & 0xF, SHU_SELPH_CA5_DLY_CKE);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA6), ca_ui & 0xF, SHU_SELPH_CA6_DLY_CKE1);
}
static void xlate_ca_mck_ui(DRAMC_CTX_T *p, u32 ui_delta,
u32 mck_old, u32 ui_old, u32 *mck_new, u32 *ui_new)
{
u8 i;
u32 mask, max;
u32 bit_ui, bit_mck;
u32 ui_tmp = 0, mck_tmp = 0;
max = get_cbtui_adjustable_maxvalue(p);
mask = max;
for (i = 0; i < CATRAINING_NUM_LP5; i++) {
bit_mck = 0;
bit_ui = ((ui_old >> (i * 4)) & mask) + ui_delta;
if (bit_ui > max) {
bit_mck = bit_ui / (max + 1);
bit_ui = bit_ui % (max + 1);
}
mck_tmp += (bit_mck << (i * 4));
ui_tmp += (bit_ui << (i * 4));
}
if (ui_new)
*ui_new = ui_tmp;
if (mck_new)
*mck_new = mck_old + mck_tmp;
}
static inline u8 get_ca_pi_per_ui(DRAMC_CTX_T *p)
{
#if __LP5_COMBO__
if (p->freq_sel == LP5_DDR4266)
return 64;
else
#endif
return 32;
}
static int get_capi_max(DRAMC_CTX_T *p)
{
if (u1IsPhaseMode(p) == TRUE)
{
return 32;
}
return 64;
}
static S16 adjust_ca_ui(DRAMC_CTX_T *p, U32 ca_mck,
U32 ca_ui, S16 pi_dly)
{
S16 p2u;
S16 ui, pi;
U32 ui_new = 0, mck_new = 0;
if (pi_dly < get_capi_max(p))
{
return pi_dly;
}
p2u = get_ca_pi_per_ui(p);
ui = pi_dly / p2u;
pi = pi_dly % p2u;
xlate_ca_mck_ui(p, ui, ca_mck, ca_ui, &mck_new, &ui_new);
put_ca_ui(p, ui_new);
put_ca_mck(p, mck_new);
mcSHOW_DBG_MSG5(("mck_new: 0x%x, ui_new: 0x%x, pi:%d\n",
mck_new, ui_new, pi));
return pi;
}
static inline u32 get_cs_mck(DRAMC_CTX_T *p)
{
if (p->rank == RANK_1)
return u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA1),
SHU_SELPH_CA1_TXDLY_CS1);
else
return u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA1),
SHU_SELPH_CA1_TXDLY_CS);
}
static inline void put_cs_mck(DRAMC_CTX_T *p, u32 cs_ui)
{
if (p->rank == RANK_1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA1),
cs_ui, SHU_SELPH_CA1_TXDLY_CS1);
else
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA1),
cs_ui, SHU_SELPH_CA1_TXDLY_CS);
}
static inline u32 get_cs_ui(DRAMC_CTX_T *p)
{
if (p->rank == RANK_1)
return u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA5),
SHU_SELPH_CA5_DLY_CS1);
else
return u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA5),
SHU_SELPH_CA5_DLY_CS);
}
static inline void put_cs_ui(DRAMC_CTX_T *p, u32 cs_ui)
{
if (p->rank == RANK_1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA5),
cs_ui, SHU_SELPH_CA5_DLY_CS1);
else
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_CA5),
cs_ui, SHU_SELPH_CA5_DLY_CS);
}
//void LP5_ShiftCSUI(DRAMC_CTX_T *p, S8 iShiftUI)
//{
// REG_TRANSFER_T TransferUIRegs = {DRAMC_REG_SHU_SELPH_CA5, SHU_SELPH_CA5_DLY_CS};
// REG_TRANSFER_T TransferMCKRegs = {DRAMC_REG_SHU_SELPH_CA1, SHU_SELPH_CA1_TXDLY_CS};
//
// ExecuteMoveDramCDelay(p, TransferUIRegs[i], TransferMCKRegs[i], iShiftUI);
//}
static S16 adjust_cs_ui(DRAMC_CTX_T *p, u32 cs_mck, u32 cs_ui, S16 pi_dly)
{
S16 p2u;
S16 ui = 0, pi = 0;
u8 ratio;
u32 ui_max;
u32 cs_bit_mask, cs_ui_tmp, cs_mck_tmp;
if (pi_dly < get_capi_max(p))
{
return pi_dly;
}
p2u = get_ca_pi_per_ui(p);
ui = pi_dly / p2u;
pi = pi_dly % p2u;
ratio = get_mck_ck_ratio(p);
if (ratio) {
/* 1:1 */
cs_bit_mask = 1;
} else {
/* 1:2 */
cs_bit_mask = 3;
}
ui_max = get_cbtui_adjustable_maxvalue(p);
cs_ui_tmp = (cs_ui & cs_bit_mask) + ui;
cs_mck_tmp = 0;
if (cs_ui_tmp > ui_max) {
cs_mck_tmp = cs_ui_tmp / (ui_max + 1);
cs_ui_tmp = cs_ui_tmp % (ui_max + 1);
}
cs_mck_tmp += cs_mck;
put_cs_ui(p, cs_ui_tmp);
put_cs_mck(p, cs_mck_tmp);
mcSHOW_DBG_MSG5(("csmck:%d, csui: %d, pi:%d before\n",
cs_mck, cs_ui, 0));
mcSHOW_DBG_MSG5(("csmck:%d, csui: %d, pi:%d after\n",
cs_mck_tmp, cs_ui_tmp, pi));
return pi;
}
static u32 get_capi_step(DRAMC_CTX_T *p)
{
u32 step;
switch (p->freq_sel) {
case LP5_DDR800:
case LP5_DDR1200:
case LP5_DDR1600:
case LP5_DDR3733:
step = 8;
break;
default:
if (vGet_DDR_Loop_Mode(p) == SEMI_OPEN_LOOP_MODE)
{
step = 8;
}
else if (vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE)
{
step = 16;
}
else
{
step = 1;
}
break;
}
#if FOR_DV_SIMULATION_USED
return 8;
#else
return step;
#endif
}
#if CBT_O1_PINMUX_WORKAROUND
static u32 CBTCompareWordaroundDecodeO1Pinmux(DRAMC_CTX_T *p, u32 o1_value, U8 *uiLPDDR_O1_Mapping)
{
U8 u1Idx;
U32 u4Result;
u4Result = 0;
for (u1Idx = 0;u1Idx < p->data_width;u1Idx++)
u4Result |= ((o1_value >> uiLPDDR_O1_Mapping[u1Idx]) & 0x1) << u1Idx;
return u4Result;
}
static u32 CBTDelayCACLKCompareWorkaround(DRAMC_CTX_T *p)
{
u8 u1pattern_index, u1ca_index, u1dq_index, u1dq_start, u1dq_end, u1ca_number_per_bit, u1bit_num_per_byte, u1pattern_choose;
U8 *uiLPDDR_O1_Mapping = NULL;
u32 u4TimeCnt, rdy, u4dq_o1, u4data_receive, u4ca_pattern, u4Result, u4Ready;
u8 u1pattern_num;
const U8 u1LP5CBT_Pattern_Mapping[2][7] =
{
{
1, 2, 4, 8, 16, 32, 64
},
{
126, 125, 123, 119, 111, 95, 63
},
};
const U8 u1LP4CBT_Pattern_Mapping[2][6] =
{
{
1, 2, 4, 8, 16, 32
},
{
62, 61, 59, 55, 47, 31
},
};
u4Result = 0;
u1bit_num_per_byte = 8;
#if (__LP5_COMBO__)
if (is_lp5_family(p))
{
uiLPDDR_O1_Mapping = (U8 *)uiLPDDR5_O1_Mapping_POP[p->channel];
u1pattern_num = 8;
u1ca_number_per_bit = CATRAINING_NUM_LP5;
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
u1dq_start = 0;
u1dq_end = 6;
}
else
{
u1dq_start = 0;
u1dq_end = 14;
}
}
else
#endif
{
uiLPDDR_O1_Mapping = (U8 *)uiLPDDR4_O1_Mapping_POP[p->channel];
u1pattern_num = 4;
u1ca_number_per_bit = CATRAINING_NUM_LP4;
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
u1dq_start = 8;
u1dq_end = 13;
}
else
{
u1dq_start = 0;
u1dq_end = 13;
}
}
vIO32WriteFldMulti(DRAMC_REG_CBT_WLEV_CTRL3, P_Fld(0x1, CBT_WLEV_CTRL3_CATRAIN_PAT_STOP0)
| P_Fld(0x1, CBT_WLEV_CTRL3_CATRAIN_PAT_STOP1));
for (u1pattern_index = 0; u1pattern_index < u1pattern_num; u1pattern_index++)
{
u1pattern_choose = (u1pattern_index > 3) ? (u1pattern_index % 2) : /* LP5 mapping */
((u1pattern_index > 1)? (3 - u1pattern_index) : u1pattern_index); /* LP5 & LP4 mapping */
for (u1ca_index = 0; u1ca_index < u1ca_number_per_bit; u1ca_index++)
{
#if (__LP5_COMBO__)
if (is_lp5_family(p))
{
u4ca_pattern = u1LP5CBT_Pattern_Mapping[u1pattern_choose][u1ca_index];
}
else
#endif
{
u4ca_pattern = u1LP4CBT_Pattern_Mapping[u1pattern_choose][u1ca_index];
}
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL3), P_Fld((u1pattern_index+1), CBT_WLEV_CTRL3_CATRAIN_1PAT_SEL0)
| P_Fld((u1ca_index+1), CBT_WLEV_CTRL3_CATRAIN_1PAT_SEL1));
u4TimeCnt = TIME_OUT_CNT;
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 1, CBT_WLEV_CTRL0_CBT_CAPATEN);
//Check CA training compare ready (dramc_conf_nao 0x3fc , CATRAIN_CMP_CPT)
do
{
u4Ready = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_STATUS1), CBT_WLEV_STATUS1_CATRAIN_CMP_CPT);
u4TimeCnt --;
mcDELAY_US(1);
}while ((u4Ready == 0) && (u4TimeCnt > 0));
if (u4TimeCnt == 0)//time out
{
mcSHOW_DBG_MSG(("[CBTDelayCACLKCompare] Resp fail (time out)\n"));
mcFPRINTF((fp_A60868, "[CBTDelayCACLKCompare] Resp fail (time out)\n"));//Eddie Test
//return DRAM_FAIL;
}
u4dq_o1 = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQO1), MISC_DQO1_DQO1_RO);
u4dq_o1 = CBTCompareWordaroundDecodeO1Pinmux(p, u4dq_o1, uiLPDDR_O1_Mapping);
if (u1dq_end >= u1ca_number_per_bit)
u4ca_pattern |= u4ca_pattern << u1bit_num_per_byte;
u4dq_o1 ^= u4ca_pattern;
for(u1dq_index=u1dq_start; u1dq_index<=u1dq_end; u1dq_index++)
{
if ((p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1) && (u1dq_index == u1ca_number_per_bit))
u1dq_index = u1bit_num_per_byte;
u4data_receive = (u4dq_o1 >> u1dq_index) & 0x1;
if (u1dq_index < u1bit_num_per_byte)
u4Result |= u4data_receive << u1dq_index;
else
u4Result |= u4data_receive << u1dq_index - u1bit_num_per_byte;
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 0, CBT_WLEV_CTRL0_CBT_CAPATEN);
}
if (u4Result == ((0x1 << u1ca_number_per_bit) - 1))
break;
}
return u4Result;
}
static u32 new_cbt_pat_compare_workaround(DRAMC_CTX_T *p, new_cbt_pat_cfg_t *ncm)
{
u8 u1pattern_index, u1ca_index, u1dq_index, u1dq_start, u1dq_end, u1ca_number_per_bit, u1bit_num_per_byte;
U8 *uiLPDDR_O1_Mapping = NULL;
u32 u4TimeCnt, rdy, u4dq_o1, u4data_receive, u4ca_pattern_a, u4ca_pattern, u4Result, u4Ready;
u8 u1pattern_num;
u4Result = 0;
u1bit_num_per_byte = 8;
#if (__LP5_COMBO__)
if (is_lp5_family(p))
{
uiLPDDR_O1_Mapping = (U8 *)uiLPDDR5_O1_Mapping_POP[p->channel];
u1pattern_num = 8;
u1ca_number_per_bit = 7;
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
u1dq_start = 0;
u1dq_end = 6;
}
else
{
u1dq_start = 0;
u1dq_end = 14;
}
}
else
#endif
{
uiLPDDR_O1_Mapping = (U8 *)uiLPDDR4_O1_Mapping_POP[p->channel];
u1pattern_num = 4;
u1ca_number_per_bit = 6;
if (p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE)
{
u1dq_start = 8;
u1dq_end = 13;
}
else
{
u1dq_start = 0;
u1dq_end = 13;
}
}
for (u1pattern_index = 0; u1pattern_index < u1pattern_num; u1pattern_index++)
{
u4ca_pattern_a = ((ncm->pat_a[u1pattern_index] >> ncm->ca_golden_sel) & 0x1) ? ((0x1 << u1ca_number_per_bit) - 1) : 0x0;
for (u1ca_index = 0; u1ca_index < u1ca_number_per_bit; u1ca_index++)
{
u4ca_pattern = u4ca_pattern_a & ~(0x1 << u1ca_index);
if ((ncm->pat_v[u1pattern_index] >> ncm->ca_golden_sel) & 0x1)
u4ca_pattern |= 0x1 << u1ca_index;
if (ncm->invert_num)
u4ca_pattern ^= (0x1 << u1ca_number_per_bit) - 1;
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL5), P_Fld(u1pattern_index, CBT_WLEV_CTRL5_NEW_CBT_PAT_NUM)
| P_Fld(u1ca_index, CBT_WLEV_CTRL5_NEW_CBT_CA_NUM));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL5), 1, CBT_WLEV_CTRL5_NEW_CBT_CAPATEN);
//Check CA training compare ready (dramc_conf_nao 0x3fc , CATRAIN_CMP_CPT)
do
{
u4Ready = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_STATUS2), CBT_WLEV_STATUS2_CBT_PAT_CMP_CPT);
u4TimeCnt --;
mcDELAY_US(1);
}while ((u4Ready == 0) && (u4TimeCnt > 0));
if (u4TimeCnt == 0)//time out
{
mcSHOW_DBG_MSG(("[CBTDelayCACLKCompare] Resp fail (time out)\n"));
mcFPRINTF((fp_A60868, "[CBTDelayCACLKCompare] Resp fail (time out)\n"));//Eddie Test
//return DRAM_FAIL;
}
u4dq_o1 = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQO1), MISC_DQO1_DQO1_RO);
u4dq_o1 = CBTCompareWordaroundDecodeO1Pinmux(p, u4dq_o1, uiLPDDR_O1_Mapping);
if (u1dq_end >= u1ca_number_per_bit)
u4ca_pattern |= u4ca_pattern << u1bit_num_per_byte;
u4dq_o1 ^= u4ca_pattern;
for(u1dq_index=u1dq_start; u1dq_index<=u1dq_end; u1dq_index++)
{
if ((p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1) && (u1dq_index == u1ca_number_per_bit))
u1dq_index = u1bit_num_per_byte;
u4data_receive = (u4dq_o1 >> u1dq_index) & 0x1;
if (u1dq_index < u1bit_num_per_byte)
u4Result |= u4data_receive << u1dq_index;
else
u4Result |= u4data_receive << u1dq_index - u1bit_num_per_byte;
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL5), 0, CBT_WLEV_CTRL5_NEW_CBT_CAPATEN);
}
if (u4Result == ((0x1 << u1ca_number_per_bit) - 1))
break;
}
return u4Result;
}
#endif
void CBTDelayCACLK(DRAMC_CTX_T *p, S32 iDelay)
{
if (iDelay < 0)
{ /* Set CLK delay */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_CMD0),
P_Fld(0, SHU_R0_CA_CMD0_RG_ARPI_CMD) |
P_Fld(-iDelay, SHU_R0_CA_CMD0_RG_ARPI_CLK) |
P_Fld(-iDelay, SHU_R0_CA_CMD0_RG_ARPI_CS));
}
/*
else if (iDelay >= 64)
{
DramcCmdUIDelaySetting(p, 2);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_CMD0),
P_Fld(iDelay - 64, SHU_R0_CA_CMD0_RG_ARPI_CMD) |
P_Fld(0, SHU_R0_CA_CMD0_RG_ARPI_CLK) |
P_Fld(0, SHU_R0_CA_CMD0_RG_ARPI_CS));
}
*/
else
{ /* Set CA output delay */
// DramcCmdUIDelaySetting(p, 0);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_CMD0),
P_Fld(iDelay, SHU_R0_CA_CMD0_RG_ARPI_CMD) |
P_Fld(0, SHU_R0_CA_CMD0_RG_ARPI_CLK) |
P_Fld(0, SHU_R0_CA_CMD0_RG_ARPI_CS));
}
}
static void CBTAdjustCS(DRAMC_CTX_T *p, int autok)
{
S32 iFirstCSPass = 0, iLastCSPass = 0, iCSFinalDelay;//iCSCenter
U8 backup_rank, ii;
u32 pi_dly;
u32 cs_ui, cs_mck;
backup_rank = u1GetRank(p);
cs_ui = get_cs_ui(p);
cs_mck = get_cs_mck(p);
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_CBT)
if (p->femmc_Ready == 1)
{
CATrain_CsDelay[p->channel][p->rank] = p->pSavetimeData->u1CBTCsDelay_Save[p->channel][p->rank];
}
#endif
// if dual rank, use average position of both rank
if(backup_rank == RANK_1)
{
iCSFinalDelay = (CATrain_CsDelay[p->channel][RANK_0] + CATrain_CsDelay[p->channel][RANK_1]) >> 1;
}
else
{
iCSFinalDelay = CATrain_CsDelay[p->channel][p->rank];
}
//Set CS output delay after training
/* p->rank = RANK_0, save to Reg Rank0 and Rank1, p->rank = RANK_1, save to Reg Rank1 */
for (ii = RANK_0; ii <= backup_rank; ii++)
{
vSetRank(p, ii);
pi_dly = adjust_cs_ui(p, cs_mck, cs_ui, iCSFinalDelay);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_CMD0), pi_dly, SHU_R0_CA_CMD0_RG_ARPI_CS);
}
vSetRank(p, backup_rank);
mcSHOW_DBG_MSG(("CS Dly: %d (%d~%d)\n", iCSFinalDelay, iFirstCSPass, iLastCSPass));
}
#if CA_PER_BIT_DELAY_CELL
static void CATrainingSetPerBitDelayCell(DRAMC_CTX_T *p, S16 *iCAFinalCenter, U8 ca_pin_num)
{
U8 *uiLPDDR_CA_Mapping = NULL;
U8 u1CA;
S8 iCA_PerBit_DelayLine[8] = {0};
#if __LP5_COMBO__
if (is_lp5_family(p))
{
uiLPDDR_CA_Mapping = (U8 *)uiLPDDR5_CA_Mapping_POP[p->channel];
}
else
#endif
{
uiLPDDR_CA_Mapping = (U8 *)uiLPDDR4_CA_Mapping_POP[p->channel];
}
for (u1CA = 0;u1CA < ca_pin_num;u1CA++)
{
iCA_PerBit_DelayLine[uiLPDDR_CA_Mapping[u1CA]] = iCAFinalCenter[u1CA];
}
// Set CA perbit delay line calibration results
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_TXDLY0),
P_Fld(iCA_PerBit_DelayLine[0], SHU_R0_CA_TXDLY0_TX_ARCA0_DLY) |
P_Fld(iCA_PerBit_DelayLine[1], SHU_R0_CA_TXDLY0_TX_ARCA1_DLY) |
P_Fld(iCA_PerBit_DelayLine[2], SHU_R0_CA_TXDLY0_TX_ARCA2_DLY) |
P_Fld(iCA_PerBit_DelayLine[3], SHU_R0_CA_TXDLY0_TX_ARCA3_DLY));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_TXDLY1),
P_Fld(iCA_PerBit_DelayLine[4], SHU_R0_CA_TXDLY1_TX_ARCA4_DLY) |
P_Fld(iCA_PerBit_DelayLine[5], SHU_R0_CA_TXDLY1_TX_ARCA5_DLY) |
P_Fld(iCA_PerBit_DelayLine[6], SHU_R0_CA_TXDLY1_TX_ARCA6_DLY) |
P_Fld(iCA_PerBit_DelayLine[7], SHU_R0_CA_TXDLY1_TX_ARCA7_DLY));
}
#endif// end of CA_PER_BIT_DELAY_CELL
static void CBTSetCACLKResult(DRAMC_CTX_T *p, U32 u4MCK, U32 u4UI, S8 iFinalCACLK, U8 ca_pin_num)
{
U8 backup_rank, rank_i, uiCA;
S16 iCAFinalCenter[CATRAINING_NUM]={0}; //for CA_PER_BIT
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_CBT)
if (p->femmc_Ready == 1)
{
CATrain_CmdDelay[p->channel][p->rank] = p->pSavetimeData->s1CBTCmdDelay_Save[p->channel][p->rank];
vSetCalibrationResult(p, DRAM_CALIBRATION_CA_TRAIN, DRAM_FAST_K);
#if CA_PER_BIT_DELAY_CELL
for (uiCA = 0; uiCA < ca_pin_num; uiCA++)
iCAFinalCenter[uiCA] = p->pSavetimeData->u1CBTCA_PerBit_DelayLine_Save[p->channel][p->rank][uiCA];
#endif
}
#endif
iFinalCACLK = CATrain_CmdDelay[p->channel][p->rank];
mcSHOW_DBG_MSG(("\n[CBTSetCACLKResult] CA Dly = %d\n", iFinalCACLK));
iFinalCACLK = adjust_ca_ui(p, u4MCK, u4UI, iFinalCACLK);
backup_rank = u1GetRank(p);
for (rank_i = RANK_0; rank_i <= backup_rank;rank_i++)
{
vSetRank(p, rank_i);
CBTDelayCACLK(p, iFinalCACLK);
#if CA_PER_BIT_DELAY_CELL
CATrainingSetPerBitDelayCell(p, iCAFinalCenter, ca_pin_num);
#endif
}
vSetRank(p, backup_rank);
}
#if (__LP5_COMBO__)
/* Return (Vref_B0 | (Vref_B1 << 8) to support Byte mode */
static U8 GetCBTVrefPinMuxValue_lp5(DRAMC_CTX_T *p, U8 u1VrefLevel)
{
U8 u2VrefBit, u2Vref_org;
U16 u2Vref_new;
u2Vref_org = u1VrefLevel & 0x7f;
u2Vref_new = 0;
for (u2VrefBit = 0; u2VrefBit < 8; u2VrefBit++)
{
//mcSHOW_DBG_MSG(("=== u2VrefBit: %d, %d\n",u2VrefBit,uiLPDDR4_O1_Mapping_POP[p->channel][u2VrefBit]));
if (u2Vref_org & (1 << u2VrefBit))
{
u2Vref_new |= (1 << uiLPDDR5_O1_Mapping_POP[p->channel][u2VrefBit]);
}
}
mcSHOW_DBG_MSG3(("=== u2Vref_new: 0x%x --> 0x%x\n", u2Vref_org, u2Vref_new));
if (lp5_cp[p->channel].dram_dq_b0)
u2Vref_new >>= 8;
return u2Vref_new;
}
#endif
static U8 GetCBTVrefPinMuxValue(DRAMC_CTX_T *p, U8 u1VrefRange, U8 u1VrefLevel)
{
U8 u2VrefBit, u2Vref_org;
U16 u2Vref_new;
if (p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
return ((u1VrefRange & 0x1) << 6) | (u1VrefLevel & 0x3f);
u2Vref_org = ((u1VrefRange & 0x1) << 6) | (u1VrefLevel & 0x3f);
u2Vref_new = 0;
for (u2VrefBit = 0; u2VrefBit < 8; u2VrefBit++)
{
//mcSHOW_DBG_MSG(("=== u2VrefBit: %d, %d\n",u2VrefBit,uiLPDDR4_O1_Mapping_POP[p->channel][u2VrefBit]));
if (u2Vref_org & (1 << u2VrefBit))
{
u2Vref_new |= (1 << uiLPDDR4_O1_Mapping_POP[p->channel][u2VrefBit]);
}
}
mcSHOW_DBG_MSG3(("=== u2Vref_new: 0x%x --> 0x%x\n", u2Vref_org, u2Vref_new));
if (lp4_cp[p->channel].dram_dq_b0)
u2Vref_new >>= 8;
return u2Vref_new;
}
static void CBTSetVrefLP4(DRAMC_CTX_T *p, U8 u1VrefRange, U8 u1VrefLevel, U8 operating_fsp, U8 stateFlag)
{
U32 fld;
U8 u4DbgValue;
U8 u1VrefValue_pinmux;
struct cbt_pinmux *cp = &lp4_cp[p->channel];
if ((p->dram_cbt_mode[p->rank] == CBT_NORMAL_MODE) &&
(stateFlag == IN_CBT))
{
u1VrefValue_pinmux = GetCBTVrefPinMuxValue(p, u1VrefRange, u1VrefLevel);
#if !REDUCE_LOG_FOR_PRELOADER
mcSHOW_DBG_MSG(("\nCH_%d, RK_%d, Range=%d, VrefValue_pinmux = 0x%x\n", p->channel, p->rank, u1VrefRange, u1VrefValue_pinmux));
#endif
u1MR12Value[p->channel][p->rank][operating_fsp] = ((u1VrefRange & 0x1) << 6) | u1VrefLevel;
fld = (cp->dram_dq_b0) ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0;
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_WRITE_LEV), ((u1VrefRange&0x1) <<6) | (u1VrefLevel & 0x3f), WRITE_LEV_DMVREFCA); //MR12, bit[25:20]=OP[5:0] bit 26=OP[6]
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
u1VrefValue_pinmux, fld); //MR12, bit[25:20]=OP[5:0] bit 26=OP[6]
//DQS_SEL=1, DQS_B1_G=1, Toggle R_DMDQS_WLEV (1 to 0)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), (0x1 << cp->dram_dq_b0), CBT_WLEV_CTRL0_CBT_WLEV_DQS_SEL);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL3), 0xa, CBT_WLEV_CTRL3_DQSBX_G);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 1, CBT_WLEV_CTRL0_CBT_WLEV_DQS_TRIG);
mcDELAY_US(1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 0, CBT_WLEV_CTRL0_CBT_WLEV_DQS_TRIG);
}
else
{
if (operating_fsp == FSP_1)
{
DramcMRWriteFldAlign(p, 13, 1, MR13_FSP_WR, TO_MR);
}
u4DbgValue = (((u1VrefRange & 0x1) << 6) | (u1VrefLevel & 0x3f));
u1MR12Value[p->channel][p->rank][operating_fsp] = u4DbgValue;
mcSHOW_DBG_MSG3(("u4DbgValue = 0x%x\n", u4DbgValue));
DramcModeRegWriteByRank(p, p->rank, 12, u4DbgValue);
}
//wait tVREF_LONG
mcDELAY_US(1);
}
#if __LP5_COMBO__
static inline u8 is_training_mode1(DRAMC_CTX_T *p)
{
return is_lp5_family(p) && p->lp5_training_mode == TRAINING_MODE1? 1: 0;
}
static inline u8 is_training_mode2(DRAMC_CTX_T *p)
{
return is_lp5_family(p) && p->lp5_training_mode == TRAINING_MODE2? 1: 0;
}
static inline u8 is_phase_falling(DRAMC_CTX_T *p)
{
return is_lp5_family(p) && p->lp5_cbt_phase == CBT_PHASE_FALLING? 1: 0;
}
static void force_dq7(DRAMC_CTX_T *p, u8 level)
{
u32 fld_b0, fld_b1;
u8 dq;
u8 dramc_byte;
struct cbt_pinmux *cp = &lp5_cp[p->channel];
/*
* TODO
*
* pinmux to selec dq7
*
*/
fld_b0 = (cp->dram_dq_b0) ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0;
fld_b1 = (cp->dram_dq_b1) ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0;
dq = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
fld_b0);
dq &= ~(1 << (cp->dram_dq7_b0 % 8));
dq |= ((level & 1) << (cp->dram_dq7_b0 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
P_Fld(dq, fld_b0));
if (is_byte_mode(p)) {
dq = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
fld_b1);
dq &= ~(1 << (cp->dram_dq7_b1 % 8));
dq |= ((level & 1) << (cp->dram_dq7_b1 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
P_Fld(dq, fld_b1));
}
}
static inline void force_dmi(DRAMC_CTX_T *p, u8 level)
{
struct cbt_pinmux *cp = &lp5_cp[p->channel];
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(level, (cp->dram_dmi_b0) ? CBT_WLEV_CTRL0_CBT_SW_DQM_B1_LP5 : CBT_WLEV_CTRL0_CBT_SW_DQM_B0_LP5));
if (is_byte_mode(p)) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(level, (cp->dram_dmi_b1 ? CBT_WLEV_CTRL0_CBT_SW_DQM_B1_LP5 : CBT_WLEV_CTRL0_CBT_SW_DQM_B0_LP5)));
}
}
static void toggle_wck(DRAMC_CTX_T *p, u8 toggle)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(toggle, CBT_WLEV_CTRL0_CBT_WLEV_WCKAO));
}
static void set_vref_by_mrw(DRAMC_CTX_T *p, u8 vref)
{
DramcModeRegWriteByRank(p, p->rank, 12, vref);
}
static void set_vref_by_dq(DRAMC_CTX_T *p, u16 vref)
{
u8 dq;
struct cbt_pinmux *cp = &lp5_cp[p->channel];
force_dmi(p, 0);
/* wait tCBTRTW */
mcDELAY_US(1);
if (is_byte_mode(p)) {
/* DRAMC B0/B1 as TX */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
3, CBT_WLEV_CTRL0_CBT_DQBYTE_OEAO_EN);
/* Set DRAM Byte 1 */
dq = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
(cp->dram_dq_b1 ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0));
/* Shall be carefully processed in case DQ[7] is changed */
dq &= (1 << (cp->dram_dq7_b1 % 8));
dq |= ((vref >> 8) & 0xff);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
P_Fld(dq, (cp->dram_dq_b1 ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0)));
} else {
/* DRAMC B0 as TX */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
(1 << cp->dram_dq_b0), CBT_WLEV_CTRL0_CBT_DQBYTE_OEAO_EN);
}
/* Set DRAM Byte 0 */
dq = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
(cp->dram_dq_b0 ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0));
dq &= (1 << (cp->dram_dq7_b0 % 8));
dq |= (vref & 0xff);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4),
P_Fld(dq, (cp->dram_dq_b0 ? CBT_WLEV_CTRL4_CBT_TXDQ_B1 : CBT_WLEV_CTRL4_CBT_TXDQ_B0)));
/* wait tDQStrain */
mcDELAY_US(1);
force_dmi(p, 1);
mcDELAY_US(1);
/* DRAMC B0/B1 as RX */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
0, CBT_WLEV_CTRL0_CBT_DQBYTE_OEAO_EN);
mcDELAY_US(1);
}
static void switch_oe_tie(DRAMC_CTX_T *p, u8 sw)
{
u8 dq_oe;
struct cbt_pinmux *cp = &lp5_cp[p->channel];
if (sw) {
/* Set DRAM Byte 0 */
if (cp->dram_dq_b0) {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1);
dq_oe |= (1 << (cp->dram_dq7_b0 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(dq_oe, B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1) |
P_Fld(1, B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(1, B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1) |
P_Fld(1, B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1));
} else {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0);
dq_oe |= (1 << (cp->dram_dq7_b0 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(dq_oe, B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0) |
P_Fld(1, B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(1, B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0) |
P_Fld(1, B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0));
}
/* Set DRAM Byte 1 */
if (is_byte_mode(p)) {
/* Set DRAM Byte 0 */
if (cp->dram_dq_b1) {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1);
dq_oe |= (1 << (cp->dram_dq7_b1 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(dq_oe, B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1) |
P_Fld(1, B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(1, B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1) |
P_Fld(1, B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1));
} else {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0);
dq_oe |= (1 << (cp->dram_dq7_b1 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(dq_oe, B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0) |
P_Fld(1, B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(1, B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0) |
P_Fld(1, B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0));
}
}
} else {
/* Set DRAM Byte 0 */
if (cp->dram_dq_b0) {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1);
dq_oe &= ~(1 << (cp->dram_dq7_b0 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(dq_oe, B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1) |
P_Fld(0, B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(0, B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1) |
P_Fld(0, B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1));
} else {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0);
dq_oe &= ~(1 << (cp->dram_dq7_b0 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(dq_oe, B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0) |
P_Fld(0, B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(0, B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0) |
P_Fld(0, B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0));
}
/* Set DRAM Byte 1 */
if (is_byte_mode(p)) {
/* Set DRAM Byte 0 */
if (cp->dram_dq_b1) {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1);
dq_oe &= ~(1 << (cp->dram_dq7_b1 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(dq_oe, B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1) |
P_Fld(0, B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2),
P_Fld(0, B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1) |
P_Fld(0, B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1));
} else {
dq_oe = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0);
dq_oe &= ~(0 << (cp->dram_dq7_b1 % 8));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(dq_oe, B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0) |
P_Fld(0, B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2),
P_Fld(0, B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0) |
P_Fld(0, B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0));
}
}
}
}
static void lp5_cbt_entry(DRAMC_CTX_T *p, u8 operating_fsp,
u16 operation_frequency)
{
lp5heff_save_disable(p);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL),
0, MISC_STBCAL_DQSIENCG_NORMAL_EN);
/* TCMDEN and CATRAINEN use MRSRK */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0),
p->rank, SWCMD_CTRL0_MRSRK);
#if 0
if (p->rank == RANK_0) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(0, CKECTRL_CKEFIXOFF) |
P_Fld(1, CKECTRL_CKEFIXON));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(1, CKECTRL_CKE1FIXOFF) |
P_Fld(0, CKECTRL_CKE1FIXON));
} else if (p->rank == RANK_1) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(0, CKECTRL_CKE1FIXOFF) |
P_Fld(1, CKECTRL_CKE1FIXON));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(1, CKECTRL_CKEFIXOFF) |
P_Fld(0, CKECTRL_CKEFIXON));
}
#else
if (p->rank == RANK_0) {
CKEFixOnOff(p, RANK_0, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
CKEFixOnOff(p, RANK_1, CKE_FIXOFF, CKE_WRITE_TO_ONE_CHANNEL);
} else if (p->rank == RANK_1){
CKEFixOnOff(p, RANK_1, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
CKEFixOnOff(p, RANK_0, CKE_FIXOFF, CKE_WRITE_TO_ONE_CHANNEL);
}
#endif
/*
* APHY TX PI Spec mode option
* for K RK1, if RK0/1 DQ UI setting is not the same, it will fail
*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_NEW_XRW2W_CTRL),
1, SHU_NEW_XRW2W_CTRL_TXPI_UPD_MODE);
/*
* APHY TX PI Spec mode option
* for K RK1, if RK0/1 DQ UI setting is not the same, it will fail
*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_NEW_XRW2W_CTRL),
1, SHU_NEW_XRW2W_CTRL_TXPI_UPD_MODE);
/*
* APHY TX PI Spec mode option
* for K RK1, if RK0/1 DQ UI setting is not the same, it will fail
*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_NEW_XRW2W_CTRL),
1, SHU_NEW_XRW2W_CTRL_TXPI_UPD_MODE);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(0x1, CBT_WLEV_CTRL0_WRITE_LEVEL_EN));
/*
* TODO
* BYTEMODE, PINMUX
*/
if (is_training_mode1(p)) {
/* DRAMC B0 as RX */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
0, CBT_WLEV_CTRL0_CBT_DQBYTE_OEAO_EN);
}
switch_oe_tie(p, 1);
/*
* MR13 OP[6], cbt mode
* 0, training mode 1
* 1, training mode 2
*
* TODO
* MR13 values??
*/
DramcModeRegWriteByRank(p, p->rank, 13, p->lp5_training_mode << 6);
if (operating_fsp == FSP_2) {
/*
* dram will switch to another FSP_OP automatically
*/
DramcModeRegWriteByRank(p, p->rank, 16,
(2 << MR16_FSP_WR_SHIFT) |
(2 << MR16_FSP_OP_SHIFT) |
(p->lp5_cbt_phase << MR16_CBT_PHASE) |
/* CBT enabled fsp[2] */
(3 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
} else if (operating_fsp == FSP_1) {
/*
* dram will switch to another FSP_OP automatically
*/
DramcModeRegWriteByRank(p, p->rank, 16,
(1 << MR16_FSP_WR_SHIFT) |
(1<< MR16_FSP_OP_SHIFT) |
(p->lp5_cbt_phase << MR16_CBT_PHASE) |
/* CBT enabled fsp[1] */
(2 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
} else {
/* FSP_0 */
DramcModeRegWriteByRank(p, p->rank, 16,
(0 << MR16_FSP_WR_SHIFT) |
(0 << MR16_FSP_OP_SHIFT) |
(p->lp5_cbt_phase << MR16_CBT_PHASE) |
/* CBT enabled fsp[0] */
(1 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
}
/* wait tCBTWCKPRE_static */
mcDELAY_US(1);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL3),
P_Fld(0x5, CBT_WLEV_CTRL3_DQSBX_G) |
P_Fld(0x5, CBT_WLEV_CTRL3_DQSBY_G) |
P_Fld(0x5, CBT_WLEV_CTRL3_DQSBX1_G) |
P_Fld(0x5, CBT_WLEV_CTRL3_DQSBY1_G));
if (is_byte_mode(p)) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 3,
CBT_WLEV_CTRL0_CBT_WLEV_DQS_SEL);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), P_Fld(1, CBT_WLEV_CTRL0_BYTEMODECBTEN) |
P_Fld(1, CBT_WLEV_CTRL0_CBT_CMP_BYTEMODE)); //BYTEMODECBTEN=1
} else {
if (lp5_cp[p->channel].dram_dq7_b0)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 0x2,
CBT_WLEV_CTRL0_CBT_WLEV_DQS_SEL);
else
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 0x1,
CBT_WLEV_CTRL0_CBT_WLEV_DQS_SEL);
}
/* toggle WCK */
toggle_wck(p, 1);
/* wait tWCK2DQ7H */
mcDELAY_US(1);
/* DQ[7] = High */
force_dq7(p, 1);
/* wait tDQ7HWCK to switch FSP */
mcDELAY_US(1);
/* stop toggle WCK */
toggle_wck(p, 0);
/* wait tDQ72DQ */
mcDELAY_US(1);
O1PathOnOff(p, 1);
/* start toggle WCK */
toggle_wck(p, 1);
/* Wait tCAENT */
mcDELAY_US(1);
}
static void lp5_cbt_exit(DRAMC_CTX_T *p, u8 operating_fsp,
u8 operation_frequency)
{
/* drive dq7 low */
force_dq7(p, 0);
/* wait tDQ7WCK */
mcDELAY_US(1);
/* stop wck toggle */
toggle_wck(p, 0);
/* wait tVREFCA_LOGNG */
mcDELAY_US(1);
if (operating_fsp == FSP_2) {
DramcModeRegWriteByRank(p, p->rank, 16,
(2 << MR16_FSP_WR_SHIFT) |
(2 << MR16_FSP_OP_SHIFT) |
(0 << MR16_CBT_PHASE) |
/* normal operation */
(0 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
} else if (operating_fsp == FSP_1) {
DramcModeRegWriteByRank(p, p->rank, 16,
(1 << MR16_FSP_WR_SHIFT) |
(1 << MR16_FSP_OP_SHIFT) |
(0 << MR16_CBT_PHASE) |
/* normal operation */
(0 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
} else {
DramcModeRegWriteByRank(p, p->rank, 16,
(0 << MR16_FSP_WR_SHIFT) |
(0 << MR16_FSP_OP_SHIFT) |
(0 << MR16_CBT_PHASE) |
/* normal operation */
(0 << MR16_FSP_CBT) |
(1 << MR16_VRCG));
}
/* wait tMRD */
mcDELAY_US(1);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0),
P_Fld(0x0, CBT_WLEV_CTRL0_WRITE_LEVEL_EN));
switch_oe_tie(p, 0);
/*
* APHY TX PI Spec mode option
* for K RK1, if RK0/1 DQ UI setting is not the same, it will fail
*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_NEW_XRW2W_CTRL),
0, SHU_NEW_XRW2W_CTRL_TXPI_UPD_MODE);
/* Disable O1 path output */
O1PathOnOff(p, 0);
if (is_byte_mode(p)) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), P_Fld(0, CBT_WLEV_CTRL0_BYTEMODECBTEN) |
P_Fld(0, CBT_WLEV_CTRL0_CBT_CMP_BYTEMODE)); //BYTEMODECBTEN=1
}
#if 0
if (p->rank == RANK_0) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(0, CKECTRL_CKEFIXOFF) |
P_Fld(0, CKECTRL_CKEFIXON));
} else if (p->rank == RANK_1) {
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL),
P_Fld(0, CKECTRL_CKE1FIXOFF) |
P_Fld(0, CKECTRL_CKE1FIXON));
}
#else
CKEFixOnOff(p, CKE_WRITE_TO_ALL_RANK, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
#endif
lp5heff_restore(p);
}
#endif
static void CBTEntryLP45(DRAMC_CTX_T *p, U8 u1FSP, U16 u2Freq)
{
#if __LP5_COMBO__
if (is_lp5_family(p))
{
lp5_cbt_entry(p, u1FSP, u2Freq);
}
else
#endif
{
if(p->dram_fsp == FSP_1)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(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));
cbt_switch_freq(p, CBT_LOW_FREQ);
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));
}
#if ENABLE_LP4Y_WA //@Darren, debugging for DFS stress
CmdBusTrainingLP4YWA(p, DISABLE);
#endif
CBTEntryLP4(p, u1FSP, u2Freq);
if(p->dram_fsp == FSP_1)
{
cbt_switch_freq(p, CBT_HIGH_FREQ);
}
}
}
static void CBTExitLP45(DRAMC_CTX_T *p, U8 u1FSP, U8 u2Freq, U8 stateFlag)
{
/* by yirong.wang
* if stateFlag == OUT_CBT, it means we finished CBT, exit CBT
* if stateFlag == IN_CBT, it means we are trying to setup vref by MRW
* IN_CBT case, only for LP5 mode 1 and LP4 byte mode
*/
#if __LP5_COMBO__
if (is_lp5_family(p))
{
if (stateFlag == OUT_CBT || is_training_mode1(p))
{
lp5_cbt_exit(p, u1FSP, u2Freq);
}
}
else
#endif
{
if (stateFlag == OUT_CBT || p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
(p->dram_fsp == FSP_1)? cbt_switch_freq(p, CBT_LOW_FREQ): NULL;
CBTExitLP4(p, u1FSP, u2Freq);
#if ENABLE_LP4Y_WA //@Darren, debugging for DFS stress
CmdBusTrainingLP4YWA(p, ENABLE);
#endif
}
}
}
static void CBTSetVrefLP45(DRAMC_CTX_T *p, U8 u1VrefRange, U8 u1VrefLevel, U8 u1FSP, U16 u2Freq, U8 stateFlag)
{
/* by yirong.wang
* if stateFlag == OUT_CBT, it means we are not in CBT, setup vref by MRW
* if stateFlag == IN_CBT, it means we are doing CBT
* LP5 training mode 1 and LP4 byte mode, exit CBT and setup vref by MRW, then re-enter CBT
* LP5 training mode 2 and LP4 normal mode, setup vref by DQ
*/
#if __LP5_COMBO__
if (is_lp5_family(p))
{
if (stateFlag == IN_CBT && is_training_mode2(p))
{
/*
* training mode2
* TODO, according to pinmux to adjust u1VrefLevel
*/
set_vref_by_dq(p, GetCBTVrefPinMuxValue_lp5(p, u1VrefLevel));
}
else
{
if (stateFlag == IN_CBT && is_training_mode1(p))
{
lp5_cbt_exit(p, u1FSP, u2Freq);
}
set_vref_by_mrw(p, u1VrefLevel);
if (stateFlag == IN_CBT && is_training_mode1(p))
{
lp5_cbt_entry(p, u1FSP, u2Freq);
}
}
}
else
#endif
{
if (stateFlag == IN_CBT && p->dram_cbt_mode[p->rank] == CBT_BYTE_MODE1)
{
// BYTE MODE: We are not in CBT now, set Vref & enter CBT
(p->dram_fsp == FSP_1)? cbt_switch_freq(p, CBT_LOW_FREQ): NULL;
CBTExitLP4(p, u1FSP, u2Freq);
CBTSetVrefLP4(p, u1VrefRange, u1VrefLevel, u1FSP, stateFlag);
CBTEntryLP4(p, u1FSP, u2Freq);
if(p->dram_fsp == FSP_1)
{
cbt_switch_freq(p, CBT_HIGH_FREQ);
}
}
else
{
CBTSetVrefLP4(p, u1VrefRange, u1VrefLevel, u1FSP, stateFlag);
}
}
}
DRAM_STATUS_T CmdBusTrainingLP45(DRAMC_CTX_T *p, int autok)
{
U8 u1FinalVref, u1FinalRange=0;
S8 iFinalCACLK;
U32 uiCAWinSumMax;
U8 operating_fsp;
U16 operation_frequency;
#if CA_PER_BIT_DELAY_CELL
S16 iCAFinalCenter[CATRAINING_NUM] = {0}; //for CA_PER_BIT
#endif
#if ENABLE_EYESCAN_GRAPH
U8 u1CBTEyeScanEnable;
U8 EyeScan_index[CATRAINING_NUM];
#endif
S16 pi_step;
S16 pi_start, pi_end;
u32 ca_ui, ca_ui_default;
u32 ca_mck;
u32 ca_cmd0;
u8 ca_pin_num;
u16 p2u;
u8 step_respi = AUTOK_RESPI_1;
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL)),
(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ2)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ2)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL1)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL2)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL3)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL4)),
(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0)),
(DRAMC_REG_ADDR(DRAMC_REG_REFCTRL0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_VREF)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_VREF)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_PHY_VREF_SEL)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_PHY_VREF_SEL)), //in O1PathOnOff()
};
p2u = get_ca_pi_per_ui(p);
pi_end = p2u * 2 - 1;
#if FOR_DV_SIMULATION_USED == 1
pi_step = (vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE) ? 16 : 8; //for simulation speed up
#else
pi_step = get_capi_step(p);
#endif
switch (p->freq_sel) {
case LP5_DDR4266:
case LP5_DDR800:
case LP5_DDR1200:
case LP5_DDR1600:
case LP5_DDR3733:
case LP5_DDR2400:
case LP5_DDR3200:
case LP5_DDR4800:
case LP5_DDR5500:
case LP5_DDR6000:
case LP5_DDR6400:
pi_start = -8;
break;
default:
/* LPDDR4 */
if (u1IsPhaseMode(p) == TRUE)
{
step_respi = AUTOK_RESPI_8;
}
#if CBT_MOVE_CA_INSTEAD_OF_CLK
pi_start = -16;
pi_end = p2u * 3 - 1;
#else
if (vGet_DDR_Loop_Mode(p) == SEMI_OPEN_LOOP_MODE)
{
pi_start = -24;
}
else if (vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE)
{
pi_start = -16;
}
else
{
pi_start = -MAX_CLK_PI_DELAY;
}
#endif
break;
}
#if MRW_CHECK_ONLY
mcSHOW_MRW_MSG(("\n==[MR Dump] %s==\n", __func__));
#endif
#if __LP5_COMBO__
if (is_lp5_family(p))
{
u1FinalVref = u1MR12Value[p->channel][p->rank][p->dram_fsp];
ca_pin_num = CATRAINING_NUM_LP5;
}
else
#endif
{
u1FinalRange = u1MR12Value[p->channel][p->rank][p->dram_fsp] >> 6;
u1FinalVref = u1MR12Value[p->channel][p->rank][p->dram_fsp] & 0x3f;
ca_pin_num = CATRAINING_NUM_LP4;
}
#if ENABLE_EYESCAN_GRAPH
u1CBTEyeScanEnable =GetEyeScanEnable(p, 0);
for (u1vrefidx = 0; u1vrefidx < VREF_VOLTAGE_TABLE_NUM_LP5-1; u1vrefidx++)
{
for (uiCA = 0; uiCA < ca_pin_num; uiCA++)
{
for (ii = 0; ii < EYESCAN_BROKEN_NUM; ii++)
{
gEyeScan_Min[u1vrefidx][uiCA][ii] = EYESCAN_DATA_INVALID;
gEyeScan_Max[u1vrefidx][uiCA][ii] = EYESCAN_DATA_INVALID;
}
}
}
#endif
vPrintCalibrationBasicInfo(p);
mcSHOW_DBG_MSG(("pi_start=%d, pi_end=%d, pi_step=%d, new_cbt_mode=%d, autok=%d\n",
pi_start, pi_end, pi_step, p->new_cbt_mode, autok));
#if __LP5_COMBO__
if (is_lp5_family(p))
{
mcSHOW_DBG_MSG(("lp5_training_mode=%d, lp5_cbt_phase=%d\n", p->lp5_training_mode, p->lp5_cbt_phase));
}
#endif
//Back up dramC register
DramcBackupRegisters(p, u4RegBackupAddress, ARRAY_SIZE(u4RegBackupAddress));
//default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_CA_TRAIN, DRAM_FAIL);
#if CA_PER_BIT_DELAY_CELL
CATrainingSetPerBitDelayCell(p, iCAFinalCenter, ca_pin_num);
#endif
#if CBT_MOVE_CA_INSTEAD_OF_CLK
if (u1IsLP4Family(p->dram_type))
{
U8 u1CaPI = 0, u1CaUI = 0;
u1CaUI = 1;
u1CaPI = 0;
DramcCmdUIDelaySetting(p, u1CaUI);
CBTDelayCACLK(p, u1CaPI);
}
#endif
/* read ca ui and mck */
ca_ui_default = ca_ui = get_ca_ui(p);
ca_mck = get_ca_mck(p);
ca_cmd0 = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_CA_CMD0));
vAutoRefreshSwitch(p, DISABLE); //When doing CA training, should make sure that auto refresh is disable
/*
* TOOD
*
* here just pass simulation,
* remove after ACTiming OK(ACTiming Table includes CATRAIN_INTV)
*/
//vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL1),
// P_Fld(0x1F, CBT_WLEV_CTRL1_CATRAIN_INTV));
set_cbt_wlev_intv(p);
/*
* tx_rank_sel is selected by SW
* Lewis@20180509: tx_rank_sel is selected by SW in CBT if TMRRI design has changed.
*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0),
p->rank, TX_SET0_TXRANK);
/* TXRANKFIX should be write after TXRANK or the rank will be fix at rank 1 */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0),
1, TX_SET0_TXRANKFIX);
//SW variable initialization
uiCAWinSumMax = 0;
iFinalCACLK = 0;
operating_fsp = p->dram_fsp;
operation_frequency = p->frequency;
// free-run dramc/ddrphy clk (DCMEN2=0, MIOCKCTRLOFF=1, PHYCLKDYNGEN=0, COMBCLKCTRL=0)
// free-run dram clk(APHYCKCG_FIXOFF =1, TCKFIXON=1)
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL),
P_Fld(0, DRAMC_PD_CTRL_DCMEN2) |
P_Fld(1, DRAMC_PD_CTRL_MIOCKCTRLOFF) |
P_Fld(0, DRAMC_PD_CTRL_PHYCLKDYNGEN) |
P_Fld(0, DRAMC_PD_CTRL_COMBCLKCTRL) |
P_Fld(1, DRAMC_PD_CTRL_APHYCKCG_FIXOFF) |
P_Fld(1, DRAMC_PD_CTRL_TCKFIXON));
//Note : Assume that there is a default CS value that can apply for CA.
CBTEntryLP45(p, operating_fsp, operation_frequency);
#if PINMUX_AUTO_TEST_PER_BIT_CA
CheckCADelayCell(p);
#endif
//Step 3: set vref range and step by ddr type
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && (BYPASS_VREF_CAL || BYPASS_CBT))
if (p->femmc_Ready == 1)
{
u1FinalVref = p->pSavetimeData->u1CBTVref_Save[p->channel][p->rank];
}
#endif
mcSHOW_DBG_MSG(("\n[CmdBusTrainingLP45] Vref(ca) range %d: %d\n", u1FinalRange, u1FinalVref));
#ifdef FOR_HQA_TEST_USED
gFinalCBTVrefCA[p->channel][p->rank] = u1FinalVref;
#endif
//Set Vref after training
// BYTE MODE: Set Vref & enter CBT
CBTSetVrefLP45(p, u1FinalRange, u1FinalVref, operating_fsp, operation_frequency, IN_CBT);
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_CBT)
#if CBT_MOVE_CA_INSTEAD_OF_CLK
// scan UI from 0, not from the UI we used to enter CBT
DramcCmdUIDelaySetting(p, 0);
ca_ui = get_ca_ui(p);
#endif
#endif
put_ca_ui(p, ca_ui);
//Set CA_PI_Delay after training
CBTSetCACLKResult(p, ca_mck, ca_ui, iFinalCACLK, ca_pin_num);
#if ENABLE_EYESCAN_GRAPH
gEyeScan_CaliDelay[0] = CATrain_CmdDelay[p->channel][p->rank] -pi_start;
#endif
//mcSHOW_DBG_MSG(("\nAverage CA Dly: %d\n", iFinalCACLK));
/* ------------- CS and CLK ---------- */
/* delay ca 1UI before K CS */
#if __LP5_COMBO__
if (is_phase_falling(p)) {
ca_mck = get_ca_mck(p);
ca_ui = get_ca_ui(p);
xlate_ca_mck_ui(p, 1,
ca_mck, ca_ui,
&ca_mck_tmp, &ca_ui_tmp);
put_ca_mck(p, ca_mck_tmp);
put_ca_ui(p, ca_ui_tmp);
}
#endif
CBTAdjustCS(p, autok);
/* restore ca mck and ui */
#if __LP5_COMBO__
if (is_phase_falling(p)) {
put_ca_mck(p, ca_mck);
put_ca_ui(p, ca_ui);
}
#endif
//------- Going to exit Command bus training(CBT) mode.-------------
CBTExitLP45(p, operating_fsp, operation_frequency, OUT_CBT);
CBTSetVrefLP45(p, u1FinalRange, u1FinalVref, operating_fsp, operation_frequency, OUT_CBT);
#if __LP5_COMBO__
if (!is_lp5_family(p))
#endif
{
if (p->dram_fsp == FSP_1)
{
#if MR_CBT_SWITCH_FREQ
DramcModeRegInit_CATerm(p, 0);
#else
DramcMRWriteFldAlign(p, 13, 1, MR13_FSP_OP, TO_MR);
#endif
}
}
#if EYESCAN_LOG || defined(FOR_HQA_TEST_USED)
gFinalCBTVrefDQ[p->channel][p->rank] = u1FinalVref;
#endif
mcSHOW_DBG_MSG3(("\n[CmdBusTrainingLP45] Done\n"));
//tx_rank_sel is selected by HW //Lewis@20180509: tx_rank_sel is selected by SW in CBT if TMRRI design has changed.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), 0, TX_SET0_TXRANK);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), 0, TX_SET0_TXRANKFIX); //TXRANKFIX should be write after TXRANK or the rank will be fix at rank 1
//Restore setting registers
DramcRestoreRegisters(p, u4RegBackupAddress, ARRAY_SIZE(u4RegBackupAddress));
return DRAM_OK;
}
#endif /* SIMUILATION_CBT */
//-------------------------------------------------------------------------
/** DramcWriteLeveling
* start Write Leveling Calibration.
* @param p Pointer of context created by DramcCtxCreate.
* @param apply (U8): 0 don't apply the register we set 1 apply the register we set ,default don't apply.
* @retval status (DRAM_STATUS_T): DRAM_OK or DRAM_FAIL
*/
//-------------------------------------------------------------------------
#define WRITE_LEVELING_MOVD_DQS 1//UI
U8 u1MCK2UI_DivShift(DRAMC_CTX_T *p)
{
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
//in LP4 1:8 mode, 8 small UI = 1 large UI
if (vGet_Div_Mode(p) == DIV4_MODE)
{
return MCK_TO_4UI_SHIFT;
}
else if (vGet_Div_Mode(p) == DIV16_MODE)
{
return MCK_TO_16UI_SHIFT;
}
else
{
return MCK_TO_8UI_SHIFT;
}
}
else
#endif
{
//in LP4 1:8 mode, 8 small UI = 1 large UI
if (vGet_Div_Mode(p) == DIV4_MODE)
{
return MCK_TO_4UI_SHIFT;
}
else
{
return MCK_TO_8UI_SHIFT;
}
}
}
static DRAM_STATUS_T ExecuteMoveDramCDelay(DRAMC_CTX_T *p,
REG_TRANSFER_T ui_reg,
REG_TRANSFER_T mck_reg,
S8 iShiftUI)
{
S32 s4HighLevelDelay, s4DelaySum;
U32 u4TmpUI, u4TmpMCK;
U8 ucDataRateDivShift = 0;
DRAM_STATUS_T MoveResult;
ucDataRateDivShift = u1MCK2UI_DivShift(p);
u4TmpUI = u4IO32ReadFldAlign(DRAMC_REG_ADDR(ui_reg.u4Addr), ui_reg.u4Fld) & (~(1 << ucDataRateDivShift));
u4TmpMCK = u4IO32ReadFldAlign(DRAMC_REG_ADDR(mck_reg.u4Addr), mck_reg.u4Fld);
//mcSHOW_DBG_MSG(("Base: u4TmpMCK:%d, u4TmpUI: %d,\n", u4TmpMCK, u4TmpUI));
s4HighLevelDelay = (u4TmpMCK << ucDataRateDivShift) + u4TmpUI;
s4DelaySum = (s4HighLevelDelay + iShiftUI);
if (s4DelaySum < 0)
{
u4TmpUI = 0;
u4TmpMCK = 0;
MoveResult = DRAM_FAIL;
}
else
{
u4TmpMCK = s4DelaySum >> ucDataRateDivShift;
u4TmpUI = s4DelaySum - (u4TmpMCK << ucDataRateDivShift);
MoveResult = DRAM_OK;
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(ui_reg.u4Addr), u4TmpUI, ui_reg.u4Fld);
vIO32WriteFldAlign(DRAMC_REG_ADDR(mck_reg.u4Addr), u4TmpMCK, mck_reg.u4Fld);
//mcSHOW_DBG_MSG(("[%d] Final ==> u4TmpMCK:%d, u4TmpUI: %d,\n", iShiftUI, u4TmpMCK, u4TmpUI));
return MoveResult;
}
static void _LoopAryToDelay(DRAMC_CTX_T *p,
REG_TRANSFER_T *ui_reg,
REG_TRANSFER_T *mck_reg,
U8 u8RG_num,
S8 iShiftUI,
BYTES_T eByteIdx)
{
U8 idx = 0, step = 1;
if (eByteIdx == BYTE_0)
{
idx = 0;
step = 2;
}
else if (eByteIdx == BYTE_1)
{
idx = 1;
step = 2;
}
for (; idx < u8RG_num; idx += step)
{
ExecuteMoveDramCDelay(p, ui_reg[idx], mck_reg[idx], iShiftUI);
}
}
static void LP4_ShiftDQSUI(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
// DQS / DQS_OEN
REG_TRANSFER_T TransferUIRegs[] = {{DRAMC_REG_SHU_SELPH_DQS1, SHU_SELPH_DQS1_DLY_DQS0}, // Byte0
{DRAMC_REG_SHU_SELPH_DQS1, SHU_SELPH_DQS1_DLY_DQS1}}; // Byte1
REG_TRANSFER_T TransferMCKRegs[] = {{DRAMC_REG_SHU_SELPH_DQS0, SHU_SELPH_DQS0_TXDLY_DQS0},
{DRAMC_REG_SHU_SELPH_DQS0, SHU_SELPH_DQS0_TXDLY_DQS1}};
_LoopAryToDelay(p, TransferUIRegs, TransferMCKRegs,
sizeof(TransferUIRegs) / sizeof(REG_TRANSFER_T),
iShiftUI, eByteIdx);
}
void LP4_ShiftDQS_OENUI(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
// DQS / DQS_OEN
REG_TRANSFER_T TransferUIRegs[] = {{DRAMC_REG_SHU_SELPH_DQS1, SHU_SELPH_DQS1_DLY_OEN_DQS0}, // Byte0
{DRAMC_REG_SHU_SELPH_DQS1, SHU_SELPH_DQS1_DLY_OEN_DQS1}}; // Byte1
REG_TRANSFER_T TransferMCKRegs[] = {{DRAMC_REG_SHU_SELPH_DQS0, SHU_SELPH_DQS0_TXDLY_OEN_DQS0},
{DRAMC_REG_SHU_SELPH_DQS0, SHU_SELPH_DQS0_TXDLY_OEN_DQS1}};
_LoopAryToDelay(p, TransferUIRegs, TransferMCKRegs,
sizeof(TransferUIRegs) / sizeof(REG_TRANSFER_T),
iShiftUI, eByteIdx);
}
static void ShiftDQUI(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
// Shift DQ / DQM / DQ_OEN / DQM_OEN
REG_TRANSFER_T TransferUIRegs[] = {{DRAMC_REG_SHURK_SELPH_DQ3, SHURK_SELPH_DQ3_DLY_DQM0}, // Byte0
{DRAMC_REG_SHURK_SELPH_DQ3, SHURK_SELPH_DQ3_DLY_DQM1}, // Byte1
{DRAMC_REG_SHURK_SELPH_DQ2, SHURK_SELPH_DQ2_DLY_DQ0}, // Byte0
{DRAMC_REG_SHURK_SELPH_DQ2, SHURK_SELPH_DQ2_DLY_DQ1}}; // Byte1
REG_TRANSFER_T TransferMCKRegs[] = {{DRAMC_REG_SHURK_SELPH_DQ1, SHURK_SELPH_DQ1_TXDLY_DQM0},
{DRAMC_REG_SHURK_SELPH_DQ1, SHURK_SELPH_DQ1_TXDLY_DQM1},
{DRAMC_REG_SHURK_SELPH_DQ0, SHURK_SELPH_DQ0_TXDLY_DQ0},
{DRAMC_REG_SHURK_SELPH_DQ0, SHURK_SELPH_DQ0_TXDLY_DQ1}};
_LoopAryToDelay(p, TransferUIRegs, TransferMCKRegs,
sizeof(TransferUIRegs) / sizeof(REG_TRANSFER_T),
iShiftUI, eByteIdx);
}
static void ShiftDQUI_AllRK(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
U8 backup_rank, rk_i;
backup_rank = u1GetRank(p);
// Shift DQ / DQM / DQ_OEN / DQM_OEN
for (rk_i = RANK_0; rk_i < p->support_rank_num; rk_i++)
{
vSetRank(p, rk_i);
ShiftDQUI(p, iShiftUI, eByteIdx);
}
vSetRank(p, backup_rank);
}
static void ShiftDQ_OENUI(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
REG_TRANSFER_T TransferUIRegs[] = {{DRAMC_REG_SHURK_SELPH_DQ3, SHURK_SELPH_DQ3_DLY_OEN_DQM0}, // Byte0
{DRAMC_REG_SHURK_SELPH_DQ3, SHURK_SELPH_DQ3_DLY_OEN_DQM1}, // Byte1
{DRAMC_REG_SHURK_SELPH_DQ2, SHURK_SELPH_DQ2_DLY_OEN_DQ0}, // Byte0
{DRAMC_REG_SHURK_SELPH_DQ2, SHURK_SELPH_DQ2_DLY_OEN_DQ1}}; // Byte1
REG_TRANSFER_T TransferMCKRegs[] = {{DRAMC_REG_SHURK_SELPH_DQ1, SHURK_SELPH_DQ1_TXDLY_OEN_DQM0},
{DRAMC_REG_SHURK_SELPH_DQ1, SHURK_SELPH_DQ1_TXDLY_OEN_DQM1},
{DRAMC_REG_SHURK_SELPH_DQ0, SHURK_SELPH_DQ0_TXDLY_OEN_DQ0},
{DRAMC_REG_SHURK_SELPH_DQ0, SHURK_SELPH_DQ0_TXDLY_OEN_DQ1}};
_LoopAryToDelay(p, TransferUIRegs, TransferMCKRegs,
sizeof(TransferUIRegs) / sizeof(REG_TRANSFER_T),
iShiftUI, eByteIdx);
}
void ShiftDQ_OENUI_AllRK(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
U8 backup_rank, rk_i;
backup_rank = u1GetRank(p);
// Shift DQ / DQM / DQ_OEN / DQM_OEN
for (rk_i = RANK_0; rk_i < p->support_rank_num; rk_i++)
{
vSetRank(p, rk_i);
ShiftDQ_OENUI(p, iShiftUI, eByteIdx);
}
vSetRank(p, backup_rank);
}
static void ShiftDQSWCK_UI(DRAMC_CTX_T *p, S8 iShiftUI, BYTES_T eByteIdx)
{
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
LP5_ShiftWCKUI(p, iShiftUI, eByteIdx);
else
#endif
{
LP4_ShiftDQSUI(p, iShiftUI, eByteIdx);
LP4_ShiftDQS_OENUI(p, iShiftUI, eByteIdx);
}
}
U8 u1IsLP4Div4DDR800(DRAMC_CTX_T *p)
{
if ((vGet_Div_Mode(p) == DIV4_MODE) && (p->frequency == 400))
return TRUE;
else
return FALSE;
}
//static void vSetDramMRWriteLevelingOnOff(DRAMC_CTX_T *p, U8 u1OnOff)
static void vSetDramMRWriteLevelingOnOff(DRAMC_CTX_T *p, U8 u1OnOff)
{
// MR2 OP[7] to enable/disable write leveling
if (u1OnOff)
u1MR02Value[p->dram_fsp] |= 0x80; // OP[7] WR LEV =1
else
u1MR02Value[p->dram_fsp] &= 0x7f; // OP[7] WR LEV =0
DramcModeRegWriteByRank(p, p->rank, 2, u1MR02Value[p->dram_fsp]);
}
U8 u1IsPhaseMode(DRAMC_CTX_T *p)
{
if ((vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE) || (vGet_DDR_Loop_Mode(p) == SEMI_OPEN_LOOP_MODE))
return TRUE;
else // DDR800_CLOSE_LOOP and NORMAL_CLOSE_LOOP
return FALSE;
}
static DRAM_STATUS_T DramcTriggerAndWait(DRAMC_CTX_T *p, REG_TRANSFER_T TriggerReg, REG_TRANSFER_T RepondsReg)
{
// U32 u4TimeCnt = TIME_OUT_CNT;
// @Darren, Rx HW AutoK simulation time
U32 u4TimeCnt = DDR_HW_AUTOK_POLLING_CNT;
DRAM_STATUS_T u4RespFlag = 0;
vIO32WriteFldAlign(DRAMC_REG_ADDR(TriggerReg.u4Addr), 0, TriggerReg.u4Fld); // Init EN status
vIO32WriteFldAlign(DRAMC_REG_ADDR(TriggerReg.u4Addr), 1, TriggerReg.u4Fld);
do
{
u4RespFlag = u4IO32ReadFldAlign(DRAMC_REG_ADDR(RepondsReg.u4Addr), RepondsReg.u4Fld);
u4TimeCnt --;
mcDELAY_US(1);
}while ((u4RespFlag == 0) && (u4TimeCnt > 0));
if (u4TimeCnt == 0)//time out
{
mcSHOW_DBG_MSG(("[DramcTriggerAndWait] Wait 0x%x respond fail (time out)\n", RepondsReg.u4Addr));
return DRAM_FAIL;
}
return DRAM_OK;
}
#if (SIMULATION_WRITE_LEVELING == 1)
#if !__ETT__
#undef ASSERT
#define ASSERT(x) \
if (!(x)) \
while (1)\
mcSHOW_ERR_MSG(("ASSERT FAIL at %s[%d]!\n", __FUNCTION__, __LINE__));
#endif
#define DQPI_PER_UI (32)
#define STORAGED_DLY_UNIT (24)
static void WriteLevelingScanRange_PI(DRAMC_CTX_T *p, S32 *ps4DlyBegin, S32 *ps4DlyEnd, U8 *pu1PIStep, S16 *pPI_bound, WLEV_DELAY_BASED_T stDelayBase)
{
S32 s4DlyBegin = 0, s4DlyEnd;
U8 u1PIStep;
S16 PI_bound;
if (stDelayBase == PI_BASED)
{
// Giving PI scan range
s4DlyBegin = WRITE_LEVELING_MOVD_DQS * 32 - MAX_CLK_PI_DELAY - 1;
s4DlyEnd = s4DlyBegin + 64 - 1;
if ((vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE))
{
u1PIStep = 16;
PI_bound = 32;
}
else if ((vGet_DDR_Loop_Mode(p) == SEMI_OPEN_LOOP_MODE))
{
u1PIStep = 8;
PI_bound = 32;
}
else
{
u1PIStep = 1;
PI_bound = 64;
}
}
else // stDelayBase == DLY_BASED
{
// Giving delay cell scan range
s4DlyBegin = 0;
s4DlyEnd = 2 * STORAGED_DLY_UNIT;
u1PIStep = 1; // One step is 1/4 delay cell
PI_bound = 1024; // No bounadary as delay cell based
}
mcSHOW_DBG_MSG2(("Begin: %d, End: %d, Step: %d, Bound: %d\n", s4DlyBegin, s4DlyEnd, u1PIStep, PI_bound));
*ps4DlyBegin = s4DlyBegin;
*ps4DlyEnd = s4DlyEnd;
*pu1PIStep = u1PIStep;
*pPI_bound = PI_bound;
}
#if ENABLE_WDQS_MODE_2
DRAM_STATUS_T WriteLevelingPosCal(DRAMC_CTX_T *p, WLEV_DELAY_BASED_T stDelayBase)
{
DRAM_RANK_T backup_rank = u1GetRank(p);
U8 wrlevel_dqs_delay[DQS_NUMBER] = {0};
U8 rank_i = 0;
if((wrlevel_dqs_final_delay[RANK_0][0] - wrlevel_dqs_final_delay[RANK_1][0])>=9 ||
(wrlevel_dqs_final_delay[RANK_0][0] - wrlevel_dqs_final_delay[RANK_1][0])<=-9 ||
(wrlevel_dqs_final_delay[RANK_0][1] - wrlevel_dqs_final_delay[RANK_1][1])>=9 ||
(wrlevel_dqs_final_delay[RANK_0][1] - wrlevel_dqs_final_delay[RANK_1][1])<=-9 )
{
mcSHOW_ERR_MSG(("[WARNING] Larger WL R2R !!\n"));
#if CHECK_HQA_CRITERIA
while(1);
#endif
}
wrlevel_dqs_delay[0] = (wrlevel_dqs_final_delay[RANK_0][0] + wrlevel_dqs_final_delay[RANK_1][0]) >> 1;
wrlevel_dqs_delay[1] = (wrlevel_dqs_final_delay[RANK_0][1] + wrlevel_dqs_final_delay[RANK_1][1]) >> 1;
wrlevel_dqs_final_delay[RANK_0][0] = wrlevel_dqs_final_delay[RANK_1][0] = wrlevel_dqs_delay[0];
wrlevel_dqs_final_delay[RANK_0][1] = wrlevel_dqs_final_delay[RANK_1][1] = wrlevel_dqs_delay[1];
for (rank_i = p->rank; rank_i < p->support_rank_num; rank_i++)
{
vSetRank(p, rank_i);
// set to best values for DQS
if (stDelayBase == PI_BASED)
{
// Adjust DQS output delay.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), wrlevel_dqs_delay[0], SHU_R0_B0_DQ0_ARPI_PBYTE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), wrlevel_dqs_delay[1], SHU_R0_B1_DQ0_ARPI_PBYTE_B1);
}
else // stDelayBase == DLY_BASED
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), wrlevel_dqs_delay[0], SHU_R0_B0_TXDLY3_TX_ARWCK_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), wrlevel_dqs_delay[1], SHU_R0_B1_TXDLY3_TX_ARWCK_DLY_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), wrlevel_dqs_delay[0], SHU_R0_B0_TXDLY3_TX_ARWCKB_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), wrlevel_dqs_delay[1], SHU_R0_B1_TXDLY3_TX_ARWCKB_DLY_B1);
}
}
vSetRank(p, backup_rank);
mcSHOW_DBG_MSG(("[WriteLevelingPosCal] DQS PI B0/B1 = %d/%d\n", wrlevel_dqs_delay[0], wrlevel_dqs_delay[1]));
}
#endif
#define SET_PATTERN_MANUALLY_FOR_DEBUG 1
DRAM_STATUS_T DramcWriteLeveling(DRAMC_CTX_T *p, u8 isAutoK, WLEV_DELAY_BASED_T stDelayBase)
{
// Note that below procedure is based on "ODT off"
DRAM_STATUS_T KResult = DRAM_FAIL;
U8 byte_i, rank_i, ucDoneFlg;
DRAM_RANK_T backup_rank;
S32 wrlevel_dqs_delay[DQS_NUMBER]; // 3 is channel number
S32 s4DlyBegin, s4DlyEnd;
U8 u1PIStep;
U8 u1OverBoundCnt = 0;
S16 PI_bound = 64;
//When doing WriteLeveling, should make sure that auto refresh is disable
vAutoRefreshSwitch(p, DISABLE);
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
#if VENDER_JV_LOG
vPrintCalibrationBasicInfo_ForJV(p);
#else
vPrintCalibrationBasicInfo(p);
#endif
fgwrlevel_done = 0;
backup_rank = u1GetRank(p);
//DramcRankSwap(p, p->rank);
//tx_rank_sel is selected by SW //Lewis@20180604: tx_rank_sel is selected by SW in WL if TMRRI design has changed.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), p->rank, TX_SET0_TXRANK);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), 1, TX_SET0_TXRANKFIX); //TXRANKFIX should be write after TXRANK
// backup mode settings
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL1)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL3)),
(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL5)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_VREF)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_VREF)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_PHY_VREF_SEL)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_PHY_VREF_SEL)), //in O1PathOnOff()
(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL))
};
DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
//default set DRAM FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_WRITE_LEVEL, DRAM_FAIL);
#if MRW_CHECK_ONLY
mcSHOW_MRW_MSG(("\n==[MR Dump] %s==\n", __func__));
#endif
if (p->isWLevInitShift[p->channel] == FALSE)
{
// It must be PI_BASED or FAIL!!
ASSERT(stDelayBase == PI_BASED);
p->isWLevInitShift[p->channel] = TRUE;
// This flow would be excuted just one time, so all ranks(maybe rank0/1) should be adjusted at once.
ShiftDQUI_AllRK(p, -WRITE_LEVELING_MOVD_DQS, ALL_BYTES);
ShiftDQ_OENUI_AllRK(p, -WRITE_LEVELING_MOVD_DQS, ALL_BYTES);
ShiftDQSWCK_UI(p, -WRITE_LEVELING_MOVD_DQS, ALL_BYTES);
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
// For DLY based WCK leveling
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ13), 0, SHU_B0_DQ13_RG_TX_ARDQ_DLY_LAT_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ13), 0, SHU_B1_DQ13_RG_TX_ARDQ_DLY_LAT_EN_B1);
// Set DQS DLY-based delay to 16
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), STORAGED_DLY_UNIT, SHU_R0_B0_TXDLY3_TX_ARWCK_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), STORAGED_DLY_UNIT, SHU_R0_B1_TXDLY3_TX_ARWCK_DLY_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), STORAGED_DLY_UNIT, SHU_R0_B0_TXDLY3_TX_ARWCKB_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), STORAGED_DLY_UNIT, SHU_R0_B1_TXDLY3_TX_ARWCKB_DLY_B1);
}
#endif
// Set DQS PI-based delay to 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), 0, SHU_R0_B0_DQ0_ARPI_PBYTE_B0); //rank0, byte0, DQS delay
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), 0, SHU_R0_B1_DQ0_ARPI_PBYTE_B1); //rank0, byte1, DQS delay
}
// decide algorithm parameters according to freq.(PI mode/ phase mode)
WriteLevelingScanRange_PI(p, &s4DlyBegin, &s4DlyEnd, &u1PIStep, &PI_bound, stDelayBase);
// Not support autok to delay cell based mode.
if (stDelayBase == DLY_BASED)
isAutoK = FALSE;
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_WRITELEVELING)
if (p->femmc_Ready == 1)
{
wrlevel_dqs_final_delay[p->rank][0] = p->pSavetimeData->u1WriteLeveling_bypass_Save[p->channel][p->rank][0];
wrlevel_dqs_final_delay[p->rank][1] = p->pSavetimeData->u1WriteLeveling_bypass_Save[p->channel][p->rank][1];
ucDoneFlg = 0xff;
KResult = DRAM_OK;
vSetCalibrationResult(p, DRAM_CALIBRATION_WRITE_LEVEL, DRAM_FAST_K);
}
#endif
if (u1OverBoundCnt > 0)
ShiftDQSWCK_UI(p, -u1OverBoundCnt * (PI_bound / DQPI_PER_UI), ALL_BYTES);
if (ucDoneFlg == 0xff)
{
// all bytes are done
fgwrlevel_done = 1;
KResult = DRAM_OK;
}
else
{
KResult = DRAM_FAIL;
#if __FLASH_TOOL_DA__
PINInfo_flashtool.WL_ERR_FLAG|=(0x1<<(p->channel*2+p->rank));
#endif
}
vSetCalibrationResult(p, DRAM_CALIBRATION_WRITE_LEVEL, KResult);
mcSHOW_DBG_MSG2(("pass bytecount = 0x%x (0xff: all bytes pass) \n\n", ucDoneFlg));
#if defined(FOR_HQA_TEST_USED) && defined(FOR_HQA_REPORT_USED)
if (gHQALog_flag == 1)
{
for (byte_i = 0; byte_i < (p->data_width / DQS_BIT_NUMBER); byte_i++)
{
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT1, "", "WriteLeveling_DQS", byte_i, wrlevel_dqs_final_delay[p->rank][byte_i], NULL);
}
}
#endif
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
vSetLP5Dram_WCK2CK_WlevOnOff(p, DISABLE);
else
#endif
vSetDramMRWriteLevelingOnOff(p, DISABLE); // Disable DDR write leveling mode: issue MR2[7] to enable write leveling
// Write leveling enable OFF
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_CBT_WLEV_CTRL0), 0, CBT_WLEV_CTRL0_WRITE_LEVEL_EN);
//Disable DQ_O1, SELO1ASO=0 for power saving
O1PathOnOff(p, OFF);
//tx_rank_sel is selected by HW
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), 0, TX_SET0_TXRANK);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_SET0), 0, TX_SET0_TXRANKFIX); //TXRANKFIX should be write after TXRANK
//restore registers.
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
// Calculate DQS "PI" delay, nothing to do with delay cell
for (byte_i = 0; byte_i < (p->data_width / DQS_BIT_NUMBER); byte_i++)
{
mcSHOW_DBG_MSG(("Write leveling (Byte %d): %d", byte_i, wrlevel_dqs_final_delay[p->rank][byte_i]));
mcDUMP_REG_MSG(("Write leveling (Byte %d): %d", byte_i, wrlevel_dqs_final_delay[p->rank][byte_i]));
if (wrlevel_dqs_final_delay[p->rank][byte_i] >= PI_bound)
{
ShiftDQSWCK_UI(p, (wrlevel_dqs_final_delay[p->rank][byte_i] / PI_bound) * (PI_bound / DQPI_PER_UI), byte_i);
wrlevel_dqs_final_delay[p->rank][byte_i] %= PI_bound;
}
wrlevel_dqs_delay[byte_i] = wrlevel_dqs_final_delay[p->rank][byte_i];
mcSHOW_DBG_MSG((" => %d\n", wrlevel_dqs_delay[byte_i]));
mcDUMP_REG_MSG((" => %d\n", wrlevel_dqs_delay[byte_i]));
}
for (rank_i = p->rank; rank_i < RANK_MAX; rank_i++)
{
vSetRank(p, rank_i);
// set to best values for DQS
if (stDelayBase == PI_BASED)
{
// Adjust DQS output delay.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), wrlevel_dqs_delay[0], SHU_R0_B0_DQ0_ARPI_PBYTE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), wrlevel_dqs_delay[1], SHU_R0_B1_DQ0_ARPI_PBYTE_B1);
}
else // stDelayBase == DLY_BASED
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), wrlevel_dqs_delay[0], SHU_R0_B0_TXDLY3_TX_ARWCK_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), wrlevel_dqs_delay[1], SHU_R0_B1_TXDLY3_TX_ARWCK_DLY_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), wrlevel_dqs_delay[0], SHU_R0_B0_TXDLY3_TX_ARWCKB_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), wrlevel_dqs_delay[1], SHU_R0_B1_TXDLY3_TX_ARWCKB_DLY_B1);
}
}
vSetRank(p, backup_rank);
mcSHOW_DBG_MSG3(("[DramcWriteLeveling] Done\n\n"));
return KResult;
}
#endif //SIMULATION_WRITE_LEVELING
#if (SIMULATION_DUTY_CYC_MONITOR == 1)
static U8 FetchRGSettingVal(int step_val)
{
if (step_val <= 0)
return (U8)(-step_val);
else
return ((U8)step_val | 0x08);
}
DRAM_STATUS_T DramcDutyCycleMonitor(DRAMC_CTX_T *p)
{
U8 backup_rank;
// U8 u8ResultDutyCycMonitor[WHOLE_STEPS_NUM] = {0};
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
vAutoRefreshSwitch(p, DISABLE);
//CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
backup_rank = u1GetRank(p);
RunTime_SW_Cmd(p, RUNTIME_SWCMD_CAS_FS);
int i = -7;
for (i = -7; i <= 7; i++)
{
// MRW MR30 OP[7:4] = i(Set DCAU) and OP[3:0] = i(Set DCAL)
U8 u8RGSettingVal = FetchRGSettingVal(i);
mcSHOW_ERR_MSG(("Set value %d into MR30\n", u8RGSettingVal));
MRWriteFldMulti(p, 30, P_Fld(u8RGSettingVal, MR30_DCAU) |
P_Fld(u8RGSettingVal, MR30_DCAL),
TO_MR);
// Start duty cycle monitor
DramcMRWriteFldAlign(p, 26, 1, MR26_DCM_START_STOP, TO_MR);
// Delay tDCMM(2us)
mcDELAY_US(2);
// Duty cycle monitor Flip 0 -> 1, and store result of flip = 0
DramcMRWriteFldAlign(p, 26, 1, MR26_DCM_FLIP, TO_MR);
// Delay tDCMM(2us)
mcDELAY_US(2);
// Duty cycle monitor Flip 1 -> 0, and store result of flip = 1
DramcMRWriteFldAlign(p, 26, 0, MR26_DCM_FLIP, TO_MR);
// Delay tDCMM(2us)
mcDELAY_US(2);
// Stop Duty cycle monitor
DramcMRWriteFldAlign(p, 26, 0, MR26_DCM_START_STOP, TO_MR);
// Delay tMRD
mcDELAY_US(2);
mcSHOW_ERR_MSG(("Wait tMRD and MRR MR26\n"));
///TODO: Read back result MR25[5:2]
// Store result into u8ResultDutyCycMonitor[]
}
///TODO: Find and set a best MR30 variables
RunTime_SW_Cmd(p, RUNTIME_SWCMD_CAS_OFF);
vAutoRefreshSwitch(p, ENABLE);
//CKEFixOnOff(p, p->rank, CKE_DYNAMIC, CKE_WRITE_TO_ONE_CHANNEL);
vSetRank(p, backup_rank);
}
#endif // SIMULATION_DUTY_CYC_MONITOR
void vResetDelayChainBeforeCalibration(DRAMC_CTX_T *p)
{
U8 u1RankIdx, u1RankIdxBak;
U32 u4WbrBackup = GetDramcBroadcast();
DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);
u1RankIdxBak = u1GetRank(p);
for(u1RankIdx=RANK_0; u1RankIdx<RANK_MAX; u1RankIdx++)
{
vSetRank(p, u1RankIdx);
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_CA_TXDLY0,
P_Fld(0, SHU_R0_CA_TXDLY0_TX_ARCA0_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY0_TX_ARCA1_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY0_TX_ARCA2_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY0_TX_ARCA3_DLY));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_CA_TXDLY1,
P_Fld(0, SHU_R0_CA_TXDLY1_TX_ARCA4_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY1_TX_ARCA5_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY1_TX_ARCA6_DLY) |
P_Fld(0, SHU_R0_CA_TXDLY1_TX_ARCA7_DLY));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_B0_TXDLY0, P_Fld(0, SHU_R0_B0_TXDLY0_TX_ARDQ0_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY0_TX_ARDQ1_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY0_TX_ARDQ2_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY0_TX_ARDQ3_DLY_B0));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_B0_TXDLY1, P_Fld(0, SHU_R0_B0_TXDLY1_TX_ARDQ4_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY1_TX_ARDQ5_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY1_TX_ARDQ6_DLY_B0)
| P_Fld(0, SHU_R0_B0_TXDLY1_TX_ARDQ7_DLY_B0));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_B1_TXDLY0, P_Fld(0, SHU_R0_B1_TXDLY0_TX_ARDQ0_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY0_TX_ARDQ1_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY0_TX_ARDQ2_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY0_TX_ARDQ3_DLY_B1));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_R0_B1_TXDLY1, P_Fld(0, SHU_R0_B1_TXDLY1_TX_ARDQ4_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY1_TX_ARDQ5_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY1_TX_ARDQ6_DLY_B1)
| P_Fld(0, SHU_R0_B1_TXDLY1_TX_ARDQ7_DLY_B1));
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_R0_B0_TXDLY3, 0x0, SHU_R0_B0_TXDLY3_TX_ARDQM0_DLY_B0);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_R0_B1_TXDLY3, 0x0, SHU_R0_B1_TXDLY3_TX_ARDQM0_DLY_B1);
}
vSetRank(p, u1RankIdxBak);
DramcBroadcastOnOff(u4WbrBackup);
}
//Reset PHY to prevent glitch when change DQS gating delay or RX DQS input delay
// [Lynx] Evere_st : cannot reset single channel. All DramC and All Phy have to reset together.
void DramPhyReset(DRAMC_CTX_T *p)
{
// Evere_st change reset order : reset DQS before DQ, move PHY reset to final.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RX_SET0), 1, RX_SET0_RDATRST);// read data counter reset
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 1, MISC_CTRL1_R_DMPHYRST);
//RG_ARCMD_RESETB & RG_ARDQ_RESETB_B0/1 only reset once at init, Justin Chan.
///TODO: need to confirm RG_ARCMD_RESETB & RG_ARDQ_RESETB_B0/1 is reset at mem.c
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
P_Fld(0, B0_DQ9_RG_RX_ARDQS0_STBEN_RESETB_B0) |
P_Fld(0, B0_DQ9_RG_RX_ARDQ_STBEN_RESETB_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
P_Fld(0, B1_DQ9_RG_RX_ARDQS0_STBEN_RESETB_B1) |
P_Fld(0, B1_DQ9_RG_RX_ARDQ_STBEN_RESETB_B1));
mcDELAY_US(1);//delay 10ns
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
P_Fld(1, B1_DQ9_RG_RX_ARDQS0_STBEN_RESETB_B1) |
P_Fld(1, B1_DQ9_RG_RX_ARDQ_STBEN_RESETB_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
P_Fld(1, B0_DQ9_RG_RX_ARDQS0_STBEN_RESETB_B0) |
P_Fld(1, B0_DQ9_RG_RX_ARDQ_STBEN_RESETB_B0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 0, MISC_CTRL1_R_DMPHYRST);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RX_SET0), 0, RX_SET0_RDATRST);// read data counter reset
}
#if SIMULATION_LP4_ZQ
//-------------------------------------------------------------------------
/** DramcZQCalibration
* start Dram ZQ calibration.
* @param p Pointer of context created by DramcCtxCreate.
* @retval status (DRAM_STATUS_T): DRAM_OK or DRAM_FAIL
*/
//-------------------------------------------------------------------------
#if ZQ_SWCMD_MODE
static DRAM_STATUS_T ZQ_SWCMD_MODE_Cal(DRAMC_CTX_T *p, U8 rank)
{
U32 u4Response;
U32 u4TimeCnt = TIME_OUT_CNT;
U32 u4SWCMDEN, u4SWCMDCTRL, u4SPDCTRL, u4CKECTRL;
// Backup rank, CKE fix on/off, HW MIOCK control settings
u4SWCMDEN = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN));
u4SWCMDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0));
u4SPDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL));
u4CKECTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL));
mcSHOW_DBG_MSG3(("[ZQCalibration]\n"));
//mcFPRINTF((fp_A60501, "[ZQCalibration]\n"));
// Disable HW MIOCK control to make CLK always on
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_APHYCKCG_FIXOFF);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_TCKFIXON);
mcDELAY_US(1);
//if CKE2RANK=1, only need to set CKEFIXON, it will apply to both rank.
CKEFixOnOff(p, rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
//select rank
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), rank, SWCMD_CTRL0_SWTRIG_ZQ_RK);
//ZQCAL Start
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_ZQCEN_SWTRIG);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP3), SPCMDRESP3_ZQC_SWTRIG_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1); // Wait tZQCAL(min) 1us or wait next polling
mcSHOW_DBG_MSG3(("%d- ", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d- ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_ZQCEN_SWTRIG);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Start fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Start fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQCAL
mcDELAY_US(1);
u4TimeCnt = TIME_OUT_CNT;
//ZQCAL Latch
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_ZQLATEN_SWTRIG);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP3), SPCMDRESP3_ZQLAT_SWTRIG_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1);// Wait tZQLAT 30ns or wait next polling
mcSHOW_DBG_MSG3(("%d=", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d= ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_ZQLATEN_SWTRIG);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Latch fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Latch fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQLAT
mcDELAY_US(1);
// Restore rank, CKE fix on, HW MIOCK control settings
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), u4SWCMDEN);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), u4SWCMDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), u4SPDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL), u4CKECTRL);
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_OK);
mcSHOW_DBG_MSG3(("\n[DramcZQCalibration] Done\n\n"));
//mcFPRINTF((fp_A60501, "\n[DramcZQCalibration] Done\n\n"));
return DRAM_OK;
}
#endif
#if ZQ_RTSWCMD_MODE
DRAM_STATUS_T ZQ_RTSWCMD_MODE_Cal(DRAMC_CTX_T *p, U8 rank)
{
U32 u4Response;
U32 u4TimeCnt = TIME_OUT_CNT;
U32 u4SWCMDEN, u4SWCMDCTRL, u4MPCCTRL, u4RTSWCMD, u4SPDCTRL, u4CKECTRL;
// Backup rank, CKE fix on/off, HW MIOCK control settings
u4SWCMDEN = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN));
u4SWCMDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL2));
u4MPCCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_MPC_CTRL));
u4RTSWCMD = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_RTSWCMD_CNT));
u4SPDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL));
u4CKECTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL));
mcSHOW_DBG_MSG3(("[ZQCalibration]\n"));
//mcFPRINTF((fp_A60501, "[ZQCalibration]\n"));
// Disable HW MIOCK control to make CLK always on
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_APHYCKCG_FIXOFF);
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_TCKFIXON);
mcDELAY_US(1);
//if CKE2RANK=1, only need to set CKEFIXON, it will apply to both rank.
//CKEFixOnOff(p, rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
//select rank
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL2),
P_Fld(rank, SWCMD_CTRL2_RTSWCMD_RK) |
P_Fld(0x20, SWCMD_CTRL2_RTSWCMD_AGE));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_MPC_CTRL), 0x1, MPC_CTRL_RTSWCMD_HPRI_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RTSWCMD_CNT), 0x2a, RTSWCMD_CNT_RTSWCMD_CNT);
//ZQCAL Start
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0x5, SWCMD_EN_RTSWCMD_SEL);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_RTSWCMDEN);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP3), SPCMDRESP3_RTSWCMD_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1); // Wait tZQCAL(min) 1us or wait next polling
mcSHOW_DBG_MSG3(("%d- ", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d- ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_RTSWCMDEN);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Start fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Start fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQCAL
mcDELAY_US(1);
u4TimeCnt = TIME_OUT_CNT;
//ZQCAL Latch
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0x6, SWCMD_EN_RTSWCMD_SEL);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_RTSWCMDEN);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP3), SPCMDRESP3_RTSWCMD_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1);// Wait tZQLAT 30ns or wait next polling
mcSHOW_DBG_MSG3(("%d=", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d= ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_RTSWCMDEN);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Latch fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Latch fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQLAT
mcDELAY_US(1);
// Restore rank, CKE fix on, HW MIOCK control settings
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), u4SWCMDEN);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL2), u4SWCMDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_MPC_CTRL), u4MPCCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_RTSWCMD_CNT), u4RTSWCMD);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), u4SPDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL), u4CKECTRL);
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_OK);
mcSHOW_DBG_MSG3(("\n[DramcZQCalibration] Done\n\n"));
//mcFPRINTF((fp_A60501, "\n[DramcZQCalibration] Done\n\n"));
return DRAM_OK;
}
#endif
#if ZQ_SCSM_MODE
DRAM_STATUS_T ZQ_SCSM_MODE_Cal(DRAMC_CTX_T *p, U8 rank)
{
U32 u4Response;
U32 u4TimeCnt = TIME_OUT_CNT;
U32 u4SWCMDEN, u4MPCCTRL, u4SWCMDCTRL, u4SPDCTRL, u4CKECTRL;
// Backup rank, CKE fix on/off, HW MIOCK control settings
u4SWCMDEN = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN));
u4SWCMDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0));
u4MPCCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_MPC_OPTION));
u4SPDCTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL));
u4CKECTRL = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL));
mcSHOW_DBG_MSG3(("[ZQCalibration]\n"));
//mcFPRINTF((fp_A60501, "[ZQCalibration]\n"));
// Disable HW MIOCK control to make CLK always on
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_APHYCKCG_FIXOFF);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), 1, DRAMC_PD_CTRL_TCKFIXON);
mcDELAY_US(1);
//if CKE2RANK=1, only need to set CKEFIXON, it will apply to both rank.
CKEFixOnOff(p, rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
//Use rank swap or MRSRK to select rank
//DramcRankSwap(p, p->rank);
//!!R_DMMRSRK(R_DMMPCRKEN=1) specify rank0 or rank1
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), rank, SWCMD_CTRL0_MRSRK);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_MPC_OPTION), 1, MPC_OPTION_MPCRKEN);
//ZQCAL Start
//R_DMZQCEN, 0x1E4[4]=1 for ZQCal Start
//Wait zqc_response=1 (dramc_conf_nao, 0x3b8[4])
//R_DMZQCEN, 0x1E4[4]=0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_ZQCEN);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP), SPCMDRESP_ZQC_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1); // Wait tZQCAL(min) 1us or wait next polling
mcSHOW_DBG_MSG3(("%d- ", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d- ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_ZQCEN);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Start fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Start fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQCAL
mcDELAY_US(1);
u4TimeCnt = TIME_OUT_CNT;
//ZQCAL Latch
//R_DMZQLATEN, 0x1E4[6]=1 for ZQCal latch
//Wait zqlat_response=1 (dramc_conf_nao, 0x3b8[28])
//R_DMZQLATEN, 0x1E4[6]=0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 1, SWCMD_EN_ZQLATEN);
do
{
u4Response = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SPCMDRESP), SPCMDRESP_ZQLAT_RESPONSE);
u4TimeCnt --;
mcDELAY_US(1);// Wait tZQLAT 30ns or wait next polling
mcSHOW_DBG_MSG3(("%d=", u4TimeCnt));
//mcFPRINTF((fp_A60501, "%d= ", u4TimeCnt));
}while((u4Response==0) &&(u4TimeCnt>0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_ZQLATEN);
if(u4TimeCnt==0)//time out
{
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_FAIL);
mcSHOW_DBG_MSG(("ZQCAL Latch fail (time out)\n"));
//mcFPRINTF((fp_A60501, "ZQCAL Latch fail (time out)\n"));
return DRAM_FAIL;
}
// [JC] delay tZQLAT
mcDELAY_US(1);
// Restore rank, CKE fix on, HW MIOCK control settings
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), u4SWCMDEN);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL2), u4SWCMDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_MPC_CTRL), u4MPCCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_DRAMC_PD_CTRL), u4SPDCTRL);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_CKECTRL), u4CKECTRL);
vSetCalibrationResult(p, DRAM_CALIBRATION_ZQ, DRAM_OK);
mcSHOW_DBG_MSG3(("\n[DramcZQCalibration] Done\n\n"));
//mcFPRINTF((fp_A60501, "\n[DramcZQCalibration] Done\n\n"));
return DRAM_OK;
}
#endif
DRAM_STATUS_T DramcZQCalibration(DRAMC_CTX_T *p, U8 rank)
{
#if ZQ_SWCMD_MODE
return ZQ_SWCMD_MODE_Cal(p, rank);
#elif ZQ_RTSWCMD_MODE
return ZQ_RTSWCMD_MODE_Cal(p, rank);
#else //ZQ_SCSM_MODE
return ZQ_SCSM_MODE_Cal(p, rank);
#endif
}
#endif
#if (SIMULATION_GATING == 1)
#define GATING_PATTERN_NUM_LP5 0x23
#define GATING_GOLDEND_DQSCNT_LP5 0x4646
#define RXDQS_GATING_AUTO_DBG_REG_NUM 6
/* Preamble & Postamble setting. Currently use macro to define.
* Later may use speed or MR setting to decide
* !!! REVIEW !!!
*/
#if GATING_ADJUST_TXDLY_FOR_TRACKING
U8 u1TXDLY_Cal_min =0xff, u1TXDLY_Cal_max=0;
U8 ucbest_coarse_mck_backup[RANK_MAX][DQS_NUMBER];
U8 ucbest_coarse_ui_backup[RANK_MAX][DQS_NUMBER];
U8 ucbest_coarse_mck_P1_backup[RANK_MAX][DQS_NUMBER];
U8 ucbest_coarse_ui_P1_backup[RANK_MAX][DQS_NUMBER];
#endif
struct rxdqs_gating_cal {
U8 dqsien_dly_mck;
U8 dqsien_dly_ui;
U8 dqsien_dly_pi;
U8 dqsien_dly_mck_p1;
U8 dqsien_dly_ui_p1;
U8 dqsien_pi_adj_step;
U8 dqsien_pi_per_ui;
U8 dqsien_ui_per_mck;
U8 dqsien_freq_div;
};
struct rxdqs_gating_trans {
U8 dqs_lead[DQS_NUMBER];
U8 dqs_lag[DQS_NUMBER];
U8 dqs_high[DQS_NUMBER];
#if GATING_LEADLAG_LOW_LEVEL_CHECK
U8 dqs_low[DQS_NUMBER];
#endif
U8 dqs_transition[DQS_NUMBER];
U8 dqs_transitioned[DQS_NUMBER];
U8 dqsien_dly_mck_leadlag[DQS_NUMBER];
U8 dqsien_dly_ui_leadlag[DQS_NUMBER];
U8 dqsien_dly_pi_leadlag[DQS_NUMBER];
};
struct rxdqs_gating_best_win {
U8 best_dqsien_dly_mck[DQS_NUMBER];
U8 best_dqsien_dly_ui[DQS_NUMBER];
U8 best_dqsien_dly_pi[DQS_NUMBER];
U8 best_dqsien_dly_mck_p1[DQS_NUMBER];
U8 best_dqsien_dly_ui_p1[DQS_NUMBER];
U8 best_dqsien_dly_pi_p1[DQS_NUMBER];
};
struct rxdqs_gating_auto_param {
U8 early_break;
U8 dbg_mode;
U8 init_mck;
U8 init_ui;
U8 end_mck;
U8 end_ui;
U8 pi_offset;
U8 burst_len;
};
#define ENABLE_GATING_AUTOK_WA 1
#if ENABLE_GATING_AUTOK_WA
U8 __wa__gating_swk_for_autok = 0;
U8 __wa__gating_autok_init_ui[RANK_MAX] = { 0 };
#endif
#if (__LP5_COMBO__)
static U8 u1GetLp5ReadLatency(DRAMC_CTX_T *p)
{
U8 read_latency;
U8 rl, ckr, dvfsc;
const U8 au1MR2MappingToRL_wo_dvfsc[2][12] = {
{3, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17}, /* CKR = 4:1 */
{6, 8, 10, 12, 16, 18}, /* CKR = 2:1 */
};
///TODO: Spec has not specify these values
const U8 au1MR2MappingToRL_wi_dvfsc[2][6] = {
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, /* CKR = 4:1 */
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, /* CKR = 2:1 */
};
ckr = (u1MR18Value[p->dram_fsp] >> 7) & 0x1;
dvfsc = !!(u1MR19Value[p->dram_fsp] & 0x3);
rl = (u1MR02Value[p->dram_fsp] & 0xf);
if (dvfsc)
read_latency = au1MR2MappingToRL_wi_dvfsc[ckr][rl];
else
read_latency = au1MR2MappingToRL_wo_dvfsc[ckr][rl];
/* note that the uint of RL is nCK, convert to nWCK */
if (ckr == 0)
read_latency *= 4;
else
read_latency *= 2;
mcSHOW_DBG_MSG(("ckr = %d, dvfsc = %d, rl = %d, read_latency = %d\n",
ckr, dvfsc, rl, read_latency));
return read_latency;
}
#endif
static U8 u1GetGatingStartPos(DRAMC_CTX_T *p, U8 u1AutoK)
{
const U8 au1MR2MappingToRL[2][8] = {{6, 10, 14, 20, 24, 28, 32, 36}, //normal mode
{6, 10, 16, 22, 26, 32, 36, 40}}; //byte mode
U8 u1MR0_LatencyMode;
U8 u1MR2RLValue;
u1MR2RLValue = u1MR02Value[p->dram_fsp] & 0x7; //MR2 Op[2:0]
U8 u1RX_Path_delay_UI, u1RealRL,u1StartUI, u1ExtraMCKfor1_4mode;
U8 u1MCK2CK_UI, u1ReadDQSINCTL, u1DQSINCTL_UI;
U8 u4TDQSCK_UI_min;
U8 u1GatingAheadDQS_UI;
/* LPDDR5 uses same bit */
if(gu2MR0_Value[p->rank] == 0xffff) //MR0 is not ready
{
u1MR0_LatencyMode = CBT_NORMAL_MODE;
}
else
{
u1MR0_LatencyMode = (gu2MR0_Value[p->rank]>>1) & 0x1; //MR0 OP[1], 0:normal mode, 1:byte mode
}
#if (__LP5_COMBO__)
if (is_lp5_family(p)) {
u4TDQSCK_UI_min = 500 * p->frequency *2/ 1000000;
u1RealRL = u1GetLp5ReadLatency(p);
} else
#endif
{
u4TDQSCK_UI_min = 1500 * p->frequency *2/ 1000000;
u1RealRL = au1MR2MappingToRL[u1MR0_LatencyMode][u1MR2RLValue];
}
///TODO: A60868 does not support LP5 DIV4, current setting is not provided for LP5
if(vGet_Div_Mode(p) == DIV4_MODE)
{
u1MCK2CK_UI = 4;
u1ExtraMCKfor1_4mode = 1;
u1GatingAheadDQS_UI = 3;
}
else if (vGet_Div_Mode(p) == DIV8_MODE)
{
u1MCK2CK_UI = 8;
u1ExtraMCKfor1_4mode = 0;
#if (__LP5_COMBO__)
if (is_lp5_family(p)) {
if (p->frequency <= 1600)
u1GatingAheadDQS_UI = 1 * u1MCK2CK_UI;
else if (p->frequency == 1866)
u1GatingAheadDQS_UI = 4;
else
u1GatingAheadDQS_UI = 8;
} else
#endif
u1GatingAheadDQS_UI = 5;
}
else
{
/* DIV16, only for LP5 */
u1MCK2CK_UI = 16;
u1ExtraMCKfor1_4mode = 0;
u1GatingAheadDQS_UI = 8;
}
// RX_Path_delay_UI = RL*2 + tDQSCK_UI<1500~3500ps> - PHY_interanl<skip 30ps> - GatingAheadDQS<2UI> + if(1:4 mod)+1MCK
u1RX_Path_delay_UI = (u1RealRL<<1) + u4TDQSCK_UI_min - u1GatingAheadDQS_UI + (u1MCK2CK_UI*u1ExtraMCKfor1_4mode);
u1ReadDQSINCTL = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RK_DQSCTL), MISC_SHU_RK_DQSCTL_DQSINCTL);
u1DQSINCTL_UI = u1ReadDQSINCTL * u1MCK2CK_UI;
if(u1AutoK)
u1RX_Path_delay_UI += 0; //HW K start position = gating min position(1500ns)
else
u1RX_Path_delay_UI -= 3; //SW K start position = gating min position(1500ns) -3UI
if(u1RX_Path_delay_UI >= u1DQSINCTL_UI)
u1StartUI = u1RX_Path_delay_UI - u1DQSINCTL_UI;
else
{
u1StartUI =0;
mcSHOW_ERR_MSG(("GatingStartPos err! Need to fine-tune default DQSINCTL value.\n(RX_Path_delay_UI %d) < DQSINCTL_UI %d)\n", u1RX_Path_delay_UI, u1DQSINCTL_UI));
#if __ETT__
while(1);
#endif
}
mcSHOW_DBG_MSG(("[GatingStartPos] MR0_LatencyMode %d, u1RealRL %d , u4TDQSCK_UI_min %d, 1:4ExtraMCK %d\n", u1MR0_LatencyMode, u1RealRL, u4TDQSCK_UI_min, u1ExtraMCKfor1_4mode));
mcDUMP_REG_MSG(("[GatingStartPos] MR0_LatencyMode %d, u1RealRL %d , u4TDQSCK_UI_min %d, 1:4ExtraMCK %d\n", u1MR0_LatencyMode, u1RealRL, u4TDQSCK_UI_min, u1ExtraMCKfor1_4mode));
if(u1AutoK)
{
mcSHOW_DBG_MSG(("RX_Path_delay_UI(%d) - DQSINCTL_UI(%d) = u1StartUI(%d)\n", u1RX_Path_delay_UI, u1DQSINCTL_UI, u1StartUI));
mcDUMP_REG_MSG(("RX_Path_delay_UI(%d) - DQSINCTL_UI(%d) = u1StartUI(%d)\n", u1RX_Path_delay_UI, u1DQSINCTL_UI, u1StartUI));
}
else
{
mcSHOW_DBG_MSG(("RX_Path_delay_UI(%d) -3 - DQSINCTL_UI(%d) = u1StartUI(%d)\n", u1RX_Path_delay_UI, u1DQSINCTL_UI, u1StartUI));
mcDUMP_REG_MSG(("RX_Path_delay_UI(%d) -3 - DQSINCTL_UI(%d) = u1StartUI(%d)\n", u1RX_Path_delay_UI, u1DQSINCTL_UI, u1StartUI));
}
return u1StartUI;
}
#if GATING_RODT_LATANCY_EN
U8 get_rodt_mck2ui(DRAMC_CTX_T *p)
{
if (vGet_Div_Mode(p) == DIV16_MODE)
return 8;
else if (vGet_Div_Mode(p) == DIV8_MODE)
return 4;
else
return 2;
}
#endif
static u8 rxdqs_gating_bypass(DRAMC_CTX_T *p)
{
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_GatingCal
if (p->femmc_Ready == 1) {
mcSHOW_DBG_MSG(("[FAST_K] Bypass Gating Calibration\n"));
return 1;
}
#endif
return 0;
}
static void rxdqs_gating_fastk_save_restore(DRAMC_CTX_T *p,
struct rxdqs_gating_best_win *best_win,
struct rxdqs_gating_cal *gating_cal)
{
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
u8 ui_per_mck = gating_cal->dqsien_ui_per_mck;
u8 freq_div = gating_cal->dqsien_freq_div;
u8 ch = p->channel;
u8 rk = p->rank;
u8 dqs_i;
if (p->femmc_Ready == 1) {
for (dqs_i = 0; dqs_i < p->data_width/DQS_BIT_NUMBER; dqs_i++) {
best_win->best_dqsien_dly_mck[dqs_i] =
p->pSavetimeData->u1Gating_MCK_Save[ch][rk][dqs_i];
best_win->best_dqsien_dly_ui[dqs_i] =
p->pSavetimeData->u1Gating_UI_Save[ch][rk][dqs_i];
best_win->best_dqsien_dly_pi[dqs_i] =
p->pSavetimeData->u1Gating_PI_Save[ch][rk][dqs_i];
/* Calculate P1 */
best_win->best_dqsien_dly_ui_p1[dqs_i] =
best_win->best_dqsien_dly_mck[dqs_i] * ui_per_mck +
best_win->best_dqsien_dly_ui[dqs_i] + freq_div; /* Total UI for Phase1 */
best_win->best_dqsien_dly_mck_p1[dqs_i] =
best_win->best_dqsien_dly_ui_p1[dqs_i] / ui_per_mck;
best_win->best_dqsien_dly_ui_p1[dqs_i] =
best_win->best_dqsien_dly_ui_p1[dqs_i] % ui_per_mck;
best_win->best_dqsien_dly_pi_p1[dqs_i] = best_win->best_dqsien_dly_pi[dqs_i];
vSetCalibrationResult(p, DRAM_CALIBRATION_GATING, DRAM_FAST_K);
mcSHOW_DBG_MSG(("[FAST_K] CH%d RK%d best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n",
ch, rk, dqs_i, best_win->best_dqsien_dly_mck[dqs_i],
best_win->best_dqsien_dly_ui[dqs_i],
best_win->best_dqsien_dly_pi[dqs_i]));
mcSHOW_DBG_MSG(("[FAST_K] CH%d RK%d best DQS%d P1 dly(MCK, UI, PI) = (%d, %d, %d)\n",
ch, rk, dqs_i, best_win->best_dqsien_dly_mck_p1[dqs_i],
best_win->best_dqsien_dly_ui_p1[dqs_i],
best_win->best_dqsien_dly_pi_p1[dqs_i]));
}
}
#endif
}
static void rxdqs_gating_misc_process(DRAMC_CTX_T *p,
struct rxdqs_gating_best_win *rxdqs_best_win)
{
#if GATING_ADJUST_TXDLY_FOR_TRACKING
U8 u1TX_dly_DQSgated = 0;
#endif
U8 dqs_i;
/* Set result of useless bytes (if any) as 0. */
for (dqs_i = (p->data_width/DQS_BIT_NUMBER); dqs_i < DQS_NUMBER; dqs_i++) {
rxdqs_best_win->best_dqsien_dly_mck[dqs_i] =
rxdqs_best_win->best_dqsien_dly_ui[dqs_i] =
rxdqs_best_win->best_dqsien_dly_pi[dqs_i]= 0;
rxdqs_best_win->best_dqsien_dly_mck_p1[dqs_i] =
rxdqs_best_win->best_dqsien_dly_ui_p1[dqs_i] =
rxdqs_best_win->best_dqsien_dly_pi_p1[dqs_i]= 0;
#if GATING_ADJUST_TXDLY_FOR_TRACKING
ucbest_coarse_mck_backup[p->rank][dqs_i] =
ucbest_coarse_ui_backup[p->rank][dqs_i] = 0;
ucbest_coarse_mck_P1_backup[p->rank][dqs_i] =
ucbest_coarse_ui_P1_backup[p->rank][dqs_i] = 0;
#endif
}
for (dqs_i=0; dqs_i<(p->data_width/DQS_BIT_NUMBER); dqs_i++) {
#ifdef FOR_HQA_REPORT_USED
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT6, "DQSINCTL ", "", 0,
u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RK_DQSCTL), MISC_SHU_RK_DQSCTL_DQSINCTL), NULL);
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0,
"Gating_Center_", "2T", dqs_i, rxdqs_best_win->best_dqsien_dly_mck[dqs_i], NULL);
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0,
"Gating_Center_", "05T", dqs_i, rxdqs_best_win->best_dqsien_dly_ui[dqs_i], NULL);
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0,
"Gating_Center_", "PI", dqs_i, rxdqs_best_win->best_dqsien_dly_pi[dqs_i], NULL);
#endif
/*TINFO="best DQS%d delay(2T, 0.5T, PI) = (%d, %d, %d)\n", dqs_i, rxdqs_best_win.best_dqsien_dly_mck[dqs_i], rxdqs_best_win.best_dqsien_dly_ui[dqs_i], rxdqs_best_win.best_dqsien_dly_pi[dqs_i])); */
mcSHOW_DBG_MSG(("best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win->best_dqsien_dly_mck[dqs_i],
rxdqs_best_win->best_dqsien_dly_ui[dqs_i],
rxdqs_best_win->best_dqsien_dly_pi[dqs_i]));
mcDUMP_REG_MSG(("best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win->best_dqsien_dly_mck[dqs_i],
rxdqs_best_win->best_dqsien_dly_ui[dqs_i],
rxdqs_best_win->best_dqsien_dly_pi[dqs_i]));
/* cc mark mcFPRINTF((fp_A60501,"best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win.best_dqsien_dly_mck[dqs_i],
rxdqs_best_win.best_dqsien_dly_ui[dqs_i],
rxdqs_best_win.best_dqsien_dly_pi[dqs_i]));
*/
#if GATING_ADJUST_TXDLY_FOR_TRACKING
u1TX_dly_DQSgated = (rxdqs_best_win->best_dqsien_dly_mck[dqs_i] << 4) +
rxdqs_best_win->best_dqsien_dly_ui[dqs_i];
if (vGet_Div_Mode(p) == DIV16_MODE)
u1TX_dly_DQSgated >>= 4;
else if (vGet_Div_Mode(p) == DIV8_MODE)
u1TX_dly_DQSgated >>= 3;
else
u1TX_dly_DQSgated >>= 2;
if (u1TX_dly_DQSgated < u1TXDLY_Cal_min)
u1TXDLY_Cal_min = u1TX_dly_DQSgated;
ucbest_coarse_ui_backup[p->rank][dqs_i] = rxdqs_best_win->best_dqsien_dly_ui[dqs_i];
ucbest_coarse_mck_backup[p->rank][dqs_i] = rxdqs_best_win->best_dqsien_dly_mck[dqs_i];
#endif
}
mcSHOW_DBG_MSG(("\n"));
//cc mark mcFPRINTF((fp_A60501,"\n"));
for (dqs_i=0; dqs_i<(p->data_width/DQS_BIT_NUMBER); dqs_i++) {
/*TINFO="best DQS%d P1 delay(2T, 0.5T, PI) = (%d, %d, %d)\n", dqs_i, rxdqs_best_win.best_dqsien_dly_mck_p1[dqs_i], rxdqs_best_win.best_dqsien_dly_ui_p1[dqs_i], rxdqs_best_win.best_dqsien_dly_pi_p1[dqs_i]*/
mcSHOW_DBG_MSG(("best DQS%d P1 dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win->best_dqsien_dly_mck_p1[dqs_i],
rxdqs_best_win->best_dqsien_dly_ui_p1[dqs_i],
rxdqs_best_win->best_dqsien_dly_pi_p1[dqs_i]));
mcDUMP_REG_MSG(("best DQS%d P1 dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win->best_dqsien_dly_mck_p1[dqs_i],
rxdqs_best_win->best_dqsien_dly_ui_p1[dqs_i],
rxdqs_best_win->best_dqsien_dly_pi_p1[dqs_i]));
/* cc mark mcFPRINTF((fp_A60501,"best DQS%d P1 dly(2T, 0.5T, PI) = (%d, %d, %d)\n", dqs_i,
rxdqs_best_win.best_dqsien_dly_mck_p1[dqs_i],
rxdqs_best_win.best_dqsien_dly_ui_p1[dqs_i],
rxdqs_best_win.best_dqsien_dly_pi_p1[dqs_i]));
*/
#if GATING_ADJUST_TXDLY_FOR_TRACKING
// find max gating TXDLY (should be in P1)
u1TX_dly_DQSgated = (rxdqs_best_win->best_dqsien_dly_mck_p1[dqs_i] << 4) +
rxdqs_best_win->best_dqsien_dly_ui_p1[dqs_i];
if (vGet_Div_Mode(p) == DIV16_MODE)
u1TX_dly_DQSgated >>= 4;
else if (vGet_Div_Mode(p) == DIV8_MODE)
u1TX_dly_DQSgated >>= 3;
else
u1TX_dly_DQSgated >>= 2;
if(u1TX_dly_DQSgated > u1TXDLY_Cal_max)
u1TXDLY_Cal_max = u1TX_dly_DQSgated;
ucbest_coarse_ui_P1_backup[p->rank][dqs_i] = rxdqs_best_win->best_dqsien_dly_ui_p1[dqs_i];
ucbest_coarse_mck_P1_backup[p->rank][dqs_i] = rxdqs_best_win->best_dqsien_dly_mck_p1[dqs_i];
#endif
}
#if RDSEL_TRACKING_EN
//Byte 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_INI_UIPI),
(ucbest_coarse_mck_backup[p->rank][0] << 4) | (ucbest_coarse_ui_backup[p->rank][0]),
SHU_R0_B0_INI_UIPI_CURR_INI_UI_B0);//UI
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_INI_UIPI), rxdqs_best_win->best_dqsien_dly_pi[0],
SHU_R0_B0_INI_UIPI_CURR_INI_PI_B0); //PI
//Byte 1
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_INI_UIPI),
(ucbest_coarse_mck_backup[p->rank][1] << 4) | (ucbest_coarse_ui_backup[p->rank][1]),
SHU_R0_B1_INI_UIPI_CURR_INI_UI_B1);//UI
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_INI_UIPI),
rxdqs_best_win->best_dqsien_dly_pi[1], SHU_R0_B1_INI_UIPI_CURR_INI_PI_B1); //PI
#endif
}
static void rxdqs_gating_auto_cal_reset(DRAMC_CTX_T *p)
{
/* Reset internal autok status and logic */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
P_Fld(0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_RK0_SW_RST) |
P_Fld(0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_RK1_SW_RST) |
P_Fld(0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_SW_RST));
mcDELAY_US(1);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
P_Fld(0x0, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_RK0_SW_RST) |
P_Fld(0x0, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_RK1_SW_RST) |
P_Fld(0x0, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_SW_RST));
}
static void rxdqs_gating_auto_cal_cfg(DRAMC_CTX_T *p,
struct rxdqs_gating_auto_param *auto_param)
{
/* Before start calibration, reset all state machine and all rank's state */
rxdqs_gating_auto_cal_reset(p);
/*-----------
* Normal Setting, Same as SW calibration
*---------------*/
if (p->frequency == 800) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_STBCNT_SW_RST);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_STBCNT_SHU_RST_EN);
/* SELPH_MODE = BY RANK */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_DQSIEN_SELPH_BY_RANK_EN);
if (p->dram_type == TYPE_LPDDR5) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_STB_PICG_EARLY_1T_EN);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_DIS_PI_TRACK_AS_NOT_RD);
/* PICG_EARLY_EN */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x1, B0_DQ6_RG_RX_ARDQ_OP_BIAS_SW_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x1, B0_DQ6_RG_RX_ARDQ_OP_BIAS_SW_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_STB_PICG_EARLY_1T_EN);
/* BURST_MODE */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL),
0x1, MISC_SHU_STBCAL_DQSIEN_BURST_MODE);
#if (__LP5_COMBO__)
if (is_lp5_family(p)) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
0x1, B0_DQ9_RG_RX_ARDQS0_DQSIENMODE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
0x1, B1_DQ9_RG_RX_ARDQS0_DQSIENMODE_B1);
} else
#endif
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
0x1, B0_DQ9_RG_RX_ARDQS0_DQSIENMODE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
0x1, B1_DQ9_RG_RX_ARDQS0_DQSIENMODE_B1);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x2, B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6),
0x2, B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL),
0x1, MISC_STBCAL_DQSIENMODE);
/* New Rank Mode */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
P_Fld(0x1, MISC_STBCAL2_STB_IG_XRANK_CG_RST) |
P_Fld(0x1, MISC_STBCAL2_STB_RST_BY_RANK) |
P_Fld(0x1, MISC_STBCAL2_DQSIEN_SELPH_BY_RANK_EN));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2),
0x1, B0_PHY2_RG_RX_ARDQS_DQSIEN_UI_LEAD_LAG_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2),
0x1, B1_PHY2_RG_RX_ARDQS_DQSIEN_UI_LEAD_LAG_EN_B1);
/* dummy read */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DUMMY_RD),
0x1, DUMMY_RD_DUMMY_RD_PA_OPT);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CG_CTRL0),
0x1, MISC_CG_CTRL0_RG_CG_PHY_OFF_DIABLE);
//Yulia add workaround for auto K pattern length. : Apply for all project before IPM_V2
//Dummy read BL should be controlled by DQSIEN_AUTOK_BURST_LENGTH, but now we can only use dummy read length(DMY_RD_LEN)
//DMY_RD_LEN (0 for BL8, 1 for BL16, 3 for BL32)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RK_DUMMY_RD_ADR), 3/*auto_param->burst_len*/, RK_DUMMY_RD_ADR_DMY_RD_LEN);
/* Decide by HW Although Dummy read used, but TA2 has higher priority */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TEST2_A4),
0x4, TEST2_A4_TESTAGENTRKSEL);
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
// MISC_STBCAL2_STBENCMPEN);
/*-----------
* Auto calibration setting
*-------------------*/
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
P_Fld(auto_param->init_mck, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_INI_MCK) |
P_Fld(auto_param->init_ui, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_INI__UI) |
P_Fld(auto_param->end_mck, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_END_MCK) |
P_Fld(auto_param->end_ui, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_END__UI) |
P_Fld(auto_param->pi_offset, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_PI_OFFSET) |
P_Fld(p->rank, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_CUR_RANK) |
P_Fld(auto_param->burst_len, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_BURST_LENGTH) |
P_Fld(0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_B0_EN) |
P_Fld(0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_B1_EN));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
auto_param->dbg_mode, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_DEBUG_MODE_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
auto_param->early_break, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_EARLY_BREAK_EN);
/*---------
* DV settings
*-------------------*/
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL),
0x0, MISC_STBCAL_PICGEN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL),
P_Fld(0x0, MISC_SHU_STBCAL_STBCALEN) |
P_Fld(0x0, MISC_SHU_STBCAL_STB_SELPHCALEN));
mcSHOW_DBG_MSG(("[Gating] AUTO K with param:\n"));
mcSHOW_DBG_MSG(("\tinit_mck: %d, init_ui: %d, end_mck: %d, end_ui: %d\n",
auto_param->init_mck, auto_param->init_ui,
auto_param->end_mck, auto_param->end_ui));
mcSHOW_DBG_MSG(("\tpi_offset: %d, early_break: %s\n", auto_param->pi_offset,
(auto_param->early_break)? "ENABLE" : "DISABLE"));
}
static void rxdqs_gating_auto_cal_trigger(DRAMC_CTX_T *p)
{
mcSHOW_DBG_MSG(("[Gating] AUTO K start...\n"));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
0x1, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_GO);
}
static void rxdqs_gating_auto_cal_stop(DRAMC_CTX_T *p)
{
mcSHOW_DBG_MSG(("[Gating] AUTO K stop...\n"));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DQSIEN_AUTOK_CFG0),
0x0, MISC_DQSIEN_AUTOK_CFG0_DQSIEN_AUTOK_GO);
rxdqs_gating_auto_cal_reset(p);
}
static void rxdqs_gating_set_final_result(DRAMC_CTX_T *p, U8 mck2ui,
struct rxdqs_gating_best_win *best_win)
{
#if GATING_RODT_LATANCY_EN
U8 reg_mck, reg_ui;
U8 value;
U8 reg_mck_rodt[DQS_NUMBER], reg_ui_rodt[DQS_NUMBER];
U8 reg_mck_rodt_p1[DQS_NUMBER], reg_ui_rodt_p1[DQS_NUMBER];
U8 dqs_i;
#endif
#if GATING_RODT_LATANCY_EN
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++) {
reg_mck = best_win->best_dqsien_dly_mck[dqs_i];
reg_ui = best_win->best_dqsien_dly_ui[dqs_i];
value = (reg_mck * mck2ui) + reg_ui;
if (value >= 11) {
U8 rodt_mck2ui = get_rodt_mck2ui(p);
value -= 11;
reg_mck_rodt[dqs_i] = value / rodt_mck2ui;
reg_ui_rodt[dqs_i] = value % rodt_mck2ui;
reg_mck_rodt_p1[dqs_i] = reg_mck_rodt[dqs_i];
reg_ui_rodt_p1[dqs_i] = reg_ui_rodt[dqs_i];
} else {
reg_mck_rodt[dqs_i] = 0;
reg_ui_rodt[dqs_i] = 0;
reg_mck_rodt_p1[dqs_i] = 4;
reg_ui_rodt_p1[dqs_i] = 4;
mcSHOW_DBG_MSG(("[Warning] RODT cannot be -11UI for B%d\n",
dqs_i));
}
mcSHOW_DBG_MSG(("DQS%d Final RODTEN: (%2d, %2d)\n",
dqs_i, reg_mck_rodt[dqs_i], reg_ui_rodt[dqs_i]));
mcSHOW_DBG_MSG(("DQS%d Final RODTEN_P1: (%2d, %2d)\n",
dqs_i, reg_mck_rodt_p1[dqs_i], reg_ui_rodt_p1[dqs_i]));
}
#endif
/* Set DQSIEN delay in MCK and UI */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_MCK_UI_DLY),
P_Fld(best_win->best_dqsien_dly_mck[0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0) |
P_Fld(best_win->best_dqsien_dly_ui[0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0) |
P_Fld(best_win->best_dqsien_dly_mck_p1[0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0) |
P_Fld(best_win->best_dqsien_dly_ui_p1[0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_MCK_UI_DLY),
P_Fld(best_win->best_dqsien_dly_mck[1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B1) |
P_Fld(best_win->best_dqsien_dly_ui[1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B1) |
P_Fld(best_win->best_dqsien_dly_mck_p1[1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B1) |
P_Fld(best_win->best_dqsien_dly_ui_p1[1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B1));
#if GATING_RODT_LATANCY_EN
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_RODTEN_MCK_UI_DLY),
P_Fld(reg_mck_rodt[0],
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_MCK_P0_B0) |
P_Fld(reg_ui_rodt[0],
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_UI_P0_B0) |
P_Fld(reg_mck_rodt_p1[0],
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_MCK_P1_B0) |
P_Fld(reg_ui_rodt_p1[0],
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_UI_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_RODTEN_MCK_UI_DLY),
P_Fld(reg_mck_rodt[1],
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_MCK_P0_B1) |
P_Fld(reg_ui_rodt[1],
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_UI_P0_B1) |
P_Fld(reg_mck_rodt_p1[1],
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_MCK_P1_B1) |
P_Fld(reg_ui_rodt_p1[1],
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_UI_P1_B1));
#endif
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY),
best_win->best_dqsien_dly_pi[0],
SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_PI_DLY),
best_win->best_dqsien_dly_pi[1],
SHU_RK_B1_DQSIEN_PI_DLY_DQSIEN_PI_B1);
}
/* By autoK: Set the result calibrated by HW to RG */
static void rxdqs_gating_auto_xlate(DRAMC_CTX_T *p,
struct rxdqs_gating_best_win *best_win,
struct rxdqs_gating_cal *rxdqs_cal)
{
u8 mck, ui, pi;
U8 mck_p1, ui_p1;
u8 mck2ui, freq_div;
U8 total_ui;
#if GATING_RODT_LATANCY_EN
U8 mck_rodt, ui_rodt;
U8 mck_rodt_p1, ui_rodt_p1;
#endif
U16 value;
u8 dqs_i;
/* Transfer HW unit to RG unit */
for (dqs_i = 0; dqs_i < p->data_width/DQS_BIT_NUMBER; dqs_i++) {
mck = best_win->best_dqsien_dly_mck[dqs_i];
ui = best_win->best_dqsien_dly_ui[dqs_i];
pi = best_win->best_dqsien_dly_pi[dqs_i];
mck2ui = rxdqs_cal->dqsien_ui_per_mck;
freq_div = rxdqs_cal->dqsien_freq_div;
if (vGet_Div_Mode(p) == DIV16_MODE)
total_ui = (mck << 4) + ui; /* 1:16 mode */
else if (vGet_Div_Mode(p) == DIV8_MODE)
total_ui = (mck << 3) + ui; /* 1: 8 mode */
else
total_ui = (mck << 2) + ui; /* 1: 4 mode */
/* RG is always 1:16 mode */
mck = (total_ui >> 4);
ui = (total_ui & 0xf);
value = mck * mck2ui + ui; /* Total UI number */
mck_p1 = (value + freq_div) / mck2ui;
ui_p1 = (value + freq_div) % mck2ui;
mcSHOW_DBG_MSG(("[Gating][RG] DQS%d Final result: (%d, %d, %d)\n", dqs_i, mck, ui, pi));
mcSHOW_DBG_MSG(("[Gating][RG] DQS%d Final result P1: (%d, %d)\n", dqs_i, mck_p1, ui_p1));
best_win->best_dqsien_dly_mck[dqs_i] = mck;
best_win->best_dqsien_dly_ui[dqs_i] = ui;
best_win->best_dqsien_dly_pi[dqs_i] = pi;
best_win->best_dqsien_dly_mck_p1[dqs_i] = mck_p1;
best_win->best_dqsien_dly_ui_p1[dqs_i] = ui_p1;
best_win->best_dqsien_dly_pi_p1[dqs_i] = pi;
}
}
#define RXDQS_GATING_AUTO_CAL_STATUS_BYTE_OFFSET 0x40
static DRAM_STATUS_T rxdqs_gating_auto_cal_status(DRAMC_CTX_T *p,
struct rxdqs_gating_auto_param *auto_param,
struct rxdqs_gating_best_win *best_win)
{
U8 mck_center[DQS_NUMBER], ui_center[DQS_NUMBER], pi_center[DQS_NUMBER];
U8 mck_left[DQS_NUMBER], ui_left[DQS_NUMBER], pi_left[DQS_NUMBER];
U8 mck_right[DQS_NUMBER], ui_right[DQS_NUMBER], pi_right[DQS_NUMBER];
U8 done[DQS_NUMBER] = { 0 }, error[DQS_NUMBER] = { 0 };
DRAM_STATUS_T ret;
U8 done_bytes, total_bytes;
U8 byte_ofst;
U8 dqs_i;
total_bytes = p->data_width / DQS_BIT_NUMBER;
done_bytes = 0;
ret = DRAM_OK;
while (done_bytes < total_bytes) {
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++) {
/* If already done, skip this byte */
if (done[dqs_i])
continue;
byte_ofst = dqs_i * RXDQS_GATING_AUTO_CAL_STATUS_BYTE_OFFSET;
done[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS0 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS0_AUTOK_DONE_B0_RK0);
error[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS0 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS0_AUTOK_ERR_B0_RK0);
/* If autok fail, done flag will not be asserted. */
if (done[dqs_i] || error[dqs_i]) {
/* Done and Pass */
if (error[dqs_i] == 0) {
mck_center[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS0 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS0_DQSIEN_AUTOK_C_MCK_B0_RK0);
ui_center[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS0 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS0_DQSIEN_AUTOK_C__UI_B0_RK0);
pi_center[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS0 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS0_DQSIEN_AUTOK_C__PI_B0_RK0);
mck_left[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_L_MCK_B0_RK0);
ui_left[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_L__UI_B0_RK0);
pi_left[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_L__PI_B0_RK0);
/* If early break mode not enabled, right boundary could be found */
if (auto_param->early_break == DISABLE) {
mck_right[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_R_MCK_B0_RK0);
ui_right[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_R__UI_B0_RK0);
pi_right[dqs_i] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_STATUS1 + byte_ofst),
DQSIEN_AUTOK_B0_RK0_STATUS1_DQSIEN_AUTOK_R__PI_B0_RK0);
}
}
else
{
/* If error occurred for this byte, it will be treated as a DONE condition */
done[dqs_i] = 1;
}
if (auto_param->dbg_mode == ENABLE) {
U32 dbg_reg_addr;
U32 dbg_reg_idx;
U32 dbg_reg_val;
dbg_reg_addr = DRAMC_REG_ADDR(
DDRPHY_REG_DQSIEN_AUTOK_B0_RK0_DBG_STATUS0 + byte_ofst);
for (dbg_reg_idx = 0;
dbg_reg_idx < RXDQS_GATING_AUTO_DBG_REG_NUM;
dbg_reg_idx++, dbg_reg_addr += 4) {
dbg_reg_val = u4IO32Read4B(dbg_reg_addr);
mcSHOW_ERR_MSG(("B%d Gating AUTOK DBG Status-%d: [0x%08x]\n",
dqs_i, dbg_reg_idx, dbg_reg_val));
}
}
done_bytes++;
}
}
mcDELAY_MS(1);
}
/* Log it */
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++) {
mcSHOW_DBG_MSG(("[Gating][%s] AUTOK of CH-%d, Rk-%d, Byte-%d:\n",
error[dqs_i]? "Fail" : "Pass", p->channel, p->rank, dqs_i));
if (done[dqs_i]) {
if (error[dqs_i] == 0) {
mcSHOW_DBG_MSG(("\tcenter(%2d, %2d, %2d)\n",
mck_center[dqs_i], ui_center[dqs_i], pi_center[dqs_i]));
mcSHOW_DBG_MSG(("\tleft(%2d, %2d, %2d)\n",
mck_left[dqs_i], ui_left[dqs_i], pi_left[dqs_i]));
if (auto_param->early_break == DISABLE) {
mcSHOW_DBG_MSG(("\tright(%2d, %2d, %2d)\n",
mck_right[dqs_i], ui_right[dqs_i], pi_right[dqs_i]));
}
}
if (error[dqs_i]) {
ret = DRAM_FAIL;
} else {
/* If passed, shall set the result to RG */
best_win->best_dqsien_dly_mck[dqs_i] = mck_center[dqs_i];
best_win->best_dqsien_dly_ui[dqs_i] = ui_center[dqs_i];
best_win->best_dqsien_dly_pi[dqs_i] = pi_center[dqs_i];
}
}
}
rxdqs_gating_auto_cal_stop(p);
return ret;
}
static DRAM_STATUS_T dramc_rx_dqs_gating_auto_cal(DRAMC_CTX_T *p)
{
struct rxdqs_gating_auto_param auto_param;
struct rxdqs_gating_best_win rxdqs_best_win;
struct rxdqs_gating_cal rxdqs_cal;
DRAM_STATUS_T ret;
U8 start_ui, end_ui;
U8 mck2ui_hw;
U32 reg_backup_address[ ] = {
(DRAMC_REG_ADDR(DRAMC_REG_DUMMY_RD)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CG_CTRL0)),
(DRAMC_REG_ADDR(DRAMC_REG_TEST2_A4)),
(DRAMC_REG_ADDR(DRAMC_REG_RK_DUMMY_RD_ADR))
};
DramcBackupRegisters(p, reg_backup_address,
sizeof (reg_backup_address) / sizeof (U32));
ret = DRAM_OK;
memset((void *)&auto_param, 0, sizeof auto_param);
memset((void *)&rxdqs_best_win, 0, sizeof rxdqs_best_win);
memset((void *)&rxdqs_cal, 0, sizeof rxdqs_cal);
if (vGet_Div_Mode(p) == DIV4_MODE)
rxdqs_cal.dqsien_freq_div = 2;
else
rxdqs_cal.dqsien_freq_div = 4;
rxdqs_cal.dqsien_ui_per_mck = DQS_GW_UI_PER_MCK;
if (!rxdqs_gating_bypass(p)) {
/* 60868 has different mck2ui relations for HW and RG */
if (vGet_Div_Mode(p) == DIV16_MODE)
mck2ui_hw = 16;
else if (vGet_Div_Mode(p) == DIV8_MODE)
mck2ui_hw = 8;
else
mck2ui_hw = 4;
#if ENABLE_GATING_AUTOK_WA
if (__wa__gating_autok_init_ui[p->rank] > 3)
start_ui = __wa__gating_autok_init_ui[p->rank] - 3;
else
#endif
start_ui = u1GetGatingStartPos(p, AUTOK_ON);
end_ui = start_ui + 32;
/* Set auto calibration params */
auto_param.early_break = ENABLE;
auto_param.dbg_mode = ENABLE;
auto_param.init_mck = start_ui / mck2ui_hw;
auto_param.init_ui = start_ui % mck2ui_hw;
auto_param.end_mck = end_ui / mck2ui_hw;
auto_param.end_ui = end_ui % mck2ui_hw;
auto_param.pi_offset = 2; /* 2 ^ 2 = 4 */
auto_param.burst_len = RXDQS_BURST_LEN_8;
#if FOR_DV_SIMULATION_USED == 1
cal_sv_rand_args_t *psra = get_psra();
if (psra) {
auto_param.early_break =
psra->dqsien_autok_early_break_en? ENABLE: DISABLE;
auto_param.dbg_mode =
psra->dqsien_autok_dbg_mode_en? ENABLE: DISABLE;
auto_param.pi_offset =
psra->dqsien_autok_pi_offset? ENABLE: DISABLE;
}
#endif /* FOR_DV_SIMULATION_USED == 1 */
rxdqs_gating_auto_cal_cfg(p, &auto_param);
/* Trigger HW auto k */
rxdqs_gating_auto_cal_trigger(p);
ret = rxdqs_gating_auto_cal_status(p, &auto_param, &rxdqs_best_win);
if (ret == DRAM_OK)
vSetCalibrationResult(p, DRAM_CALIBRATION_GATING, DRAM_OK);
rxdqs_gating_auto_xlate(p, &rxdqs_best_win, &rxdqs_cal);
}
rxdqs_gating_fastk_save_restore(p, &rxdqs_best_win, &rxdqs_cal);
rxdqs_gating_set_final_result(p, rxdqs_cal.dqsien_ui_per_mck, &rxdqs_best_win);
rxdqs_gating_misc_process(p, &rxdqs_best_win);
DramcRestoreRegisters(p, reg_backup_address,
sizeof (reg_backup_address) / sizeof (U32));
DramPhyReset(p);
return ret;
}
static void rxdqs_gating_sw_cal_init(DRAMC_CTX_T *p, U8 use_enhanced_rdqs)
{
/* Disable Per-Bank ref */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_CONF0), 0, SHU_CONF0_PBREFEN);
/*----------------
* From DV
*------------------------*/
if (p->frequency == 800) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_STBCNT_SW_RST);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_STBCNT_SHU_RST_EN);
/* SELPH_MODE = BY RANK */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_DQSIEN_SELPH_BY_RANK_EN);
if (p->dram_type == TYPE_LPDDR5) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_STB_PICG_EARLY_1T_EN);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1),
0x1, MISC_STBCAL1_DIS_PI_TRACK_AS_NOT_RD);
/* PICG_EARLY_EN */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x1, B0_DQ6_RG_RX_ARDQ_OP_BIAS_SW_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x1, B0_DQ6_RG_RX_ARDQ_OP_BIAS_SW_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
0x1, MISC_STBCAL2_STB_PICG_EARLY_1T_EN);
/* BURST_MODE */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL),
0x1, MISC_SHU_STBCAL_DQSIEN_BURST_MODE);
#if (__LP5_COMBO__)
if (is_lp5_family(p)) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
0x1, B0_DQ9_RG_RX_ARDQS0_DQSIENMODE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
0x1, B1_DQ9_RG_RX_ARDQS0_DQSIENMODE_B1);
} else
#endif
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ9),
0x1, B0_DQ9_RG_RX_ARDQS0_DQSIENMODE_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ9),
0x1, B1_DQ9_RG_RX_ARDQS0_DQSIENMODE_B1);
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6),
0x2, B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6),
0x2, B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL),
0x1, MISC_STBCAL_DQSIENMODE);
/* New Rank Mode */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2),
P_Fld(0x1, MISC_STBCAL2_STB_IG_XRANK_CG_RST) |
P_Fld(0x1, MISC_STBCAL2_STB_RST_BY_RANK) |
P_Fld(0x1, MISC_STBCAL2_DQSIEN_SELPH_BY_RANK_EN));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2),
0x1, B0_PHY2_RG_RX_ARDQS_DQSIEN_UI_LEAD_LAG_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2),
0x1, B1_PHY2_RG_RX_ARDQS_DQSIEN_UI_LEAD_LAG_EN_B1);
//DramcHWGatingOnOff(p, 0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
MISC_STBCAL2_STBENCMPEN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RX_SET0), 0,
RX_SET0_DM4TO1MODE);
/* enable &reset DQS counter */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
MISC_STBCAL2_DQSG_CNT_EN);
mcDELAY_US(4); /* wait 1 auto refresh after DQS Counter enable */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
MISC_STBCAL2_DQSG_CNT_RST);
mcDELAY_US(1); /* delay 2T */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 0,
MISC_STBCAL2_DQSG_CNT_RST);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1),
u1GetRank(p), MISC_CTRL1_R_DMSTBENCMP_RK_OPT);
DramcEngine2Init(p, 0x55000000,
0xaa000000 | GATING_PATTERN_NUM_LP5, TEST_AUDIO_PATTERN, 0, TE_NO_UI_SHIFT);
if (use_enhanced_rdqs) {
/* TBD. Enter Enhanced RDQS training mode */
}
}
static void rxdqs_gating_set_dqsien_dly(DRAMC_CTX_T *p, U8 dly_ui,
struct rxdqs_gating_cal *rxdqs_cal)
{
U32 reg_mck, reg_ui;
U32 reg_mck_p1, reg_ui_p1;
#if GATING_RODT_LATANCY_EN
U32 reg_mck_rodt, reg_ui_rodt;
U32 reg_mck_rodt_p1, reg_ui_rodt_p1;
#endif
U8 mck2ui = rxdqs_cal->dqsien_ui_per_mck;
rxdqs_cal->dqsien_dly_mck = dly_ui / rxdqs_cal->dqsien_ui_per_mck;
rxdqs_cal->dqsien_dly_ui = dly_ui % rxdqs_cal->dqsien_ui_per_mck;
rxdqs_cal->dqsien_dly_mck_p1 = (dly_ui + rxdqs_cal->dqsien_freq_div) / mck2ui;
rxdqs_cal->dqsien_dly_ui_p1 = (dly_ui + rxdqs_cal->dqsien_freq_div) % mck2ui;
reg_mck = rxdqs_cal->dqsien_dly_mck;
reg_ui = rxdqs_cal->dqsien_dly_ui;
reg_mck_p1 = rxdqs_cal->dqsien_dly_mck_p1;
reg_ui_p1 = rxdqs_cal->dqsien_dly_ui_p1;
#if GATING_RODT_LATANCY_EN
value = (reg_mck * mck2ui) + reg_ui;
if (value >= 11) {
/* For RODT, MCK2UI is different from Gating */
U8 rodt_mck2ui = get_rodt_mck2ui(p);
value -= 11;
reg_mck_rodt = value / rodt_mck2ui;
reg_ui_rodt = value % rodt_mck2ui;
reg_mck_rodt_p1 = reg_mck_rodt;
reg_ui_rodt_p1 = reg_ui_rodt;
} else {
reg_mck_rodt = 0;
reg_ui_rodt = 0;
reg_mck_rodt_p1 = 4;
reg_ui_rodt_p1 = 4;
mcSHOW_DBG_MSG(("[Warning] RODT cannot be -11UI\n"));
}
#endif
/* Set DQSIEN delay in MCK and UI */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_MCK_UI_DLY),
P_Fld(reg_mck,
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0) |
P_Fld(reg_ui,
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0) |
P_Fld(reg_mck_p1,
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0) |
P_Fld(reg_ui_p1,
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_MCK_UI_DLY),
P_Fld(reg_mck,
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B1) |
P_Fld(reg_ui,
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B1) |
P_Fld(reg_mck_p1,
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B1) |
P_Fld(reg_ui_p1,
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B1));
#if GATING_RODT_LATANCY_EN
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_RODTEN_MCK_UI_DLY),
P_Fld(reg_mck_rodt,
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_MCK_P0_B0) |
P_Fld(reg_ui_rodt,
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_UI_P0_B0) |
P_Fld(reg_mck_rodt_p1,
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_MCK_P1_B0) |
P_Fld(reg_ui_rodt_p1,
SHU_RK_B0_RODTEN_MCK_UI_DLY_RODTEN_UI_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_RODTEN_MCK_UI_DLY),
P_Fld(reg_mck_rodt,
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_MCK_P0_B1) |
P_Fld(reg_ui_rodt,
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_UI_P0_B1) |
P_Fld(reg_mck_rodt_p1,
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_MCK_P1_B1) |
P_Fld(reg_ui_rodt_p1,
SHU_RK_B1_RODTEN_MCK_UI_DLY_RODTEN_UI_P1_B1));
#endif
}
static void rxdqs_gating_sw_cal_trigger(DRAMC_CTX_T *p,
struct rxdqs_gating_cal *rxdqs_cal)
{
#if 0//ENABLE_DDR800_OPEN_LOOP_MODE_OPTION -> No 0.5UI after A60868
if (u1IsPhaseMode(p) == TRUE) {
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0),
rxdqs_cal->dqsien_dly_pi >> 4, SHU_R0_B0_DQ0_DA_ARPI_DDR400_0D5UI_RK0_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0),
rxdqs_cal->dqsien_dly_pi >> 4, SHU_R0_B1_DQ0_DA_ARPI_DDR400_0D5UI_RK0_B1);
} else
#endif
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY),
rxdqs_cal->dqsien_dly_pi, SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_PI_DLY),
rxdqs_cal->dqsien_dly_pi, SHU_RK_B1_DQSIEN_PI_DLY_DQSIEN_PI_B1);
}
DramPhyReset(p);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 1,
MISC_STBCAL2_DQSG_CNT_RST);
mcDELAY_US(1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2), 0,
MISC_STBCAL2_DQSG_CNT_RST);
/* enable TE2, audio pattern */
DramcEngine2Run(p, TE_OP_READ_CHECK, TEST_AUDIO_PATTERN);
}
static void rxdqs_gating_get_leadlag(DRAMC_CTX_T *p,
struct rxdqs_gating_trans *rxdqs_trans,
struct rxdqs_gating_cal *rxdqs_cal)
{
U8 dqs_i;
U8 debounce_thrd_PI = 16;
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++) {
if (dqs_i == 0) {
rxdqs_trans->dqs_lead[0] = u4IO32ReadFldAlign(
DRAMC_REG_ADDR(DDRPHY_REG_MISC_PHY_RGS_STBEN_B0),
MISC_PHY_RGS_STBEN_B0_AD_RX_ARDQS0_STBEN_LEAD_B0);
rxdqs_trans->dqs_lag[0] = u4IO32ReadFldAlign(
DRAMC_REG_ADDR(DDRPHY_REG_MISC_PHY_RGS_STBEN_B0),
MISC_PHY_RGS_STBEN_B0_AD_RX_ARDQS0_STBEN_LAG_B0);
} else {
rxdqs_trans->dqs_lead[1] = u4IO32ReadFldAlign(
DRAMC_REG_ADDR(DDRPHY_REG_MISC_PHY_RGS_STBEN_B1),
MISC_PHY_RGS_STBEN_B1_AD_RX_ARDQS0_STBEN_LEAD_B1);
rxdqs_trans->dqs_lag[1] = u4IO32ReadFldAlign(
DRAMC_REG_ADDR(DDRPHY_REG_MISC_PHY_RGS_STBEN_B1),
MISC_PHY_RGS_STBEN_B1_AD_RX_ARDQS0_STBEN_LAG_B1);
}
if ((rxdqs_trans->dqs_lead[dqs_i] == 1) &&
(rxdqs_trans->dqs_lag[dqs_i] == 1)) {
rxdqs_trans->dqs_high[dqs_i]++;
rxdqs_trans->dqs_transition[dqs_i] = 1;
/* Record the latest value that causes (lead, lag) = (1, 1) */
rxdqs_trans->dqsien_dly_mck_leadlag[dqs_i] =
rxdqs_cal->dqsien_dly_mck;
rxdqs_trans->dqsien_dly_ui_leadlag[dqs_i] =
rxdqs_cal->dqsien_dly_ui;
rxdqs_trans->dqsien_dly_pi_leadlag[dqs_i] =
rxdqs_cal->dqsien_dly_pi;
} else if ((rxdqs_trans->dqs_high[dqs_i] *
rxdqs_cal->dqsien_pi_adj_step) >= debounce_thrd_PI) {
/* Consecutive 16 PI DQS high for de-glitch */
if (((rxdqs_trans->dqs_lead[dqs_i] == 1) &&
(rxdqs_trans->dqs_lag[dqs_i] == 0)) ||
((rxdqs_trans->dqs_lead[dqs_i] == 0) &&
(rxdqs_trans->dqs_lag[dqs_i] == 1))) {
rxdqs_trans->dqs_transition[dqs_i]++;
}
#if GATING_LEADLAG_LOW_LEVEL_CHECK
else if ((rxdqs_trans->dqs_lead[dqs_i] == 0) &&
(rxdqs_trans->dqs_lag[dqs_i] == 0)){
if ((rxdqs_trans->dqs_low[dqs_i] *
rxdqs_cal->dqsien_pi_adj_step) >= debounce_thrd_PI) {
/* (lead, lag) = (0, 0), transition done */
rxdqs_trans->dqs_transitioned[dqs_i] = 1;
}
rxdqs_trans->dqs_low[dqs_i]++;
}else {
rxdqs_trans->dqs_high[dqs_i] = 0;
rxdqs_trans->dqs_low[dqs_i] = 0;
}
#else
else {
/* (lead, lag) = (0, 0), transition done */
rxdqs_trans->dqs_transitioned[dqs_i] = 1;
}
#endif
} else {
/* Lead/lag = (1, 1) number is too few. Reset dqs_high */
rxdqs_trans->dqs_high[dqs_i] = 0;
#if GATING_LEADLAG_LOW_LEVEL_CHECK
rxdqs_trans->dqs_low[dqs_i] = 0;
#endif
}
}
}
static U8 rxdqs_gating_sw_cal(DRAMC_CTX_T *p,
struct rxdqs_gating_trans *rxdqs_trans,
struct rxdqs_gating_cal *rxdqs_cal, U8 *pass_byte_count,
struct rxdqs_gating_best_win *best_win, U8 dly_ui, U8 dly_ui_end)
{
U8 gating_error[DQS_NUMBER];
U32 debug_cnt[DQS_NUMBER];
U32 debug_pass_cnt;
U8 dqs_i;
U8 passed_bytes;
memset(debug_cnt, 0, sizeof(debug_cnt));
passed_bytes = *pass_byte_count;
rxdqs_gating_sw_cal_trigger(p, rxdqs_cal);
if (p->rank == RANK_0) {
gating_error[0] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_MISC_STBERR_ALL),
MISC_STBERR_ALL_GATING_ERROR_B0_RK0);
gating_error[1] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_MISC_STBERR_ALL),
MISC_STBERR_ALL_GATING_ERROR_B1_RK0);
} else {
gating_error[0] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_MISC_STBERR_ALL),
MISC_STBERR_ALL_GATING_ERROR_B0_RK1);
gating_error[1] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(
DDRPHY_REG_MISC_STBERR_ALL),
MISC_STBERR_ALL_GATING_ERROR_B1_RK1);
}
/* read DQS counter
* Note: DQS counter is no longer used as pass condition. Here
* Read it and log it is just as debug method. Any way, DQS counter
* can still be used as a clue: it will be n*0x23 when gating is correct
*/
debug_cnt[0] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_CAL_DQSG_CNT_B0));
debug_cnt[1] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_CAL_DQSG_CNT_B1));
/* read (lead, lag) */
rxdqs_gating_get_leadlag(p, rxdqs_trans, rxdqs_cal);
mcSHOW_DBG_MSG(("%2d %2d %2d | ",
rxdqs_cal->dqsien_dly_mck, rxdqs_cal->dqsien_dly_ui,
rxdqs_cal->dqsien_dly_pi));
mcSHOW_DBG_MSG(("B1->B0 | %x %x | %x %x | (%d %d) (%d %d)\n",
debug_cnt[1], debug_cnt[0],
gating_error[1], gating_error[0],
rxdqs_trans->dqs_lead[1], rxdqs_trans->dqs_lag[1],
rxdqs_trans->dqs_lead[0], rxdqs_trans->dqs_lag[0]));
#if (__LP5_COMBO__)
if((is_lp5_family(p)) && (vGet_Div_Mode(p) == DIV16_MODE))
debug_pass_cnt = (GATING_GOLDEND_DQSCNT_LP5 >> 1);
else
#endif
debug_pass_cnt = GATING_GOLDEND_DQSCNT_LP5;
/* Decide the window center */
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++) {
if (passed_bytes & (1 << dqs_i))
continue;
if ((gating_error[dqs_i] == 0) && (debug_cnt[dqs_i] == debug_pass_cnt)) {
/* Calcuate DQSIEN position */
if (rxdqs_trans->dqs_transitioned[dqs_i] != 0) {
U8 pass_count = rxdqs_trans->dqs_transition[dqs_i];
U8 offset = (pass_count * rxdqs_cal->dqsien_pi_adj_step) / 2;
U8 mck2ui, ui2pi, freq_div;
U8 tmp;
mck2ui = rxdqs_cal->dqsien_ui_per_mck;
ui2pi = rxdqs_cal->dqsien_pi_per_ui;
freq_div = rxdqs_cal->dqsien_freq_div;
/* PI */
tmp = rxdqs_trans->dqsien_dly_pi_leadlag[dqs_i] + offset;
best_win->best_dqsien_dly_pi[dqs_i] = tmp % ui2pi;
best_win->best_dqsien_dly_pi_p1[dqs_i] =
best_win->best_dqsien_dly_pi[dqs_i];
/* UI & MCK - P0 */
tmp /= ui2pi;
tmp = rxdqs_trans->dqsien_dly_ui_leadlag[dqs_i] + tmp;
best_win->best_dqsien_dly_ui[dqs_i] = tmp % mck2ui;
best_win->best_dqsien_dly_mck[dqs_i] =
rxdqs_trans->dqsien_dly_mck_leadlag[dqs_i] + (tmp / mck2ui);
/* UI & MCK - P1 */
best_win->best_dqsien_dly_ui_p1[dqs_i] =
best_win->best_dqsien_dly_mck[dqs_i] * mck2ui +
best_win->best_dqsien_dly_ui[dqs_i] + freq_div; /* Total UI for Phase1 */
mcSHOW_DBG_MSG(("Total UI for P1: %d, mck2ui %d\n",
best_win->best_dqsien_dly_mck_p1[dqs_i], mck2ui));
best_win->best_dqsien_dly_mck_p1[dqs_i] =
best_win->best_dqsien_dly_ui_p1[dqs_i] / mck2ui;
best_win->best_dqsien_dly_ui_p1[dqs_i] =
best_win->best_dqsien_dly_ui_p1[dqs_i] % mck2ui;
mcSHOW_DBG_MSG(("best dqsien dly found for B%d: "
"(%2d, %2d, %2d)\n", dqs_i,
best_win->best_dqsien_dly_mck[dqs_i],
best_win->best_dqsien_dly_ui[dqs_i],
best_win->best_dqsien_dly_pi[dqs_i]));
passed_bytes |= 1 << dqs_i;
if (((p->data_width == DATA_WIDTH_16BIT) &&
(passed_bytes == 0x3)) ||
((p->data_width == DATA_WIDTH_32BIT) &&
(passed_bytes == 0xf))) {
dly_ui = dly_ui_end;
break;
}
}
} else {
/* Clear lead lag info in case lead/lag flag toggled
* while gating counter & gating error still incorrect
*/
rxdqs_trans->dqs_high[dqs_i] = 0;
rxdqs_trans->dqs_transition[dqs_i] = 0;
rxdqs_trans->dqs_transitioned[dqs_i] = 0;
}
}
*pass_byte_count = passed_bytes;
return dly_ui;
}
static DRAM_STATUS_T dramc_rx_dqs_gating_sw_cal(DRAMC_CTX_T *p,
U8 use_enhance_rdqs)
{
struct rxdqs_gating_cal rxdqs_cal;
struct rxdqs_gating_trans rxdqs_trans;
struct rxdqs_gating_best_win rxdqs_best_win;
U8 dly_ui, dly_ui_start, dly_ui_end;
U8 pi_per_ui, ui_per_mck, freq_div;
U8 pass_byte_count;
U8 dqs_i;
U8 u1GatingErrorFlag=0;
if (p == NULL) {
mcSHOW_ERR_MSG(("[Error] Context NULL\n"));
return DRAM_FAIL;
}
memset(&rxdqs_cal, 0, sizeof(struct rxdqs_gating_cal));
memset(&rxdqs_trans, 0, sizeof(struct rxdqs_gating_trans));
memset(&rxdqs_best_win, 0, sizeof(struct rxdqs_gating_best_win));
pi_per_ui = DQS_GW_PI_PER_UI; /* 1 UI = ? PI. Sams as CBT, differ according to data rate?? */
ui_per_mck = DQS_GW_UI_PER_MCK; /* 1 mck = ? UI. Decided by (Tmck/Tck) * (Tck/Twck) */
if (vGet_Div_Mode(p) == DIV4_MODE)
freq_div = 2;
else
freq_div = 4;
#if ENABLE_DDR800_OPEN_LOOP_MODE_OPTION
if (u1IsPhaseMode(p) == TRUE)
rxdqs_cal.dqsien_pi_adj_step = (0x1 << 4); // Divide by 16 (90 degree)
else
#endif
rxdqs_cal.dqsien_pi_adj_step = DQS_GW_FINE_STEP;
#if ENABLE_GATING_AUTOK_WA
if (__wa__gating_swk_for_autok)
rxdqs_cal.dqsien_pi_adj_step = pi_per_ui;
#endif
rxdqs_cal.dqsien_pi_per_ui = pi_per_ui;
rxdqs_cal.dqsien_ui_per_mck = ui_per_mck;
rxdqs_cal.dqsien_freq_div = freq_div;
U32 reg_backup_address[ ] = {
(DRAMC_REG_ADDR(DRAMC_REG_REFCTRL0)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL1)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2)),
};
/* Register backup */
DramcBackupRegisters(p, reg_backup_address,
sizeof (reg_backup_address) / sizeof (U32));
if (!rxdqs_gating_bypass(p)) {
rxdqs_gating_sw_cal_init(p, use_enhance_rdqs);
#if 1
#if (LP5_DDR4266_RDBI_WORKAROUND)
if((is_lp5_family(p)) && (p->frequency == 2133))
dly_ui_start = 15;
else if((is_lp5_family(p)) && (p->frequency == 2750))
dly_ui_start = 12;
else
dly_ui_start = u1GetGatingStartPos(p, AUTOK_OFF);//7; //12;ly_ui_start + 32;
#else
if((is_lp5_family(p)) && ((p->frequency == 2133) || (p->frequency == 2750)))
dly_ui_start = 5;
else
dly_ui_start = u1GetGatingStartPos(p, AUTOK_OFF);//7; //12;ly_ui_start + 32;
#endif
dly_ui_end = dly_ui_start+ 32;
pass_byte_count = 0;
#else
#if __LP5_COMBO__
if (is_lp5_family(p))
{
if (p->frequency == 1600)
dly_ui_start = 7; //12;
else
dly_ui_start = 8; //12;
dly_ui_end = dly_ui_start + 32;
pass_byte_count = 0;
}
else
#endif
{
dly_ui_start = 9; //12; Eddie change to 9 for Hynix Normal Mode
if(p->freq_sel==LP4_DDR4266)
{
dly_ui_start = 16;
}
dly_ui_end = dly_ui_start + 32;
pass_byte_count = 0;
}
#endif
for (dly_ui = dly_ui_start; dly_ui < dly_ui_end;
dly_ui += DQS_GW_COARSE_STEP) {
rxdqs_gating_set_dqsien_dly(p, dly_ui, &rxdqs_cal);
for (rxdqs_cal.dqsien_dly_pi = 0; rxdqs_cal.dqsien_dly_pi <
pi_per_ui; rxdqs_cal.dqsien_dly_pi +=
rxdqs_cal.dqsien_pi_adj_step) {
dly_ui = rxdqs_gating_sw_cal(p, &rxdqs_trans, &rxdqs_cal,
&pass_byte_count, &rxdqs_best_win, dly_ui, dly_ui_end);
if (dly_ui == dly_ui_end)
break;
}
}
DramcEngine2End(p);
//check if there is no pass taps for each DQS
for (dqs_i=0; dqs_i<(p->data_width/DQS_BIT_NUMBER); dqs_i++)
{
if ((pass_byte_count<< dqs_i)==0)
{
u1GatingErrorFlag=1;
/*TINFO="error, no pass taps in DQS_%d !!!\n", dqs_i*/
mcSHOW_ERR_MSG(("error, no pass taps in DQS_%d!\n", dqs_i));
}
}
if (u1GatingErrorFlag==0)
vSetCalibrationResult(p, DRAM_CALIBRATION_GATING, DRAM_OK);
#if (ENABLE_GATING_AUTOK_WA)
if (!u1GatingErrorFlag && __wa__gating_swk_for_autok) {
U8 ui[DQS_NUMBER], ui_min = 0xff;
U8 dqs_index;
for (dqs_index = 0; dqs_index < (p->data_width/DQS_BIT_NUMBER); dqs_index++){
ui[dqs_index] = rxdqs_best_win.best_dqsien_dly_mck[dqs_index] * ui_per_mck +
rxdqs_best_win.best_dqsien_dly_ui[dqs_index];
if (ui[dqs_index] < ui_min)
ui_min = ui[dqs_index];
}
__wa__gating_autok_init_ui[p->rank] = ui_min;
DramcRestoreRegisters(p, reg_backup_address,
sizeof (reg_backup_address) / sizeof (U32));
return DRAM_OK;
}
#endif
}
rxdqs_gating_fastk_save_restore(p, &rxdqs_best_win, &rxdqs_cal);
rxdqs_gating_misc_process(p, &rxdqs_best_win);
mcSHOW_DBG_MSG(("[Gating] SW calibration Done\n"));
/* Set MCK & UI */
rxdqs_gating_set_final_result(p, ui_per_mck, &rxdqs_best_win);
DramcRestoreRegisters(p, reg_backup_address,
sizeof (reg_backup_address) / sizeof (U32));
DramPhyReset(p);
return DRAM_OK;
}
/* LPDDR5 Rx DQS Gating */
DRAM_STATUS_T dramc_rx_dqs_gating_cal(DRAMC_CTX_T *p,
u8 autok, U8 use_enhanced_rdqs)
{
DRAM_STATUS_T ret;
vPrintCalibrationBasicInfo(p);
#if ENABLE_GATING_AUTOK_WA
if (autok) {
__wa__gating_swk_for_autok = 1;
dramc_rx_dqs_gating_sw_cal(p, use_enhanced_rdqs);
__wa__gating_swk_for_autok = 0;
}
#endif
// default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_GATING, DRAM_FAIL);
/* Try HW auto calibration first. If failed,
* will try SW mode.
*/
if (autok) {
#if ENABLE_GATING_AUTOK_WA
if (rxdqs_gating_bypass(p)) /* Already done by SWK */
return DRAM_OK;
#endif
ret = dramc_rx_dqs_gating_auto_cal(p);
if (ret == DRAM_OK) {
vSetCalibrationResult(p, DRAM_CALIBRATION_GATING, DRAM_OK);
return DRAM_OK;
}
mcSHOW_ERR_MSG(("[Error] Gating auto calibration fail!!\n"));
}
mcSHOW_DBG_MSG(("[Gating] SW mode calibration\n"));
return dramc_rx_dqs_gating_sw_cal(p, use_enhanced_rdqs);
}
///TODO: wait for porting +++
#if GATING_ADJUST_TXDLY_FOR_TRACKING
void DramcRxdqsGatingPostProcess(DRAMC_CTX_T *p)
{
U8 dqs_i;
U8 u1RankIdx, u1RankMax;
S8 s1ChangeDQSINCTL;
#if XRTRTR_NEW_CROSS_RK_MODE
U16 u2PHSINCTL = 0;
U32 u4Rank_Sel_MCK_P0[2], u4Rank_Sel_MCK_P1[2], u4RANKINCTL_STB;
#endif
#if RDSEL_TRACKING_EN
U32 u4PI_value[2] = {0};
#endif
U32 backup_rank;
U32 u4ReadDQSINCTL, u4RankINCTL_ROOT, u4XRTR2R, reg_TX_dly_DQSgated_min = 0;
U8 mck2ui_shift;
backup_rank = u1GetRank(p);
#ifdef XRTR2R_PERFORM_ENHANCE_DQSG_RX_DLY
if (vGet_Div_Mode(p) == DIV8_MODE)
{
// wei-jen: DQSgated_min should be 2 when freq >= 1333, 1 when freq < 1333
if (p->frequency >= 1333)
{
reg_TX_dly_DQSgated_min = 2;
}
else
{
reg_TX_dly_DQSgated_min = 1;
}
}
else // for LPDDR4 1:4 mode
{
// 1866,1600,1333,1200 : reg_TX_dly_DQSgated (min) =2
reg_TX_dly_DQSgated_min = 2;
}
#else
// wei-jen: DQSgated_min should be 3 when freq >= 1333, 2 when freq < 1333
if (p->frequency >= 1333)
{
reg_TX_dly_DQSgated_min = 3;
}
else
{
reg_TX_dly_DQSgated_min = 2;
}
#endif
//Sylv_ia MP setting is switched to new mode, so RANKRXDVS can be set as 0 (review by HJ Huang)
#if 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_SHU_B0_DQ7), u1RankRxDVS, SHU_B0_DQ7_R_DMRANKRXDVS_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_SHU_B1_DQ7), u1RankRxDVS, SHU_B1_DQ7_R_DMRANKRXDVS_B1);
#endif
// === End of DVS setting =====
s1ChangeDQSINCTL = reg_TX_dly_DQSgated_min - u1TXDLY_Cal_min;
mcSHOW_DBG_MSG(("[RxdqsGatingPostProcess] freq %d\n"
"ChangeDQSINCTL %d, reg_TX_dly_DQSgated_min %d, u1TXDLY_Cal_min %d\n",
p->frequency,
s1ChangeDQSINCTL, reg_TX_dly_DQSgated_min, u1TXDLY_Cal_min));
mcDUMP_REG_MSG(("[RxdqsGatingPostProcess] freq %d\n"
"ChangeDQSINCTL %d, reg_TX_dly_DQSgated_min %d, u1TXDLY_Cal_min %d\n",
p->frequency,
s1ChangeDQSINCTL, reg_TX_dly_DQSgated_min, u1TXDLY_Cal_min));
if (vGet_Div_Mode(p) == DIV16_MODE)
mck2ui_shift = 4;
else if (vGet_Div_Mode(p) == DIV8_MODE)
mck2ui_shift = 3;
else
mck2ui_shift = 2;
if (s1ChangeDQSINCTL != 0) // need to change DQSINCTL and TXDLY of each byte
{
u1TXDLY_Cal_min += s1ChangeDQSINCTL;
u1TXDLY_Cal_max += s1ChangeDQSINCTL;
if (p->support_rank_num == RANK_DUAL)
u1RankMax = RANK_MAX;
else
u1RankMax = RANK_1;
for (u1RankIdx = 0; u1RankIdx < u1RankMax; u1RankIdx++)
{
mcSHOW_DBG_MSG2(("Rank: %d\n", u1RankIdx));
mcDUMP_REG_MSG(("Rank: %d\n", u1RankIdx));
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++)
{
#if 1
U8 total_ui, total_ui_P1;
total_ui = (ucbest_coarse_mck_backup[u1RankIdx][dqs_i] << 4) + ucbest_coarse_ui_backup[u1RankIdx][dqs_i];
total_ui_P1 = (ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i] << 4) + ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i];
total_ui += (s1ChangeDQSINCTL << mck2ui_shift);
total_ui_P1 += (s1ChangeDQSINCTL << mck2ui_shift);
ucbest_coarse_mck_backup[u1RankIdx][dqs_i] = (total_ui >> 4);
ucbest_coarse_ui_backup[u1RankIdx][dqs_i] = total_ui & 0xf;
ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i] = (total_ui_P1 >> 4);
ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i] = total_ui_P1 & 0xf;
#else
if (vGet_Div_Mode(p) == DIV8_MODE)
{
u4ReadTXDLY[u1RankIdx][dqs_i] = ucbest_coarse_mck_backup[u1RankIdx][dqs_i];
u4ReadTXDLY_P1[u1RankIdx][dqs_i] = ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i];
u4ReadTXDLY[u1RankIdx][dqs_i] += s1ChangeDQSINCTL;
u4ReadTXDLY_P1[u1RankIdx][dqs_i] += s1ChangeDQSINCTL;
ucbest_coarse_mck_backup[u1RankIdx][dqs_i] = u4ReadTXDLY[u1RankIdx][dqs_i];
ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i] = u4ReadTXDLY_P1[u1RankIdx][dqs_i];
}
else // LP3 or LP4 1:4 mode
{
u4ReadTXDLY[u1RankIdx][dqs_i] = ((ucbest_coarse_mck_backup[u1RankIdx][dqs_i] << 1) + ((ucbest_coarse_ui_backup[u1RankIdx][dqs_i] >> 2) & 0x1));
u4ReadTXDLY_P1[u1RankIdx][dqs_i] = ((ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i] << 1) + ((ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i] >> 2) & 0x1));
u4ReadTXDLY[u1RankIdx][dqs_i] += s1ChangeDQSINCTL;
u4ReadTXDLY_P1[u1RankIdx][dqs_i] += s1ChangeDQSINCTL;
ucbest_coarse_mck_backup[u1RankIdx][dqs_i] = (u4ReadTXDLY[u1RankIdx][dqs_i] >> 1);
ucbest_coarse_ui_backup[u1RankIdx][dqs_i] = ((u4ReadTXDLY[u1RankIdx][dqs_i] & 0x1) << 2) + (ucbest_coarse_ui_backup[u1RankIdx][dqs_i] & 0x3);
ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i] = (u4ReadTXDLY_P1[u1RankIdx][dqs_i] >> 1);
ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i] = ((u4ReadTXDLY_P1[u1RankIdx][dqs_i] & 0x1) << 2) + (ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i] & 0x3);
}
#endif
mcSHOW_DBG_MSG(("best DQS%d dly(2T, 0.5T) = (%d, %d)\n", dqs_i, ucbest_coarse_mck_backup[u1RankIdx][dqs_i], ucbest_coarse_ui_backup[u1RankIdx][dqs_i]));
mcDUMP_REG_MSG(("PostProcess best DQS%d dly(2T, 0.5T) = (%d, %d)\n", dqs_i, ucbest_coarse_mck_backup[u1RankIdx][dqs_i], ucbest_coarse_ui_backup[u1RankIdx][dqs_i]));
}
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++)
{
mcSHOW_DBG_MSG(("best DQS%d P1 dly(2T, 0.5T) = (%d, %d)\n", dqs_i, ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i], ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i]));
mcDUMP_REG_MSG(("PostProcess best DQS%d P1 dly(2T, 0.5T) = (%d, %d)\n", dqs_i, ucbest_coarse_mck_P1_backup[u1RankIdx][dqs_i], ucbest_coarse_ui_P1_backup[u1RankIdx][dqs_i]));
}
}
for (u1RankIdx = 0; u1RankIdx < u1RankMax; u1RankIdx++)
{
vSetRank(p, u1RankIdx);
// 4T or 2T coarse tune
/* Set DQSIEN delay in MCK and UI */
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_MCK_UI_DLY),
P_Fld(ucbest_coarse_mck_backup[u1RankIdx][0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0) |
P_Fld(ucbest_coarse_ui_backup[u1RankIdx][0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0) |
P_Fld(ucbest_coarse_mck_P1_backup[u1RankIdx][0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0) |
P_Fld(ucbest_coarse_ui_P1_backup[u1RankIdx][0],
SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_MCK_UI_DLY),
P_Fld(ucbest_coarse_mck_backup[u1RankIdx][1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B1) |
P_Fld(ucbest_coarse_ui_backup[u1RankIdx][1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B1) |
P_Fld(ucbest_coarse_mck_P1_backup[u1RankIdx][1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B1) |
P_Fld(ucbest_coarse_ui_P1_backup[u1RankIdx][1],
SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B1));
#if RDSEL_TRACKING_EN
//Byte 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_INI_UIPI),
(ucbest_coarse_mck_backup[u1RankIdx][0] << 4) | (ucbest_coarse_ui_backup[u1RankIdx][0]),
SHU_R0_B0_INI_UIPI_CURR_INI_UI_B0);//UI
//Byte 1
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_INI_UIPI),
(ucbest_coarse_mck_backup[u1RankIdx][1] << 4) | (ucbest_coarse_ui_backup[u1RankIdx][1]),
SHU_R0_B1_INI_UIPI_CURR_INI_UI_B1);//UI
#endif
}
}
vSetRank(p, backup_rank);
u4ReadDQSINCTL = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RK_DQSCTL),
MISC_SHU_RK_DQSCTL_DQSINCTL);
mcDUMP_REG_MSG(("u4ReadDQSINCTL=%d\n", u4ReadDQSINCTL));
u4ReadDQSINCTL -= s1ChangeDQSINCTL;
#if ENABLE_READ_DBI
if (p->DBI_R_onoff[p->dram_fsp])
{
u4ReadDQSINCTL++;
#if 0//cc mark for reg not found
u4ReadRODT = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ODTCTRL), SHU_ODTCTRL_RODT);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ODTCTRL), u4ReadRODT + 1, SHU_ODTCTRL_RODT); //update RODT value when READ_DBI is on
#endif
}
#endif
#if XRTRTR_NEW_CROSS_RK_MODE
for (dqs_i = 0; dqs_i < (p->data_width / DQS_BIT_NUMBER); dqs_i++)
{
if (ucbest_coarse_mck_backup[RANK_0][dqs_i] > ucbest_coarse_mck_backup[RANK_1][dqs_i])
{
u4Rank_Sel_MCK_P0[dqs_i] = (ucbest_coarse_mck_backup[RANK_0][dqs_i] > 0)? (ucbest_coarse_mck_backup[RANK_0][dqs_i] - 1): 0;
u4Rank_Sel_MCK_P1[dqs_i] = (ucbest_coarse_mck_P1_backup[RANK_0][dqs_i] > 0)? (ucbest_coarse_mck_P1_backup[RANK_0][dqs_i] - 1): 0;
}
else
{
u4Rank_Sel_MCK_P0[dqs_i] = (ucbest_coarse_mck_backup[RANK_1][dqs_i] > 0)? (ucbest_coarse_mck_backup[RANK_1][dqs_i] - 1): 0;
u4Rank_Sel_MCK_P1[dqs_i] = (ucbest_coarse_mck_P1_backup[RANK_1][dqs_i] > 0)? (ucbest_coarse_mck_P1_backup[RANK_1][dqs_i] - 1): 0;
}
}
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_RANK_SELPH_UI_DLY),
P_Fld(u4Rank_Sel_MCK_P0[0], SHU_B0_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P0_B0) |
P_Fld(u4Rank_Sel_MCK_P1[0], SHU_B0_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P1_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_RANK_SELPH_UI_DLY),
P_Fld(u4Rank_Sel_MCK_P0[1], SHU_B1_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P0_B1) |
P_Fld(u4Rank_Sel_MCK_P1[1], SHU_B1_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P1_B1));
u4RANKINCTL_STB = (u4ReadDQSINCTL > 2)? (u4ReadDQSINCTL - 2): 0;
u2PHSINCTL = (u4ReadDQSINCTL == 0)? 0: (u4ReadDQSINCTL - 1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RANKCTL), u4RANKINCTL_STB, MISC_SHU_RANKCTL_RANKINCTL_STB);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_RANK_SEL_STB), u2PHSINCTL, SHU_MISC_RANK_SEL_STB_RANK_SEL_PHSINCTL);
#endif
#ifdef XRTR2R_PERFORM_ENHANCE_DQSG_RX_DLY
// Wei-Jen: RANKINCTL_RXDLY = RANKINCTL = RankINCTL_ROOT = u4ReadDQSINCTL-2, if XRTR2R_PERFORM_ENHANCE_DQSG_RX_DLY enable
// Wei-Jen: New algorithm : u4ReadDQSINCTL-2 >= 0
if (u4ReadDQSINCTL >= 2)
{
u4RankINCTL_ROOT = u4ReadDQSINCTL - 2;
}
else
{
u4RankINCTL_ROOT = 0;
mcSHOW_ERR_MSG(("u4RankINCTL_ROOT <2, Please check\n"));
#if (__ETT__)
while (1);
#endif
}
#else
//Modify for corner IC failed at HQA test XTLV
if (u4ReadDQSINCTL >= 3)
{
u4RankINCTL_ROOT = u4ReadDQSINCTL - 3;
}
else
{
u4RankINCTL_ROOT = 0;
mcSHOW_ERR_MSG(("u4RankINCTL_ROOT <3, Risk for supporting 1066/RL8\n"));
}
#endif
//DQSINCTL
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RK_DQSCTL),
u4ReadDQSINCTL, MISC_SHU_RK_DQSCTL_DQSINCTL); //Rank0 DQSINCTL
vSetRank(p, RANK_1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RK_DQSCTL),
u4ReadDQSINCTL, MISC_SHU_RK_DQSCTL_DQSINCTL); //Rank1 DQSINCTL
vSetRank(p, backup_rank);
//No need to update RODT. If we update RODT, also need to update SELPH_ODTEN0_TXDLY
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ODTCTRL), u4ReadDQSINCTL, SHU_ODTCTRL_RODT); //RODT = DQSINCTL
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RANKCTL),
u4ReadDQSINCTL, MISC_SHU_RANKCTL_RANKINCTL_PHY); //RANKINCTL_PHY = DQSINCTL
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RANKCTL),
u4RankINCTL_ROOT, MISC_SHU_RANKCTL_RANKINCTL); //RANKINCTL= DQSINCTL -3
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RANKCTL),
u4RankINCTL_ROOT, MISC_SHU_RANKCTL_RANKINCTL_ROOT1); //RANKINCTL_ROOT1= DQSINCTL -3
#ifdef XRTR2R_PERFORM_ENHANCE_DQSG_RX_DLY
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RANKCTL),
u4RankINCTL_ROOT, MISC_SHU_RANKCTL_RANKINCTL_RXDLY);
u4XRTR2R = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ACTIM_XRT), SHU_ACTIM_XRT_XRTR2R);
mcSHOW_DBG_MSG2(("TX_dly_DQSgated check: min %d max %d, ChangeDQSINCTL=%d\n", u1TXDLY_Cal_min, u1TXDLY_Cal_max, s1ChangeDQSINCTL));
mcSHOW_DBG_MSG2(("DQSINCTL=%d, RANKINCTL=%d, u4XRTR2R=%d\n", u4ReadDQSINCTL, u4RankINCTL_ROOT, u4XRTR2R));
mcDUMP_REG_MSG(("DQSINCTL=%d, RANKINCTL=%d, u4XRTR2R=%d\n", u4ReadDQSINCTL, u4RankINCTL_ROOT, u4XRTR2R));
#else
//XRTR2R=A-phy forbidden margin(6T) + reg_TX_dly_DQSgated (max) +Roundup(tDQSCKdiff/MCK+0.25MCK)+1(05T sel_ph margin)-1(forbidden margin overlap part)
//Roundup(tDQSCKdiff/MCK+1UI) =1~2 all LP3 and LP4 timing
//u4XRTR2R= 8 + u1TXDLY_Cal_max; // 6+ u1TXDLY_Cal_max +2
//Modify for corner IC failed at HQA test XTLV @ 3200MHz
u4XRTR2R = 8 + u1TXDLY_Cal_max + 1; // 6+ u1TXDLY_Cal_max +2
if (u4XRTR2R > 12)
{
u4XRTR2R = 12;
mcSHOW_ERR_MSG(("XRTR2R > 12, Max value is 12\n"));
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ACTIM_XRT), u4XRTR2R, SHU_ACTIM_XRT_XRTR2R);
mcSHOW_DBG_MSG2(("TX_dly_DQSgated check: min %d max %d, ChangeDQSINCTL=%d\n", u1TXDLY_Cal_min, u1TXDLY_Cal_max, s1ChangeDQSINCTL));
mcSHOW_DBG_MSG2(("DQSINCTL=%d, RANKINCTL=%d, u4XRTR2R=%d\n", u4ReadDQSINCTL, u4RankINCTL_ROOT, u4XRTR2R));
mcDUMP_REG_MSG(("DQSINCTL=%d, RANKINCTL=%d, u4XRTR2R=%d\n", u4ReadDQSINCTL, u4RankINCTL_ROOT, u4XRTR2R));
#endif
#if 0//ENABLE_RODT_TRACKING
//Because Ki_bo+,WE2,Bi_anco,Vin_son...or behind project support WDQS, they need to apply the correct new setting
//The following 2 items are indepentent
//1. if TX_WDQS on(by vendor_id) or p->odt_onoff = 1, ROEN/RODTE/RODTE2 = 1
//2. if ENABLE_RODT_TRACKING on, apply new setting and RODTENSTB_TRACK_EN = ROEN
// LP4 support only
U8 u1ReadROEN;
u1ReadROEN = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_ODTCTRL), SHU_ODTCTRL_ROEN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHU_RODTENSTB), P_Fld(0xff, SHU_RODTENSTB_RODTENSTB_EXT) | \
P_Fld(u1ReadROEN, SHU_RODTENSTB_RODTENSTB_TRACK_EN));
#endif
#ifdef XRTR2W_PERFORM_ENHANCE_RODTEN
// LP4 support only
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RODTENSTB),
P_Fld(0x0fff, MISC_SHU_RODTENSTB_RODTENSTB_EXT) |
P_Fld(1, MISC_SHU_RODTENSTB_RODTEN_P1_ENABLE) |
P_Fld(1, MISC_SHU_RODTENSTB_RODTENSTB_TRACK_EN));
#endif
vSetRank(p, backup_rank);
}
#endif
#if GATING_ADJUST_TXDLY_FOR_TRACKING
void DramcRxdqsGatingPreProcess(DRAMC_CTX_T *p)
{
u1TXDLY_Cal_min = 0xff;
u1TXDLY_Cal_max = 0;
}
#endif
///TODO: wait for porting ---
#endif
#if RDSEL_TRACKING_EN
void RDSELRunTimeTracking_preset(DRAMC_CTX_T *p)
{
U8 u1RankIdx;
S32 s4PosVH, s4NegVH;
U32 u4Gating_shift=0, u4Gating_origin_B0=0, u4Gating_origin_B1=0;
U32 u4Gating_origin_final=0xff;
s4NegVH = divRoundClosest(400, ((1000000 / p->frequency) / 64));
for (u1RankIdx = 0; u1RankIdx < p->support_rank_num; u1RankIdx++)
{
u4Gating_origin_B0 = ((ucbest_coarse_mck_backup[u1RankIdx][0] << 4) | (ucbest_coarse_ui_backup[u1RankIdx][0]));
u4Gating_origin_B1 = ((ucbest_coarse_mck_backup[u1RankIdx][1] << 4) | (ucbest_coarse_ui_backup[u1RankIdx][1]));
if (u4Gating_origin_B0 < u4Gating_origin_B1)
{
u4Gating_origin_final = (u4Gating_origin_B0 < u4Gating_origin_final) ? u4Gating_origin_B0 : u4Gating_origin_final;
}
else
{
u4Gating_origin_final = (u4Gating_origin_B1 < u4Gating_origin_final) ? u4Gating_origin_B1 : u4Gating_origin_final;
}
}
u4Gating_shift = ((((u4Gating_origin_final >> 3) & 0x1f) << 4) | (u4Gating_origin_final & 7)) - u4Gating_origin_B0;
s4PosVH = s4NegVH + (u4Gating_shift << 5);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_RDSEL_TRACK), P_Fld(s4PosVH, SHU_MISC_RDSEL_TRACK_SHU_GW_THRD_POS)
| P_Fld(-s4NegVH, SHU_MISC_RDSEL_TRACK_SHU_GW_THRD_NEG));
}
#endif
#if RDDQC_PINMUX_WORKAROUND
static void RDDQCPinmuxWorkaround(DRAMC_CTX_T *p)
{
U8 *uiLPDDR_RDDQC_Mapping;
#if (__LP5_COMBO__)
const U8 uiLPDDR5_RDDQC_Mapping_POP[CHANNEL_NUM][16] =
{
{
8, 9, 10, 11, 12, 15, 14, 13,
0, 1, 2, 3, 4, 7, 6, 5,
},
#if (CHANNEL_NUM>1)
{
8, 9, 10, 11, 12, 15, 14, 13,
0, 1, 2, 3, 4, 7, 6, 5,
},
#endif
};
#endif
const U8 uiLPDDR4_RDDQC_Mapping_POP[PINMUX_MAX][CHANNEL_NUM][16] =
{
{
// for DSC
//CH-A
{
0, 1, 6, 7, 4, 5, 3, 2,
9, 8, 11, 10, 15, 14, 12, 13
},
#if (CHANNEL_NUM>1)
//CH-B
{
1, 0, 5, 4, 7, 2, 3, 6,
8, 9, 11, 10, 12, 14, 13, 15
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
0, 1, 6, 7, 4, 5, 3, 2,
9, 8, 11, 10, 15, 14, 12, 13
},
//CH-D
{
1, 0, 5, 4, 7, 2, 3, 6,
8, 9, 11, 10, 12, 14, 13, 15
},
#endif
},
{
// for LPBK
// TODO: need porting
},
{
// for EMCP
//CH-A
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 12, 15, 14, 11, 13
},
#if (CHANNEL_NUM>1)
//CH-B
{
0, 1, 7, 4, 2, 5, 6, 3,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
#if (CHANNEL_NUM>2)
//CH-C
{
1, 0, 3, 2, 4, 7, 6, 5,
8, 9, 10, 12, 15, 14, 11, 13
},
//CH-D
{
0, 1, 7, 4, 2, 5, 6, 3,
9, 8, 10, 12, 11, 14, 13, 15
},
#endif
}
};
#if (__LP5_COMBO__)
if (is_lp5_family(p))
{
uiLPDDR_RDDQC_Mapping = (U8 *)uiLPDDR5_RDDQC_Mapping_POP[p->channel];
}
else
#endif
{
uiLPDDR_RDDQC_Mapping = (U8 *)uiLPDDR4_RDDQC_Mapping_POP[p->DRAMPinmux][p->channel];
}
//Set RDDQC pinmux
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX1), P_Fld(uiLPDDR_RDDQC_Mapping[0], MRR_BIT_MUX1_MRR_BIT0_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[1], MRR_BIT_MUX1_MRR_BIT1_SEL) |
P_Fld(uiLPDDR_RDDQC_Mapping[2], MRR_BIT_MUX1_MRR_BIT2_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[3], MRR_BIT_MUX1_MRR_BIT3_SEL));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX2), P_Fld(uiLPDDR_RDDQC_Mapping[4], MRR_BIT_MUX2_MRR_BIT4_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[5], MRR_BIT_MUX2_MRR_BIT5_SEL) |
P_Fld(uiLPDDR_RDDQC_Mapping[6], MRR_BIT_MUX2_MRR_BIT6_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[7], MRR_BIT_MUX2_MRR_BIT7_SEL));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX3), P_Fld(uiLPDDR_RDDQC_Mapping[8], MRR_BIT_MUX3_MRR_BIT8_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[9], MRR_BIT_MUX3_MRR_BIT9_SEL) |
P_Fld(uiLPDDR_RDDQC_Mapping[10], MRR_BIT_MUX3_MRR_BIT10_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[11], MRR_BIT_MUX3_MRR_BIT11_SEL));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX4), P_Fld(uiLPDDR_RDDQC_Mapping[12], MRR_BIT_MUX4_MRR_BIT12_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[13], MRR_BIT_MUX4_MRR_BIT13_SEL) |
P_Fld(uiLPDDR_RDDQC_Mapping[14], MRR_BIT_MUX4_MRR_BIT14_SEL) | P_Fld(uiLPDDR_RDDQC_Mapping[15], MRR_BIT_MUX4_MRR_BIT15_SEL));
}
#endif
#define RDDQCGOLDEN_LP5_MR30_BIT_CTRL_LOWER RDDQCGOLDEN_MR15_GOLDEN
#define RDDQCGOLDEN_LP5_MR31_BIT_CTRL_UPPER RDDQCGOLDEN_MR20_GOLDEN
#define RDDQCGOLDEN_LP5_MR32_PATTERN_A RDDQCGOLDEN_MR32_GOLDEN
#define RDDQCGOLDEN_LP5_MR33_PATTERN_B RDDQCGOLDEN_MR40_GOLDEN
U32 DramcRxWinRDDQCInit(DRAMC_CTX_T *p)
{
U8 RDDQC_Bit_Ctrl_Lower = 0x55;
U8 RDDQC_Bit_Ctrl_Upper = 0x55;
U8 RDDQC_Pattern_A = 0x5A;
U8 RDDQC_Pattern_B = 0x3C;
#if FOR_DV_SIMULATION_USED == 1
cal_sv_rand_args_t *psra = get_psra();
if (psra) {
RDDQC_Bit_Ctrl_Lower = psra->low_byte_invert_golden & 0xFF;
RDDQC_Bit_Ctrl_Upper = psra->upper_byte_invert_golden & 0xFF;
RDDQC_Pattern_A = psra->mr_dq_a_golden;
RDDQC_Pattern_B = psra->mr_dq_b_golden;
/*
* TODO
*
* sv also passes mr20_6 and mr20_7 to sa.
* currently, sa does NOT use these two random arguments.
*/
}
#endif /* FOR_DV_SIMULATION_USED == 1 */
// Disable Read DBI
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ7), 0, SHU_B0_DQ7_R_DMDQMDBI_SHU_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ7), 0, SHU_B1_DQ7_R_DMDQMDBI_SHU_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), u1GetRank(p), SWCMD_CTRL0_MRSRK);
#if RDDQC_PINMUX_WORKAROUND
// Translate pin order by MRR bit sel
RDDQCPinmuxWorkaround(p);
#endif
// Set golden values into dram MR
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
DramcModeRegWriteByRank(p, p->rank, 31, RDDQC_Bit_Ctrl_Lower);
DramcModeRegWriteByRank(p, p->rank, 32, RDDQC_Bit_Ctrl_Upper);
DramcModeRegWriteByRank(p, p->rank, 33, RDDQC_Pattern_A);
DramcModeRegWriteByRank(p, p->rank, 34, RDDQC_Pattern_B);
}
else
#endif
{
DramcModeRegWriteByRank(p, p->rank, 15, RDDQC_Bit_Ctrl_Lower);
DramcModeRegWriteByRank(p, p->rank, 20, RDDQC_Bit_Ctrl_Upper);
DramcModeRegWriteByRank(p, p->rank, 32, RDDQC_Pattern_A);
DramcModeRegWriteByRank(p, p->rank, 40, RDDQC_Pattern_B);
}
//Set golden values into RG, watch out the MR_index of RGs are reference LP4
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_RDDQCGOLDEN),
P_Fld(RDDQC_Bit_Ctrl_Lower, RDDQCGOLDEN_LP5_MR30_BIT_CTRL_LOWER) |
P_Fld(RDDQC_Bit_Ctrl_Upper, RDDQCGOLDEN_LP5_MR31_BIT_CTRL_UPPER) |
P_Fld(RDDQC_Pattern_A, RDDQCGOLDEN_LP5_MR32_PATTERN_A) |
P_Fld(RDDQC_Pattern_B, RDDQCGOLDEN_LP5_MR33_PATTERN_B));
// Open gated clock, by KaiHsin (DCM)
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ8),
P_Fld(1, SHU_B0_DQ8_R_DMRXDLY_CG_IG_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ8),
P_Fld(1, SHU_B1_DQ8_R_DMRXDLY_CG_IG_B1));
#if (__LP5_COMBO__ == TRUE)
if (is_lp5_family(p))
{
// Set function mode applied to DQ & DMI
// U8 RDDQC_RDC_DQ_mode = 0;
// U8 RDDQC_RDC_DMI_mode = 0;
// vSetLP5DramRDDQC_DQandDMI(p, RDDQC_RDC_DQ_mode, RDDQC_RDC_DMI_mode);
// vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_RDDQCGOLDEN1),
// P_Fld(RDDQC_RDC_DQ_mode, RDDQCGOLDEN1_LP5_MR20_7_GOLDEN) |
// P_Fld(RDDQC_RDC_DMI_mode, RDDQCGOLDEN1_LP5_MR20_6_GOLDEN));
if (is_heff_mode(p) == FALSE)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_COMMON0), 1, SHU_COMMON0_LP5WCKON);
// Enable MR18 "WCK always ON mode"
vSetLP5Dram_WCKON_OnOff(p, ON);
}
RunTime_SW_Cmd(p, RUNTIME_SWCMD_CAS_FS);
}
#endif
return 0;
}
U32 DramcRxWinRDDQCEnd(DRAMC_CTX_T *p)
{
// Recover MPC Rank
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL0), 0, SWCMD_CTRL0_MRSRK);
#if (__LP5_COMBO__ == TRUE)
if (is_lp5_family(p))
{
RunTime_SW_Cmd(p, RUNTIME_SWCMD_CAS_OFF);
if (is_heff_mode(p) == FALSE)
{
// Disable MR18 "WCK always ON mode"
vSetLP5Dram_WCKON_OnOff(p, OFF);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_COMMON0), 0, SHU_COMMON0_LP5WCKON);
}
}
#endif
return 0;
}
/* Issue "RD DQ Calibration"
* 1. SWCMD_CTRL1_RDDQC_LP_ENB = 1 to stop RDDQC burst
* 2. RDDQCEN = 1 for RDDQC
* 3. Wait rddqc_response = 1
* 4. Read compare result
* 5. RDDQCEN = 0
*/
U32 DramcRxWinRDDQCRun(DRAMC_CTX_T *p)
{
U32 u4Result = 0, u4TmpResult;
DRAM_STATUS_T u4Response = DRAM_FAIL;
//Issue RD DQ calibration
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_CTRL1), 1, SWCMD_CTRL1_RDDQC_LP_ENB);
// Trigger and wait
REG_TRANSFER_T TriggerReg = {DRAMC_REG_SWCMD_EN, SWCMD_EN_RDDQCEN};
REG_TRANSFER_T RepondsReg = {DRAMC_REG_SPCMDRESP, SPCMDRESP_RDDQC_RESPONSE};
u4Response = DramcTriggerAndWait(p, TriggerReg, RepondsReg);
// Read RDDQC compare result
u4TmpResult = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_RDQC_CMP));
u4Result = (0xFFFF) & ((u4TmpResult) | (u4TmpResult >> 16)); // (BL0~7) | (BL8~15)
#if (FEATURE_RDDQC_K_DMI == TRUE)
// Read DQM compare result
u4TmpResult = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RDQC_DQM_CMP), RDQC_DQM_CMP_RDDQC_DQM_CMP0_ERR);
u4TmpResult |= u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_RDQC_DQM_CMP), RDQC_DQM_CMP_RDDQC_DQM_CMP1_ERR);
u4Result |= (u4TmpResult << 16);
#endif
//R_DMRDDQCEN -> 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SWCMD_EN), 0, SWCMD_EN_RDDQCEN);
return u4Result;
}
DRAM_STATUS_T DramcRxWindowPerbitCal(DRAMC_CTX_T *p,
RX_PATTERN_OPTION_T u1UseTestEngine,
U8 *u1AssignedVref,
u8 isAutoK)
{
U8 u1BitIdx, u1ByteIdx;
U16 u16DelayStep = 1;
PASS_WIN_DATA_T FinalWinPerBit[DQ_DATA_WIDTH + RDDQC_ADD_DMI_NUM];
S32 iDQSDlyPerbyte[DQS_NUMBER], iDQMDlyPerbyte[DQS_NUMBER];//, iFinalDQSDly[DQS_NUMBER];
U8 u1VrefScanEnable = FALSE;
U16 u2FinalVref [DQS_NUMBER]= {0xe, 0xe};
U16 u2VrefBegin, u2VrefEnd, u2VrefStep;
U8 u1RXEyeScanEnable=0,u1PrintCalibrationProc;
U8 u1CalDQMNum = 0;
#if ENABLE_EYESCAN_GRAPH
U8 EyeScan_index[DQ_DATA_WIDTH_LP4 + RDDQC_ADD_DMI_NUM] = {0};
U8 u1pass_in_this_vref_flag[DQ_DATA_WIDTH_LP4 + RDDQC_ADD_DMI_NUM];
#endif
U8 backup_rank, rank_i, u1KnownVref[2]={0xff, 0xff};
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
#if RDDQC_PINMUX_WORKAROUND
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX1)),
(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX2)),
(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX3)),
(DRAMC_REG_ADDR(DRAMC_REG_MRR_BIT_MUX4)),
};
//Back up dramC register
DramcBackupRegisters(p, u4RegBackupAddress, ARRAY_SIZE(u4RegBackupAddress));
#endif
if (u1UseTestEngine == PATTERN_TEST_ENGINE)
u1RXEyeScanEnable = GetEyeScanEnable(p, 1);
#if (FEATURE_RDDQC_K_DMI == TRUE)
if (u1UseTestEngine == PATTERN_RDDQC)
{
u1CalDQMNum = 2;
iDQMDlyPerbyte[0] = -0xFFFFFF;
iDQMDlyPerbyte[1] = -0xFFFFFF;
}
else
#endif
{
u1CalDQMNum = 0;
iDQMDlyPerbyte[0] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY4), SHU_R0_B0_RXDLY4_RX_ARDQM0_R_DLY_B0);
iDQMDlyPerbyte[1] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY4), SHU_R0_B1_RXDLY4_RX_ARDQM0_R_DLY_B1);
}
#if ENABLE_EYESCAN_GRAPH
if (u1UseTestEngine == PATTERN_TEST_ENGINE)
{
for(u1vrefidx=0; u1vrefidx<EYESCAN_RX_VREF_RANGE_END;u1vrefidx++)
{
for (u1BitIdx = 0; u1BitIdx < DQ_DATA_WIDTH_LP4; u1BitIdx++)
{
for(ii=0; ii<EYESCAN_BROKEN_NUM; ii++)
{
gEyeScan_Min[u1vrefidx][u1BitIdx][ii] = EYESCAN_DATA_INVALID;
gEyeScan_Max[u1vrefidx][u1BitIdx][ii] = EYESCAN_DATA_INVALID;
gEyeScan_ContinueVrefHeight[u1BitIdx] = 0;
gEyeScan_TotalPassCount[u1BitIdx] = 0;
}
}
}
}
#endif
//When doing RxWindowPerbitCal, should make sure that auto refresh is disable
vAutoRefreshSwitch(p, DISABLE);
//CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
backup_rank = u1GetRank(p);
//defult set result fail. When window found, update the result as oK
if (u1UseTestEngine == PATTERN_TEST_ENGINE)
{
vSetCalibrationResult(p, DRAM_CALIBRATION_RX_PERBIT, DRAM_FAIL);
// Something wrong with TA2 pattern -- SI, which causes RX autoK fail.
if (isAutoK == TRUE)
{
DramcEngine2Init(p, p->test2_1, p->test2_2, TEST_XTALK_PATTERN, 0, TE_NO_UI_SHIFT);
}
else
{
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern | 0x80, 0, TE_UI_SHIFT);//UI_SHIFT + LEN1
#else
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern, 0, TE_NO_UI_SHIFT);
#endif
}
}
else
{
vSetCalibrationResult(p, DRAM_CALIBRATION_RX_RDDQC, DRAM_FAIL);
DramcRxWinRDDQCInit(p);
}
// Intialize, diable RX Vref
u2VrefBegin = 0;
u2VrefEnd = 0;
u2VrefStep = 1;
if ((u1UseTestEngine == PATTERN_TEST_ENGINE))
{
#if (FOR_DV_SIMULATION_USED==0 && SW_CHANGE_FOR_SIMULATION==0)
if ((p->rank==RANK_0) || (p->frequency >= RX_VREF_DUAL_RANK_K_FREQ) || (u1RXEyeScanEnable==1))
u1VrefScanEnable =1;
#else
u1VrefScanEnable =0;
#endif
}
u1PrintCalibrationProc = ((u1VrefScanEnable == 0) || (u1RXEyeScanEnable == 1) || (u1AssignedVref != NULL));
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
if (p->femmc_Ready == 1 && ((p->Bypass_RDDQC && u1UseTestEngine == PATTERN_RDDQC) || (p->Bypass_RXWINDOW && u1UseTestEngine == PATTERN_TEST_ENGINE)))
{
mcSHOW_DBG_MSG(("[FAST_K] Bypass RX Calibration\n"));
}
else
#endif
{
#if VENDER_JV_LOG
#if 0 //BU don't want customer knows our RX's ability
if (u1UseTestEngine == 1)
vPrintCalibrationBasicInfo_ForJV(p);
#endif
#else
vPrintCalibrationBasicInfo(p);
#endif
mcSHOW_DBG_MSG2(("Start DQ dly to find pass range UseTestEngine =%d\n", u1UseTestEngine));
}
mcSHOW_DBG_MSG2(("UseTestEngine: %d\n", u1UseTestEngine));
mcSHOW_DBG_MSG(("RX Vref Scan: %d\n", u1VrefScanEnable));
if (u1VrefScanEnable)
{
if ((Get_Vref_Calibration_OnOff(p) == VREF_CALI_OFF) && (u1RXEyeScanEnable == 0))
{
u2VrefBegin = 0;
u2VrefEnd = 0;
u1KnownVref[0] = gFinalRXVrefDQForSpeedUp[p->channel][p->rank][p->odt_onoff][0];// byte 0
u1KnownVref[1] = gFinalRXVrefDQForSpeedUp[p->channel][p->rank][p->odt_onoff][1];// byte 1
if (u1UseTestEngine == PATTERN_TEST_ENGINE && ((u1KnownVref[0] == 0) || (u1KnownVref[1] == 0)))
{
// mcSHOW_ERR_MSG(("\nWrong frequency K order= %d\n"));
#if __ETT__
while (1);
#endif
}
}
else if (u1AssignedVref != NULL) // need to specify RX Vref and don't scan RX Vref.
{
u2VrefBegin = 0;
u2VrefEnd = 0;
u1KnownVref[0] = u1AssignedVref[0]; // byte 0
u1KnownVref[1] = u1AssignedVref[1]; // byte 1
}
else
{
#if (SW_CHANGE_FOR_SIMULATION || FOR_DV_SIMULATION_USED)
u2VrefBegin = RX_VREF_RANGE_BEGIN;
#else
if (u1RXEyeScanEnable == 0)
{
if (p->odt_onoff)
{
u2VrefBegin = RX_VREF_RANGE_BEGIN_ODT_ON;
}
else
{
u2VrefBegin = RX_VREF_RANGE_BEGIN_ODT_OFF;
}
u2VrefEnd = RX_VREF_RANGE_END-1;
mcSHOW_DBG_MSG(("\nSet Vref Range= %d -> %d\n",u2VrefBegin,u2VrefEnd));
}
else
{
u2VrefBegin = 0;//Lewis@20160817: Enlarge RX Vref range for eye scan
u2VrefEnd = EYESCAN_RX_VREF_RANGE_END-1;
mcSHOW_DBG_MSG(("\nSet Eyescan Vref Range= %d -> %d\n",u2VrefBegin,u2VrefEnd));
}
#endif
}
if (u1RXEyeScanEnable == 0)
{
u2VrefStep = RX_VREF_RANGE_STEP;
}
else
{
u2VrefStep = EYESCAN_GRAPH_RX_VREF_STEP;
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5), 1, B0_DQ5_RG_RX_ARDQ_VREF_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5), 1, B1_DQ5_RG_RX_ARDQ_VREF_EN_B1);
}
else // Disable RX Vref
{
u2VrefBegin = 0;
u2VrefEnd = 0;
u2VrefStep = 1;
}
//if RDDQD, roughly calibration
if (u1UseTestEngine == PATTERN_RDDQC)
u16DelayStep <<= 1;
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
if (p->femmc_Ready == 1 && ((p->Bypass_RDDQC && u1UseTestEngine == PATTERN_RDDQC) || (p->Bypass_RXWINDOW && u1UseTestEngine == PATTERN_TEST_ENGINE)))
{
// load RX DQS and DQM delay from eMMC
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
if (u1VrefScanEnable)
{
// load RX Vref from eMMC
#if ( SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_VREF_CAL)
u2FinalVref[u1ByteIdx] = p->pSavetimeData->u1RxWinPerbitVref_Save[p->channel][p->rank][u1ByteIdx];
#endif
}
iDQSDlyPerbyte[u1ByteIdx] = p->pSavetimeData->u1RxWinPerbit_DQS[p->channel][p->rank][u1ByteIdx];
iDQMDlyPerbyte[u1ByteIdx] = p->pSavetimeData->u1RxWinPerbit_DQM[p->channel][p->rank][u1ByteIdx];
}
// load RX DQ delay from eMMC
for (u1BitIdx = 0; u1BitIdx < 16; u1BitIdx++)
{
FinalWinPerBit[u1BitIdx].best_dqdly = p->pSavetimeData->u1RxWinPerbit_DQ[p->channel][p->rank][u1BitIdx];
}
if (u1UseTestEngine == PATTERN_TEST_ENGINE)
vSetCalibrationResult(p, DRAM_CALIBRATION_RX_PERBIT, DRAM_FAST_K);
else
vSetCalibrationResult(p, DRAM_CALIBRATION_RX_RDDQC, DRAM_FAST_K);
}
#endif
if (u1VrefScanEnable == TRUE)
{
// When only calibrate RX Vref for Rank 0, apply the same value for Rank 1.
for (rank_i = p->rank; rank_i < p->support_rank_num; rank_i++)
{
vSetRank(p, rank_i);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_PHY_VREF_SEL),
P_Fld(u2FinalVref[0], SHU_B0_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_LB_B0) |
P_Fld(u2FinalVref[0], SHU_B0_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_UB_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_PHY_VREF_SEL),
P_Fld(u2FinalVref[1], SHU_B1_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_LB_B1) |
P_Fld(u2FinalVref[1], SHU_B1_PHY_VREF_SEL_RG_RX_ARDQ_VREF_SEL_UB_B1));
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
mcSHOW_DBG_MSG(("\nFinal RX Vref Byte %d = %d to rank%d", u1ByteIdx, u2FinalVref[u1ByteIdx], rank_i));
mcDUMP_REG_MSG(("\nFinal RX Vref Byte %d = %d to rank%d", u1ByteIdx, u2FinalVref[u1ByteIdx], rank_i));
gFinalRXVrefDQ[p->channel][rank_i][u1ByteIdx] = (U8) u2FinalVref[u1ByteIdx];
gFinalRXVrefDQForSpeedUp[p->channel][rank_i][p->odt_onoff][u1ByteIdx] = (U8) u2FinalVref[u1ByteIdx];
}
}
vSetRank(p, backup_rank);
}
#if DUMP_TA2_WINDOW_SIZE_RX_TX
//RX
if (u1UseTestEngine == PATTERN_TEST_ENGINE)
{
U32 u4B0Tatal =0;
U32 u4B1Tatal =0;
mcSHOW_DBG_MSG(("RX window per bit CH[%d] Rank[%d] window size\n", p->channel, p->rank));
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
mcSHOW_DBG_MSG(("DQ[%d] size = %d\n", u1BitIdx, gFinalRXPerbitWin[p->channel][p->rank][u1BitIdx]));
if(u1BitIdx < 8)
{
u4B0Tatal += gFinalRXPerbitWin[p->channel][p->rank][u1BitIdx];
}
else
{
u4B1Tatal += gFinalRXPerbitWin[p->channel][p->rank][u1BitIdx];
}
}
mcSHOW_DBG_MSG(("total rx window size B0: %d B1: %d\n", u4B0Tatal, u4B1Tatal));
}
#endif
// set dqs delay, (dqm delay)
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY5),
P_Fld((U32)iDQSDlyPerbyte[0], SHU_R0_B0_RXDLY5_RX_ARDQS0_R_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY4),
P_Fld((U32)iDQMDlyPerbyte[0], SHU_R0_B0_RXDLY4_RX_ARDQM0_R_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY5),
P_Fld((U32)iDQSDlyPerbyte[1], SHU_R0_B1_RXDLY5_RX_ARDQS0_R_DLY_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY4),
P_Fld((U32)iDQMDlyPerbyte[1], SHU_R0_B1_RXDLY4_RX_ARDQM0_R_DLY_B1));
// set dq delay
for (u1BitIdx = 0; u1BitIdx < DQS_BIT_NUMBER; u1BitIdx += 2)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY0 + u1BitIdx * 2),
P_Fld(((U32)FinalWinPerBit[u1BitIdx].best_dqdly), SHU_R0_B0_RXDLY0_RX_ARDQ0_R_DLY_B0) |
P_Fld(((U32)FinalWinPerBit[u1BitIdx + 1].best_dqdly), SHU_R0_B0_RXDLY0_RX_ARDQ1_R_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY0 + u1BitIdx * 2),
P_Fld((U32)FinalWinPerBit[u1BitIdx + 8].best_dqdly, SHU_R0_B1_RXDLY0_RX_ARDQ0_R_DLY_B1) |
P_Fld((U32)FinalWinPerBit[u1BitIdx + 9].best_dqdly, SHU_R0_B1_RXDLY0_RX_ARDQ1_R_DLY_B1));
//mcSHOW_DBG_MSG(("u1BitId %d Addr 0x%2x = %2d %2d %2d %2d \n", u1BitIdx, DDRPHY_RXDQ1+u1BitIdx*2,
// FinalWinPerBit[u1BitIdx].best_dqdly, FinalWinPerBit[u1BitIdx+1].best_dqdly, FinalWinPerBit[u1BitIdx+8].best_dqdly, FinalWinPerBit[u1BitIdx+9].best_dqdly));
}
DramPhyReset(p);
#if RDDQC_PINMUX_WORKAROUND
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
#endif
vSetRank(p, backup_rank);
vPrintCalibrationBasicInfo(p);
#ifdef ETT_PRINT_FORMAT
mcSHOW_DBG_MSG(("DQS Delay:\nDQS0 = %d, DQS1 = %d\n"
"DQM Delay:\nDQM0 = %d, DQM1 = %d\n",
iDQSDlyPerbyte[0], iDQSDlyPerbyte[1],
iDQMDlyPerbyte[0], iDQMDlyPerbyte[1]));
mcDUMP_REG_MSG(("DQS Delay:\nDQS0 = %d, DQS1 = %d\n"
"DQM Delay:\nDQM0 = %d, DQM1 = %d\n",
iDQSDlyPerbyte[0], iDQSDlyPerbyte[1],
iDQMDlyPerbyte[0], iDQMDlyPerbyte[1]));
#else
mcSHOW_DBG_MSG(("DQS Delay:\nDQS0 = %2d, DQS1 = %2d\n"
"DQM Delay:\nDQM0 = %2d, DQM1 = %2d\n",
iDQSDlyPerbyte[0], iDQSDlyPerbyte[1],
iDQMDlyPerbyte[0], iDQMDlyPerbyte[1]));
mcDUMP_REG_MSG(("DQS Delay:\nDQS0 = %2d, DQS1 = %2d\n"
"DQM Delay:\nDQM0 = %2d, DQM1 = %2d\n",
iDQSDlyPerbyte[0], iDQSDlyPerbyte[1],
iDQMDlyPerbyte[0], iDQMDlyPerbyte[1]));
#endif
mcSHOW_DBG_MSG(("DQ Delay:\n"));
mcDUMP_REG_MSG(("DQ Delay:\n"));
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx = u1BitIdx + 4)
{
#ifdef ETT_PRINT_FORMAT
mcSHOW_DBG_MSG(("DQ%d =%d, DQ%d =%d, DQ%d =%d, DQ%d =%d\n", u1BitIdx, FinalWinPerBit[u1BitIdx].best_dqdly, u1BitIdx+1, FinalWinPerBit[u1BitIdx+1].best_dqdly, u1BitIdx+2, FinalWinPerBit[u1BitIdx+2].best_dqdly, u1BitIdx+3, FinalWinPerBit[u1BitIdx+3].best_dqdly));
mcDUMP_REG_MSG(("DQ%d =%d, DQ%d =%d, DQ%d =%d, DQ%d =%d\n", u1BitIdx, FinalWinPerBit[u1BitIdx].best_dqdly, u1BitIdx+1, FinalWinPerBit[u1BitIdx+1].best_dqdly, u1BitIdx+2, FinalWinPerBit[u1BitIdx+2].best_dqdly, u1BitIdx+3, FinalWinPerBit[u1BitIdx+3].best_dqdly));
#else
mcSHOW_DBG_MSG(("DQ%2d =%2d, DQ%2d =%2d, DQ%2d =%2d, DQ%2d =%2d\n", u1BitIdx, FinalWinPerBit[u1BitIdx].best_dqdly, u1BitIdx+1, FinalWinPerBit[u1BitIdx+1].best_dqdly, u1BitIdx+2, FinalWinPerBit[u1BitIdx+2].best_dqdly, u1BitIdx+3, FinalWinPerBit[u1BitIdx+3].best_dqdly));
mcDUMP_REG_MSG(("DQ%2d =%2d, DQ%2d =%2d, DQ%2d =%2d, DQ%2d =%2d\n", u1BitIdx, FinalWinPerBit[u1BitIdx].best_dqdly, u1BitIdx+1, FinalWinPerBit[u1BitIdx+1].best_dqdly, u1BitIdx+2, FinalWinPerBit[u1BitIdx+2].best_dqdly, u1BitIdx+3, FinalWinPerBit[u1BitIdx+3].best_dqdly));
#endif
}
mcSHOW_DBG_MSG(("\n\n"));
mcSHOW_DBG_MSG3(("[DramcRxWindowPerbitCal] Done\n"));
#if LP5_DDR4266_RDBI_WORKAROUND
if((is_lp5_family(p)) && (p->frequency >= 2133))
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ7), 1, SHU_B0_DQ7_R_DMDQMDBI_SHU_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ7), 1, SHU_B1_DQ7_R_DMDQMDBI_SHU_B1);
}
#endif
return DRAM_OK;
// Log example ==> Neec to update
/*
------------------------------------------------------
Start calculate dq time and dqs time /
Find max DQS delay per byte / Adjust DQ delay to align DQS...
------------------------------------------------------
bit# 0 : dq time=11 dqs time= 8
bit# 1 : dq time=11 dqs time= 8
bit# 2 : dq time=11 dqs time= 6
bit# 3 : dq time=10 dqs time= 8
bit# 4 : dq time=11 dqs time= 8
bit# 5 : dq time=10 dqs time= 8
bit# 6 : dq time=11 dqs time= 8
bit# 7 : dq time= 9 dqs time= 6
----seperate line----
bit# 8 : dq time=12 dqs time= 7
bit# 9 : dq time=10 dqs time= 8
bit#10 : dq time=11 dqs time= 8
bit#11 : dq time=10 dqs time= 8
bit#12 : dq time=11 dqs time= 8
bit#13 : dq time=11 dqs time= 8
bit#14 : dq time=11 dqs time= 8
bit#15 : dq time=12 dqs time= 8
----seperate line----
bit#16 : dq time=11 dqs time= 7
bit#17 : dq time=10 dqs time= 8
bit#18 : dq time=11 dqs time= 7
bit#19 : dq time=11 dqs time= 6
bit#20 : dq time=10 dqs time= 9
bit#21 : dq time=11 dqs time=10
bit#22 : dq time=11 dqs time=10
bit#23 : dq time= 9 dqs time= 9
----seperate line----
bit#24 : dq time=12 dqs time= 6
bit#25 : dq time=13 dqs time= 6
bit#26 : dq time=13 dqs time= 7
bit#27 : dq time=11 dqs time= 7
bit#28 : dq time=12 dqs time= 8
bit#29 : dq time=10 dqs time= 8
bit#30 : dq time=13 dqs time= 7
bit#31 : dq time=11 dqs time= 8
----seperate line----
==================================================
dramc_rxdqs_perbit_swcal_v2
channel=2(2:cha, 3:chb) apply = 1
==================================================
DQS Delay :
DQS0 = 0 DQS1 = 0 DQS2 = 0 DQS3 = 0
DQ Delay :
DQ 0 = 1 DQ 1 = 1 DQ 2 = 2 DQ 3 = 1
DQ 4 = 1 DQ 5 = 1 DQ 6 = 1 DQ 7 = 1
DQ 8 = 2 DQ 9 = 1 DQ10 = 1 DQ11 = 1
DQ12 = 1 DQ13 = 1 DQ14 = 1 DQ15 = 2
DQ16 = 2 DQ17 = 1 DQ18 = 2 DQ19 = 2
DQ20 = 0 DQ21 = 0 DQ22 = 0 DQ23 = 0
DQ24 = 3 DQ25 = 3 DQ26 = 3 DQ27 = 2
DQ28 = 2 DQ29 = 1 DQ30 = 3 DQ31 = 1
_______________________________________________________________
*/
}
#if SIMULATION_RX_DVS
static U8 DramcRxDVSCal(DRAMC_CTX_T *p, U8 u1byte)
{
U8 u1rising_lead, u1falling_lead, u1rising_lag, u1falling_lag, u1lead_lag;
if (u1byte == 0)
{
u1rising_lead = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS0), MISC_FT_STATUS0_AD_RX_ARDQ_DVS_R_LEAD_B0);
u1falling_lead = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS1), MISC_FT_STATUS1_AD_RX_ARDQ_DVS_F_LEAD_B0);
u1rising_lag = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS0), MISC_FT_STATUS0_AD_RX_ARDQ_DVS_R_LAG_B0);
u1falling_lag = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS1), MISC_FT_STATUS1_AD_RX_ARDQ_DVS_F_LAG_B0);
}
else //byte1
{
u1rising_lead = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS0), MISC_FT_STATUS0_AD_RX_ARDQ_DVS_R_LAG_B1);
u1falling_lead = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS1), MISC_FT_STATUS1_AD_RX_ARDQ_DVS_F_LEAD_B1);
u1rising_lag = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS0), MISC_FT_STATUS0_AD_RX_ARDQ_DVS_R_LAG_B1);
u1falling_lag = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_FT_STATUS1), MISC_FT_STATUS1_AD_RX_ARDQ_DVS_F_LAG_B1);
}
mcSHOW_DBG_MSG2(("Byte%d | LEAD(%d %d) | LAG(%d %d)\n", u1byte, u1rising_lead, u1falling_lead, u1rising_lag, u1falling_lag));
u1lead_lag = (u1rising_lead | u1falling_lead | u1rising_lag | u1falling_lag);
return u1lead_lag;
}
DRAM_STATUS_T DramcRxDVSWindowCal(DRAMC_CTX_T *p)
{
U8 ii, u1ByteIdx;
S16 iDelay = 0, S16DelayBegin = 0;
U16 u16DelayEnd = 0, u16DelayStep = 1;
U32 u4err_value;
U8 u1lead_lag, u1DVS_first_flag[DQS_NUMBER_LP4]={0}, u1DVS_first_pass[DQS_NUMBER_LP4]={0}, u1DVS_pass_window[DQS_NUMBER_LP4]={0}, u1finish_flag[DQS_NUMBER_LP4]={0};
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY5)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY5)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY4)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY4)),
};
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
mcSHOW_DBG_MSG(("\\\RX DVS calibration\\\\n"));
//When doing RxWindowPerbitCal, should make sure that auto refresh is disable
vAutoRefreshSwitch(p, DISABLE);
//CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), 1, SHU_B0_DQ11_RG_RX_ARDQ_DVS_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), 1, SHU_B1_DQ11_RG_RX_ARDQ_DVS_EN_B1);
//defult set result fail. When window found, update the result as oK
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern | 0x80, 0, TE_UI_SHIFT);//PIC Need to check if need to use UI_SHIFT;//UI_SHIFT + LEN1
#else
DramcEngine2Init(p, p->test2_1, p->test2_2, TEST_XTALK_PATTERN, 0, TE_NO_UI_SHIFT);
#endif
#if (__LP5_COMBO__ == TRUE)
if (is_lp5_family(p))
{
// 1 step = 1/4 delay cell
// Adjust step = 1/2/4(precision adjustment) by data-rate
if (p->frequency <= GetFreqBySel(p,LP5_DDR3200))
u16DelayStep = 4;
else if (p->frequency <= GetFreqBySel(p,LP5_DDR4800)) // 3733, 4266, 4800
u16DelayStep = 2;
else // 5500, 6000, 6400
u16DelayStep = 1;
}
#endif
else
{
u16DelayStep = 4;
}
// Just for DV SIM test
S16DelayBegin = -80;
u16DelayEnd = 100;
mcSHOW_DBG_MSG(("\nRX Delay %d -> %d, step: %d\n", S16DelayBegin, u16DelayEnd, u16DelayStep));
{
// Adjust DQM output delay to 0
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_RXDLY4),
P_Fld(0, SHU_R0_B0_RXDLY4_RX_ARDQM0_R_DLY_B0) |
P_Fld(0, SHU_R0_B0_RXDLY4_RX_ARDQM0_F_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_RXDLY4),
P_Fld(0, SHU_R0_B1_RXDLY4_RX_ARDQM0_R_DLY_B1) |
P_Fld(0, SHU_R0_B1_RXDLY4_RX_ARDQM0_F_DLY_B1));
// Adjust DQ output delay to 0
//every 2bit dq have the same delay register address
for (ii = 0; ii < 4; ii++)
SetRxDqDelay(p, ii, 0);
{
// non-autok flow
for (iDelay = S16DelayBegin; iDelay <= u16DelayEnd; iDelay += u16DelayStep)
{
SetRxDqDqsDelay(p, iDelay);
u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, p->test_pattern);
mcSHOW_DBG_MSG2(("iDelay= %4d, err_value: 0x%x", iDelay, u4err_value));
for(u1ByteIdx=0; u1ByteIdx<(p->data_width/DQS_BIT_NUMBER); u1ByteIdx++)
{
u1lead_lag = DramcRxDVSCal(p, u1ByteIdx);
if ((u1lead_lag == 0) && (u1DVS_first_flag[u1ByteIdx] == 0) && (((u4err_value >> (u1ByteIdx<<3)) & 0xff) == 0))
{
u1DVS_first_pass[u1ByteIdx] = iDelay;
u1DVS_first_flag[u1ByteIdx] = 1;
mcSHOW_DBG_MSG(("Byte%d find first pass delay\n"))
}
else if (((u1lead_lag == 1) || (((u4err_value >> (u1ByteIdx<<3)) & 0xff) != 0)) && (u1DVS_first_flag[u1ByteIdx] == 1) && (u1finish_flag[u1ByteIdx] == 0))
{
u1DVS_pass_window[u1ByteIdx] = iDelay - u1DVS_first_pass[u1ByteIdx] - u16DelayStep;
if (u1DVS_pass_window[u1ByteIdx] < 7) //if window size bigger than 7, consider as real pass window.
{
u1DVS_pass_window[u1ByteIdx] = 0;
u1DVS_first_flag[u1ByteIdx] = 0;
mcSHOW_DBG_MSG(("Byte%d find fake window\n"))
}
else
{
u1finish_flag[u1ByteIdx] = 1;
mcSHOW_DBG_MSG(("Byte%d find pass window\n"))
}
}
}
if ((u1finish_flag[0]==1) && (u1finish_flag[1]==1))
{
mcSHOW_DBG_MSG(("Two byte DVS window find, early break!\n"));
break;
}
}
}
}
DramcEngine2End(p);
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
u1DVS_increase[p->rank][u1ByteIdx] = (u1DVS_pass_window[u1ByteIdx] > 8)? ((u1DVS_pass_window[u1ByteIdx] - 8) >> 3): 0;
mcSHOW_DBG_MSG(("\nByte %d final DVS window size(M) %d, DVS increase %d\n", u1ByteIdx, u1DVS_pass_window[u1ByteIdx], u1DVS_increase[p->rank][u1ByteIdx]));
}
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
vAutoRefreshSwitch(p, ENABLE);
DramPhyReset(p);
vPrintCalibrationBasicInfo(p);
mcSHOW_DBG_MSG(("\n\n"));
mcSHOW_DBG_MSG3(("[DramcRxDVSWindowCal] Done\n"));
return DRAM_OK;
}
void DramcDramcRxDVSCalPostProcess(DRAMC_CTX_T *p)
{
U8 rank_i, u1ByteIdx, u1DVS_increase_final, u1DVS_dly_final[DQS_NUMBER_LP4]={0};
U8 backup_rank = p->rank;
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
if (p->support_rank_num == RANK_DUAL)
u1DVS_increase_final = (u1DVS_increase[RANK_0][u1ByteIdx] < u1DVS_increase[RANK_1][u1ByteIdx])? u1DVS_increase[RANK_0][u1ByteIdx] : u1DVS_increase[RANK_1][u1ByteIdx];
else
u1DVS_increase_final = u1DVS_increase[p->rank][u1ByteIdx];
if (u1ByteIdx == 0)
{
u1DVS_dly_final[u1ByteIdx] = u1DVS_increase_final + (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), SHU_B0_DQ11_RG_RX_ARDQ_DVS_DLY_B0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), u1DVS_dly_final[u1ByteIdx], SHU_B0_DQ11_RG_RX_ARDQ_DVS_DLY_B0);
}
else //byte1
{
u1DVS_dly_final[u1ByteIdx] = u1DVS_increase_final + (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), SHU_B1_DQ11_RG_RX_ARDQ_DVS_DLY_B1));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), u1DVS_dly_final[u1ByteIdx], SHU_B1_DQ11_RG_RX_ARDQ_DVS_DLY_B1);
}
mcSHOW_DBG_MSG(("Byte%d final DVS delay: %d\n", u1ByteIdx, u1DVS_dly_final[u1ByteIdx]));
}
for(rank_i=RANK_0; rank_i< p->support_rank_num; rank_i++)
{
vSetRank(p, rank_i);
DramcRxWindowPerbitCal(p, PATTERN_TEST_ENGINE, DVS_CAL_KEEP_VREF, AUTOK_OFF);
}
if ((DramcRxDVSCal(p, 0) == 1) || (DramcRxDVSCal(p, 1) == 1)) //Prevent set wrong DV dly
{
mcSHOW_ERR_MSG(("Final DVS delay is out of RX window\n"));
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
if (u1DVS_dly_final[u1ByteIdx] > 0)
{
u1DVS_dly_final[u1ByteIdx] -= 1;
if (u1ByteIdx == 0)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), u1DVS_dly_final[u1ByteIdx], SHU_B0_DQ11_RG_RX_ARDQ_DVS_DLY_B0);
}
else //byte1
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), u1DVS_dly_final[u1ByteIdx], SHU_B1_DQ11_RG_RX_ARDQ_DVS_DLY_B1);
}
}
for(rank_i=RANK_0; rank_i< p->support_rank_num; rank_i++)
{
vSetRank(p, rank_i);
DramcRxWindowPerbitCal(p, PATTERN_TEST_ENGINE, DVS_CAL_KEEP_VREF, AUTOK_OFF);
}
}
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), 1, SHU_B0_DQ11_RG_RX_ARDQ_DVS_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), 1, SHU_B1_DQ11_RG_RX_ARDQ_DVS_EN_B1);
vSetRank(p, backup_rank);
}
#endif
#if SIMULATION_DATLAT
static void dle_factor_handler(DRAMC_CTX_T *p, U8 curr_val)
{
U8 u1DATLAT_DSEL = 0;
U8 u1DLECG_OptionEXT1 = 0;
U8 u1DLECG_OptionEXT2 = 0;
U8 u1DLECG_OptionEXT3 = 0;
// If (RX_PIPE_BYPASS_ENABLE == 1) bypass RX PIPE, so RG_DATLAT_DSEL = RG_DATLAT
// else RG_DATLAT_DSEL = RG_DATLAT - 1
if (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_RX_PIPE_CTRL), SHU_MISC_RX_PIPE_CTRL_RX_PIPE_BYPASS_EN))
{
u1DATLAT_DSEL = curr_val;
}
else
{
if (curr_val < 1)
u1DATLAT_DSEL = curr_val;
else
u1DATLAT_DSEL = curr_val - 1;
}
// mcSHOW_DBG_MSG(("DATLAT: %d, u1DATLAT_DSEL: %d\n", curr_val, u1DATLAT_DSEL));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RDAT),
P_Fld(curr_val, MISC_SHU_RDAT_DATLAT) |
P_Fld(u1DATLAT_DSEL, MISC_SHU_RDAT_DATLAT_DSEL) |
P_Fld(u1DATLAT_DSEL, MISC_SHU_RDAT_DATLAT_DSEL_PHY));
// Had been adjusted for 868 already.
//(>=8 & <14) set EXT1 =1, EXT2=0, EXT3=0
//(>= 14 & <19) set EXT1=1, EXT2=1, EXT3=0
//(>=19) set EXT1=1, EXT2=1, EXT3=1
u1DLECG_OptionEXT1 = (curr_val >= 8)? (1): (0);
u1DLECG_OptionEXT2 = (curr_val >= 14)? (1): (0);
u1DLECG_OptionEXT3 = (curr_val >= 19)? (1): (0);
// mcSHOW_DBG_MSG(("u1DLECG_OptionEXT1: %d, 2 for %d, 3 for %d\n", u1DLECG_OptionEXT1, u1DLECG_OptionEXT2, u1DLECG_OptionEXT3));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHU_RX_CG_SET0),
P_Fld(u1DLECG_OptionEXT1, SHU_RX_CG_SET0_READ_START_EXTEND1) |
P_Fld(u1DLECG_OptionEXT1, SHU_RX_CG_SET0_DLE_LAST_EXTEND1) |
P_Fld((u1DLECG_OptionEXT2), SHU_RX_CG_SET0_READ_START_EXTEND2) |
P_Fld((u1DLECG_OptionEXT2), SHU_RX_CG_SET0_DLE_LAST_EXTEND2) |
P_Fld((u1DLECG_OptionEXT3), SHU_RX_CG_SET0_READ_START_EXTEND3) |
P_Fld((u1DLECG_OptionEXT3), SHU_RX_CG_SET0_DLE_LAST_EXTEND3));
DramPhyReset(p);
}
static U8 aru1RxDatlatResult[RANK_MAX];
DRAM_STATUS_T DramcRxdatlatCal(DRAMC_CTX_T *p)
{
U32 u4prv_register_080;
U8 ucfirst, ucbegin, ucsum, ucbest_step;
U16 u2DatlatBegin;
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
mcSHOW_DBG_MSG(("\n[DATLAT]\n"
"Freq=%d, CH%d RK%d\n\n", p->frequency, p->channel, p->rank));
// pre-save
// 0x07c[6:4] DATLAT bit2-bit0
u4prv_register_080 = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RDAT));
//default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_DATLAT, DRAM_FAIL);
// init best_step to default
ucbest_step = (U8) u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_RDAT), MISC_SHU_RDAT_DATLAT);
mcSHOW_DBG_MSG(("DATLAT Default: 0x%x\n", ucbest_step));
mcDUMP_REG_MSG(("DATLAT Default: 0x%x\n", ucbest_step));
// 1.set DATLAT 0-15 (0-21 for MT6595)
// 2.enable engine1 or engine2
// 3.check result ,3~4 taps pass
// 4.set DATLAT 2nd value for optimal
// Initialize
ucfirst = 0xff;
ucbegin = 0;
ucsum = 0;
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern | 0x80, 0, TE_UI_SHIFT);//UI_SHIFT + LEN1
u2DatlatBegin = 0;
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_DATLAT)
if (p->femmc_Ready == 1)
{
ucbest_step = p->pSavetimeData->u1RxDatlat_Save[p->channel][p->rank];
}
#endif
aru1RxDatlatResult[p->rank] = ucbest_step;
mcSHOW_DBG_MSG(("best_step = %d\n\n", ucbest_step));
mcDUMP_REG_MSG(("best_step=%d\n\n", ucbest_step));
#if __A60868_TO_BE_PORTING__
#if __ETT__
U8 _init_Datlat_value = vDramcACTimingGetDatLat(p);
if ((_init_Datlat_value > (ucbest_step + 1)) || (_init_Datlat_value < (ucbest_step - 1)))
{
mcSHOW_DBG_MSG(("[WARNING!!] Datlat initial value(%d) = best_step(%d) %c %d, out of range!\n\n",
_init_Datlat_value,
ucbest_step,
(ucbest_step > _init_Datlat_value)? '-': '+',
abs(ucbest_step - _init_Datlat_value)));
while (1);
}
#endif
#endif
#if defined(FOR_HQA_TEST_USED) && defined(FOR_HQA_REPORT_USED)
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT2, "DATLAT", "", 0, ucbest_step, NULL);
#endif
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_DATLAT)
if (p->femmc_Ready == 1)
{
dle_factor_handler(p, ucbest_step);
vSetCalibrationResult(p, DRAM_CALIBRATION_DATLAT, DRAM_FAST_K);
}
#endif
mcSHOW_DBG_MSG3(("[DramcRxdatlatCal] Done\n"));
return DRAM_OK;
}
DRAM_STATUS_T DramcDualRankRxdatlatCal(DRAMC_CTX_T *p)
{
U8 u1FinalDatlat, u1Datlat0, u1Datlat1;
u1Datlat0 = aru1RxDatlatResult[0];
u1Datlat1 = aru1RxDatlatResult[1];
if (p->support_rank_num == RANK_DUAL)
{
if (u1Datlat0 > u1Datlat1)
{
u1FinalDatlat = u1Datlat0;
}
else
{
u1FinalDatlat = u1Datlat1;
}
}
else
{
u1FinalDatlat = u1Datlat0;
}
#if ENABLE_READ_DBI
if (p->DBI_R_onoff[p->dram_fsp])
{
u1FinalDatlat++;
}
#endif
dle_factor_handler(p, u1FinalDatlat);
#if RDSEL_TRACKING_EN
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_RDSEL_TRACK), u1FinalDatlat, SHU_MISC_RDSEL_TRACK_DMDATLAT_I);
#endif
mcSHOW_DBG_MSG(("[DualRankRxdatlatCal] RK0: %d, RK1: %d, Final_Datlat %d\n", u1Datlat0, u1Datlat1, u1FinalDatlat));
return DRAM_OK;
}
#endif // SIMULATION_DATLAT
#if SIMULATION_TX_PERBIT
//=============================================================
///// DramC TX perbi calibration ----------Begin--------------
//=============================================================
//-------------------------------------------------------------------------
/** DramcTxWindowPerbitCal (v2)
* TX DQS per bit SW calibration.
* @param p Pointer of context created by DramcCtxCreate.
* @param apply (U8): 0 don't apply the register we set 1 apply the register we set ,default don't apply.
* @retval status (DRAM_STATUS_T): DRAM_OK or DRAM_FAIL
*/
//-------------------------------------------------------------------------
#if (SW_CHANGE_FOR_SIMULATION || FOR_DV_SIMULATION_USED)
#define TX_VREF_RANGE_BEGIN 0
#define TX_VREF_RANGE_END 2 // binary 110010
#define TX_VREF_RANGE_STEP 2
#else
#define TX_VREF_RANGE_BEGIN 16
#define TX_VREF_RANGE_END 50 // binary 110010
#define TX_VREF_RANGE_STEP 2
#endif
#define TX_DQ_UI_TO_PI_TAP 64 // 1 PI = tCK/64, total 128 PI, 1UI = 32 PI
#define TX_PHASE_DQ_UI_TO_PI_TAP 32 // 1 PI = tCK/64, total 128 PI, 1UI = 32 PI for DDR800 semi open loop mode
#define LP4_TX_VREF_DATA_NUM 50
#define LP4_TX_VREF_PASS_CONDITION 0
#define TX_PASS_WIN_CRITERIA 7
#define LP4_TX_VREF_BOUNDARY_NOT_READY 0xff
typedef struct _PASS_WIN_DATA_BY_VREF_T
{
U16 u2VrefUsed;
U16 u2WinSum_byVref;
U8 u1WorseBitWinSize_byVref;
U8 u1WorseBitIdx_byVref;
} PASS_WIN_DATA_BY_VREF_T;
static void TxWinTransferDelayToUIPI(DRAMC_CTX_T *p, U16 uiDelay, U8 u1AdjustPIToCenter, U8* pu1UILarge_DQ, U8* pu1UISmall_DQ, U8* pu1PI, U8* pu1UILarge_DQOE, U8* pu1UISmall_DQOE)
{
U8 u1Small_ui_to_large, u1PI = 0, u164PIto1UI, u1TxDQOEShift = 0;
U16 u2TmpValue, u2DQOE_shift;
DDR800_MODE_T eDdr800Mode = vGet_DDR_Loop_Mode(p);
U8 u1PiTap = (u1IsPhaseMode(p) == TRUE) ? TX_PHASE_DQ_UI_TO_PI_TAP : TX_DQ_UI_TO_PI_TAP;
u1Small_ui_to_large = u1MCK2UI_DivShift(p);
#if ENABLE_WDQS_MODE_2
u1TxDQOEShift = WDQSMode2AcTxOEShift(p);
#else
u1TxDQOEShift = TX_DQ_OE_SHIFT_LP4;
#endif
if(pu1PI != NULL)
{
u1PI = uiDelay & (u1PiTap-1);
*pu1PI =u1PI;
}
if (u1IsLP4Div4DDR800(p) /*DDR800 close loop mode*/ || u1IsPhaseMode(p))
u164PIto1UI = 0;
else
u164PIto1UI = 1;
u2TmpValue = (uiDelay /u1PiTap)<<u164PIto1UI; // 1:8 mode for 2UI carry, DDR800 1:4 mode for 1UI carry
if (u1AdjustPIToCenter && (pu1PI != NULL) && (eDdr800Mode == CLOSE_LOOP_MODE))
{
if (u1PI < 10)
{
u1PI += (u1PiTap) >> 1;
u2TmpValue --;
}
else if (u1PI > u1PiTap - 10)
{
u1PI -= (u1PiTap) >> 1;
u2TmpValue ++;
}
*pu1PI = u1PI;
}
#if 0
*pu1UISmall_DQ = u2TmpValue % u1Small_ui_to_large;
*pu1UILarge_DQ = u2TmpValue / u1Small_ui_to_large;
#else
*pu1UISmall_DQ = u2TmpValue - ((u2TmpValue >> u1Small_ui_to_large) << u1Small_ui_to_large);
*pu1UILarge_DQ = (u2TmpValue >> u1Small_ui_to_large);
#endif
// calculate DQ OE according to DQ UI
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
u2TmpValue -= TX_DQ_OE_SHIFT_LP5;
}
else
#endif
{
u2TmpValue -= u1TxDQOEShift;
}
if(((u1MR03Value[p->dram_fsp]&0x80)>>7)==1) //if WDBI is on, OE_DLY don't need to shift 1 MCK with DLY
{
if (vGet_Div_Mode(p) == DIV4_MODE)
u2DQOE_shift = 4; //OE_shift = OE_shift - 3(original OE position) + 4 (MCK)
else
u2DQOE_shift = 8; //OE_shift = OE_shift - 3(original OE position) + 8 (MCK)
u2TmpValue += u2DQOE_shift;
}
*pu1UISmall_DQOE = u2TmpValue - ((u2TmpValue >> u1Small_ui_to_large) << u1Small_ui_to_large);
*pu1UILarge_DQOE = (u2TmpValue >> u1Small_ui_to_large);
}
static void TXPerbitCalibrationInit(DRAMC_CTX_T *p, U8 calType)
{
//Set TX delay chain to 0
if (calType != TX_DQ_DQS_MOVE_DQM_ONLY)
{
#if 1
#if PINMUX_AUTO_TEST_PER_BIT_TX
if(gTX_check_per_bit_flag == 1)
{
//not reset delay cell
}
else
#endif
{
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY0), 0);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY1), 0);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY0), 0);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY1), 0);
}
#else
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_SHU_R0_B0_DQ0), P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ7_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ6_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ5_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ4_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ3_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ2_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ1_DLY_B0)
| P_Fld(0x0, SHU_R0_B0_DQ0_RK0_TX_ARDQ0_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_SHU_R0_B1_DQ0), P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ7_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ6_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ5_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ4_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ3_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ2_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ1_DLY_B1)
| P_Fld(0x0, SHU_R0_B1_DQ0_RK0_TX_ARDQ0_DLY_B1));
#endif
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY3), 0x0, SHU_R0_B0_TXDLY3_TX_ARDQM0_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY3), 0x0, SHU_R0_B1_TXDLY3_TX_ARDQM0_DLY_B1);
}
//Use HW TX tracking value
//R_DMARPIDQ_SW :drphy_conf (0x170[7])(default set 1)
// 0: DQS2DQ PI setting controlled by HW
//R_DMARUIDQ_SW : Dramc_conf(0x156[15])(default set 1)
// 0: DQS2DQ UI setting controlled by HW
///TODO: need backup original setting?
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_MISC_CTRL1), 1, MISC_CTRL1_R_DMARPIDQ_SW);
//vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DQSOSCR), 1, DQSOSCR_ARUIDQ_SW);
}
#define TX_TDQS2DQ_PRE_CAL 0
#if TX_TDQS2DQ_PRE_CAL
// (1) DDR800 1:4 mode
// (2) DDR1200/1600 1:4 mode
// (3) 1:8 mode
// The 3 condition have different MCK2UI/UI2PI. Therefore, TX DQS2DQ should be record separately.
// Here, we record (2) and (3). DDR800 1:4 skip recording DQS2DQ.
U16 u2DQS2DQ_Pre_Cal[CHANNEL_NUM][RANK_MAX][2/*DIV_Mode*/] = {0};
#endif
static void TXScanRange_PI(DRAMC_CTX_T *p, DRAM_TX_PER_BIT_CALIBRATION_TYTE_T calType, U16 *pu2Begin, U16 *pu2End)
{
U8 u1MCK2UI, u1UI2PI, u1ByteIdx;
U32 u4RegValue_TXDLY, u4RegValue_dly;
U8 ucdq_ui_large_bak[DQS_NUMBER], ucdq_ui_small_bak[DQS_NUMBER];
U16 u2TempVirtualDelay, u2SmallestVirtualDelay = 0xffff;
U16 u2DQDelayBegin = 0, u2DQDelayEnd = 0;
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
u4RegValue_TXDLY = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_WCK_WR_MCK));
u4RegValue_dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_WCK_WR_UI));
}
else
#endif
{
u4RegValue_TXDLY = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_DQS0));
u4RegValue_dly = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHU_SELPH_DQS1));
}
u1MCK2UI = u1MCK2UI_DivShift(p);
if (vGet_DDR_Loop_Mode(p) == DDR800_CLOSE_LOOP)
u1UI2PI = 6;
else
u1UI2PI = 5;
// find smallest DQS delay
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
ucdq_ui_large_bak[u1ByteIdx] = (u4RegValue_TXDLY >> (u1ByteIdx << 2)) & 0x7;// MCK
ucdq_ui_small_bak[u1ByteIdx] = (u4RegValue_dly >> (u1ByteIdx << 2)) & 0x7;// UI
//wrlevel_dqs_final_delay[p->rank][u1ByteIdx] ==> PI
//LP4 : Virtual Delay = 256 * MCK + 32*UI + PI;
//LP3 : Virtual Delay = 128 * MCK + 32*UI + PI;
u2TempVirtualDelay = (((ucdq_ui_large_bak[u1ByteIdx] << u1MCK2UI) + ucdq_ui_small_bak[u1ByteIdx]) << u1UI2PI) + wrlevel_dqs_final_delay[p->rank][u1ByteIdx];
if (u2TempVirtualDelay < u2SmallestVirtualDelay)
{
u2SmallestVirtualDelay = u2TempVirtualDelay;
}
}
u2DQDelayBegin = u2SmallestVirtualDelay;
#if TX_TDQS2DQ_PRE_CAL
if (u1IsLP4Div4DDR800(p) == FALSE)
{
if (u2DQS2DQ_Pre_Cal[p->channel][p->rank][vGet_Div_Mode(p)] > 0)
{
U16 u2TmpShift;
mcSHOW_DBG_MSG(("TX_TDQS2DQ_PRE_CAL : change DQ begin %d -->", u2DQDelayBegin));
u2TmpShift = (u2DQS2DQ_Pre_Cal[p->channel][p->rank][vGet_Div_Mode(p)]* p->frequency) / 1000;
if (u2TmpShift >= 15)
u2TmpShift -= 15;
else
u2TmpShift = 0;
u2DQDelayBegin += u2TmpShift;
mcSHOW_DBG_MSG(("%d (+%d)\n", u2DQDelayBegin, u2TmpShift));
}
}
#endif
#if (__LP5_COMBO__)
if (is_lp5_family(p)) {
/* For DDR3200, +1.5 MCK */
if (p->frequency == 1600)
u2DQDelayBegin += (((1 << u1MCK2UI) + ((1 << u1MCK2UI) >> 1)) << u1UI2PI);
else if (p->frequency == 2133)
u2DQDelayBegin += ((1 << u1MCK2UI) << u1UI2PI);
else if (p->frequency == 2750)
u2DQDelayBegin += (9 << u1UI2PI);
}
#endif
#if TX_K_DQM_WITH_WDBI
if (calType == TX_DQ_DQS_MOVE_DQM_ONLY)
{
// DBI on, calibration range -1MCK
u2DQDelayBegin -= (1 << (u1MCK2UI + 5));
}
#endif
/* Scan range: 1MCK */
u2DQDelayEnd = u2DQDelayBegin + ((1 << u1MCK2UI) << u1UI2PI);
*pu2Begin = u2DQDelayBegin;
*pu2End = u2DQDelayEnd;
#if 0//TX_TDQS2DQ_PRE_CAL
mcSHOW_DBG_MSG(("TXScanRange_PI %d~%d\n", u2DQDelayBegin, u2DQDelayEnd));
#endif
}
static void TXScanRange_Vref(DRAMC_CTX_T *p, U8 u1VrefScanEnable, U16* pu2Range, U16 *pu2Begin, U16 *pu2End, U16 *pu2Setp)
{
U16 u2VrefBegin = 0, u2VrefEnd = 0;
if (u1VrefScanEnable)
{
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_VREF_CAL)
if (p->femmc_Ready == 1)
{
// if fast K, use TX Vref that saved.
u2VrefBegin = p->pSavetimeData->u1TxWindowPerbitVref_Save[p->channel][p->rank];
u2VrefEnd = u2VrefBegin + 1;
}
#endif
}
else //LPDDR3, the for loop will only excute u2VrefLevel=TX_VREF_RANGE_END/2.
{
u2VrefBegin = 0;
u2VrefEnd = 0;
}
*pu2Range = (!p->odt_onoff);
*pu2Begin = u2VrefBegin;
*pu2End = u2VrefEnd;
*pu2Setp = TX_VREF_RANGE_STEP;
}
static U16 TxChooseVref(DRAMC_CTX_T *p, PASS_WIN_DATA_BY_VREF_T pVrefInfo[], U8 u1VrefNum)
{
U8 u1VrefIdx, u1WorseBitIdx = 0, u1WinSizeOfWorseBit = 0;
U16 u2MaxWinSum = 0;
U16 u2FinalVref = 0;
for (u1VrefIdx = 0; u1VrefIdx < u1VrefNum; u1VrefIdx++)
{
mcSHOW_DBG_MSG(("TX Vref=%d, minBit %d, minWin=%d, winSum=%d\n",
pVrefInfo[u1VrefIdx].u2VrefUsed,
pVrefInfo[u1VrefIdx].u1WorseBitIdx_byVref,
pVrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref,
pVrefInfo[u1VrefIdx].u2WinSum_byVref));
#if LP4_TX_VREF_PASS_CONDITION
if ((pVrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref > LP4_TX_VREF_PASS_CONDITION))
{
if (u1VrefPassBegin == LP4_TX_VREF_BOUNDARY_NOT_READY)
{
u1VrefPassBegin = pVrefInfo[u1VrefIdx].u2VrefUsed;
u1TempPassNum = 1;
}
else
u1TempPassNum ++;
if (u1VrefIdx == u1VrefNum - 1)
{
u1VrefPassEnd = pVrefInfo[u1VrefIdx].u2VrefUsed;
if (u1TempPassNum > u1MaxVerfPassNum)
{
u1VrefPassBegin_Final = u1VrefPassBegin;
u1VrefPassEnd_Final = u1VrefPassEnd;
u1MaxVerfPassNum = u1TempPassNum;
}
}
}
else
{
if ((u1VrefPassBegin != LP4_TX_VREF_BOUNDARY_NOT_READY) && (u1VrefPassEnd == LP4_TX_VREF_BOUNDARY_NOT_READY))
{
u1VrefPassEnd = pVrefInfo[u1VrefIdx].u2VrefUsed - TX_VREF_RANGE_STEP;
if (u1TempPassNum > u1MaxVerfPassNum)
{
u1VrefPassBegin_Final = u1VrefPassBegin;
u1VrefPassEnd_Final = u1VrefPassEnd;
u1MaxVerfPassNum = u1TempPassNum;
}
u1VrefPassBegin = 0xff;
u1VrefPassEnd = 0xff;
u1TempPassNum = 0;
}
}
#endif
}
#if LP4_TX_VREF_PASS_CONDITION
//if((u1VrefPassBegin_Final !=LP4_TX_VREF_BOUNDARY_NOT_READY) && (u1VrefPassEnd_Final!=LP4_TX_VREF_BOUNDARY_NOT_READY))
if (u1MaxVerfPassNum > 0)
{
// vref pass window found
u2FinalVref = (u1VrefPassBegin_Final + u1VrefPassEnd_Final) >> 1;
mcSHOW_DBG_MSG(("[TxChooseVref] Window > %d, Vref (%d~%d), Final Vref %d\n", LP4_TX_VREF_PASS_CONDITION, u1VrefPassBegin_Final, u1VrefPassEnd_Final, u2FinalVref));
}
else
#endif
{
// not vref found
for (u1VrefIdx = 0; u1VrefIdx < u1VrefNum; u1VrefIdx++)
{
if ((pVrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref > u1WinSizeOfWorseBit) ||
((pVrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref == u1WinSizeOfWorseBit) && (pVrefInfo[u1VrefIdx].u2WinSum_byVref > u2MaxWinSum)))
{
u1WinSizeOfWorseBit = pVrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref;
u1WorseBitIdx = pVrefInfo[u1VrefIdx].u1WorseBitIdx_byVref;
u2MaxWinSum = pVrefInfo[u1VrefIdx].u2WinSum_byVref;
u2FinalVref = pVrefInfo[u1VrefIdx].u2VrefUsed;
}
}
mcSHOW_DBG_MSG(("[TxChooseVref] Worse bit %d, Min win %d, Win sum %d, Final Vref %d\n", u1WorseBitIdx, u1WinSizeOfWorseBit, u2MaxWinSum, u2FinalVref));
}
return u2FinalVref;
}
static void DramcTXSetVref(DRAMC_CTX_T *p, U8 u1VrefRange, U8 u1VrefValue)
{
U8 u1TempOPValue;
#ifdef __LP5_COMBO__
if (is_lp5_family(p))
u1TempOPValue = ((u1VrefValue & 0x7f));
else
#endif
u1TempOPValue = ((u1VrefValue & 0x3f) | (u1VrefRange << 6));
u1MR14Value[p->channel][p->rank][p->dram_fsp] = u1TempOPValue;
//For TX VREF of different byte
DramcModeRegWriteByRank(p, p->rank, 14, u1TempOPValue);
#ifdef __LP5_COMBO__
if (is_lp5_family(p))
DramcModeRegWriteByRank(p, p->rank, 15, u1TempOPValue);
#endif
#if CALIBRATION_SPEED_UP_DEBUG
mcSHOW_DBG_MSG(("Yulia TX Vref : CH%d Rank%d, TX Range %d Vref %d\n\n", p->channel, p->rank, u1VrefRange, (u1VrefValue & 0x3f)));
#endif
}
static void TXSetFinalVref(DRAMC_CTX_T *p, U16 u2FinalRange, U16 u2FinalVref)
{
DramcTXSetVref(p, u2FinalRange, u2FinalVref);
#ifdef FOR_HQA_TEST_USED
gFinalTXVrefDQ[p->channel][p->rank] = (U8) u2FinalVref;
#endif
#if VENDER_JV_LOG
mcSHOW_DBG_MSG5(("\nFinal TX Range %d Vref %d\n\n", u2FinalRange, u2FinalVref));
#else
mcSHOW_DBG_MSG(("\nFinal TX Range %d Vref %d\n\n", u2FinalRange, u2FinalVref));
#endif
#if CALIBRATION_SPEED_UP_DEBUG
mcSHOW_DBG_MSG(("Yulia TX Vref Final: CH%d Rank%d, TX Range %d Vref %d\n\n", p->channel, p->rank, u2FinalRange, u2FinalVref));
#endif
}
#if ENABLE_TX_TRACKING
#if !BYPASS_CALIBRATION
static
#endif
void TXUpdateTXTracking(DRAMC_CTX_T *p, DRAM_TX_PER_BIT_CALIBRATION_TYTE_T calType, U8 ucdq_pi[], U8 ucdqm_pi[])
{
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY || calType == TX_DQ_DQS_MOVE_DQM_ONLY)
{
//make a copy to dramc reg for TX DQ tracking used
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_PI),
P_Fld(ucdq_pi[0], SHURK_PI_RK0_ARPI_DQ_B0) | P_Fld(ucdq_pi[1], SHURK_PI_RK0_ARPI_DQ_B1));
// Source DQ
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_DQS2DQ_CAL1),
P_Fld(ucdq_pi[1], SHURK_DQS2DQ_CAL1_BOOT_ORIG_UI_RK0_DQ1) |
P_Fld(ucdq_pi[0], SHURK_DQS2DQ_CAL1_BOOT_ORIG_UI_RK0_DQ0));
// Target DQ
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_DQS2DQ_CAL2),
P_Fld(ucdq_pi[1], SHURK_DQS2DQ_CAL2_BOOT_TARG_UI_RK0_DQ1) |
P_Fld(ucdq_pi[0], SHURK_DQS2DQ_CAL2_BOOT_TARG_UI_RK0_DQ0));
}
//if(calType ==TX_DQ_DQS_MOVE_DQM_ONLY || (calType ==TX_DQ_DQS_MOVE_DQ_ONLY))
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_PI),
P_Fld(ucdqm_pi[0], SHURK_PI_RK0_ARPI_DQM_B0) | P_Fld(ucdqm_pi[1], SHURK_PI_RK0_ARPI_DQM_B1));
// Target DQM
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_DQS2DQ_CAL5),
P_Fld(ucdqm_pi[1], SHURK_DQS2DQ_CAL5_BOOT_TARG_UI_RK0_DQM1) |
P_Fld(ucdqm_pi[0], SHURK_DQS2DQ_CAL5_BOOT_TARG_UI_RK0_DQM0));
}
}
#if 0// for LP3 , TX tracking will be disable, don't need to set DQ delay in DramC.
///TODO: check LP3 byte mapping of dramC
vIO32WriteFldMulti(DRAMC_REG_SHURK0_PI + (CHANNEL_A << POS_BANK_NUM), \
P_Fld(ucdq_final_pi[0], SHURK0_PI_RK0_ARPI_DQ_B0) | P_Fld(ucdq_final_pi[1], SHURK0_PI_RK0_ARPI_DQ_B1));
vIO32WriteFldMulti(DRAMC_REG_SHURK0_PI + SHIFT_TO_CHB_ADDR, \
P_Fld(ucdq_final_pi[2], SHURK0_PI_RK0_ARPI_DQ_B0) | P_Fld(ucdq_final_pi[3], SHURK0_PI_RK0_ARPI_DQ_B1));
#endif
}
#endif //End ENABLE_TX_TRACKING
#if !BYPASS_CALIBRATION
static
#endif
void TXSetDelayReg_DQ(DRAMC_CTX_T *p, U8 u1UpdateRegUI, U8 ucdq_ui_large[], U8 ucdq_oen_ui_large[], U8 ucdq_ui_small[], U8 ucdq_oen_ui_small[], U8 ucdql_pi[])
{
if (u1UpdateRegUI)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), \
P_Fld(ucdq_ui_large[0], SHURK_SELPH_DQ0_TXDLY_DQ0) |
P_Fld(ucdq_ui_large[1], SHURK_SELPH_DQ0_TXDLY_DQ1) |
P_Fld(ucdq_ui_large[2], SHURK_SELPH_DQ0_TXDLY_DQ2) |
P_Fld(ucdq_ui_large[3], SHURK_SELPH_DQ0_TXDLY_DQ3) |
P_Fld(ucdq_oen_ui_large[0], SHURK_SELPH_DQ0_TXDLY_OEN_DQ0) |
P_Fld(ucdq_oen_ui_large[1], SHURK_SELPH_DQ0_TXDLY_OEN_DQ1) |
P_Fld(ucdq_oen_ui_large[2], SHURK_SELPH_DQ0_TXDLY_OEN_DQ2) |
P_Fld(ucdq_oen_ui_large[3], SHURK_SELPH_DQ0_TXDLY_OEN_DQ3));
// DLY_DQ[2:0]
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), \
P_Fld(ucdq_ui_small[0], SHURK_SELPH_DQ2_DLY_DQ0) |
P_Fld(ucdq_ui_small[1], SHURK_SELPH_DQ2_DLY_DQ1) |
P_Fld(ucdq_ui_small[2], SHURK_SELPH_DQ2_DLY_DQ2) |
P_Fld(ucdq_ui_small[3], SHURK_SELPH_DQ2_DLY_DQ3) |
P_Fld(ucdq_oen_ui_small[0], SHURK_SELPH_DQ2_DLY_OEN_DQ0) |
P_Fld(ucdq_oen_ui_small[1], SHURK_SELPH_DQ2_DLY_OEN_DQ1) |
P_Fld(ucdq_oen_ui_small[2], SHURK_SELPH_DQ2_DLY_OEN_DQ2) |
P_Fld(ucdq_oen_ui_small[3], SHURK_SELPH_DQ2_DLY_OEN_DQ3));
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), ucdql_pi[0], SHU_R0_B0_DQ0_SW_ARPI_DQ_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), ucdql_pi[1], SHU_R0_B1_DQ0_SW_ARPI_DQ_B1);
}
#if !BYPASS_CALIBRATION
static
#endif
void TXSetDelayReg_DQM(DRAMC_CTX_T *p, U8 u1UpdateRegUI, U8 ucdqm_ui_large[], U8 ucdqm_oen_ui_large[], U8 ucdqm_ui_small[], U8 ucdqm_oen_ui_small[], U8 ucdqm_pi[])
{
if (u1UpdateRegUI)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1),
P_Fld(ucdqm_ui_large[0], SHURK_SELPH_DQ1_TXDLY_DQM0) |
P_Fld(ucdqm_ui_large[1], SHURK_SELPH_DQ1_TXDLY_DQM1) |
P_Fld(ucdqm_ui_large[2], SHURK_SELPH_DQ1_TXDLY_DQM2) |
P_Fld(ucdqm_ui_large[3], SHURK_SELPH_DQ1_TXDLY_DQM3) |
P_Fld(ucdqm_oen_ui_large[0], SHURK_SELPH_DQ1_TXDLY_OEN_DQM0) |
P_Fld(ucdqm_oen_ui_large[1], SHURK_SELPH_DQ1_TXDLY_OEN_DQM1) |
P_Fld(ucdqm_oen_ui_large[2], SHURK_SELPH_DQ1_TXDLY_OEN_DQM2) |
P_Fld(ucdqm_oen_ui_large[3], SHURK_SELPH_DQ1_TXDLY_OEN_DQM3));
// DLY_DQM[2:0]
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3),
P_Fld(ucdqm_ui_small[0], SHURK_SELPH_DQ3_DLY_DQM0) |
P_Fld(ucdqm_ui_small[1], SHURK_SELPH_DQ3_DLY_DQM1) |
P_Fld(ucdqm_ui_small[2], SHURK_SELPH_DQ3_DLY_DQM2) |
P_Fld(ucdqm_ui_small[3], SHURK_SELPH_DQ3_DLY_DQM3) |
P_Fld(ucdqm_oen_ui_small[0], SHURK_SELPH_DQ3_DLY_OEN_DQM0) |
P_Fld(ucdqm_oen_ui_small[1], SHURK_SELPH_DQ3_DLY_OEN_DQM1) |
P_Fld(ucdqm_oen_ui_small[2], SHURK_SELPH_DQ3_DLY_OEN_DQM2) |
P_Fld(ucdqm_oen_ui_small[3], SHURK_SELPH_DQ3_DLY_OEN_DQM3));
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), ucdqm_pi[0], SHU_R0_B0_DQ0_SW_ARPI_DQM_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), ucdqm_pi[1], SHU_R0_B1_DQ0_SW_ARPI_DQM_B1);
}
#if TX_AUTO_K_ENABLE
static void Tx_Auto_K_Init(DRAMC_CTX_T *p, DRAM_TX_PER_BIT_CALIBRATION_TYTE_T calType, U8 ucdq_pi, U8 u1PI_Len)
{
u8 pi_thrd = 0xa;
#if FOR_DV_SIMULATION_USED == 1
cal_sv_rand_args_t *psra = get_psra();
if (psra) {
pi_thrd = psra->tx_atk_pass_pi_thrd & 0xFF;
early_break = psra->tx_atk_early_break & 0xFF;
}
#endif
#if ENABLE_PA_IMPRO_FOR_TX_AUTOK
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_DCM_SUB_CTRL), 0x1, DCM_SUB_CTRL_SUBCLK_CTRL_TX_AUTOK);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_CG_SET0), 0x1, TX_CG_SET0_TX_ATK_CLKRUN);
#endif
if (calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1),
P_Fld(0x1, TX_ATK_SET1_TX_ATK_DQ_PI_EN) | //enable TX DQ auto K
P_Fld(0x1, TX_ATK_SET1_TX_ATK_DQM_PI_EN)); //enable TX DQM auto K
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET0),
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQ_B0_PI_INIT) | //Set begin position of DQ B0
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQ_B1_PI_INIT) | //Set begin position of DQ B1
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQM_B0_PI_INIT) | //Set begin position of DQM B0
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQM_B1_PI_INIT)); //Set begin position of DQM B1
}
else if (calType == TX_DQ_DQS_MOVE_DQM_ONLY)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x1, TX_ATK_SET1_TX_ATK_DQM_PI_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET0),
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQM_B0_PI_INIT) |
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQM_B1_PI_INIT));
}
else
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x1, TX_ATK_SET1_TX_ATK_DQ_PI_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET0),
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQ_B0_PI_INIT) |
P_Fld(ucdq_pi, TX_ATK_SET0_TX_ATK_DQ_B1_PI_INIT));
}
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 0, MISC_CTRL1_R_DMARPIDQ_SW); //Switch PI SW mode to HW mode (control by DRAMC not APHY)
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1),
P_Fld(u1PI_Len, TX_ATK_SET1_TX_ATK_PI_LEN) | //enable TX auto k len
P_Fld(pi_thrd, TX_ATK_SET1_TX_ATK_PASS_PI_THRD)); //Set threshold of PI pass window
#if (fcFOR_CHIP_ID == fcIPM) //Fix at Mar_gaux
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), early_break, TX_ATK_SET1_TX_ATK_EARLY_BREAK); //Enable early break
#endif
#if (__LP5_COMBO__ == TRUE)
if (TRUE == is_lp5_family(p))
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHU_TX_SET0),
P_Fld(0x5, SHU_TX_SET0_TXOEN_AUTOSET_OFFSET) |
P_Fld(0x1, SHU_TX_SET0_TXOEN_AUTOSET_EN)); //Enable OE auto adjust
}
else
#endif
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHU_TX_SET0),
P_Fld(0x3, SHU_TX_SET0_TXOEN_AUTOSET_OFFSET) |
P_Fld(0x1, SHU_TX_SET0_TXOEN_AUTOSET_EN)); //Enable OE auto adjust
}
#if TX_AUTO_K_DEBUG_ENABLE
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x1, TX_ATK_SET1_TX_ATK_DBG_EN);
#endif
}
static void Tx_Auto_K_complete_check(DRAMC_CTX_T *p)
{
U32 u4loop_count = 0;
while ((u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_RESULT8), TX_ATK_RESULT8_TX_ATK_DONE) != 0x1))
{
mcDELAY_US(1);
u4loop_count++;
//mcSHOW_DBG_MSG(("Wait! TX auto K is not done!\n"));
if (u4loop_count > 100000)
{
mcSHOW_ERR_MSG(("Error! TX auto K is not done!\n"));
break;
}
}
if ((u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_RESULT8), TX_ATK_RESULT8_TX_ATK_FIND_PW) == 0x1))
{
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_PERBIT, DRAM_OK);
mcSHOW_DBG_MSG(("Tx auto K, all bit find passs window\n"));
}
else
{
mcSHOW_ERR_MSG(("Error! TX auto K is fail!\n"));
}
}
static void Tx_Auto_K_Clear(DRAMC_CTX_T *p)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x0, TX_ATK_SET1_TX_ATK_TRIG); //Disable Tx auto K
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHU_TX_SET0), 0x0, SHU_TX_SET0_TXOEN_AUTOSET_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 0x1, MISC_CTRL1_R_DMARPIDQ_SW);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x0, TX_ATK_SET1_TX_ATK_DBG_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x1, TX_ATK_SET1_TX_ATK_CLR); //Clear state machine
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x0, TX_ATK_SET1_TX_ATK_CLR);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1),
P_Fld(0x0, TX_ATK_SET1_TX_ATK_PI_LEN) |
P_Fld(0x0, TX_ATK_SET1_TX_ATK_DQ_PI_EN) |
P_Fld(0x0, TX_ATK_SET1_TX_ATK_DQM_PI_EN));
#if ENABLE_PA_IMPRO_FOR_TX_AUTOK
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_CG_SET0), 0x0, TX_CG_SET0_TX_ATK_CLKRUN);
#endif
}
#if TX_AUTO_K_WORKAROUND
static void Tx_Auto_K_DQM_Workaround(DRAMC_CTX_T *p)
{
//Set RK1 DQM DLY to RK0
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), u4DQM_MCK_RK1_backup);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), u4DQM_UI_RK1_backup);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), u4DQM_PI_RK1_backup[0]);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), u4DQM_PI_RK1_backup[1]);
}
static void Tx_Auto_K_DQ_Workaround(DRAMC_CTX_T *p)
{
//Set RK1 DQM DLY to RK0
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), u4DQ_MCK_RK1_backup);
vIO32Write4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), u4DQ_UI_RK1_backup);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), u4DQ_PI_RK1_backup[0]);
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), u4DQ_PI_RK1_backup[1]);
}
#endif
#if TX_AUTO_K_DEBUG_ENABLE
static void Tx_Auto_K_Debug_Message(DRAMC_CTX_T *p, U8 u1PI_Len)
{
U8 u1bit_num = 0, u1BitIdx;
U16 u2Length = 0, u2Length_max = 0;
U32 u4status;
U32 u4status_bit[4][DQ_DATA_WIDTH_LP4];
if (u1PI_Len == 0)
u2Length_max = 48;
else
u2Length_max = 32 * (1 + u1PI_Len);
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), u1BitIdx, TX_ATK_SET1_TX_ATK_DBG_BIT_SEL);
u4status_bit[0][u1BitIdx] = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_DBG_BIT_STATUS1));
u4status_bit[1][u1BitIdx] = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_DBG_BIT_STATUS2));
u4status_bit[2][u1BitIdx] = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_DBG_BIT_STATUS3));
u4status_bit[3][u1BitIdx] = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_DBG_BIT_STATUS4));
}
mcSHOW_DBG_MSG2(("Debug TX DQ PASS/FAIL status:\n"));
for (u2Length = 0; u2Length < u2Length_max; u2Length++)
{
mcSHOW_DBG_MSG2(("Delay=%3d ", u2Length));
for (u1bit_num = 0; u1bit_num < p->data_width; u1bit_num++)
{
u4status = ((u4status_bit[u2Length / 32][u1bit_num] >> (u2Length % 32)) & 0x1);
if (u4status == 0)
{
mcSHOW_DBG_MSG2(("x"));
}
else
{
mcSHOW_DBG_MSG2(("o"));
}
if (u1bit_num == (p->data_width - 1))
{
mcSHOW_DBG_MSG2((" \n"));
}
}
}
//mcSHOW_DBG_MSG(("Debug DQ PASS(1)/FAIL(0) bit: %d, STATUS1: 0x%x, STATUS2: 0x%x, STATUS3: 0x%x, STATUS4: 0x%x,\n",u1BitIdx,u4status_bit[0][u1BitIdx],u4status_bit[1][u1BitIdx],u4status_bit[2][u1BitIdx],u4status_bit[3][u1BitIdx]));
}
#endif
#endif
#if TX_K_DQM_WITH_WDBI
void vSwitchWriteDBISettings(DRAMC_CTX_T *p, U8 u1OnOff)
{
S8 u1TXShiftMCK;
u1TXShiftMCK = (u1OnOff)? -1: 1;
DramcWriteShiftMCKForWriteDBI(p, u1TXShiftMCK); //Tx DQ/DQM -1 MCK for write DBI ON
SetDramModeRegForWriteDBIOnOff(p, p->dram_fsp, u1OnOff);
DramcWriteDBIOnOff(p, u1OnOff);
#if (TX_AUTO_K_ENABLE && TX_AUTO_K_WORKAROUND)
if (p->rank == RANK_1)
{
u4DQ_MCK_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0));
u4DQ_UI_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2));
u4DQ_PI_RK1_backup[0] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0));
u4DQ_PI_RK1_backup[1] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0));
}
#endif
}
#endif
PASS_WIN_DATA_T WinPerBit[DQ_DATA_WIDTH], VrefWinPerBit[DQ_DATA_WIDTH], FinalWinPerBit[DQ_DATA_WIDTH];
DRAM_STATUS_T DramcTxWindowPerbitCal(DRAMC_CTX_T *p, DRAM_TX_PER_BIT_CALIBRATION_TYTE_T calType, U8 u1VrefScanEnable, u8 isAutoK)
{
U8 u1BitTemp, u1BitIdx, u1ByteIdx, u1RankIdx, backup_rank;
U32 uiFinishCount;
U16 uiDelay, u2DQDelayBegin, u2DQDelayEnd, u2DQDelayStep = 1;
U8 ucdq_pi, ucdq_ui_small, ucdq_ui_large, ucdq_oen_ui_small, ucdq_oen_ui_large;
U8 ucdq_ui_small_reg_value, u1UpdateRegUI; // for UI and TXDLY change check, if different , set reg.
U8 ucdq_reg_pi[DQS_NUMBER], ucdq_reg_ui_large[DQS_NUMBER], ucdq_reg_ui_small[DQS_NUMBER];
U8 ucdq_reg_oen_ui_large[DQS_NUMBER], ucdq_reg_oen_ui_small[DQS_NUMBER];
U8 ucdq_reg_dqm_pi[DQS_NUMBER] = {0}, ucdq_reg_dqm_ui_large[DQS_NUMBER] = {0}, ucdq_reg_dqm_ui_small[DQS_NUMBER] = {0};
U8 ucdq_reg_dqm_oen_ui_large[DQS_NUMBER] = {0}, ucdq_reg_dqm_oen_ui_small[DQS_NUMBER] = {0};
#if 1//TX_DQM_CALC_MAX_MIN_CENTER
U16 u2DQM_Delay; // LP4 only
U16 u2Center_min[DQS_NUMBER] = {0}, u2Center_max[DQS_NUMBER] = {0};
#endif
U8 u1EnableDelayCell = 0;
U16 u2DelayCellOfst[DQ_DATA_WIDTH] = {0};
U32 u4err_value, u4fail_bit;
U16 u2FinalRange = 0, u2FinalVref;
U16 u2VrefLevel, u2VrefBegin = 0, u2VrefEnd = 0, u2VrefStep;
U16 u2TempWinSum, u2MaxWindowSum = 0;//, u2tx_window_sum[LP4_TX_VREF_DATA_NUM]={0};
U8 u1min_bit, u1min_winsize = 0;
U8 u1VrefIdx = 0;
U8 u1PIDiff;
PASS_WIN_DATA_BY_VREF_T VrefInfo[LP4_TX_VREF_DATA_NUM];
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
#if TX_AUTO_K_ENABLE
U8 u1PI_Len, u1dq_shift;
U32 PwMaxInitReg[4] = {DRAMC_REG_TX_ATK_RESULT0, DRAMC_REG_TX_ATK_RESULT1, DRAMC_REG_TX_ATK_RESULT2, DRAMC_REG_TX_ATK_RESULT3};
U32 PwMaxLenReg[4] = {DRAMC_REG_TX_ATK_RESULT4, DRAMC_REG_TX_ATK_RESULT5, DRAMC_REG_TX_ATK_RESULT6, DRAMC_REG_TX_ATK_RESULT7};
U32 u4Length = 0;
#if TX_AUTO_K_WORKAROUND
U8 u1backup_Rank = 0;
#endif
#if TX_AUTO_K_WORKAROUND
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0)),
};
#endif
#endif
#if VENDER_JV_LOG
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
vPrintCalibrationBasicInfo_ForJV(p);
#else
vPrintCalibrationBasicInfo(p);
#endif
backup_rank = u1GetRank(p);
TXPerbitCalibrationInit(p, calType);
TXScanRange_PI(p, calType, &u2DQDelayBegin, &u2DQDelayEnd);
TXScanRange_Vref(p, u1VrefScanEnable, &u2FinalRange, &u2VrefBegin, &u2VrefEnd, &u2VrefStep);
//default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_PERBIT, DRAM_FAIL);
if (isAutoK)
{
#if TX_AUTO_K_ENABLE
//CKEFixOnOff(p, p->rank, CKE_FIXON, CKE_WRITE_TO_ONE_CHANNEL); //Let CLK always on
//Set base address of TX MCK and UI
u1UpdateRegUI = 1;
uiDelay = u2DQDelayBegin;
u1PI_Len = 3;
TxWinTransferDelayToUIPI(p, uiDelay, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
for (u1ByteIdx = 0; u1ByteIdx < DQS_NUMBER; u1ByteIdx++)
{
if (u1UpdateRegUI)
{
ucdq_reg_ui_large[u1ByteIdx] = ucdq_ui_large;
ucdq_reg_ui_small[u1ByteIdx] = ucdq_ui_small;
ucdq_reg_oen_ui_large[u1ByteIdx] = ucdq_oen_ui_large;
ucdq_reg_oen_ui_small[u1ByteIdx] = ucdq_oen_ui_small;
ucdq_reg_dqm_ui_large[u1ByteIdx] = ucdq_ui_large;
ucdq_reg_dqm_ui_small[u1ByteIdx] = ucdq_ui_small;
ucdq_reg_dqm_oen_ui_large[u1ByteIdx] = ucdq_oen_ui_large;
ucdq_reg_dqm_oen_ui_small[u1ByteIdx] = ucdq_oen_ui_small;
}
ucdq_reg_pi[u1ByteIdx] = ucdq_pi;
ucdq_reg_dqm_pi[u1ByteIdx] = ucdq_pi;
}
#if TX_AUTO_K_WORKAROUND
if (p->rank == 1)
{
u1backup_Rank = 1;
p->rank = 0;
DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
}
#endif
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
TXSetDelayReg_DQ(p, u1UpdateRegUI, ucdq_reg_ui_large, ucdq_reg_oen_ui_large, ucdq_reg_ui_small, ucdq_reg_oen_ui_small, ucdq_reg_pi);
mcSHOW_DBG_MSG(("TX Auto-K set begin delay DQ MCK: %d, UI: %d, PI: %d\n", ucdq_reg_ui_large[0], ucdq_reg_ui_small[0], ucdq_reg_pi[0]));
#if TX_AUTO_K_WORKAROUND
if ((calType == TX_DQ_DQS_MOVE_DQ_ONLY) && (u1backup_Rank == 1))
Tx_Auto_K_DQM_Workaround(p); //Set best DLY value of RK1 DQM to RK0 DQM
#endif
}
if (calType == TX_DQ_DQS_MOVE_DQM_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
TXSetDelayReg_DQM(p, u1UpdateRegUI, ucdq_reg_dqm_ui_large, ucdq_reg_dqm_oen_ui_large, ucdq_reg_dqm_ui_small, ucdq_reg_dqm_oen_ui_small, ucdq_reg_dqm_pi);
mcSHOW_DBG_MSG(("TX Auto-K set begin delay DQM MCK: %d, UI: %d, PI: %d\n", ucdq_reg_dqm_ui_large[0], ucdq_reg_dqm_ui_small[0], ucdq_reg_dqm_pi[0]));
#if TX_AUTO_K_WORKAROUND
if ((calType == TX_DQ_DQS_MOVE_DQM_ONLY) && (u1backup_Rank == 1))
Tx_Auto_K_DQ_Workaround(p); //Set best DLY value of RK1 DQ to RK0 DQ
#endif
}
#if TX_AUTO_K_WORKAROUND
if (u1backup_Rank == 1)
p->rank = 1;
#endif
//Tx_Auto_K_Init(p, calType, ucdq_pi, u1PI_Len); //u1PI_Len = 1 means that PI len is 64 PI
#endif
}
else
{
if (vGet_DDR_Loop_Mode(p) == SEMI_OPEN_LOOP_MODE)
u2DQDelayStep = (1 << 3);
else if (vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE)
u2DQDelayStep = (1 << 4);
else if (calType == TX_DQ_DQS_MOVE_DQ_DQM)
u2DQDelayStep = 2;
else
u2DQDelayStep = 1;
if (is_lp5_family(p))
u2DQDelayStep = 4; /* To speed up simulation */
#if (FOR_DV_SIMULATION_USED == 1)
u2DQDelayStep = (vGet_DDR_Loop_Mode(p) == OPEN_LOOP_MODE) ? 16 : 8;
#endif
}
#if 0
mcSHOW_DBG_MSG(("[TxWindowPerbitCal] calType=%d, VrefScanEnable %d (Range %d, VrefBegin %d, u2VrefEnd %d)\n"
"\nBegin, DQ Scan Range %d~%d\n",
calType, u1VrefScanEnable, u2FinalRange, u2VrefBegin, u2VrefEnd, u2DQDelayBegin, u2DQDelayEnd));
#endif
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
if (p->femmc_Ready == 1 && (p->Bypass_TXWINDOW))
{
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
u2Center_min[u1ByteIdx] = p->pSavetimeData->u1TxCenter_min_Save[p->channel][p->rank][u1ByteIdx];
u2Center_max[u1ByteIdx] = p->pSavetimeData->u1TxCenter_max_Save[p->channel][p->rank][u1ByteIdx];
for (u1BitIdx = 0; u1BitIdx < DQS_BIT_NUMBER; u1BitIdx++)
{
u1BitTemp = u1ByteIdx * DQS_BIT_NUMBER + u1BitIdx;
FinalWinPerBit[u1BitTemp].win_center = p->pSavetimeData->u1Txwin_center_Save[p->channel][p->rank][u1BitTemp];
}
}
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_PERBIT, DRAM_FAST_K);
}
else
#endif
{
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern | 0x80, 0, TE_UI_SHIFT);//UI_SHIFT + LEN1
#else
DramcEngine2Init(p, p->test2_1, p->test2_2, TEST_XTALK_PATTERN, 0, TE_NO_UI_SHIFT);
#endif
for (u2VrefLevel = u2VrefBegin; u2VrefLevel <= u2VrefEnd; u2VrefLevel += u2VrefStep)
{
// SET tx Vref (DQ) here, LP3 no need to set this.
if (u1VrefScanEnable)
{
#if (!REDUCE_LOG_FOR_PRELOADER)
mcSHOW_DBG_MSG(("\n\n\tLP4 TX VrefRange %d, VrefLevel=%d\n", u2FinalRange, u2VrefLevel));
#endif
#if VENDER_JV_LOG
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
mcSHOW_DBG_MSG5(("\n\tLP4 TX VrefRange %d, VrefLevel=%d\n", u2FinalRange, u2VrefLevel));
}
#endif
DramcTXSetVref(p, u2FinalRange, u2VrefLevel);
}
else
{
mcSHOW_DBG_MSG(("\n\n\tTX Vref Scan disable\n"));
}
// initialize parameters
uiFinishCount = 0;
u2TempWinSum = 0;
ucdq_ui_small_reg_value = 0xff;
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
WinPerBit[u1BitIdx].first_pass = (S16)PASS_RANGE_NA;
WinPerBit[u1BitIdx].last_pass = (S16)PASS_RANGE_NA;
VrefWinPerBit[u1BitIdx].first_pass = (S16)PASS_RANGE_NA;
VrefWinPerBit[u1BitIdx].last_pass = (S16)PASS_RANGE_NA;
}
if (isAutoK)
{
#if TX_AUTO_K_ENABLE
Tx_Auto_K_Init(p, calType, ucdq_pi, u1PI_Len); //u1PI_Len = 1 means that PI len is 64 PI
vIO32WriteFldAlign(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET1), 0x1, TX_ATK_SET1_TX_ATK_TRIG); //TX Auto K start
#endif
}
else
{
//Move DQ delay , 1 PI = tCK/64, total 128 PI, 1UI = 32 PI
//For data rate 3200, max tDQS2DQ is 2.56UI (82 PI)
//For data rate 4266, max tDQS2DQ is 3.41UI (109 PI)
for (uiDelay = u2DQDelayBegin; uiDelay < u2DQDelayEnd; uiDelay += u2DQDelayStep)
{
TxWinTransferDelayToUIPI(p, uiDelay, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
// Check if TX UI changed, if not change , don't need to set reg again
if (ucdq_ui_small_reg_value != ucdq_ui_small)
{
u1UpdateRegUI = 1;
ucdq_ui_small_reg_value = ucdq_ui_small;
}
else
u1UpdateRegUI = 0;
for (u1ByteIdx = 0; u1ByteIdx < DQS_NUMBER; u1ByteIdx++)
{
if (u1UpdateRegUI)
{
ucdq_reg_ui_large[u1ByteIdx] = ucdq_ui_large;
ucdq_reg_ui_small[u1ByteIdx] = ucdq_ui_small;
ucdq_reg_oen_ui_large[u1ByteIdx] = ucdq_oen_ui_large;
ucdq_reg_oen_ui_small[u1ByteIdx] = ucdq_oen_ui_small;
ucdq_reg_dqm_ui_large[u1ByteIdx] = ucdq_ui_large;
ucdq_reg_dqm_ui_small[u1ByteIdx] = ucdq_ui_small;
ucdq_reg_dqm_oen_ui_large[u1ByteIdx] = ucdq_oen_ui_large;
ucdq_reg_dqm_oen_ui_small[u1ByteIdx] = ucdq_oen_ui_small;
}
ucdq_reg_pi[u1ByteIdx] = ucdq_pi;
ucdq_reg_dqm_pi[u1ByteIdx] = ucdq_pi;
}
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
TXSetDelayReg_DQ(p, u1UpdateRegUI, ucdq_reg_ui_large, ucdq_reg_oen_ui_large, ucdq_reg_ui_small, ucdq_reg_oen_ui_small, ucdq_reg_pi);
}
if (calType == TX_DQ_DQS_MOVE_DQM_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
TXSetDelayReg_DQM(p, u1UpdateRegUI, ucdq_reg_dqm_ui_large, ucdq_reg_dqm_oen_ui_large, ucdq_reg_dqm_ui_small, ucdq_reg_dqm_oen_ui_small, ucdq_reg_dqm_pi);
}
u4err_value = 0;
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
//DramcEngine2SetPat(p, p->test_pattern, 0, 0, TE_UI_SHIFT);
u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, p->test_pattern);
#else
//audio + xtalk pattern
DramcEngine2SetPat(p, TEST_AUDIO_PATTERN, 0, 0, TE_NO_UI_SHIFT);
u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN);
DramcEngine2SetPat(p, TEST_XTALK_PATTERN, 0, 1, TE_NO_UI_SHIFT);
u4err_value |= DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN);
#endif
//audio + xtalk pattern
//u4err_value = 0;
//DramcEngine2SetPat(p, TEST_AUDIO_PATTERN, 0, 0);
//u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN);
//DramcEngine2SetPat(p, TEST_XTALK_PATTERN, 0, 1);
//u4err_value |= DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN);
if (u1VrefScanEnable == 0 && (calType != TX_DQ_DQS_MOVE_DQM_ONLY))
{
//mcSHOW_DBG_MSG(("Delay=%3d |%2d %2d %3d| %2d %2d| 0x%8x [0]",uiDelay, ucdq_ui_large,ucdq_ui_small, ucdq_pi, ucdq_oen_ui_large,ucdq_oen_ui_small, u4err_value));
#ifdef ETT_PRINT_FORMAT
if (u4err_value != 0)
{
mcSHOW_DBG_MSG2(("%d |%d %d %d|[0]", uiDelay, ucdq_ui_large, ucdq_ui_small, ucdq_pi));
}
#else
mcSHOW_DBG_MSG2(("Delay=%3d |%2d %2d %3d| 0x%8x [0]", uiDelay, ucdq_ui_large, ucdq_ui_small, ucdq_pi, u4err_value));
#endif
}
// check fail bit ,0 ok ,others fail
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
u4fail_bit = u4err_value & ((U32)1 << u1BitIdx);
if (u1VrefScanEnable == 0 && (calType != TX_DQ_DQS_MOVE_DQM_ONLY))
{
if(u4err_value != 0)
{
if (u1BitIdx % DQS_BIT_NUMBER == 0)
{
mcSHOW_DBG_MSG2((" "));
}
if (u4fail_bit == 0)
{
mcSHOW_DBG_MSG2(("o"));
}
else
{
mcSHOW_DBG_MSG2(("x"));
}
}
}
if (WinPerBit[u1BitIdx].first_pass == PASS_RANGE_NA)
{
if (u4fail_bit == 0) //compare correct: pass
{
WinPerBit[u1BitIdx].first_pass = uiDelay;
#if TX_TDQS2DQ_PRE_CAL
if ((u1IsLP4Div4DDR800(p) == FALSE) && (calType == TX_DQ_DQS_MOVE_DQ_ONLY) && (u1VrefScanEnable == FALSE))
{
if (u2DQS2DQ_Pre_Cal[p->channel][p->rank][vGet_Div_Mode(p)] == 0)
{
u2DQS2DQ_Pre_Cal[p->channel][p->rank][vGet_Div_Mode(p)] = ((uiDelay - u2DQDelayBegin)* 1000) / p->frequency;
}
if (uiDelay == u2DQDelayBegin)
{
mcSHOW_ERR_MSG(("TX_TDQS2DQ_PRE_CAL: Warning, possible miss TX window boundary\n"));
#if __ETT__
while (1);
#endif
}
}
#endif
}
}
else if (WinPerBit[u1BitIdx].last_pass == PASS_RANGE_NA)
{
if (u4fail_bit != 0) //compare error : fail
{
WinPerBit[u1BitIdx].last_pass = uiDelay - u2DQDelayStep;
}
else if (uiDelay > (u2DQDelayEnd - u2DQDelayStep))
{
WinPerBit[u1BitIdx].last_pass = uiDelay;
}
if (WinPerBit[u1BitIdx].last_pass != PASS_RANGE_NA)
{
if ((WinPerBit[u1BitIdx].last_pass - WinPerBit[u1BitIdx].first_pass) >= (VrefWinPerBit[u1BitIdx].last_pass - VrefWinPerBit[u1BitIdx].first_pass))
{
if ((VrefWinPerBit[u1BitIdx].last_pass != PASS_RANGE_NA) && (VrefWinPerBit[u1BitIdx].last_pass - VrefWinPerBit[u1BitIdx].first_pass) > 0)
{
mcSHOW_DBG_MSG2(("Bit[%d] Bigger window update %d > %d, window broken?\n", u1BitIdx, \
(WinPerBit[u1BitIdx].last_pass - WinPerBit[u1BitIdx].first_pass), (VrefWinPerBit[u1BitIdx].last_pass - VrefWinPerBit[u1BitIdx].first_pass)));
}
//if window size bigger than TX_PASS_WIN_CRITERIA, consider as real pass window. If not, don't update finish counte and won't do early break;
if ((WinPerBit[u1BitIdx].last_pass - WinPerBit[u1BitIdx].first_pass) > TX_PASS_WIN_CRITERIA)
uiFinishCount |= (1 << u1BitIdx);
//update bigger window size
VrefWinPerBit[u1BitIdx].first_pass = WinPerBit[u1BitIdx].first_pass;
VrefWinPerBit[u1BitIdx].last_pass = WinPerBit[u1BitIdx].last_pass;
}
//reset tmp window
WinPerBit[u1BitIdx].first_pass = PASS_RANGE_NA;
WinPerBit[u1BitIdx].last_pass = PASS_RANGE_NA;
}
}
}
if(u1VrefScanEnable==0 && (calType != TX_DQ_DQS_MOVE_DQM_ONLY))
{
if(u4err_value != 0)
{
mcSHOW_DBG_MSG2((" [MSB]\n"));
}
}
//if all bits widnow found and all bits turns to fail again, early break;
if (uiFinishCount == 0xffff)
{
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_PERBIT, DRAM_OK);
#if !REDUCE_LOG_FOR_PRELOADER
#ifdef ETT_PRINT_FORMAT
mcSHOW_DBG_MSG2(("TX calibration finding left boundary early break. PI DQ delay=0x%B\n", uiDelay));
#else
mcSHOW_DBG_MSG2(("TX calibration finding left boundary early break. PI DQ delay=0x%2x\n", uiDelay));
#endif
#endif
break; //early break
}
}
}
if (isAutoK)
{
#if TX_AUTO_K_ENABLE
Tx_Auto_K_complete_check(p);
#if TX_AUTO_K_DEBUG_ENABLE
Tx_Auto_K_Debug_Message(p, u1PI_Len);
#endif
#endif
}
// (1) calculate per bit window size
// (2) find out min win of all DQ bits
// (3) calculate perbit window center
u1min_winsize = 0xff;
u1min_bit = 0xff;
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
if (isAutoK)
{
#if TX_AUTO_K_ENABLE
u1dq_shift = ((u1BitIdx % 4) * 8);
VrefWinPerBit[u1BitIdx].first_pass = u2DQDelayBegin - ucdq_pi + ((u4IO32Read4B(DRAMC_REG_ADDR(PwMaxInitReg[u1BitIdx / 4])) & (0xff << u1dq_shift)) >> u1dq_shift);
VrefWinPerBit[u1BitIdx].last_pass = ((u4IO32Read4B(DRAMC_REG_ADDR(PwMaxLenReg[u1BitIdx / 4])) & (0xff << u1dq_shift)) >> u1dq_shift) + VrefWinPerBit[u1BitIdx].first_pass;
VrefWinPerBit[u1BitIdx].win_size = ((u4IO32Read4B(DRAMC_REG_ADDR(PwMaxLenReg[u1BitIdx / 4])) & (0xff << u1dq_shift)) >> u1dq_shift);
if (u1PI_Len == 0)
u4Length = 48;
else
u4Length = 32 * (1 + u1PI_Len);
if ((VrefWinPerBit[u1BitIdx].first_pass == (int)(u2DQDelayBegin - ucdq_pi)) || (VrefWinPerBit[u1BitIdx].last_pass == (int)(u2DQDelayBegin + u4Length)))
{
mcSHOW_ERR_MSG(("Error! Probably miss pass window!\n"));
}
mcSHOW_DBG_MSG(("TX DQ bit %d, first pass: %d, last pass: %d\n", u1BitIdx, VrefWinPerBit[u1BitIdx].first_pass, VrefWinPerBit[u1BitIdx].last_pass));
#else
//if(VrefWinPerBit[u1BitIdx].last_pass == VrefWinPerBit[u1BitIdx].first_pass)
if (VrefWinPerBit[u1BitIdx].first_pass == PASS_RANGE_NA)
VrefWinPerBit[u1BitIdx].win_size = 0;
else
VrefWinPerBit[u1BitIdx].win_size = VrefWinPerBit[u1BitIdx].last_pass - VrefWinPerBit[u1BitIdx].first_pass + u2DQDelayStep;
#endif
}
else
{
if (VrefWinPerBit[u1BitIdx].first_pass == PASS_RANGE_NA)
VrefWinPerBit[u1BitIdx].win_size = 0;
else
VrefWinPerBit[u1BitIdx].win_size = VrefWinPerBit[u1BitIdx].last_pass - VrefWinPerBit[u1BitIdx].first_pass + u2DQDelayStep;
}
if (VrefWinPerBit[u1BitIdx].win_size < u1min_winsize)
{
u1min_bit = u1BitIdx;
u1min_winsize = VrefWinPerBit[u1BitIdx].win_size;
}
u2TempWinSum += VrefWinPerBit[u1BitIdx].win_size; //Sum of CA Windows for vref selection
#if VENDER_JV_LOG
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
mcSHOW_DBG_MSG5(("TX Bit%d, %d%%\n", u1BitIdx, (VrefWinPerBit[u1BitIdx].win_size * 100 + 31) / 32));
}
#endif
// calculate per bit window position and print
VrefWinPerBit[u1BitIdx].win_center = (VrefWinPerBit[u1BitIdx].first_pass + VrefWinPerBit[u1BitIdx].last_pass) >> 1;
#if PINMUX_AUTO_TEST_PER_BIT_TX
gFinalTXPerbitFirstPass[p->channel][u1BitIdx] = VrefWinPerBit[u1BitIdx].first_pass;
#endif
}
#if __ETT__
if (u1VrefScanEnable == 0)
{
//mcSHOW_DBG_MSG(("\n\tCH=%d, VrefRange= %d, VrefLevel = %d\n", p->channel, u2FinalRange, u2VrefLevel));
TxPrintWidnowInfo(p, VrefWinPerBit);
}
#endif
if (u1VrefScanEnable == 1)
{
if (u2TempWinSum > u2MaxWindowSum)
u2MaxWindowSum = u2TempWinSum;
VrefInfo[u1VrefIdx].u2VrefUsed = u2VrefLevel;
VrefInfo[u1VrefIdx].u1WorseBitWinSize_byVref = u1min_winsize;
VrefInfo[u1VrefIdx].u1WorseBitIdx_byVref = u1min_bit;
VrefInfo[u1VrefIdx].u2WinSum_byVref = u2TempWinSum;
u1VrefIdx ++;
}
#if TX_AUTO_K_ENABLE
if (isAutoK)
Tx_Auto_K_Clear(p);
#endif
#if LP4_TX_VREF_PASS_CONDITION
if (u1VrefScanEnable && (u2TempWinSum < (u2MaxWindowSum * 95 / 100)) && (u1min_winsize < LP4_TX_VREF_PASS_CONDITION))
#else
if (u1VrefScanEnable && (u2TempWinSum < (u2MaxWindowSum * 95 / 100)) && (u1min_winsize > TX_PASS_WIN_CRITERIA))
#endif
{
mcSHOW_DBG_MSG(("\nTX Vref early break, caculate TX vref\n"));
break;
}
#if TX_AUTO_K_ENABLE
Tx_Auto_K_Clear(p);
#endif
}
DramcEngine2End(p);
#if (TX_AUTO_K_ENABLE && TX_AUTO_K_WORKAROUND)
if ((isAutoK) && (p->rank == RANK_1))
{
vSetRank(p, RANK_0);
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
vSetRank(p, backup_rank);
}
#endif
if (u1VrefScanEnable == 0)// ..if time domain (not vref scan) , calculate window center of all bits.
{
// Calculate the center of DQ pass window
// Record center sum of each byte
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
#if 1//TX_DQM_CALC_MAX_MIN_CENTER
u2Center_min[u1ByteIdx] = 0xffff;
u2Center_max[u1ByteIdx] = 0;
#endif
for (u1BitIdx = 0; u1BitIdx < DQS_BIT_NUMBER; u1BitIdx++)
{
u1BitTemp = u1ByteIdx * DQS_BIT_NUMBER + u1BitIdx;
memcpy(FinalWinPerBit, VrefWinPerBit, sizeof(PASS_WIN_DATA_T) * DQ_DATA_WIDTH);
if (FinalWinPerBit[u1BitTemp].win_center < u2Center_min[u1ByteIdx])
u2Center_min[u1ByteIdx] = FinalWinPerBit[u1BitTemp].win_center;
if (FinalWinPerBit[u1BitTemp].win_center > u2Center_max[u1ByteIdx])
u2Center_max[u1ByteIdx] = FinalWinPerBit[u1BitTemp].win_center;
#ifdef FOR_HQA_TEST_USED
if ((calType == TX_DQ_DQS_MOVE_DQ_ONLY) && (u1VrefScanEnable == 0))
{
gFinalTXPerbitWin[p->channel][p->rank][u1BitTemp] = FinalWinPerBit[u1BitTemp].win_size;
}
#endif
}
}
}
}
// SET tx Vref (DQ) = u2FinalVref, LP3 no need to set this.
if (u1VrefScanEnable)
{
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION && BYPASS_VREF_CAL
if (p->femmc_Ready == 1 && (p->Bypass_TXWINDOW))
{
u2FinalVref = p->pSavetimeData->u1TxWindowPerbitVref_Save[p->channel][p->rank];
}
else
#endif
{
u2FinalVref = TxChooseVref(p, VrefInfo, u1VrefIdx);
}
TXSetFinalVref(p, u2FinalRange, u2FinalVref);
return DRAM_OK;
}
#ifdef FOR_HQA_TEST_USED
// LP4 DQ time domain || LP3 DQ_DQM time domain
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
gFinalTXPerbitWin_min_max[p->channel][p->rank] = u1min_winsize;
if(u1min_winsize<16)
{
mcSHOW_ERR_MSG(("[WARNING] Smaller TX win !!\n"));
#if CHECK_HQA_CRITERIA
while(1);
#endif
}
}
#endif
// LP3 only use "TX_DQ_DQS_MOVE_DQ_DQM" scan
// first freq 800(LP4-1600) doesn't support jitter meter(data < 1T), therefore, don't use delay cell
if ((calType == TX_DQ_DQS_MOVE_DQ_ONLY) && (p->frequency >= 1333) && (p->u2DelayCellTimex100 != 0))
{
u1EnableDelayCell = 1;
mcSHOW_DBG_MSG(("[TX_PER_BIT_DELAY_CELL] DelayCellTimex100 =%d/100 ps\n", p->u2DelayCellTimex100));
}
//Calculate the center of DQ pass window
//average the center delay
for (u1ByteIdx = 0; u1ByteIdx < (p->data_width / DQS_BIT_NUMBER); u1ByteIdx++)
{
mcSHOW_DBG_MSG((" == TX Byte %d ==\n", u1ByteIdx));
u2DQM_Delay = ((u2Center_min[u1ByteIdx] + u2Center_max[u1ByteIdx]) >> 1); //(max +min)/2
if (u1EnableDelayCell == 0)
{
uiDelay = u2DQM_Delay;
}
else// if(calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
uiDelay = u2Center_min[u1ByteIdx]; // for DQ PI delay , will adjust with delay cell
// calculate delay cell perbit
for (u1BitIdx = 0; u1BitIdx < DQS_BIT_NUMBER; u1BitIdx++)
{
u1BitTemp = u1ByteIdx * DQS_BIT_NUMBER + u1BitIdx;
u1PIDiff = FinalWinPerBit[u1BitTemp].win_center - u2Center_min[u1ByteIdx];
if (p->u2DelayCellTimex100 != 0)
{
u2DelayCellOfst[u1BitTemp] = (u1PIDiff * 100000000 / (p->frequency << 6)) / p->u2DelayCellTimex100;
mcSHOW_DBG_MSG(("u2DelayCellOfst[%d]=%d cells (%d PI)\n", u1BitTemp, u2DelayCellOfst[u1BitTemp], u1PIDiff));
if(u2DelayCellOfst[u1BitTemp]>255)
{
mcSHOW_DBG_MSG(("[WARNING] TX DQ%d delay cell %d >255, adjust to 255 cell\n", u1BitIdx, u2DelayCellOfst[u1BitTemp]));
u2DelayCellOfst[u1BitTemp] =255;
}
}
else
{
mcSHOW_ERR_MSG(("Error: Cell time (p->u2DelayCellTimex100) is 0 \n"));
break;
}
}
}
TxWinTransferDelayToUIPI(p, uiDelay, 1, &ucdq_reg_ui_large[u1ByteIdx], &ucdq_reg_ui_small[u1ByteIdx], &ucdq_reg_pi[u1ByteIdx], \
&ucdq_reg_oen_ui_large[u1ByteIdx], &ucdq_reg_oen_ui_small[u1ByteIdx]);
TxWinTransferDelayToUIPI(p, u2DQM_Delay, 1, &ucdq_reg_dqm_ui_large[u1ByteIdx], &ucdq_reg_dqm_ui_small[u1ByteIdx], &ucdq_reg_dqm_pi[u1ByteIdx], \
&ucdq_reg_dqm_oen_ui_large[u1ByteIdx], &ucdq_reg_dqm_oen_ui_small[u1ByteIdx]);
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
mcSHOW_DBG_MSG(("Update DQ dly =%d (%d ,%d, %d) DQ OEN =(%d ,%d)\n",
uiDelay, ucdq_reg_ui_large[u1ByteIdx], ucdq_reg_ui_small[u1ByteIdx], ucdq_reg_pi[u1ByteIdx], \
ucdq_reg_oen_ui_large[u1ByteIdx], ucdq_reg_oen_ui_small[u1ByteIdx]));
}
//if(calType ==TX_DQ_DQS_MOVE_DQM_ONLY || calType== TX_DQ_DQS_MOVE_DQ_DQM)
{
mcSHOW_DBG_MSG(("Update DQM dly =%d (%d ,%d, %d) DQM OEN =(%d ,%d)",
u2DQM_Delay, ucdq_reg_dqm_ui_large[u1ByteIdx], ucdq_reg_dqm_ui_small[u1ByteIdx], ucdq_reg_dqm_pi[u1ByteIdx], \
ucdq_reg_dqm_oen_ui_large[u1ByteIdx], ucdq_reg_dqm_oen_ui_small[u1ByteIdx]));
}
mcSHOW_DBG_MSG(("\n"));
#ifdef FOR_HQA_REPORT_USED
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY)
{
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT1, "TX_Window_Center_", "DQ", u1BitIdx, FinalWinPerBit[u1BitIdx].win_center, NULL);
}
}
if (calType == TX_DQ_DQS_MOVE_DQM_ONLY)
{
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0, "TX_Window_Center_", "DQM", u1ByteIdx, u2DQM_Delay, NULL);
}
#if 0
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT1, "TX_Window_Center_", "LargeUI", u1ByteIdx, ucdq_reg_ui_large[u1ByteIdx], NULL);
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0, "TX_Window_Center_", "SmallUI", u1ByteIdx, ucdq_reg_ui_small[u1ByteIdx], NULL);
HQA_Log_Message_for_Report(p, p->channel, p->rank, HQA_REPORT_FORMAT0, "TX_Window_Center_", "PI", u1ByteIdx, ucdq_reg_pi[u1ByteIdx], NULL);
#endif
#endif
}
#if REG_ACCESS_PORTING_DGB
RegLogEnable = 1;
#endif
/* p->rank = RANK_0, save to Reg Rank0 and Rank1, p->rank = RANK_1, save to Reg Rank1 */
for (u1RankIdx = p->rank; u1RankIdx < RANK_MAX; u1RankIdx++)
{
vSetRank(p, u1RankIdx);
if (calType == TX_DQ_DQS_MOVE_DQ_ONLY || calType == TX_DQ_DQS_MOVE_DQ_DQM)
{
TXSetDelayReg_DQ(p, TRUE, ucdq_reg_ui_large, ucdq_reg_oen_ui_large, ucdq_reg_ui_small, ucdq_reg_oen_ui_small, ucdq_reg_pi);
}
TXSetDelayReg_DQM(p, TRUE, ucdq_reg_dqm_ui_large, ucdq_reg_dqm_oen_ui_large, ucdq_reg_dqm_ui_small, ucdq_reg_dqm_oen_ui_small, ucdq_reg_dqm_pi);
if (u1EnableDelayCell)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY0),
P_Fld(u2DelayCellOfst[3], SHU_R0_B0_TXDLY0_TX_ARDQ3_DLY_B0)
| P_Fld(u2DelayCellOfst[2], SHU_R0_B0_TXDLY0_TX_ARDQ2_DLY_B0)
| P_Fld(u2DelayCellOfst[1], SHU_R0_B0_TXDLY0_TX_ARDQ1_DLY_B0)
| P_Fld(u2DelayCellOfst[0], SHU_R0_B0_TXDLY0_TX_ARDQ0_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_TXDLY1),
P_Fld(u2DelayCellOfst[7], SHU_R0_B0_TXDLY1_TX_ARDQ7_DLY_B0)
| P_Fld(u2DelayCellOfst[6], SHU_R0_B0_TXDLY1_TX_ARDQ6_DLY_B0)
| P_Fld(u2DelayCellOfst[5], SHU_R0_B0_TXDLY1_TX_ARDQ5_DLY_B0)
| P_Fld(u2DelayCellOfst[4], SHU_R0_B0_TXDLY1_TX_ARDQ4_DLY_B0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY0),
P_Fld(u2DelayCellOfst[11], SHU_R0_B1_TXDLY0_TX_ARDQ3_DLY_B1)
| P_Fld(u2DelayCellOfst[10], SHU_R0_B1_TXDLY0_TX_ARDQ2_DLY_B1)
| P_Fld(u2DelayCellOfst[9], SHU_R0_B1_TXDLY0_TX_ARDQ1_DLY_B1)
| P_Fld(u2DelayCellOfst[8], SHU_R0_B1_TXDLY0_TX_ARDQ0_DLY_B1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_TXDLY1),
P_Fld(u2DelayCellOfst[15], SHU_R0_B1_TXDLY1_TX_ARDQ7_DLY_B1)
| P_Fld(u2DelayCellOfst[14], SHU_R0_B1_TXDLY1_TX_ARDQ6_DLY_B1)
| P_Fld(u2DelayCellOfst[13], SHU_R0_B1_TXDLY1_TX_ARDQ5_DLY_B1)
| P_Fld(u2DelayCellOfst[12], SHU_R0_B1_TXDLY1_TX_ARDQ4_DLY_B1));
}
#if ENABLE_TX_TRACKING
TXUpdateTXTracking(p, calType, ucdq_reg_pi, ucdq_reg_dqm_pi);
#endif
}
vSetRank(p, backup_rank);
if (isAutoK)
{
#if TX_AUTO_K_ENABLE
#if TX_AUTO_K_WORKAROUND
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_TX_ATK_SET0),
P_Fld(ucdq_reg_pi[0], TX_ATK_SET0_TX_ATK_DQ_B0_PI_INIT) |
P_Fld(ucdq_reg_pi[1], TX_ATK_SET0_TX_ATK_DQ_B1_PI_INIT) |
P_Fld(ucdq_reg_dqm_pi[0], TX_ATK_SET0_TX_ATK_DQM_B0_PI_INIT) |
P_Fld(ucdq_reg_dqm_pi[1], TX_ATK_SET0_TX_ATK_DQM_B1_PI_INIT)); //If TX auto-k is enable, TX_PI will be switch to PI_INIT
#endif
#endif
}
#if REG_ACCESS_PORTING_DGB
RegLogEnable = 0;
#endif
#if (TX_AUTO_K_ENABLE && TX_AUTO_K_WORKAROUND)
if ((isAutoK) && (p->rank == RANK_1) && (calType == TX_DQ_DQS_MOVE_DQ_DQM))
{
u4DQM_MCK_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1));
u4DQM_UI_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3));
u4DQM_PI_RK1_backup[0] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0));
u4DQM_PI_RK1_backup[1] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0));
u4DQ_MCK_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0));
u4DQ_UI_RK1_backup = u4IO32Read4B(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2));
u4DQ_PI_RK1_backup[0] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0));
u4DQ_PI_RK1_backup[1] = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0));
}
#endif
mcSHOW_DBG_MSG3(("[TxWindowPerbitCal] Done\n\n"));
#if 0
vIO32WriteFldAlign_All(DRAMC_REG_ADDR(DRAMC_REG_PADCTL4), 1, PADCTL4_CKEFIXON); // test only
#endif
return DRAM_OK;
}
#endif //SIMULATION_TX_PERBIT
#if ENABLE_EYESCAN_GRAPH
void Dramc_K_TX_EyeScan_Log(DRAMC_CTX_T *p)
{
U8 ucindex, u1BitIdx, u1ByteIdx;
U8 ii, backup_rank, u1PrintWinData, u1vrefidx;
PASS_WIN_DATA_T WinPerBit[DQ_DATA_WIDTH], VrefWinPerBit[DQ_DATA_WIDTH], FinalWinPerBit[DQ_DATA_WIDTH];
U16 tx_pi_delay[4], tx_dqm_pi_delay[4];
U16 u2DQDelayBegin, uiDelay;
U16 u2VrefLevel, u2VrefBegin, u2VrefEnd, u2VrefStep, u2VrefRange;
U8 ucdq_pi, ucdq_ui_small, ucdq_ui_large,ucdq_oen_ui_small, ucdq_oen_ui_large;
U32 uiFinishCount;
U16 u2TempWinSum, u2tx_window_sum=0;
U32 u4err_value, u4fail_bit;
#if 1//TX_DQM_CALC_MAX_MIN_CENTER
U16 u2Center_min[DQS_NUMBER],u2Center_max[DQS_NUMBER];
#endif
U16 TXPerbitWin_min_max = 0;
U32 min_bit, min_winsize;
U16 u2FinalVref=0xd;
U16 u2FinalRange=0;
U8 EyeScan_index[DQ_DATA_WIDTH];
U16 backup_u1MR14Value;
U8 u1pass_in_this_vref_flag[DQ_DATA_WIDTH];
U8 u1MCK2UI, u1UI2PI;
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1)),
(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0)),
};
if (GetEyeScanEnable(p, 2)==DISABLE) return;
//if (gTX_EYE_Scan_only_higheset_freq_flag==1 && p->frequency != u2DFSGetHighestFreq(p)) return;
//backup register value
DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress)/sizeof(U32));
backup_u1MR14Value = u1MR14Value[p->channel][p->rank][p->dram_fsp];
//Jimmy Temp
DramcModeRegReadByRank(p, p->rank, 14, &backup_u1MR14Value);
if (gFinalTXVrefDQ[p->channel][p->rank] ==0) //Set final TX Vref as default value
gFinalTXVrefDQ[p->channel][p->rank] = u1MR14Value[p->channel][p->rank][p->dram_fsp];
//set initial values
for(u1vrefidx=0; u1vrefidx<=VREF_VOLTAGE_TABLE_NUM_LP5-1;u1vrefidx++)
{
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
for(ii=0; ii<EYESCAN_BROKEN_NUM; ii++)
{
gEyeScan_Min[u1vrefidx][u1BitIdx][ii] = EYESCAN_DATA_INVALID;
gEyeScan_Max[u1vrefidx][u1BitIdx][ii] = EYESCAN_DATA_INVALID;
}
gEyeScan_ContinueVrefHeight[u1BitIdx] = 0;
gEyeScan_TotalPassCount[u1BitIdx] = 0;
}
}
u1MCK2UI = u1MCK2UI_DivShift(p);
//if (vGet_DDR800_Mode(p) == DDR800_CLOSE_LOOP)
// u1UI2PI = 6;
//else
u1UI2PI = 5;
for(u1ByteIdx=0; u1ByteIdx < p->data_width/DQS_BIT_NUMBER; u1ByteIdx++)
{
if (u1ByteIdx == 0)
{
tx_pi_delay[u1ByteIdx] = (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), SHURK_SELPH_DQ0_TXDLY_DQ0)<<(u1MCK2UI+u1UI2PI)) +
(u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), SHURK_SELPH_DQ2_DLY_DQ0)<<u1UI2PI) +
u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), SHU_R0_B0_DQ0_SW_ARPI_DQ_B0)*(u1IsPhaseMode(p)==TRUE ? 8 : 1);
tx_dqm_pi_delay[u1ByteIdx] = (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), SHURK_SELPH_DQ1_TXDLY_DQM0)<<(u1MCK2UI+u1UI2PI)) +
(u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), SHURK_SELPH_DQ3_DLY_DQM0)<<u1UI2PI) +
u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), SHU_R0_B0_DQ0_SW_ARPI_DQM_B0)*(u1IsPhaseMode(p)==TRUE ? 8 : 1);
}
else
{
tx_pi_delay[u1ByteIdx] = (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), SHURK_SELPH_DQ0_TXDLY_DQ1)<<(u1MCK2UI+u1UI2PI)) +
(u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), SHURK_SELPH_DQ2_DLY_DQ1)<<u1UI2PI) +
u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), SHU_R0_B1_DQ0_SW_ARPI_DQ_B1)*(u1IsPhaseMode(p)==TRUE ? 8 : 1);
tx_dqm_pi_delay[u1ByteIdx] = (u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), SHURK_SELPH_DQ1_TXDLY_DQM1)<<(u1MCK2UI+u1UI2PI)) +
(u4IO32ReadFldAlign(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), SHURK_SELPH_DQ3_DLY_DQM1)<<u1UI2PI) +
u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), SHU_R0_B1_DQ0_SW_ARPI_DQM_B1)*(u1IsPhaseMode(p)==TRUE ? 8 : 1);
}
}
if (tx_pi_delay[0] < tx_pi_delay[1])
{
u2DQDelayBegin = tx_pi_delay[0]-32;
}
else
{
u2DQDelayBegin = tx_pi_delay[1]-32;
}
u2VrefRange = 0;
u2VrefBegin = 0;
u2VrefEnd = (p->dram_type==TYPE_LPDDR5?VREF_VOLTAGE_TABLE_NUM_LP5:VREF_VOLTAGE_TABLE_NUM_LP4)-1;
u2VrefStep = EYESCAN_GRAPH_CATX_VREF_STEP;
mcSHOW_DBG_MSG3(("\nTX Vref %d -> %d, step: %d\n", u2VrefBegin, u2VrefEnd, u2VrefStep));
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
DramcEngine2Init(p, p->test2_1, p->test2_2, p->test_pattern | 0x80, 0, TE_UI_SHIFT);//UI_SHIFT + LEN1
#else
DramcEngine2Init(p, p->test2_1, p->test2_2, TEST_XTALK_PATTERN, 0, TE_NO_UI_SHIFT);
#endif
for(u2VrefLevel = u2VrefBegin; u2VrefLevel <= u2VrefEnd; u2VrefLevel += u2VrefStep)
{
//set vref
//fra u1MR14Value[p->channel][p->rank][p->dram_fsp] = (u2VrefLevel | (u2VrefRange<<6));
DramcTXSetVref(p, u2VrefRange, u2VrefLevel);
mcSHOW_DBG_MSG3(("\n\n Set TX VrefRange %d, VrefLevel=%d\n", u2VrefRange, u2VrefLevel));
// initialize parameters
uiFinishCount = 0;
u2TempWinSum =0;
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
WinPerBit[u1BitIdx].first_pass = (S16)PASS_RANGE_NA;
WinPerBit[u1BitIdx].last_pass = (S16)PASS_RANGE_NA;
VrefWinPerBit[u1BitIdx].first_pass = (S16)PASS_RANGE_NA;
VrefWinPerBit[u1BitIdx].last_pass = (S16)PASS_RANGE_NA;
gEyeScan_DelayCellPI[u1BitIdx] = 0;
EyeScan_index[u1BitIdx] = 0;
u1pass_in_this_vref_flag[u1BitIdx] = 0;
}
for (uiDelay=0; uiDelay<64; uiDelay+=(u1IsPhaseMode(p)==TRUE ? 8 : 1))
{
TxWinTransferDelayToUIPI(p, tx_pi_delay[0]+uiDelay-32, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), \
P_Fld(ucdq_ui_large, SHURK_SELPH_DQ0_TXDLY_DQ0) | \
P_Fld(ucdq_oen_ui_large, SHURK_SELPH_DQ0_TXDLY_OEN_DQ0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), \
P_Fld(ucdq_ui_small, SHURK_SELPH_DQ2_DLY_DQ0) | \
P_Fld(ucdq_oen_ui_small, SHURK_SELPH_DQ2_DLY_OEN_DQ0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), ucdq_pi, SHU_R0_B0_DQ0_SW_ARPI_DQ_B0);
TxWinTransferDelayToUIPI(p, tx_pi_delay[1]+uiDelay-32, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), \
P_Fld(ucdq_ui_large, SHURK_SELPH_DQ0_TXDLY_DQ1) | \
P_Fld(ucdq_oen_ui_large, SHURK_SELPH_DQ0_TXDLY_OEN_DQ1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), \
P_Fld(ucdq_ui_small, SHURK_SELPH_DQ2_DLY_DQ1) | \
P_Fld(ucdq_oen_ui_small, SHURK_SELPH_DQ2_DLY_OEN_DQ1));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), ucdq_pi, SHU_R0_B1_DQ0_SW_ARPI_DQ_B1);
TxWinTransferDelayToUIPI(p, tx_dqm_pi_delay[0]+uiDelay-32, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), \
P_Fld(ucdq_ui_large, SHURK_SELPH_DQ1_TXDLY_DQM0) | \
P_Fld(ucdq_oen_ui_large, SHURK_SELPH_DQ1_TXDLY_OEN_DQM0));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), \
P_Fld(ucdq_ui_small, SHURK_SELPH_DQ3_DLY_DQM0) | \
P_Fld(ucdq_oen_ui_small, SHURK_SELPH_DQ3_DLY_OEN_DQM0));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B0_DQ0), ucdq_pi, SHU_R0_B0_DQ0_SW_ARPI_DQM_B0);
TxWinTransferDelayToUIPI(p, tx_dqm_pi_delay[1]+uiDelay-32, 0, &ucdq_ui_large, &ucdq_ui_small, &ucdq_pi, &ucdq_oen_ui_large, &ucdq_oen_ui_small);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), \
P_Fld(ucdq_ui_large, SHURK_SELPH_DQ1_TXDLY_DQM1) | \
P_Fld(ucdq_oen_ui_large, SHURK_SELPH_DQ1_TXDLY_OEN_DQM1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), \
P_Fld(ucdq_ui_small, SHURK_SELPH_DQ3_DLY_DQM1) | \
P_Fld(ucdq_oen_ui_small, SHURK_SELPH_DQ3_DLY_OEN_DQM1));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_R0_B1_DQ0), ucdq_pi, SHU_R0_B1_DQ0_SW_ARPI_DQM_B1);
u4err_value=0;
#if ENABLE_K_WITH_WORST_SI_UI_SHIFT
//DramcEngine2SetPat(p, p->test_pattern, 0, 0, TE_UI_SHIFT);
u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, p->test_pattern);
#else
//audio + xtalk pattern
DramcEngine2SetPat(p, TEST_AUDIO_PATTERN, 0, 0, TE_NO_UI_SHIFT);
u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN);
DramcEngine2SetPat(p, TEST_XTALK_PATTERN, 0, 1, TE_NO_UI_SHIFT);
u4err_value |= DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN);
#endif
// audio + xtalk pattern
//u4err_value=0;
//DramcEngine2SetPat(p,TEST_AUDIO_PATTERN, 0, 0, TE_NO_UI_SHIFT);
//u4err_value = DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN);
//DramcEngine2SetPat(p,TEST_XTALK_PATTERN, 0, 1, TE_NO_UI_SHIFT);
//u4err_value |= DramcEngine2Run(p, TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN);
// check fail bit ,0 ok ,others fail
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
u4fail_bit = u4err_value&((U32)1<<u1BitIdx);
if (u4fail_bit == 0)
{
gEyeScan_TotalPassCount[u1BitIdx]+=EYESCAN_GRAPH_CATX_VREF_STEP;
}
if(WinPerBit[u1BitIdx].first_pass== PASS_RANGE_NA)
{
if(u4fail_bit==0) //compare correct: pass
{
WinPerBit[u1BitIdx].first_pass = uiDelay;
u1pass_in_this_vref_flag[u1BitIdx] = 1;
}
}
else if(WinPerBit[u1BitIdx].last_pass == PASS_RANGE_NA)
{
if(u4fail_bit !=0) //compare error : fail
{
WinPerBit[u1BitIdx].last_pass = (uiDelay-1);
}
else if (uiDelay>=63)
{
WinPerBit[u1BitIdx].last_pass = 63;
}
if(WinPerBit[u1BitIdx].last_pass !=PASS_RANGE_NA)
{
if((WinPerBit[u1BitIdx].last_pass -WinPerBit[u1BitIdx].first_pass) >= (VrefWinPerBit[u1BitIdx].last_pass -VrefWinPerBit[u1BitIdx].first_pass))
{
//if window size bigger than 7, consider as real pass window. If not, don't update finish counte and won't do early break;
if((WinPerBit[u1BitIdx].last_pass -WinPerBit[u1BitIdx].first_pass) >7)
uiFinishCount |= (1<<u1BitIdx);
//update bigger window size
VrefWinPerBit[u1BitIdx].first_pass = WinPerBit[u1BitIdx].first_pass;
VrefWinPerBit[u1BitIdx].last_pass = WinPerBit[u1BitIdx].last_pass;
}
if (EyeScan_index[u1BitIdx] < EYESCAN_BROKEN_NUM)
{
#if VENDER_JV_LOG || defined(RELEASE)
gEyeScan_Min[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = WinPerBit[u1BitIdx].first_pass;
gEyeScan_Max[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = WinPerBit[u1BitIdx].last_pass;
#else
//fra gEyeScan_Min[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = WinPerBit[u1BitIdx].first_pass + tx_pi_delay[u1BitIdx/8]-32;
//fra gEyeScan_Max[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = WinPerBit[u1BitIdx].last_pass + tx_pi_delay[u1BitIdx/8]-32;
gEyeScan_Min[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = (S8) WinPerBit[u1BitIdx].first_pass;
gEyeScan_Max[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]] = (S8) WinPerBit[u1BitIdx].last_pass;
mcSHOW_DBG_MSG3(("VrefRange %d, VrefLevel=%d, u1BitIdx=%d, index=%d (%d, %d)==\n",u2VrefRange,u2VrefLevel, u1BitIdx, EyeScan_index[u1BitIdx], gEyeScan_Min[u2VrefLevel/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]], gEyeScan_Max[u2VrefLevel/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx][EyeScan_index[u1BitIdx]]));
gEyeScan_MinMax_store_delay[u1BitIdx/8] = tx_pi_delay[u1BitIdx/8]-32; /* save this information for HQA pass/fail judgement used */
#endif
EyeScan_index[u1BitIdx]=EyeScan_index[u1BitIdx]+1;
}
//reset tmp window
WinPerBit[u1BitIdx].first_pass = PASS_RANGE_NA;
WinPerBit[u1BitIdx].last_pass = PASS_RANGE_NA;
}
}
}
}
min_winsize = 0xffff;
min_bit = 0xff;
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
VrefWinPerBit[u1BitIdx].win_size = VrefWinPerBit[u1BitIdx].last_pass- VrefWinPerBit[u1BitIdx].first_pass +(VrefWinPerBit[u1BitIdx].last_pass==VrefWinPerBit[u1BitIdx].first_pass?0:1);
if (VrefWinPerBit[u1BitIdx].win_size < min_winsize)
{
min_bit = u1BitIdx;
min_winsize = VrefWinPerBit[u1BitIdx].win_size;
}
u2TempWinSum += VrefWinPerBit[u1BitIdx].win_size; //Sum of CA Windows for vref selection
gEyeScan_WinSize[(u2VrefLevel+u2VrefRange*30)/EYESCAN_GRAPH_CATX_VREF_STEP][u1BitIdx] = VrefWinPerBit[u1BitIdx].win_size;
#ifdef FOR_HQA_TEST_USED
if((((backup_u1MR14Value>>6)&1) == u2VrefRange) && ((backup_u1MR14Value&0x3f)==u2VrefLevel))
{
gFinalTXPerbitWin[p->channel][p->rank][u1BitIdx] = VrefWinPerBit[u1BitIdx].win_size;
}
#endif
}
if ((min_winsize > TXPerbitWin_min_max) || ((min_winsize == TXPerbitWin_min_max) && (u2TempWinSum >u2tx_window_sum)))
{
TXPerbitWin_min_max = min_winsize;
u2tx_window_sum =u2TempWinSum;
u2FinalRange = u2VrefRange;
u2FinalVref = u2VrefLevel;
//Calculate the center of DQ pass window
// Record center sum of each byte
for (u1ByteIdx=0; u1ByteIdx<(p->data_width/DQS_BIT_NUMBER); u1ByteIdx++)
{
#if 1//TX_DQM_CALC_MAX_MIN_CENTER
u2Center_min[u1ByteIdx] = 0xffff;
u2Center_max[u1ByteIdx] = 0;
#endif
for (u1BitIdx=0; u1BitIdx<DQS_BIT_NUMBER; u1BitIdx++)
{
ucindex = u1ByteIdx * DQS_BIT_NUMBER + u1BitIdx;
FinalWinPerBit[ucindex].first_pass = VrefWinPerBit[ucindex].first_pass;
FinalWinPerBit[ucindex].last_pass = VrefWinPerBit[ucindex].last_pass;
FinalWinPerBit[ucindex].win_size = VrefWinPerBit[ucindex].win_size;
FinalWinPerBit[ucindex].win_center = (FinalWinPerBit[ucindex].first_pass + FinalWinPerBit[ucindex].last_pass) >> 1;
if(FinalWinPerBit[ucindex].win_center < u2Center_min[u1ByteIdx])
u2Center_min[u1ByteIdx] = FinalWinPerBit[ucindex].win_center;
if(FinalWinPerBit[ucindex].win_center > u2Center_max[u1ByteIdx])
u2Center_max[u1ByteIdx] = FinalWinPerBit[ucindex].win_center;
}
}
}
if(u2VrefRange==0 && u2VrefLevel ==50 && p->dram_type!=TYPE_LPDDR5)
{
u2VrefRange = 1;
u2VrefLevel = 20;
}
for (u1BitIdx = 0; u1BitIdx < p->data_width; u1BitIdx++)
{
if (u1pass_in_this_vref_flag[u1BitIdx]) gEyeScan_ContinueVrefHeight[u1BitIdx]+=EYESCAN_GRAPH_CATX_VREF_STEP; //count pass number of continue vref
}
}
DramcEngine2End(p);
//Calculate the center of DQ pass window
//average the center delay
for (u1ByteIdx=0; u1ByteIdx<(p->data_width/DQS_BIT_NUMBER); u1ByteIdx++)
{
uiDelay = ((u2Center_min[u1ByteIdx] + u2Center_max[u1ByteIdx])>>1); //(max +min)/2
#if VENDER_JV_LOG || defined(RELEASE)
gEyeScan_CaliDelay[u1ByteIdx] = uiDelay;
#else
gEyeScan_CaliDelay[u1ByteIdx] = uiDelay + tx_pi_delay[u1ByteIdx]-32;
#endif
}
//restore to orignal value
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress)/sizeof(U32));
//restore Vref
#ifdef __LP5_COMBO__
if (is_lp5_family(p))
{
u2VrefRange = 0;
u2VrefLevel = backup_u1MR14Value;
}
else
#endif
{
u2VrefRange = backup_u1MR14Value>>6;
u2VrefLevel = backup_u1MR14Value & 0x3f;
}
DramcTXSetVref(p, u2VrefRange, u2VrefLevel);
u1MR14Value[p->channel][p->rank][p->dram_fsp] = backup_u1MR14Value;
}
#endif
#if TX_OE_CALIBATION
#define TX_OE_PATTERN_USE_TA2 1
#define TX_OE_SCAN_FULL_RANGE 0
void DramcTxOECalibration(DRAMC_CTX_T *p)
{
U8 u1ByteIdx;
//U8 ucbegin=0xff, , ucfirst, ucsum, ucbest_step;
U8 ucdq_oen_ui_large[2] = {0}, ucdq_oen_ui_small[2] = {0};
//U8 ucdq_ui_large_reg_value=0xff, ucdq_ui_small_reg_value=0xff;
U8 u1TxDQOEShift = 0;
u1TxDQOEShift = TX_DQ_OE_SHIFT_LP4;
#if TX_OE_PATTERN_USE_TA2
mcSHOW_DBG_MSG(("\n[DramC_TX_OE_Calibration] TA2\n"));
#else
mcSHOW_DBG_MSG(("\n[DramC_TX_OE_Calibration] DMA\n"));
#endif
//default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_OE, DRAM_FAIL);
#if (SUPPORT_SAVE_TIME_FOR_CALIBRATION)
if (p->femmc_Ready == 1)
{
for (u1ByteIdx = 0; u1ByteIdx < DQS_NUMBER_LP4; u1ByteIdx++)
{
ucdq_oen_ui_large[u1ByteIdx] = p->pSavetimeData->u1TX_OE_DQ_MCK[p->channel][p->rank][u1ByteIdx];
ucdq_oen_ui_small[u1ByteIdx] = p->pSavetimeData->u1TX_OE_DQ_UI[p->channel][p->rank][u1ByteIdx];
}
vSetCalibrationResult(p, DRAM_CALIBRATION_TX_OE, DRAM_FAST_K);
}
#endif
for (u1ByteIdx = 0; u1ByteIdx < DQS_NUMBER_LP4; u1ByteIdx++)
{
mcSHOW_DBG_MSG(("Byte%d TX OE(2T, 0.5T) = (%d, %d)\n", u1ByteIdx, ucdq_oen_ui_large[u1ByteIdx], ucdq_oen_ui_small[u1ByteIdx]));
}
mcSHOW_DBG_MSG(("\n\n"));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ0), \
P_Fld(ucdq_oen_ui_large[0], SHURK_SELPH_DQ0_TXDLY_OEN_DQ0) | \
P_Fld(ucdq_oen_ui_large[1], SHURK_SELPH_DQ0_TXDLY_OEN_DQ1));
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ1), \
P_Fld(ucdq_oen_ui_large[0], SHURK_SELPH_DQ1_TXDLY_OEN_DQM0) | \
P_Fld(ucdq_oen_ui_large[1], SHURK_SELPH_DQ1_TXDLY_OEN_DQM1));
// DLY_DQ[2:0]
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ2), \
P_Fld(ucdq_oen_ui_small[0], SHURK_SELPH_DQ2_DLY_OEN_DQ0) | \
P_Fld(ucdq_oen_ui_small[1], SHURK_SELPH_DQ2_DLY_OEN_DQ1) );
// DLY_DQM[2:0]
vIO32WriteFldMulti(DRAMC_REG_ADDR(DRAMC_REG_SHURK_SELPH_DQ3), \
P_Fld(ucdq_oen_ui_small[0], SHURK_SELPH_DQ3_DLY_OEN_DQM0) | \
P_Fld(ucdq_oen_ui_small[1], SHURK_SELPH_DQ3_DLY_OEN_DQM1));
}
#endif
//-------------------------------------------------------------------------
/** DramcMiockJmeter
* start MIOCK jitter meter.
* @param p Pointer of context created by DramcCtxCreate.
* @param block_no (U8): block 0 or 1.
* @retval status (DRAM_STATUS_T): DRAM_OK or DRAM_FAIL
*/
//-------------------------------------------------------------------------
#ifdef ENABLE_MIOCK_JMETER
DRAM_STATUS_T DramcMiockJmeter(DRAMC_CTX_T *p)
{
U16 ucsearch_state, fgcurrent_value, fginitial_value, ucstart_period = 0, ucmiddle_period = 0, ucend_period = 0;
U32 u4sample_cnt, u4ones_cnt[DQS_NUMBER];
U16 u2real_freq, u2real_period, ucdqs_dly;
U16 u2Jm_dly_start = 0, u2Jm_dly_end = 512, u2Jm_dly_step = 4;
U8 u1ShuLevel;
U32 u4PLL3_ADDR, u4B0_DQ;
U32 u4PLL5_ADDR;
U32 u4PLL8_ADDR;
U32 u4SDM_PCW;
U32 u4PREDIV;
U32 u4POSDIV;
U32 u4CKDIV4;
U32 u4VCOFreq;
U32 u4DataRate;
U8 u1RxGatingPI = 0, u1RxGatingPI_start = 0, u1RxGatingPI_end = 63;
U8 backup_rank, u1RankIdx, u1FBKSEL;
u1RxGatingPI = 0x0;
u2gdelay_cell_ps = 0;
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL4)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DLL_ARPI2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DLL_ARPI2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD11)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY)), // need porting to Jmeter
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY + DDRPHY_AO_RANK_OFFSET)), // need porting to Jmeter
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_JMETER)),
//(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2)), // for gating on/off
//(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DVFSCTL2)), // for gating on/off
//(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL)), // for gating on/off
((DDRPHY_REG_SHU_CA_DLL1)),
((DDRPHY_REG_SHU_B0_DLL1)),
((DDRPHY_REG_SHU_B1_DLL1)),
((DDRPHY_REG_B0_DQ2)),
((DDRPHY_REG_B1_DQ2)),
((DDRPHY_REG_CA_CMD2)),
((DDRPHY_REG_SHU_B0_DQ13)),
((DDRPHY_REG_SHU_B1_DQ13)),
((DDRPHY_REG_SHU_CA_CMD13)),
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHB_ADDR),
#if (CHANNEL_NUM > 2)
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHD_ADDR),
#endif
};
backup_rank = u1GetRank(p);
//backup register value
DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
//OE disable - start
vIO32WriteFldMulti_All(DDRPHY_REG_B0_DQ2, P_Fld( 0 , B0_DQ2_RG_TX_ARDQS_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARDQS_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARWCK_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARWCK_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARWCKB_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARWCKB_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0 ) \
| P_Fld( 0xff , B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_B1_DQ2, P_Fld( 0 , B1_DQ2_RG_TX_ARDQS_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARDQS_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARWCK_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARWCK_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARWCKB_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARWCKB_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1 ) \
| P_Fld( 0xff , B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_CA_CMD2, P_Fld( 0 , CA_CMD2_RG_TX_ARCLK_OE_TIE_SEL_CA ) \
| P_Fld( 1 , CA_CMD2_RG_TX_ARCLK_OE_TIE_EN_CA ) \
| P_Fld( 0 , CA_CMD2_RG_TX_ARCS_OE_TIE_SEL_CA ) \
| P_Fld( 1 , CA_CMD2_RG_TX_ARCS_OE_TIE_EN_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 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B0_DQ13 , P_Fld( 0 , SHU_B0_DQ13_RG_TX_ARDQSB_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , SHU_B0_DQ13_RG_TX_ARDQSB_OE_TIE_EN_B0 ));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B1_DQ13 , P_Fld( 0 , SHU_B1_DQ13_RG_TX_ARDQSB_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , SHU_B1_DQ13_RG_TX_ARDQSB_OE_TIE_EN_B1 ));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_CA_CMD13, P_Fld( 0 , SHU_CA_CMD13_RG_TX_ARCLKB_OE_TIE_SEL_CA ) \
| P_Fld( 1 , SHU_CA_CMD13_RG_TX_ARCLKB_OE_TIE_EN_CA ));
//OE disable - end
//DramcHWGatingOnOff(p, 0); // disable Gating tracking for DQS PI, Remove to vApplyConfigBeforeCalibration
// @A60868 for *RANK_SEL_SER_EN* = 0 to DA_RX_ARDQ_RANK_SEL_TXD_*[0]
// for *RANK_SEL_SER_EN* = 1 to DA_RX_ARDQ_RANK_SEL_TXD_*[7:0]
// The *RANK_SEL_SER_EN* = 0 is old mode.
// The *RANK_SEL_SER_EN* = 1 is new mode when background no any access.
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), 0, SHU_B0_DQ11_RG_RX_ARDQ_RANK_SEL_SER_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), 0, SHU_B1_DQ11_RG_RX_ARDQ_RANK_SEL_SER_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD11), 0, SHU_CA_CMD11_RG_RX_ARCA_RANK_SEL_SER_EN_CA);
//@Darren, DLL off to stable fix middle transion from high to low or low to high at high vcore
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_CA_DLL1, P_Fld(0x0, SHU_CA_DLL1_RG_ARDLL_PHDET_EN_CA)
| P_Fld(0x0, SHU_CA_DLL1_RG_ARDLL_PHDET_OUT_SEL_CA));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B0_DLL1, P_Fld(0x0, SHU_B0_DLL1_RG_ARDLL_PHDET_EN_B0)
| P_Fld(0x0, SHU_B0_DLL1_RG_ARDLL_PHDET_OUT_SEL_B0));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B1_DLL1, P_Fld(0x0, SHU_B1_DLL1_RG_ARDLL_PHDET_EN_B1)
| P_Fld(0x0, SHU_B1_DLL1_RG_ARDLL_PHDET_OUT_SEL_B1));
//MCK4X CG
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 0, MISC_CTRL1_R_DMDQSIENCG_EN);
//@A60868, DQS PI mode for JMTR
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DLL_ARPI2), 0, SHU_B0_DLL_ARPI2_RG_ARPI_CG_DQSIEN_B0); // DQS PI mode
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DLL_ARPI2), 0, SHU_B1_DLL_ARPI2_RG_ARPI_CG_DQSIEN_B1); // DQS PI mode
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_CG_EN); // enable toggle cnt
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL4), 0, MISC_CTRL4_R_OPT2_CG_DQSIEN); // Remove to Golden settings for Jmeter clock
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL), 0, MISC_STBCAL_DQSIENCG_NORMAL_EN); // @Darren need confirm for DQS*_ERR_CNT, APHY PICG freerun
//@A60868, End
// Bypass DQS glitch-free mode
// RG_RX_*RDQ_EYE_DLY_DQS_BYPASS_B**
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6), 1, B0_DQ6_RG_RX_ARDQ_EYE_DLY_DQS_BYPASS_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6), 1, B1_DQ6_RG_RX_ARDQ_EYE_DLY_DQS_BYPASS_B1);
//Enable DQ eye scan
//RG_*_RX_EYE_SCAN_EN
//RG_*_RX_VREF_EN
//RG_*_RX_SMT_EN
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_DQS_SYNC_EN)
| P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_NEW_DQ_SYNC_EN)
| P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_DQ_SYNC_EN));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5), 1, B0_DQ5_RG_RX_ARDQ_EYE_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5), 1, B1_DQ5_RG_RX_ARDQ_EYE_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5), 1, B0_DQ5_RG_RX_ARDQ_VREF_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5), 1, B1_DQ5_RG_RX_ARDQ_VREF_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ3), 1, B0_DQ3_RG_RX_ARDQ_SMT_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ3), 1, B1_DQ3_RG_RX_ARDQ_SMT_EN_B1);
//@A60868, JMTR en
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), 1, B0_PHY2_RG_RX_ARDQS_JM_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), 1, B1_PHY2_RG_RX_ARDQS_JM_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_JMETER), 1, MISC_JMETER_JMTR_EN);
//@A60868, End
//@A60868, JM_SEL = 1, JM_SEL = 0 for LPBK
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), 1, B0_PHY2_RG_RX_ARDQS_JM_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), 1, B1_PHY2_RG_RX_ARDQS_JM_SEL_B1);
//@A60868, End
//Enable MIOCK jitter meter mode ( RG_RX_MIOCK_JIT_EN=1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_MIOCK_JIT_EN);
//Disable DQ eye scan (b'1), for counter clear
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_DQSERRCNT_DIS);
for (u1RxGatingPI = u1RxGatingPI_start; u1RxGatingPI < u1RxGatingPI_end; u1RxGatingPI++)
{
mcSHOW_DBG_MSG(("\n[DramcMiockJmeter] u1RxGatingPI = %d\n", u1RxGatingPI));
ucsearch_state = 0;
for (u1RankIdx = RANK_0; u1RankIdx < p->support_rank_num; u1RankIdx++)
{
vSetRank(p, u1RankIdx);
// SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0[6] no use (ignore)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY), u1RxGatingPI, SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0); // for rank*_B0
//Darren---vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B1_DQSIEN_PI_DLY), u1RxGatingPI, SHU_RK_B1_DQSIEN_PI_DLY_DQSIEN_PI_B1); // for rank*_B0
}
vSetRank(p, backup_rank);
for (ucdqs_dly = u2Jm_dly_start; ucdqs_dly < u2Jm_dly_end; ucdqs_dly += u2Jm_dly_step)
{
//@A60868, Set DQS delay (RG_*_RX_DQS_EYE_DLY)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), ucdqs_dly, B0_PHY2_RG_RX_ARDQS_JM_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), ucdqs_dly, B1_PHY2_RG_RX_ARDQS_JM_DLY_B1);
//@A60868, End
DramPhyReset(p);
//Reset eye scan counters (reg_sw_rst): 1 to 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_REG_SW_RST);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_REG_SW_RST);
//Enable DQ eye scan (b'1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
//2ns/sample, here we delay 1ms about 500 samples
mcDELAY_US(10);
//Disable DQ eye scan (b'1), for counter latch
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
//Read the counter values from registers (toggle_cnt*, dqs_err_cnt*);
u4sample_cnt = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_TOGGLE_CNT), MISC_DUTY_TOGGLE_CNT_TOGGLE_CNT);
u4ones_cnt[0] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS0_ERR_CNT), MISC_DUTY_DQS0_ERR_CNT_DQS0_ERR_CNT);
//u4ones_cnt[1] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS1_ERR_CNT), MISC_DUTY_DQS1_ERR_CNT_DQS1_ERR_CNT);
//u4ones_cnt[2] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS2_ERR_CNT), MISC_DUTY_DQS2_ERR_CNT_DQS2_ERR_CNT);
//u4ones_cnt[3] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS3_ERR_CNT), MISC_DUTY_DQS3_ERR_CNT_DQS3_ERR_CNT);
#ifdef ETT_PRINT_FORMAT
mcSHOW_DBG_MSG(("%d : %d, %d\n", ucdqs_dly, u4sample_cnt, u4ones_cnt[0]));
#else
mcSHOW_DBG_MSG(("%3d : %8d, %8d\n", ucdqs_dly, u4sample_cnt, u4ones_cnt[0]));
#endif
//change to boolean value
if (u4ones_cnt[0] < (u4sample_cnt / 2))
{
fgcurrent_value = 0;
}
else
{
fgcurrent_value = 1;
}
#if 1//more than 1T data
{
if (ucsearch_state == 0)
{
//record initial value at the beginning
fginitial_value = fgcurrent_value;
ucsearch_state = 1;
}
else if (ucsearch_state == 1)
{
// check if change value
if (fgcurrent_value != fginitial_value)
{
// start of the period
fginitial_value = fgcurrent_value;
ucstart_period = ucdqs_dly;
ucsearch_state = 2;
}
}
else if (ucsearch_state == 2)
{
// check if change value
if (fgcurrent_value != fginitial_value)
{
fginitial_value = fgcurrent_value;
ucmiddle_period = ucdqs_dly;
ucsearch_state = 3;
}
}
else if (ucsearch_state == 3)
{
// check if change value
if (fgcurrent_value != fginitial_value)
{
// end of the period, break the loop
ucend_period = ucdqs_dly;
ucsearch_state = 4;
break;
}
}
else
{
//nothing
}
}
#else //only 0.5T data
{
if (ucsearch_state == 0)
{
//record initial value at the beginning
fginitial_value = fgcurrent_value;
ucsearch_state = 1;
}
else if (ucsearch_state == 1)
{
// check if change value
if (fgcurrent_value != fginitial_value)
{
// start of the period
fginitial_value = fgcurrent_value;
ucstart_period = ucdqs_dly;
ucsearch_state = 2;
}
}
else if (ucsearch_state == 2)
{
// check if change value
if (fgcurrent_value != fginitial_value)
{
// end of the period, break the loop
ucend_period = ucdqs_dly;
ucsearch_state = 4;
break;
}
}
}
#endif
}
if ((ucsearch_state == 4) || (ucsearch_state == 3))
break;
}
//restore to orignal value
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
if (ucsearch_state != 4)
{
if (ucsearch_state != 3)
{
mcSHOW_DBG_MSG(("\n\tMIOCK jitter meter - ch=%d\n", p->channel));
mcSHOW_DBG_MSG(("\tLess than 0.5T data. Cannot calculate delay cell time\n\n"));
u2g_num_dlycell_perT = 0; //for LP3 and LP4 lookup table used
return DRAM_FAIL;
}
else
{
//Calculate 1 delay cell = ? ps
// 1T = ? delay cell
u2g_num_dlycell_perT = (ucmiddle_period - ucstart_period) * 2;
// 1T = ? ps
}
}
else
{
//Calculate 1 delay cell = ? ps
// 1T = ? delay cell
u2g_num_dlycell_perT = (ucend_period - ucstart_period);
// 1T = ? ps
}
u1ShuLevel = u4IO32ReadFldAlign(DDRPHY_REG_DVFS_STATUS, DVFS_STATUS_OTHER_SHU_GP);
u4PLL5_ADDR = DDRPHY_REG_SHU_PHYPLL1 + DDRPHY_AO_SHU_OFFSET * u1ShuLevel;
u4PLL8_ADDR = DDRPHY_REG_SHU_PHYPLL2 + DDRPHY_AO_SHU_OFFSET * u1ShuLevel;
u4PLL3_ADDR = DDRPHY_REG_SHU_PHYPLL3 + DDRPHY_AO_SHU_OFFSET * u1ShuLevel;
u4B0_DQ = DDRPHY_REG_SHU_B0_DQ1 + DDRPHY_AO_SHU_OFFSET * u1ShuLevel;
u4SDM_PCW = u4IO32ReadFldAlign(u4PLL5_ADDR, SHU_PHYPLL1_RG_RPHYPLL_SDM_PCW);
u4PREDIV = u4IO32ReadFldAlign(u4PLL8_ADDR, SHU_PHYPLL2_RG_RPHYPLL_PREDIV);
u4POSDIV = u4IO32ReadFldAlign(u4PLL8_ADDR, SHU_PHYPLL2_RG_RPHYPLL_POSDIV);
u4CKDIV4 = u4IO32ReadFldAlign(u4B0_DQ, SHU_B0_DQ1_RG_ARPI_MIDPI_CKDIV4_EN_B0);
u1FBKSEL = u4IO32ReadFldAlign(u4PLL3_ADDR, SHU_PHYPLL3_RG_RPHYPLL_FBKSEL);
u4VCOFreq = (((52 >> u4PREDIV) * (u4SDM_PCW >> 8)) >> u4POSDIV) << u1FBKSEL;
u4DataRate = u4VCOFreq >> u4CKDIV4;
u2real_freq = u4DataRate >> 1;
u2real_period = (U16) (1000000 / u2real_freq);
//calculate delay cell time
u2gdelay_cell_ps = u2real_period * 100 / u2g_num_dlycell_perT;
if (ucsearch_state == 4)
{ // 1T
mcSHOW_DBG_MSG(("\n\tMIOCK jitter meter\tch=%d\n\n"
"1T = (%d-%d) = %d dly cells\n"
"Clock freq = %d MHz, period = %d ps, 1 dly cell = %d/100 ps\n",
p->channel,
ucend_period, ucstart_period, u2g_num_dlycell_perT,
u2real_freq, u2real_period, u2gdelay_cell_ps));
}
else
{ // 0.5T
mcSHOW_DBG_MSG(("\n\tMIOCK jitter meter\tch=%d\n\n"
"1T = (%d-%d)*2 = %d dly cells\n"
"Clock freq = %d MHz, period = %d ps, 1 dly cell = %d/100 ps\n",
p->channel,
ucmiddle_period, ucstart_period, u2g_num_dlycell_perT,
u2real_freq, u2real_period, u2gdelay_cell_ps));
}
return DRAM_OK;
// log example
/* dly: sample_cnt DQS0_cnt DQS1_cnt
0 : 10962054, 0, 0
1 : 10958229, 0, 0
2 : 10961109, 0, 0
3 : 10946916, 0, 0
4 : 10955421, 0, 0
5 : 10967274, 0, 0
6 : 10893582, 0, 0
7 : 10974762, 0, 0
8 : 10990278, 0, 0
9 : 10972026, 0, 0
10 : 7421004, 0, 0
11 : 10943883, 0, 0
12 : 10984275, 0, 0
13 : 10955268, 0, 0
14 : 10960326, 0, 0
15 : 10952451, 0, 0
16 : 10956906, 0, 0
17 : 10960803, 0, 0
18 : 10944108, 0, 0
19 : 10959939, 0, 0
20 : 10959246, 0, 0
21 : 11002212, 0, 0
22 : 10919700, 0, 0
23 : 10977489, 0, 0
24 : 11009853, 0, 0
25 : 10991133, 0, 0
26 : 10990431, 0, 0
27 : 10970703, 11161, 0
28 : 10970775, 257118, 0
29 : 10934442, 9450467, 0
30 : 10970622, 10968475, 0
31 : 10968831, 10968831, 0
32 : 10956123, 10956123, 0
33 : 10950273, 10950273, 0
34 : 10975770, 10975770, 0
35 : 10983024, 10983024, 0
36 : 10981701, 10981701, 0
37 : 10936782, 10936782, 0
38 : 10889523, 10889523, 0
39 : 10985913, 10985913, 55562
40 : 10970235, 10970235, 272294
41 : 10996056, 10996056, 9322868
42 : 10972350, 10972350, 10969738
43 : 10963917, 10963917, 10963917
44 : 10967895, 10967895, 10967895
45 : 10961739, 10961739, 10961739
46 : 10937097, 10937097, 10937097
47 : 10937952, 10937952, 10937952
48 : 10926018, 10926018, 10926018
49 : 10943793, 10943793, 10943793
50 : 10954638, 10954638, 10954638
51 : 10968048, 10968048, 10968048
52 : 10944036, 10944036, 10944036
53 : 11012112, 11012112, 11012112
54 : 10969137, 10969137, 10969137
55 : 10968516, 10968516, 10968516
56 : 10952532, 10952532, 10952532
57 : 10985832, 10985832, 10985832
58 : 11002527, 11002527, 11002527
59 : 10950660, 10873571, 10950660
60 : 10949022, 10781797, 10949022
61 : 10974366, 10700617, 10974366
62 : 10972422, 1331974, 10972422
63 : 10926567, 0, 10926567
64 : 10961658, 0, 10961658
65 : 10978893, 0, 10978893
66 : 10962828, 0, 10962828
67 : 10957599, 0, 10957599
68 : 10969227, 0, 10969227
69 : 10960722, 0, 10960722
70 : 10970937, 0, 10963180
71 : 10962054, 0, 10711639
72 : 10954719, 0, 10612707
73 : 10958778, 0, 479589
74 : 10973898, 0, 0
75 : 11004156, 0, 0
76 : 10944261, 0, 0
77 : 10955340, 0, 0
78 : 10998153, 0, 0
79 : 10998774, 0, 0
80 : 10953234, 0, 0
81 : 10960020, 0, 0
82 : 10923831, 0, 0
83 : 10951362, 0, 0
84 : 10965249, 0, 0
85 : 10949103, 0, 0
86 : 10948707, 0, 0
87 : 10941147, 0, 0
88 : 10966572, 0, 0
89 : 10971333, 0, 0
90 : 10943721, 0, 0
91 : 10949337, 0, 0
92 : 10965942, 0, 0
93 : 10970397, 0, 0
94 : 10956429, 0, 0
95 : 10939896, 0, 0
96 : 10967112, 0, 0
97 : 10951911, 0, 0
98 : 10953702, 0, 0
99 : 10971090, 0, 0
100 : 10939590, 0, 0
101 : 10993392, 0, 0
102 : 10975932, 0, 0
103 : 10949499, 40748, 0
104 : 10962522, 258638, 0
105 : 10951524, 275292, 0
106 : 10982475, 417642, 0
107 : 10966887, 10564347, 0
===============================================================================
MIOCK jitter meter - channel=0
===============================================================================
1T = (107-29) = 78 delay cells
Clock frequency = 936 MHz, Clock period = 1068 ps, 1 delay cell = 13 ps
*/
}
/* "picoseconds per delay cell" depends on Vcore only (frequency doesn't matter)
* 1. Retrieve current freq's vcore voltage using pmic API
* 2. Perform delay cell time calculation (Bypass if shuffle vcore value is the same as before)
*/
static void GetVcoreDelayCellTime(DRAMC_CTX_T *p, U8 shuffleIdx)
{
U32 channel_i;
#if __ETT__
#if (FOR_DV_SIMULATION_USED==0 && SW_CHANGE_FOR_SIMULATION==0)
u4gVcore[shuffleIdx] = pmic_vcore_voltage_read();
#endif
/* delay cell calculation is skipped if vcore is same as previous shuffle's */
if (u4gVcore[shuffleIdx] != u4previousVcore)
{
u4previousVcore = u4gVcore[shuffleIdx];
DramcMiockJmeter(p);
}
#else
DramcMiockJmeter(p);
#endif
for(channel_i=CHANNEL_A; channel_i < p->support_channel_num; channel_i++)
{
u2g_num_dlycell_perT_all[shuffleIdx][channel_i] = u2g_num_dlycell_perT;
u2gdelay_cell_ps_all[shuffleIdx][channel_i] = u2gdelay_cell_ps;
}
#if __ETT__
mcSHOW_DBG_MSG(("Freq=%d, CH_%d, VCORE=%d, cell=%d\n", p->frequency, p->channel, u4gVcore[shuffleIdx], u2gdelay_cell_ps_all[shuffleIdx][p->channel]));
#endif
return;
}
void DramcMiockJmeterHQA(DRAMC_CTX_T *p)
{
//do MiockJitterMeter@DDR2667
U8 shuffleIdx;
mcSHOW_DBG_MSG(("[MiockJmeterHQA]\n"));
shuffleIdx = get_shuffleIndex_by_Freq(p);
if(p->channel == CHANNEL_A)
{
if (p->frequency <= 600)
{
u2g_num_dlycell_perT_all[shuffleIdx][p->channel] = 0; // always lookup table
u2gdelay_cell_ps_all[shuffleIdx][p->channel] = 270; // @Darren, Wait arnold for lookup table
}
else
GetVcoreDelayCellTime(p, shuffleIdx);
}
u2gdelay_cell_ps_all[shuffleIdx][CHANNEL_B] = u2gdelay_cell_ps_all[shuffleIdx][CHANNEL_A];
#ifdef FOR_HQA_TEST_USED
if (u2g_num_dlycell_perT_all[shuffleIdx][p->channel] == 0) GetVcoreDelayCellTimeFromTable(p); //lookup table
#endif
/* Use highest freq's delay cell time measurement results as reference */
p->u2num_dlycell_perT = u2g_num_dlycell_perT_all[shuffleIdx][p->channel];
p->u2DelayCellTimex100 = u2gdelay_cell_ps_all[shuffleIdx][p->channel];
mcSHOW_DBG_MSG3(("DelayCellTimex100 CH_%d, (VCORE=%d, cell=%d)\n",p->channel, u4gVcore[shuffleIdx], p->u2DelayCellTimex100));
}
#endif
//-------------------------------------------------------------------------
/** Dramc8PhaseCal
* start 8-Phase Calibration.
* @param p Pointer of context created by DramcCtxCreate.
* @param block_no (U8): block 0 or 1.
* @retval status (DRAM_STATUS_T): DRAM_OK or DRAM_FAIL
*/
//-------------------------------------------------------------------------
DRAM_STATUS_T Dramc8PhaseCal(DRAMC_CTX_T *p)
{
#if ENABLE_8PHASE_CALIBRATION
U8 u1DqsLevel = 0xff, u18Ph_dly_loop_break = 0;
U8 u1DqsienPI = 0;
U8 u18Phase_SM = DQS_8PH_DEGREE_0, u18Ph_dly = 0, u18Ph_start = 0, u18Ph_end = 0, u18Ph_dly_final = 0xff;
U16 u2R0 = 0xffff, u2R180 = 0xffff, u2R = 0xffff;
U16 u2P = 0xffff, ucdqs_dly = 0;
S16 s2Err_code = 0x7fff, s2Err_code_min = 0x7fff;
U16 u2Jm_dly_start = 0, u2Jm_dly_end = 512, u2Jm_dly_step = 1;
U32 u4sample_cnt, u4ones_cnt[DQS_NUMBER];
U8 backup_rank, u1RankIdx, u18PhDlyBackup = 0;
U8 u1loop_cnt = 0, u1early_break_cnt = 5;
U32 u4backup_broadcast= GetDramcBroadcast();
DRAM_STATUS_T eDRAMStatus = DRAM_OK;
#ifdef DUMP_INIT_RG_LOG_TO_DE //for FT dump 3733 dram_init.c
return DRAM_OK;
#endif
u1DqsienPI = 0x0;
// error handling
if (!p)
{
mcSHOW_ERR_MSG(("context NULL\n"));
return DRAM_FAIL;
}
if (p->frequency < 1866)
{
//mcSHOW_ERR_MSG(("skip 8-Phase Calib Freq is %d < 1866 !!!\n", p->frequency));
return DRAM_OK;
}
U32 u4RegBackupAddress[] =
{
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ3)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL4)),
(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DLL_ARPI2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DLL_ARPI2)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD11)),
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY)), // need porting to Jmeter
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY + DDRPHY_AO_RANK_OFFSET)), // need porting to Jmeter
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_JMETER)),
//(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL2)), // for gating on/off backup/restore
//(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DVFSCTL2)), // for gating on/off backup/restore
(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL)), // for gating on/off backup/restore
#if 0
(DRAMC_REG_ADDR(DDRPHY_REG_B0_DLL_ARPI0)),
(DRAMC_REG_ADDR(DDRPHY_REG_B1_DLL_ARPI0)),
(DRAMC_REG_ADDR(DDRPHY_REG_CA_DLL_ARPI0)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ6)),
(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD6)),
#endif
((DDRPHY_REG_SHU_CA_DLL1)),
((DDRPHY_REG_SHU_B0_DLL1)),
((DDRPHY_REG_SHU_B1_DLL1)),
((DDRPHY_REG_B0_DQ2)),
((DDRPHY_REG_B1_DQ2)),
((DDRPHY_REG_CA_CMD2)),
((DDRPHY_REG_SHU_B0_DQ13)),
((DDRPHY_REG_SHU_B1_DQ13)),
((DDRPHY_REG_SHU_CA_CMD13)),
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHB_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHB_ADDR),
#if (CHANNEL_NUM > 2)
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHC_ADDR),
((DDRPHY_REG_SHU_CA_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B0_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B1_DLL1) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_B0_DQ2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_B1_DQ2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_CA_CMD2) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B0_DQ13) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_B1_DQ13) + SHIFT_TO_CHD_ADDR),
((DDRPHY_REG_SHU_CA_CMD13) + SHIFT_TO_CHD_ADDR),
#endif
};
backup_rank = u1GetRank(p);
DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);
//backup register value
DramcBackupRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
//OE disable - start
vIO32WriteFldMulti_All(DDRPHY_REG_B0_DQ2, P_Fld( 0 , B0_DQ2_RG_TX_ARDQS_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARDQS_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARWCK_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARWCK_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARWCKB_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARWCKB_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , B0_DQ2_RG_TX_ARDQM_OE_TIE_EN_B0 ) \
| P_Fld( 0 , B0_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B0 ) \
| P_Fld( 0xff , B0_DQ2_RG_TX_ARDQ_OE_TIE_EN_B0 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_B1_DQ2, P_Fld( 0 , B1_DQ2_RG_TX_ARDQS_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARDQS_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARWCK_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARWCK_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARWCKB_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARWCKB_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARDQM_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , B1_DQ2_RG_TX_ARDQM_OE_TIE_EN_B1 ) \
| P_Fld( 0 , B1_DQ2_RG_TX_ARDQ_OE_TIE_SEL_B1 ) \
| P_Fld( 0xff , B1_DQ2_RG_TX_ARDQ_OE_TIE_EN_B1 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_CA_CMD2, P_Fld( 0 , CA_CMD2_RG_TX_ARCLK_OE_TIE_SEL_CA ) \
| P_Fld( 1 , CA_CMD2_RG_TX_ARCLK_OE_TIE_EN_CA ) \
| P_Fld( 0 , CA_CMD2_RG_TX_ARCS_OE_TIE_SEL_CA ) \
| P_Fld( 1 , CA_CMD2_RG_TX_ARCS_OE_TIE_EN_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 ) );
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B0_DQ13 , P_Fld( 0 , SHU_B0_DQ13_RG_TX_ARDQSB_OE_TIE_SEL_B0 ) \
| P_Fld( 1 , SHU_B0_DQ13_RG_TX_ARDQSB_OE_TIE_EN_B0 ));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B1_DQ13 , P_Fld( 0 , SHU_B1_DQ13_RG_TX_ARDQSB_OE_TIE_SEL_B1 ) \
| P_Fld( 1 , SHU_B1_DQ13_RG_TX_ARDQSB_OE_TIE_EN_B1 ));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_CA_CMD13, P_Fld( 0 , SHU_CA_CMD13_RG_TX_ARCLKB_OE_TIE_SEL_CA ) \
| P_Fld( 1 , SHU_CA_CMD13_RG_TX_ARCLKB_OE_TIE_EN_CA ));
//OE disable - end
u18PhDlyBackup = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ1), SHU_B0_DQ1_RG_ARPI_MIDPI_8PH_DLY_B0);
//DramcHWGatingOnOff(p, 0); // disable Gating tracking for DQS PI, Remove to vApplyConfigBeforeCalibration
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_SHU_STBCAL), P_Fld(0x0, MISC_SHU_STBCAL_STBCALEN)
| P_Fld(0x0, MISC_SHU_STBCAL_STB_SELPHCALEN));
#if 0 // 8-Phase calib must to do before DLL init for test only
//@A60868, Reset PI code to avoid 8-phase offset
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DLL_ARPI0), 0, B0_DLL_ARPI0_RG_ARPI_RESETB_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DLL_ARPI0), 0, B1_DLL_ARPI0_RG_ARPI_RESETB_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_CA_DLL_ARPI0), 0, CA_DLL_ARPI0_RG_ARPI_RESETB_CA);
mcDELAY_US(1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DLL_ARPI0), 1, B0_DLL_ARPI0_RG_ARPI_RESETB_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DLL_ARPI0), 1, B1_DLL_ARPI0_RG_ARPI_RESETB_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_CA_DLL_ARPI0), 1, CA_DLL_ARPI0_RG_ARPI_RESETB_CA);
//@A60868, End
// @A60868, DQSIEN PI offset clear to 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ6), 0, SHU_B0_DQ6_RG_ARPI_OFFSET_DQSIEN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ6), 0, SHU_B1_DQ6_RG_ARPI_OFFSET_DQSIEN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD6), 0, SHU_CA_CMD6_RG_ARPI_OFFSET_DQSIEN_CA);
#endif
// @A60868 for *RANK_SEL_SER_EN* = 0 to DA_RX_ARDQ_RANK_SEL_TXD_*[0]
// for *RANK_SEL_SER_EN* = 1 to DA_RX_ARDQ_RANK_SEL_TXD_*[7:0]
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ11), 0, SHU_B0_DQ11_RG_RX_ARDQ_RANK_SEL_SER_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ11), 0, SHU_B1_DQ11_RG_RX_ARDQ_RANK_SEL_SER_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD11), 0, SHU_CA_CMD11_RG_RX_ARCA_RANK_SEL_SER_EN_CA);
//@Darren, DLL off to stable fix middle transion from high to low or low to high at high vcore
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_CA_DLL1, P_Fld(0x0, SHU_CA_DLL1_RG_ARDLL_PHDET_EN_CA)
| P_Fld(0x0, SHU_CA_DLL1_RG_ARDLL_PHDET_OUT_SEL_CA));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B0_DLL1, P_Fld(0x0, SHU_B0_DLL1_RG_ARDLL_PHDET_EN_B0)
| P_Fld(0x0, SHU_B0_DLL1_RG_ARDLL_PHDET_OUT_SEL_B0));
vIO32WriteFldMulti_All(DDRPHY_REG_SHU_B1_DLL1, P_Fld(0x0, SHU_B1_DLL1_RG_ARDLL_PHDET_EN_B1)
| P_Fld(0x0, SHU_B1_DLL1_RG_ARDLL_PHDET_OUT_SEL_B1));
//MCK4X CG
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL1), 0, MISC_CTRL1_R_DMDQSIENCG_EN);
//@A60868, DQS PI mode for JMTR
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DLL_ARPI2), 0, SHU_B0_DLL_ARPI2_RG_ARPI_CG_DQSIEN_B0); // DQS PI mode
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DLL_ARPI2), 0, SHU_B1_DLL_ARPI2_RG_ARPI_CG_DQSIEN_B1); // DQS PI mode
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_CG_EN); // enable toggle cnt
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_CTRL4), 0, MISC_CTRL4_R_OPT2_CG_DQSIEN); // Remove to Golden settings for Jmeter clock
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_STBCAL), 0, MISC_STBCAL_DQSIENCG_NORMAL_EN); // for DQS*_ERR_CNT
//@A60868, End
// Bypass DQS glitch-free mode
// RG_RX_*RDQ_EYE_DLY_DQS_BYPASS_B**
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ6), 1, B0_DQ6_RG_RX_ARDQ_EYE_DLY_DQS_BYPASS_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ6), 1, B1_DQ6_RG_RX_ARDQ_EYE_DLY_DQS_BYPASS_B1);
//Enable DQ eye scan
//RG_*_RX_EYE_SCAN_EN
//RG_*_RX_VREF_EN
//RG_*_RX_SMT_EN
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_DQS_SYNC_EN)
| P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_NEW_DQ_SYNC_EN)
| P_Fld(0x1, MISC_DUTYSCAN1_EYESCAN_DQ_SYNC_EN));
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5), 1, B0_DQ5_RG_RX_ARDQ_EYE_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5), 1, B1_DQ5_RG_RX_ARDQ_EYE_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ5), 1, B0_DQ5_RG_RX_ARDQ_VREF_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ5), 1, B1_DQ5_RG_RX_ARDQ_VREF_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_DQ3), 1, B0_DQ3_RG_RX_ARDQ_SMT_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_DQ3), 1, B1_DQ3_RG_RX_ARDQ_SMT_EN_B1);
//@A60868, JMTR en
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), 1, B0_PHY2_RG_RX_ARDQS_JM_EN_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), 1, B1_PHY2_RG_RX_ARDQS_JM_EN_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_JMETER), 1, MISC_JMETER_JMTR_EN);
//@A60868, End
//@A60868, JM_SEL = 1, JM_SEL = 0 for LPBK
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), 1, B0_PHY2_RG_RX_ARDQS_JM_SEL_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), 1, B1_PHY2_RG_RX_ARDQS_JM_SEL_B1);
//Enable MIOCK jitter meter mode ( RG_RX_MIOCK_JIT_EN=1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_MIOCK_JIT_EN);
//Disable DQ eye scan (b'1), for counter clear
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_DQSERRCNT_DIS);
for (u18Phase_SM = DQS_8PH_DEGREE_0; u18Phase_SM < DQS_8PH_DEGREE_MAX; u18Phase_SM++)
{
switch (u18Phase_SM)
{
case DQS_8PH_DEGREE_0:
u1DqsienPI = 16;
u18Ph_start = 0;
u18Ph_end = 1;
break;
case DQS_8PH_DEGREE_180:
u1DqsienPI = 48;
u18Ph_start = 0;
u18Ph_end = 1;
break;
case DQS_8PH_DEGREE_45:
u1DqsienPI = 24;
u18Ph_start = 0;
u18Ph_end = 32;
break;
default:
mcSHOW_ERR_MSG(("u18Phase_SM err!\n"));
#if __ETT__
while (1);
#endif
}
mcSHOW_DBG_MSG(("\n[Dramc8PhaseCal] 8-Phase SM_%d, 8PH_dly (%d~%d), DQSIEN PI = %d, 8PH_Dly = %d\n", u18Phase_SM, u18Ph_start, u18Ph_end, u1DqsienPI, u18PhDlyBackup));
//to see 1T(H,L) or 1T(L,H) from delaycell=0 to 127
//NOTE: Must set dual ranks for Rx path
for (u1RankIdx = RANK_0; u1RankIdx < p->support_rank_num; u1RankIdx++)
{
vSetRank(p, u1RankIdx);
// SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0[6] no use (ignore)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_RK_B0_DQSIEN_PI_DLY), u1DqsienPI, SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0); // for rank*_B0
}
vSetRank(p, backup_rank);
for (u18Ph_dly = u18Ph_start; u18Ph_dly < u18Ph_end; u18Ph_dly++)
{
mcSHOW_DBG_MSG(("8PH dly = %d\n", u18Ph_dly));
u1DqsLevel = 0xff;
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_DQ1), u18Ph_dly, SHU_B0_DQ1_RG_ARPI_MIDPI_8PH_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B1_DQ1), u18Ph_dly, SHU_B1_DQ1_RG_ARPI_MIDPI_8PH_DLY_B1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD1), u18Ph_dly, SHU_CA_CMD1_RG_ARPI_MIDPI_8PH_DLY_CA);
for (ucdqs_dly = u2Jm_dly_start; ucdqs_dly < u2Jm_dly_end; ucdqs_dly += u2Jm_dly_step)
{
//Set DQS delay (RG_*_RX_DQS_EYE_DLY)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B0_PHY2), ucdqs_dly, B0_PHY2_RG_RX_ARDQS_JM_DLY_B0);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_B1_PHY2), ucdqs_dly, B1_PHY2_RG_RX_ARDQS_JM_DLY_B1);
DramPhyReset(p);
//Reset eye scan counters (reg_sw_rst): 1 to 0
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_REG_SW_RST);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_REG_SW_RST);
//Enable DQ eye scan (b'1)
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 1, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
//2ns/sample, here we delay 1ms about 500 samples
mcDELAY_US(10);
//Disable DQ eye scan (b'1), for counter latch
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTYSCAN1), 0, MISC_DUTYSCAN1_RX_EYE_SCAN_EN);
//Read the counter values from registers (toggle_cnt*, dqs_err_cnt*);
u4sample_cnt = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_TOGGLE_CNT), MISC_DUTY_TOGGLE_CNT_TOGGLE_CNT);
u4ones_cnt[0] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS0_ERR_CNT), MISC_DUTY_DQS0_ERR_CNT_DQS0_ERR_CNT);
//u4ones_cnt[1] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS1_ERR_CNT), MISC_DUTY_DQS1_ERR_CNT_DQS1_ERR_CNT);
//u4ones_cnt[2] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS2_ERR_CNT), MISC_DUTY_DQS2_ERR_CNT_DQS2_ERR_CNT);
//u4ones_cnt[3] = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_DUTY_DQS3_ERR_CNT), MISC_DUTY_DQS3_ERR_CNT_DQS3_ERR_CNT);
//Darren-mcSHOW_DBG_MSG(("%3d : %8d, %8d, %8d\n", ucdqs_dly, u4sample_cnt, u4ones_cnt[0], u4ones_cnt[1]));
//change to boolean value
if (u4ones_cnt[0] < (u4sample_cnt / 2))
{
if (u1DqsLevel == 0xff) // print once
{
mcSHOW_DBG_MSG(("[L] %d, %8d\n", ucdqs_dly, u4ones_cnt[0]));
//mcSHOW_DBG_MSG(("[L] %d, %8d, %8d\n", ucdqs_dly, u4ones_cnt[0], u4ones_cnt[1]));
}
u1DqsLevel = 0;
}
else
{
if (u1DqsLevel == 0) // from low to high
{
u1DqsLevel = 1;
mcSHOW_DBG_MSG(("[H] %d, %8d\n", ucdqs_dly, u4ones_cnt[0]));
//mcSHOW_DBG_MSG(("[H] %d, %8d, %8d\n", ucdqs_dly, u4ones_cnt[0], u4ones_cnt[1]));
if (u18Phase_SM == DQS_8PH_DEGREE_0)
{
u2R0 = ucdqs_dly;
mcSHOW_DBG_MSG(("R0 = %d\n", u2R0));
break; // break ucdqs_dly for loop
}
else if (u18Phase_SM == DQS_8PH_DEGREE_180)
{
u2R180 = ucdqs_dly;
if (u2R180 > u2R0)
{
u2R = u2R0 + ((u2R180 - u2R0) >> 2); // u2R180 >= u2R0 for (u1R180 - u1R0)/4 for 180 degree. /2 for 90 degree
mcSHOW_DBG_MSG(("R = %d, R180 = %d\n", u2R, u2R180));
break; // break ucdqs_dly for loop
}
else
{
u1DqsLevel = 0xff; //next u2Jm_dly to find edge (L->H)
}
}
else if (u18Phase_SM == DQS_8PH_DEGREE_45)
{
u2P = ucdqs_dly;
if (u2P > u2R0) // u2P ~= DQS_8PH_DEGREE_180
{
// Absolute to find min diff
if (u2R > u2P)
s2Err_code = u2R - u2P;
else
s2Err_code = u2P - u2R;
if (s2Err_code == 0)
{
u18Ph_dly_final = u18Ph_dly;
u18Ph_dly_loop_break = 1;
}
else if (s2Err_code < s2Err_code_min)
{
s2Err_code_min = s2Err_code;
u18Ph_dly_final = u18Ph_dly;
u1loop_cnt = 0;
}
else if (s2Err_code >= s2Err_code_min)
{
// check early break for u18Ph_dly for loop
u1loop_cnt++;
if (u1loop_cnt > u1early_break_cnt)
{
u18Ph_dly_loop_break = 1;
}
}
mcSHOW_DBG_MSG(("diff (P-R) = %d, min = %d, break count = %d\n", s2Err_code, s2Err_code_min, u1loop_cnt));
break; // if (s2Err_code == s2Err_code_min) for next u18Ph_dly
}
else
{
u1DqsLevel = 0xff; //next u2Jm_dly to find edge (L->H)
}
}
else
{
mcSHOW_ERR_MSG(("u18Phase_SM err!\n"));
#if __ETT__
while (1);
#endif
}
}
}
}
// Error handing
if ((u1DqsLevel == 0xff) || (u1DqsLevel == 0))
{
// (u1DqsLevel == 0) => skip from 1 to all's 0 or all's 0
// (u1DqsLevel == 0xff) => skip all's 1
// NOTE: 8-Phase calib must from 0 to 1
u18Ph_dly_final = u18PhDlyBackup; //rollback to init settings
eDRAMStatus = DRAM_FAIL;
mcSHOW_ERR_MSG(("\n[Dramc8PhaseCal] 8-Phase SM_%d is fail (to Default)!!!\n", u18Phase_SM));
goto exit;
} else if (u18Ph_dly_loop_break == 1)
break;
}
}
exit:
mcSHOW_DBG_MSG(("\n[Dramc8PhaseCal] u18Ph_dly_final = %d\n\n", u18Ph_dly_final));
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_B0_DQ1, u18Ph_dly_final, SHU_B0_DQ1_RG_ARPI_MIDPI_8PH_DLY_B0);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_B1_DQ1, u18Ph_dly_final, SHU_B1_DQ1_RG_ARPI_MIDPI_8PH_DLY_B1);
vIO32WriteFldAlign_All(DDRPHY_REG_SHU_CA_CMD1, u18Ph_dly_final, SHU_CA_CMD1_RG_ARPI_MIDPI_8PH_DLY_CA);
//restore to orignal value
DramcRestoreRegisters(p, u4RegBackupAddress, sizeof(u4RegBackupAddress) / sizeof(U32));
DramcBroadcastOnOff(u4backup_broadcast);
return eDRAMStatus;
#endif
}
#if SIMULATION_SW_IMPED
void DramcSwImpedanceSaveRegister(DRAMC_CTX_T *p, U8 ca_freq_option, U8 dq_freq_option, U8 save_to_where)
{
U32 backup_broadcast;
backup_broadcast = GetDramcBroadcast();
DramcBroadcastOnOff(DRAMC_BROADCAST_ON);
//DQ
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING1 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVP], SHU_MISC_DRVING1_DQDRVP2) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVN], SHU_MISC_DRVING1_DQDRVN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING2 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVP], SHU_MISC_DRVING2_DQDRVP1) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVN], SHU_MISC_DRVING2_DQDRVN1));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTP], SHU_MISC_DRVING3_DQODTP2) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTN], SHU_MISC_DRVING3_DQODTN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING4 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTP], SHU_MISC_DRVING4_DQODTP1) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTN], SHU_MISC_DRVING4_DQODTN1));
//DQS
#if SUPPORT_HYNIX_RX_DQS_WEAK_PULL
if (p->vendor_id == VENDOR_HYNIX)
{ U32 temp_value[4];
int i;
for(i=0; i<4; i++)
{
temp_value[i] = SwImpedanceAdjust(gDramcSwImpedanceResult[dq_freq_option][i], 2);
}
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING1 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(temp_value[0], SHU_MISC_DRVING1_DQSDRVP2) | P_Fld(temp_value[1], SHU_MISC_DRVING1_DQSDRVN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING1 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(temp_value[0], SHU_MISC_DRVING1_DQSDRVP1) | P_Fld(temp_value[1], SHU_MISC_DRVING1_DQSDRVN1));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(temp_value[2], SHU_MISC_DRVING3_DQSODTP2) | P_Fld(temp_value[3], SHU_MISC_DRVING3_DQSODTN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(temp_value[2], SHU_MISC_DRVING3_DQSODTP) | P_Fld(temp_value[3], SHU_MISC_DRVING3_DQSODTN));
}
else
#endif
{
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING1 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVP], SHU_MISC_DRVING1_DQSDRVP2) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVN], SHU_MISC_DRVING1_DQSDRVN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING1 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVP], SHU_MISC_DRVING1_DQSDRVP1) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][DRVN], SHU_MISC_DRVING1_DQSDRVN1));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTP], SHU_MISC_DRVING3_DQSODTP2) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTN], SHU_MISC_DRVING3_DQSODTN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTP], SHU_MISC_DRVING3_DQSODTP) | P_Fld(gDramcSwImpedanceResult[dq_freq_option][ODTN], SHU_MISC_DRVING3_DQSODTN));
}
//CMD & CLK
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING2 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[ca_freq_option][DRVP], SHU_MISC_DRVING2_CMDDRVP2) | P_Fld(gDramcSwImpedanceResult[ca_freq_option][DRVN], SHU_MISC_DRVING2_CMDDRVN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING2 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[ca_freq_option][DRVP], SHU_MISC_DRVING2_CMDDRVP1) | P_Fld(gDramcSwImpedanceResult[ca_freq_option][DRVN], SHU_MISC_DRVING2_CMDDRVN1));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING4 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[ca_freq_option][ODTP], SHU_MISC_DRVING4_CMDODTP2) | P_Fld(gDramcSwImpedanceResult[ca_freq_option][ODTN], SHU_MISC_DRVING4_CMDODTN2));
vIO32WriteFldMulti((DDRPHY_REG_SHU_MISC_DRVING4 + save_to_where * SHU_GRP_DDRPHY_OFFSET), P_Fld(gDramcSwImpedanceResult[ca_freq_option][ODTP], SHU_MISC_DRVING4_CMDODTP1) | P_Fld(gDramcSwImpedanceResult[ca_freq_option][ODTN], SHU_MISC_DRVING4_CMDODTN1));
//RG_TX_*RCKE_DRVP/RG_TX_*RCKE_DRVN doesn't set, so set 0xA first
//@Maoauo confirm, RG no function
//vIO32WriteFldAlign((DDRPHY_SHU_CA_CMD11 + save_to_where * SHU_GRP_DDRPHY_OFFSET), gDramcSwImpedanceResult[ca_freq_option][DRVP], SHU_CA_CMD11_RG_TX_ARCKE_DRVP);
//vIO32WriteFldAlign((DDRPHY_SHU_CA_CMD11 + save_to_where * SHU_GRP_DDRPHY_OFFSET), gDramcSwImpedanceResult[ca_freq_option][DRVN], SHU_CA_CMD11_RG_TX_ARCKE_DRVN);
//CKE
// CKE is full swing.
// LP4/LP4X set DRVP/DRVN as LP3's default value
// DRVP=8 -> 0xA for 868 by Alucary Chen
// DRVN=9 -> 0xA for 868 by Alucary Chen
//DRVP[4:0] = RG_TX_ARCMD_PU_PRE<1:0>, RG_TX_ARCLK_DRVN_PRE<2:0> for La_fite only
//@Darren-vIO32WriteFldAlign((DDRPHY_REG_SHU_CA_CMD3 + save_to_where * SHU_GRP_DDRPHY_OFFSET), (8>>3)&0x3, SHU_CA_CMD3_RG_TX_ARCMD_PU_PRE); //Darren need confirm
//@Darren-vIO32WriteFldAlign((DDRPHY_REG_SHU_CA_CMD0 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 8&0x7, SHU_CA_CMD0_RG_TX_ARCLK_DRVN_PRE); //Darren need confirm
//DRVN[4:0] = RG_ARCMD_REV<12:8>
//@Darren-vIO32WriteFldAlign_All((DDRPHY_SHU_CA_DLL2 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 9, SHU_CA_DLL2_RG_TX_ARCKE_DRVN_B0);
#if (fcFOR_CHIP_ID == fcA60868) // for 868 CS and CKE control together
vIO32WriteFldAlign((DDRPHY_REG_MISC_SHU_DRVING8 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 0xA, MISC_SHU_DRVING8_CS_DRVP);
vIO32WriteFldAlign((DDRPHY_REG_MISC_SHU_DRVING8 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 0xA, MISC_SHU_DRVING8_CS_DRVN);
#elif (fcFOR_CHIP_ID == fcMargaux)
// @Darren, confirm with ACD Alucary,
// MISC_SHU_DRVING8_CS_DRVP & MISC_SHU_DRVING8_CS_DRVN -> DA_TX_ARCKE_DRVP_C0[4:0] & DA_TX_ARCKE_DRVN_C0[4:0]
vIO32WriteFldAlign((DDRPHY_REG_MISC_SHU_DRVING8 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 0xF, MISC_SHU_DRVING8_CS_DRVP);
vIO32WriteFldAlign((DDRPHY_REG_MISC_SHU_DRVING8 + save_to_where * SHU_GRP_DDRPHY_OFFSET), 0x14, MISC_SHU_DRVING8_CS_DRVN);
#endif
DramcBroadcastOnOff(backup_broadcast);
}
//-------------------------------------------------------------------------
/** vImpCalVrefSel
* Set IMP_VREF_SEL for DRVP, DRVN, Run-time/Tracking
* (Refer to "IMPCAL Settings" document register "RG_RIMP_VREF_SEL" settings)
* @param p Pointer of context created by DramcCtxCreate.
* @param freq_region (enum): pass freq_region (IMP_LOW_FREQ/IMP_HIGH_FREQ) for LP4X
* @param u1ImpCalStage (U8): During DRVP, DRVN, run-time/tracking stages
* some vref_sel values are different
*/
//-------------------------------------------------------------------------
/* Definitions to make IMPCAL_VREF_SEL function more readable */
#define IMPCAL_STAGE_DRVP 0
#define IMPCAL_STAGE_DRVN 1
#define IMPCAL_STAGE_ODTP 2
#define IMPCAL_STAGE_ODTN 3
#define IMPCAL_STAGE_TRACKING 4
/* LP4X IMP_VREF_SEL w/o term ==== */
#define IMP_TRACK_LP4X_LOWFREQ_VREF_SEL 0x37 // for <= DDR3733
#define IMP_TRACK_LP4X_HIGHFREQ_VREF_SEL 0x3a // for > 3733 and Samsung NT-ODTN
/* LPDDR5 IMP_VREF_SEL w/o term ==== */
#define IMP_TRACK_LP5_LOWFREQ_VREF_SEL 0x38 // for <= DDR3733
#define IMP_TRACK_LP5_HIGHFREQ_VREF_SEL 0x3a // for > 3733 and Samsung NT-ODTN
static const U8 ImpLP4VrefSel[IMP_VREF_MAX][IMP_DRV_MAX] = {
/* DRVP DRVN ODTP ODTN */
/* IMP_LOW_FREQ */ {0x37, 0x33, 0x00, 0x37},
/* IMP_HIGH_FREQ */ {0x3a, 0x33, 0x00, 0x3a},
/* IMP_NT_ODTN */ {0x2a, 0x2a, 0x00, 0x3a}
};
static const U8 ImpLP5VrefSel[IMP_VREF_MAX][IMP_DRV_MAX] = {
/* DRVP DRVN ODTP ODTN */
/* IMP_LOW_FREQ */ {0x38, 0x33, 0x00, 0x38},
/* IMP_HIGH_FREQ */ {0x3a, 0x33, 0x00, 0x3a},
/* IMP_NT_ODTN */ {0x2a, 0x2a, 0x00, 0x3a}
};
/* Refer to "IMPCAL Settings" document register "RG_RIMP_VREF_SEL" settings */
// @Maoauo: DRVP/ODTN for IMP tracking. But DRVN not support IMP tracking. (before La_fite)
// DRVP/DRVN/ODTN for IMP tracking after Pe_trus
static void vImpCalVrefSel(DRAMC_CTX_T *p, DRAMC_IMP_T efreq_region, U8 u1ImpCalStage)
{
U8 u1RegTmpValue = 0;
U32 u4DrvFld = 0;
if (p->dram_type == TYPE_LPDDR4X)
{
if (u1ImpCalStage == IMPCAL_STAGE_TRACKING)
u1RegTmpValue = (efreq_region == IMP_LOW_FREQ) ? IMP_TRACK_LP4X_LOWFREQ_VREF_SEL : IMP_TRACK_LP4X_HIGHFREQ_VREF_SEL;
else
u1RegTmpValue = ImpLP4VrefSel[efreq_region][u1ImpCalStage];
}
else if (p->dram_type == TYPE_LPDDR5)
{
if (u1ImpCalStage == IMPCAL_STAGE_TRACKING)
u1RegTmpValue = (efreq_region == IMP_LOW_FREQ) ? IMP_TRACK_LP5_LOWFREQ_VREF_SEL : IMP_TRACK_LP5_HIGHFREQ_VREF_SEL;
else
u1RegTmpValue = ImpLP5VrefSel[efreq_region][u1ImpCalStage];
}
else
{
mcSHOW_ERR_MSG(("[vImpCalVrefSel] Warnning: Need confirm DRAM type for IMP_VREF_SEL !!!\n"));
#if __ETT__
while(1);
#endif
}
switch (u1ImpCalStage)
{
case IMPCAL_STAGE_DRVP:
u4DrvFld = SHU_CA_CMD12_RG_RIMP_VREF_SEL_DRVP;
break;
case IMPCAL_STAGE_DRVN:
u4DrvFld = SHU_CA_CMD12_RG_RIMP_VREF_SEL_DRVN;
break;
case IMPCAL_STAGE_ODTN:
u4DrvFld = SHU_CA_CMD12_RG_RIMP_VREF_SEL_ODTN;
break;
default:
mcSHOW_ERR_MSG(("[vImpCalVrefSel] Warnning: Need confirm u1ImpCalStage for SW IMP Calibration !!!\n"));
break;
}
// dbg msg after vref_sel selection
mcSHOW_DBG_MSG3(("[vImpCalVrefSel] IMP_VREF_SEL 0x%x, IMPCAL stage:%u, freq_region:%u\n",
u1RegTmpValue, u1ImpCalStage, efreq_region));
/* Set IMP_VREF_SEL register field's value */
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD12), u1RegTmpValue, u4DrvFld);
return;
}
static U32 DramcSwImpCalResult(DRAMC_CTX_T *p, const char *drvType, U32 u4Fld)
{
U32 u4ImpxDrv = 0, u4ImpCalResult = 0;
U32 u4CheckImpChange = (u4Fld == SHU_MISC_IMPCAL1_IMPDRVP)? 1: 0;
for (u4ImpxDrv = 0; u4ImpxDrv < 32; u4ImpxDrv++)
{
#if 0 // for A60868 no need
if (u4ImpxDrv == 16) //0~15, 29~31
u4ImpxDrv = 29;
#endif
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_IMPCAL1), u4ImpxDrv, u4Fld);
mcDELAY_US(1);
u4ImpCalResult = u4IO32ReadFldAlign((DDRPHY_REG_MISC_PHY_RGS_CMD), MISC_PHY_RGS_CMD_RGS_RIMPCALOUT);
mcSHOW_DBG_MSG2(("OCD %s=%d ,CALOUT=%d\n", drvType, u4ImpxDrv, u4ImpCalResult));
if (u4ImpCalResult == u4CheckImpChange)//first found
{
mcSHOW_DBG_MSG2(("\nOCD %s calibration OK! %s=%d\n\n", drvType, drvType, u4ImpxDrv));
break;
}
}
if (u4ImpxDrv == 32) // Can't find SwImp drv results
{
u4ImpxDrv = 31;
mcSHOW_DBG_MSG2(("\nOCD %s calibration FAIL! %s=%d\n\n", drvType, drvType, u4ImpxDrv));
}
return u4ImpxDrv;
}
DRAM_STATUS_T DramcSwImpedanceCal(DRAMC_CTX_T *p, U8 u1Para, DRAMC_IMP_T freq_region)
{
U32 u4DRVP_Result = 0xff, u4ODTN_Result = 0xff, u4DRVN_Result = 0xff;
//U32 u4BaklReg_DDRPHY_MISC_IMP_CTRL0, u4BaklReg_DDRPHY_MISC_IMP_CTRL1;
U32 u4BaklReg_DRAMC_REG_IMPCAL;
U8 backup_channel;
U32 backup_broadcast;
U8 u1DrvType = 0, u1CALI_ENP = 0, u1CALI_ENN = 0, u1DDR4 = 0;
U32 u4SwImpCalResult = 0, u4DrvFld = 0;
const char *drvStr = "NULL";
backup_broadcast = GetDramcBroadcast();
DramcBroadcastOnOff(DRAMC_BROADCAST_OFF);
//default set FAIL
vSetCalibrationResult(p, DRAM_CALIBRATION_SW_IMPEDANCE, DRAM_FAIL);
//Suspend: DA_RIMP_DMSUS=1
vIO32WriteFldMulti_All(DDRPHY_REG_MISC_LP_CTRL, P_Fld(0x0, MISC_LP_CTRL_RG_ARDMSUS_10) | \
P_Fld(0x0, MISC_LP_CTRL_RG_ARDMSUS_10_LP_SEL) | \
P_Fld(0x0, MISC_LP_CTRL_RG_RIMP_DMSUS_10) | \
P_Fld(0x0, MISC_LP_CTRL_RG_RIMP_DMSUS_10_LP_SEL));
//Disable IMP HW Tracking
//Hw Imp tracking disable for all channels Because SwImpCal will be K again when resume from DDR reserved mode
vIO32WriteFldAlign_All(DDRPHY_REG_MISC_IMPCAL, 0, MISC_IMPCAL_IMPCAL_HW);
backup_channel = p->channel;
vSetPHY2ChannelMapping(p, CHANNEL_A);
//Register backup
//u4BaklReg_DDRPHY_MISC_IMP_CTRL0 = u4IO32Read4B((DDRPHY_MISC_IMP_CTRL0));
//u4BaklReg_DDRPHY_MISC_IMP_CTRL1 = u4IO32Read4B((DDRPHY_MISC_IMP_CTRL1));
u4BaklReg_DRAMC_REG_IMPCAL = u4IO32Read4B(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL));
//RG_IMPCAL_VREF_SEL (now set in vImpCalVrefSel())
//RG_IMPCAL_LP3_EN=0, RG_IMPCAL_LP4_EN=1
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMP_CTRL1), 0, MISC_IMP_CTRL1_RG_RIMP_PRE_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL), P_Fld(0, MISC_IMPCAL_IMPCAL_CALI_ENN) | P_Fld(1, MISC_IMPCAL_IMPCAL_IMPPDP) | \
P_Fld(1, MISC_IMPCAL_IMPCAL_IMPPDN)); //RG_RIMP_BIAS_EN and RG_RIMP_VREF_EN move to IMPPDP and IMPPDN
if (is_lp5_family(p))
u1DDR4 = 0;
else //LPDDR4
u1DDR4 = 1;
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMP_CTRL1), P_Fld(1, MISC_IMP_CTRL1_RG_IMP_EN) | \
P_Fld(0, MISC_IMP_CTRL1_RG_RIMP_DDR3_SEL) | \
P_Fld(1, MISC_IMP_CTRL1_RG_RIMP_VREF_EN) | \
P_Fld(u1DDR4, MISC_IMP_CTRL1_RG_RIMP_DDR4_SEL));
mcDELAY_US(1);
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL), 1, MISC_IMPCAL_IMPCAL_CALI_EN);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_IMPCAL1), P_Fld(0, SHU_MISC_IMPCAL1_IMPDRVN) | P_Fld(0, SHU_MISC_IMPCAL1_IMPDRVP));
//LP4X: ODTN/DRVN/DRVP calibration start
for (u1DrvType = DRVP; u1DrvType < IMP_DRV_MAX; u1DrvType++) // Calibration sequence for DRVP, DRVN and ODTN
{
if (u1DrvType == ODTP) // no use, skip ODTP
continue;
/* Set IMP_VREF_SEL value for DRVP/DRVN and ODTN */
vImpCalVrefSel(p, freq_region, u1DrvType);
switch (u1DrvType)
{
case DRVP:
drvStr = "DRVP";
u1CALI_ENP = 0x1;
u1CALI_ENN = 0x0;
u4DrvFld = SHU_MISC_IMPCAL1_IMPDRVP;
u4DRVP_Result = 0;
break;
case DRVN:
case ODTN:
drvStr = (u1DrvType == DRVN)? "DRVN" : "ODTN";
u1CALI_ENP = 0x0;
u1CALI_ENN = (u1DrvType == DRVN)? 0x0: 0x1; // 0x1 change to ODTN path
u4DrvFld = SHU_MISC_IMPCAL1_IMPDRVN;
break;
default:
mcSHOW_ERR_MSG(("[DramcSwImpedanceCal] Warnning: Need confirm u1DrvType for SW IMP Calibration !!!\n"));
break;
}
// @A60868 for DRVn/p and ODTn select
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL), u1CALI_ENP, MISC_IMPCAL_IMPCAL_CALI_ENP); //MISC_IMP_CTRL1_RG_IMP_OCD_PUCMP_EN move to CALI_ENP
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL), u1CALI_ENN, MISC_IMPCAL_IMPCAL_CALI_ENN); //MISC_IMP_CTRL1_RG_RIMP_ODT_EN move to CALI_ENN
mcSHOW_DBG_MSG2(("\n\n\tK %s\n", drvStr));
//DRVP=DRVP_FINAL
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_MISC_IMPCAL1), u4DRVP_Result, SHU_MISC_IMPCAL1_IMPDRVP); //PUCMP_EN move to CALI_ENP
//RIMP_DRV05 for LP4/5
vIO32WriteFldAlign(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_CMD12), 0, SHU_CA_CMD12_RG_RIMP_DRV05);
//If RGS_TX_OCD_IMPCALOUTX=1
//RG_IMPX_DRVN++;
//Else save RG_IMPX_DRVN value and assign to DRVN
u4SwImpCalResult = DramcSwImpCalResult(p, drvStr, u4DrvFld);
switch (u1DrvType)
{
case DRVP:
u4DRVP_Result = u4SwImpCalResult;
break;
case DRVN:
u4DRVN_Result = u4SwImpCalResult;
break;
case ODTN:
u4ODTN_Result = u4SwImpCalResult;
break;
default:
mcSHOW_ERR_MSG(("[DramcSwImpedanceCal] Warnning: Need confirm u4SwImpCalResult for SW IMP Calibration !!!\n"));
break;
}
}
//Register Restore
vIO32Write4B(DRAMC_REG_ADDR(DDRPHY_REG_MISC_IMPCAL), u4BaklReg_DRAMC_REG_IMPCAL);
//vIO32Write4B((DDRPHY_MISC_IMP_CTRL0), u4BaklReg_DDRPHY_MISC_IMP_CTRL0);
//vIO32Write4B((DDRPHY_MISC_IMP_CTRL1), u4BaklReg_DDRPHY_MISC_IMP_CTRL1);
/*** default value if K fail
LP3: DRVP=8, DRVN=9
LP4: DRVP=6, DRVN=9, ODTN=14
LP4X(UT): DRVP=12, DRVN=9
LP4X(T): DRVP=5, DRVN=9, ODTN=14
LP4P: DRVP=8, DRVN=10
***/
mcSHOW_DBG_MSG(("[SwImpedanceCal] DRVP=%d, DRVN=%d, ODTN=%d\n", u4DRVP_Result, u4DRVN_Result, u4ODTN_Result));
#if 0//HYNIX_IMPX_ADJUST
if (u1Para)
{
u4ODTN_Result = ImpedanceAdjustment_Hynix(u4ODTN_Result, u1Para);
}
#endif
gDramcSwImpedanceResult[freq_region][DRVP] = u4DRVP_Result;
gDramcSwImpedanceResult[freq_region][DRVN] = u4DRVN_Result;
gDramcSwImpedanceResult[freq_region][ODTP] = 0;
gDramcSwImpedanceResult[freq_region][ODTN] = u4ODTN_Result;
#if RUNTIME_SHMOO_RELEATED_FUNCTION && SUPPORT_SAVE_TIME_FOR_CALIBRATION
{
U8 u1drv;
{
for (u1drv = 0; u1drv < 4; u1drv++)
{
if (p->femmc_Ready == 0)
p->pSavetimeData->u1SwImpedanceResule[freq_region][u1drv] = gDramcSwImpedanceResult[freq_region][u1drv];
else
{
gDramcSwImpedanceResult[freq_region][u1drv] = p->pSavetimeData->u1SwImpedanceResule[freq_region][u1drv];
vSetCalibrationResult(p, DRAM_CALIBRATION_SW_IMPEDANCE, DRAM_FAST_K);
}
}
}
}
#endif
mcSHOW_DBG_MSG(("freq_region=%d, Reg: DRVP=%d, DRVN=%d, ODTN=%d\n", freq_region, gDramcSwImpedanceResult[freq_region][DRVP],
gDramcSwImpedanceResult[freq_region][DRVN], gDramcSwImpedanceResult[freq_region][ODTN]));
#if APPLY_SIGNAL_WAVEFORM_SETTINGS_ADJUST
if ((p->dram_type == TYPE_LPDDR4) && (freq_region == 0))
{
gDramcSwImpedanceResult[freq_region][DRVP] = SwImpedanceAdjust(gDramcSwImpedanceResult[freq_region][DRVP], gDramcSwImpedanceAdjust[freq_region][DRVP]);
gDramcSwImpedanceResult[freq_region][DRVN] = SwImpedanceAdjust(gDramcSwImpedanceResult[freq_region][DRVN], gDramcSwImpedanceAdjust[freq_region][ODTN]);
}
else
{
gDramcSwImpedanceResult[freq_region][DRVP] = SwImpedanceAdjust(gDramcSwImpedanceResult[freq_region][DRVP], gDramcSwImpedanceAdjust[freq_region][DRVP]);
gDramcSwImpedanceResult[freq_region][ODTN] = SwImpedanceAdjust(gDramcSwImpedanceResult[freq_region][ODTN], gDramcSwImpedanceAdjust[freq_region][ODTN]);
}
mcSHOW_DBG_MSG(("freq_region=%d, Reg: DRVP=%d, DRVN=%d, ODTN=%d (After Adjust)\n", freq_region, gDramcSwImpedanceResult[freq_region][DRVP],
gDramcSwImpedanceResult[freq_region][DRVN], gDramcSwImpedanceResult[freq_region][ODTN]));
#endif
#if __FLASH_TOOL_DA__
if((gDramcSwImpedanceResult[freq_region][ODTN] ==0)||(gDramcSwImpedanceResult[freq_region][ODTN] >=31))
{
mcSHOW_DBG_MSG(("[WARNING] freq_region = %d, ODTN = %d ==> unexpect value\n", freq_region, gDramcSwImpedanceResult[freq_region][ODTN]));
PINInfo_flashtool.IMP_ERR_FLAG |= (0x1<<(freq_region+ODTN));
}
else if((gDramcSwImpedanceResult[freq_region][DRVP] ==0)||(gDramcSwImpedanceResult[freq_region][DRVP] >=31))
{
mcSHOW_DBG_MSG(("[WARNING] freq_region = %d, DRVP = %d ==> unexpect value\n", freq_region, gDramcSwImpedanceResult[freq_region][DRVP]));
PINInfo_flashtool.IMP_ERR_FLAG |= (0x1<<(freq_region+DRVP));
}
else if((gDramcSwImpedanceResult[freq_region][DRVN] ==0)||(gDramcSwImpedanceResult[freq_region][DRVN] >=31))
{
mcSHOW_DBG_MSG(("[WARNING] freq_region = %d, DRVN = %d ==> unexpect value\n", freq_region, gDramcSwImpedanceResult[freq_region][DRVN]));
PINInfo_flashtool.IMP_ERR_FLAG |= (0x1<<(freq_region+DRVN));
}
else
#endif
{
vSetCalibrationResult(p, DRAM_CALIBRATION_SW_IMPEDANCE, DRAM_OK);
}
mcSHOW_DBG_MSG3(("[DramcSwImpedanceCal] Done\n\n"));
vSetPHY2ChannelMapping(p, backup_channel);
DramcBroadcastOnOff(backup_broadcast);
return DRAM_OK;
}
#endif //SIMULATION_SW_IMPED
#if ENABLE_WRITE_DBI || TX_K_DQM_WITH_WDBI
void DramcWriteShiftMCKForWriteDBI(DRAMC_CTX_T *p, S8 iShiftMCK)
{
U8 ucDataRateDivShift = 0;
S8 s1UIMove = 0;
ucDataRateDivShift = u1MCK2UI_DivShift(p);
s1UIMove = iShiftMCK * (S8)(1 << ucDataRateDivShift);
ShiftDQUI(p, s1UIMove, ALL_BYTES);
}
#endif
#if ENABLE_DUTY_SCAN_V2
#define DutyPrintAllLog 0
#define DutyPrintCalibrationLog 0
#define DUTY_OFFSET_START -28
#define DUTY_OFFSET_END 28
#define DUTY_OFFSET_STEP 4
#define CLOCK_PI_START 0
#define CLOCK_PI_END 63
#if FOR_DV_SIMULATION_USED
#define CLOCK_PI_STEP 8
#else
#define CLOCK_PI_STEP 2
#endif
#define ClockDutyFailLowerBound 4500 // 45%
#define ClockDutyFailUpperBound 5500 // 55%
#define ClockDutyMiddleBound 5000 // 50%
/*
* duty form smallest to biggest
* 011111->011110->...->000001-->000000=100000->100001-->...->111111
*/
static U8 DramcDutyDelayRGSettingConvert(DRAMC_CTX_T *p, S8 scDutyDelay,
U8 *tDly)
{
U8 tDelay;
if (scDutyDelay < 0)
{
tDelay = -scDutyDelay;
}
else if (scDutyDelay > 0)
{
tDelay = scDutyDelay + (1 << 5);
}
else
{
tDelay = 0;
}
*tDly = tDelay;
return tDelay;
}
static void DramcClockDutySetClkDelayCell(DRAMC_CTX_T *p, S8 *scDutyDelay)
{
U8 u1ShuffleIdx = 0;
U32 save_offset;
U8 tDelay;
DramcDutyDelayRGSettingConvert(p, scDutyDelay[0], &tDelay);
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
for(u1ShuffleIdx = 0; u1ShuffleIdx<DRAM_DFS_SHUFFLE_MAX; u1ShuffleIdx++)
#endif
{
save_offset = u1ShuffleIdx * SHU_GRP_DDRPHY_OFFSET;
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_CA_TXDUTY + save_offset),
P_Fld(tDelay, SHU_CA_TXDUTY_DA_TX_ARCLK_DUTY_DLY));
}
}
static void DQSDutyScan_SetDqsDelayCell(DRAMC_CTX_T *p, S8 *scDutyDelay)
{
U8 u1ShuffleIdx = 0, u1DQSIdx;
U32 save_offset;
U8 tDelay[2];
// mcSHOW_DBG_MSG(("CH%d, Final DQS0 duty delay cell = %d\n", p->channel, scDutyDelay[0]));
// mcSHOW_DBG_MSG(("CH%d, Final DQS1 duty delay cell = %d\n", p->channel, scDutyDelay[1]));
for(u1DQSIdx=0; u1DQSIdx<2; u1DQSIdx++)
{
DramcDutyDelayRGSettingConvert(p, scDutyDelay[u1DQSIdx], &(tDelay[u1DQSIdx]));
}
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
for(u1ShuffleIdx = 0; u1ShuffleIdx<DRAM_DFS_SHUFFLE_MAX; u1ShuffleIdx++)
#endif
{
{
for(u1DQSIdx = 0; u1DQSIdx<2; u1DQSIdx++)
{
save_offset = u1ShuffleIdx * SHU_GRP_DDRPHY_OFFSET + u1DQSIdx*DDRPHY_AO_B0_B1_OFFSET;
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_TXDUTY) + save_offset,
P_Fld(tDelay[u1DQSIdx], SHU_B0_TXDUTY_DA_TX_ARDQS_DUTY_DLY_B0));
}
}
}
}
static void WCKDutyScan_SetWCKDelayCell(DRAMC_CTX_T *p, S8 *scDutyDelay)
{
U8 u1ShuffleIdx = 0, u1DQSIdx;
U32 save_offset;
U8 tDelay[2];
for(u1DQSIdx=0; u1DQSIdx<2; u1DQSIdx++)
{
DramcDutyDelayRGSettingConvert(p, scDutyDelay[u1DQSIdx], &(tDelay[u1DQSIdx]));
}
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
for(u1ShuffleIdx = 0; u1ShuffleIdx<DRAM_DFS_SHUFFLE_MAX; u1ShuffleIdx++)
#endif
{
{
for(u1DQSIdx = 0; u1DQSIdx<2; u1DQSIdx++)
{
save_offset = u1ShuffleIdx * SHU_GRP_DDRPHY_OFFSET + u1DQSIdx*DDRPHY_AO_B0_B1_OFFSET;
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_TXDUTY) + save_offset,
P_Fld(tDelay[u1DQSIdx], SHU_B0_TXDUTY_DA_TX_ARWCK_DUTY_DLY_B0));
}
}
}
}
#if APPLY_DQDQM_DUTY_CALIBRATION
static void DQDQMDutyScan_SetDQDQMDelayCell(DRAMC_CTX_T *p, U8 u1ChannelIdx, S8 *scDutyDelay, U8 k_type)
{
U8 u1ShuffleIdx = 0, u1DQSIdx;
U32 save_offset;
U8 tDelay[2];
for(u1DQSIdx=0; u1DQSIdx<2; u1DQSIdx++)
{
DramcDutyDelayRGSettingConvert(p, scDutyDelay[u1DQSIdx], &(tDelay[u1DQSIdx]));
}
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
for(u1ShuffleIdx = 0; u1ShuffleIdx<DRAM_DFS_SHUFFLE_MAX; u1ShuffleIdx++)
#endif
{
for(u1DQSIdx = 0; u1DQSIdx<2; u1DQSIdx++)
{
save_offset = u1ShuffleIdx * SHU_GRP_DDRPHY_OFFSET + u1DQSIdx*DDRPHY_AO_B0_B1_OFFSET;
if (k_type == DutyScan_Calibration_K_DQ)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_TXDUTY) + save_offset,
P_Fld(tDelay[u1DQSIdx], SHU_B0_TXDUTY_DA_TX_ARDQ_DUTY_DLY_B0));
}
if (k_type == DutyScan_Calibration_K_DQM)
{
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_REG_SHU_B0_TXDUTY) + save_offset,
P_Fld(tDelay[u1DQSIdx], SHU_B0_TXDUTY_DA_TX_ARDQM_DUTY_DLY_B0));
}
}
}
}
#if 0
void DQDQMDutyScan_CopyDQRG2DQMRG(DRAMC_CTX_T *p)
{
U8 u1ShuffleIdx = 0, u1DQSIdx, u1RankIdx = 0;
U32 save_offset;
U8 ucDQDQMDelay;
U8 ucRev_DQDQM_Bit0, ucRev_DQDQM_Bit1;
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
for(u1ShuffleIdx = 0; u1ShuffleIdx<DRAM_DFS_SHUFFLE_MAX; u1ShuffleIdx++)
#endif
{
for(u1DQSIdx = 0; u1DQSIdx<2; u1DQSIdx++)
{
save_offset = u1ShuffleIdx * SHU_GRP_DDRPHY_OFFSET + u1DQSIdx*DDRPHY_AO_B0_B1_OFFSET_0X80;
ucDQDQMDelay = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_SHU_B0_DQ3) + save_offset, SHU_B0_DQ3_RG_ARDQ_DUTYREV_B0_DQ_DLY);
ucRev_DQDQM_Bit0 = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_SHU_B0_DQ3) + save_offset, SHU_B0_DQ3_RG_TX_ARDQS0_PU_PRE_B0_BIT0);
ucRev_DQDQM_Bit1 = u4IO32ReadFldAlign(DRAMC_REG_ADDR(DDRPHY_SHU_B0_DQ3) + save_offset, SHU_B0_DQ3_RG_TX_ARDQS0_PU_PRE_B0_BIT0);
vIO32WriteFldMulti(DRAMC_REG_ADDR(DDRPHY_SHU_B0_DQ3) + save_offset, P_Fld(ucDQDQMDelay, SHU_B0_DQ3_RG_ARDQ_DUTYREV_B0_DQM_DLY)
| P_Fld(ucRev_DQDQM_Bit0, SHU_B0_DQ3_RG_TX_ARDQS0_PU_B0_BIT0)
| P_Fld(ucRev_DQDQM_Bit1, SHU_B0_DQ3_RG_TX_ARDQS0_PU_B0_BIT1));
}
}
}
#endif
#endif
S8 gcFinal_K_CLK_delay_cell[CHANNEL_NUM][DQS_NUMBER];
S8 gcFinal_K_DQS_delay_cell[CHANNEL_NUM][DQS_NUMBER];
S8 gcFinal_K_WCK_delay_cell[CHANNEL_NUM][DQS_NUMBER];
#if APPLY_DQDQM_DUTY_CALIBRATION
S8 gcFinal_K_DQ_delay_cell[CHANNEL_NUM][DQS_NUMBER];
S8 gcFinal_K_DQM_delay_cell[CHANNEL_NUM][DQS_NUMBER];
#endif
void DramcNewDutyCalibration(DRAMC_CTX_T *p)
{
U8 u1backup_channel, u1backup_rank;
#if(DQS_DUTY_SLT_CONDITION_TEST)
U16 u2TestCnt, u2FailCnt=0, u2TestCntTotal =20; //fra 400;
U8 u1ByteIdx, u1PI_FB;
U32 u4Variance;
#endif
u1backup_rank = u1GetRank(p);
vSetRank(p, RANK_0);
#if !FT_DSIM_USED
#if DUTY_SCAN_V2_ONLY_K_HIGHEST_FREQ
if((p->frequency == u2DFSGetHighestFreq(p)) && (Get_PRE_MIOCK_JMETER_HQA_USED_flag()==0))
#else
//TODO if(Get_PRE_MIOCK_JMETER_HQA_USED_flag()==0)
#endif
#endif
{
U8 u1ChannelIdx;
u1backup_channel = vGetPHY2ChannelMapping(p);
#if SUPPORT_SAVE_TIME_FOR_CALIBRATION
if(p->femmc_Ready==1)
{
for(u1ChannelIdx=CHANNEL_A; u1ChannelIdx<p->support_channel_num; u1ChannelIdx++)
{
vSetPHY2ChannelMapping(p, u1ChannelIdx);
DramcClockDutySetClkDelayCell(p, p->pSavetimeData->s1ClockDuty_clk_delay_cell[p->channel]);
DQSDutyScan_SetDqsDelayCell(p, p->pSavetimeData->s1DQSDuty_clk_delay_cell[p->channel]);
WCKDutyScan_SetWCKDelayCell(p, p->pSavetimeData->s1WCKDuty_clk_delay_cell[p->channel]);
#if APPLY_DQDQM_DUTY_CALIBRATION
DQDQMDutyScan_SetDQDQMDelayCell(p, p->channel, p->pSavetimeData->s1DQMDuty_clk_delay_cell[p->channel], DutyScan_Calibration_K_DQM);
DQDQMDutyScan_SetDQDQMDelayCell(p, p->channel, p->pSavetimeData->s1DQDuty_clk_delay_cell[p->channel], DutyScan_Calibration_K_DQ);
#endif
}
vSetPHY2ChannelMapping(p, u1backup_channel);
return;
}
#endif
vSetPHY2ChannelMapping(p, u1backup_channel);
}
vSetRank(p, u1backup_rank);
}
#endif