| /* $NoKeywords:$ */ |
| /** |
| * @file |
| * |
| * mtthrcSt.c |
| * |
| * Phy assisted DQS receiver enable seedless training |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: AGESA |
| * @e sub-project: (Mem/Tech) |
| * @e \$Revision: 84150 $ @e \$Date: 2012-12-12 15:46:25 -0600 (Wed, 12 Dec 2012) $ |
| * |
| **/ |
| /***************************************************************************** |
| * |
| * Copyright (c) 2008 - 2013, Advanced Micro Devices, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of Advanced Micro Devices, Inc. nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * *************************************************************************** |
| * |
| */ |
| |
| /* |
| *---------------------------------------------------------------------------- |
| * MODULES USED |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| |
| |
| #include "AGESA.h" |
| #include "amdlib.h" |
| #include "Ids.h" |
| #include "mm.h" |
| #include "mn.h" |
| #include "mt.h" |
| #include "mttEdgeDetect.h" |
| #include "Filecode.h" |
| CODE_GROUP (G1_PEICC) |
| RDATA_GROUP (G1_PEICC) |
| |
| #define FILECODE PROC_MEM_TECH_MTTHRCSEEDTRAIN_FILECODE |
| /*---------------------------------------------------------------------------- |
| 3 * DEFINITIONS AND MACROS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * TYPEDEFS AND STRUCTURES |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * PROTOTYPES OF LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| VOID |
| STATIC |
| MemTRdPosRxEnSeedSetDly3 ( |
| IN OUT MEM_TECH_BLOCK *TechPtr, |
| IN OUT UINT16 RcvEnDly, |
| IN OUT UINT8 ByteLane |
| ); |
| |
| VOID |
| STATIC |
| MemTRdPosRxEnSeedCheckRxEndly3 ( |
| IN OUT MEM_TECH_BLOCK *TechPtr |
| ); |
| /*---------------------------------------------------------------------------- |
| * EXPORTED FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| /*---------------------------------------------------------------------------- |
| * LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| /*----------------------------------------------------------------------------- |
| * |
| * |
| * This function checks each bytelane for no window error. |
| * |
| * |
| * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK |
| * @param[in,out] OptParam - Optional parameter |
| * |
| * @return TRUE |
| * ---------------------------------------------------------------------------- |
| */ |
| BOOLEAN |
| MemTTrackRxEnSeedlessRdWrNoWindBLError ( |
| IN OUT MEM_TECH_BLOCK *TechPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| UINT8 i; |
| SWEEP_INFO SweepData; |
| SweepData = *(SWEEP_INFO*)OptParam; |
| for (i = 0; i < ((TechPtr->NBPtr->MCTPtr->Status[SbEccDimms] && TechPtr->NBPtr->IsSupported[EccByteTraining]) ? 9 : 8) ; i++) { |
| // |
| /// Skip Bytelanes that have already reached the desired result |
| // |
| if ((SweepData.ResultFound & ((UINT16)1 << i)) == 0) { |
| if (SweepData.TrnDelays[i] == SweepData.EndDelay) { |
| if ((SweepData.EndResult & ((UINT16) (1 << i))) != 0) { |
| TechPtr->ByteLaneError[i] = TRUE; |
| } else { |
| TechPtr->ByteLaneError[i] = FALSE; |
| } |
| } |
| } |
| } |
| return TRUE; |
| } |
| /*----------------------------------------------------------------------------- |
| * |
| * |
| * This function checks each bytelane for small window error. |
| * |
| * |
| * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK |
| * @param[in,out] OptParam - Optional parameter(Unused) |
| * |
| * @return TRUE |
| * ---------------------------------------------------------------------------- |
| */ |
| BOOLEAN |
| MemTTrackRxEnSeedlessRdWrSmallWindBLError ( |
| IN OUT MEM_TECH_BLOCK *TechPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| TechPtr->ByteLaneError[TechPtr->Bytelane] = TRUE; |
| return TRUE; |
| } |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function sets the RxEn delay |
| * |
| * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK |
| * @param[in,out] *RcvEnDly - Receiver Enable Delay |
| * @param[in,out] *ByteLane - Bytelane |
| * |
| */ |
| VOID |
| STATIC |
| MemTRdPosRxEnSeedSetDly3 ( |
| IN OUT MEM_TECH_BLOCK *TechPtr, |
| IN OUT UINT16 RcvEnDly, |
| IN OUT UINT8 ByteLane |
| ) |
| { |
| TechPtr->NBPtr->ChannelPtr->RcvEnDlys[(TechPtr->ChipSel / TechPtr->NBPtr->CsPerDelay) * TechPtr->DlyTableWidth () + ByteLane] = RcvEnDly; |
| TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS ((TechPtr->ChipSel / TechPtr->NBPtr->CsPerDelay), ByteLane), RcvEnDly); |
| TechPtr->NBPtr->FamilySpecificHook[ResetRxFifoPtr] (TechPtr->NBPtr, TechPtr->NBPtr); |
| } |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function determines if the currert RxEn delay settings have failed |
| * |
| * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK |
| * |
| */ |
| VOID |
| STATIC |
| MemTRdPosRxEnSeedCheckRxEndly3 ( |
| IN OUT MEM_TECH_BLOCK *TechPtr |
| ) |
| { |
| UINT8 MaxDlyDimm; |
| TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &MaxDlyDimm); |
| TechPtr->NBPtr->SetMaxLatency (TechPtr->NBPtr, TechPtr->MaxDlyForMaxRdLat); |
| TechPtr->DqsRdWrPosSaved = 0; |
| MemTTrainDQSEdgeDetect (TechPtr); |
| } |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function executes RdDQS training and if fails adjusts the RxEn Gross results for |
| * each bytelane |
| * |
| * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK |
| * |
| * @return TRUE - All bytelanes pass |
| * @return FALSE - Some bytelanes fail |
| */ |
| BOOLEAN |
| MemTRdPosWithRxEnDlySeeds3 ( |
| IN OUT MEM_TECH_BLOCK *TechPtr |
| ) |
| { |
| UINT8 ByteLane; |
| UINT16 PassTestRxEnDly[MAX_BYTELANES_PER_CHANNEL + 1]; |
| UINT16 FailTestRxEnDly[MAX_BYTELANES_PER_CHANNEL + 1]; |
| UINT16 FinalRxEnCycle[MAX_BYTELANES_PER_CHANNEL + 1]; |
| UINT16 RxOrig[MAX_BYTELANES_PER_CHANNEL]; |
| UINT8 i; |
| UINT8 j; |
| UINT8 NumBLWithTargetFound; |
| UINT8 MaxByteLanes; |
| INT16 RxEn; |
| BOOLEAN status; |
| BOOLEAN EsbNoDqsPosSave; |
| BOOLEAN OutOfRange[MAX_BYTELANES_PER_CHANNEL]; |
| BOOLEAN ByteLanePass[MAX_BYTELANES_PER_CHANNEL]; |
| BOOLEAN ByteLaneFail[MAX_BYTELANES_PER_CHANNEL]; |
| BOOLEAN RxEnMemClkTested[MAX_BYTELANES_PER_CHANNEL][MAX_POS_RX_EN_SEED_GROSS_RANGE]; |
| BOOLEAN RxEnMemClkSt[MAX_BYTELANES_PER_CHANNEL][MAX_POS_RX_EN_SEED_GROSS_RANGE]; |
| BOOLEAN RxEnDlyTargetFound[MAX_BYTELANES_PER_CHANNEL]; |
| BOOLEAN DlyWrittenToReg[MAX_BYTELANES_PER_CHANNEL]; |
| UINT16 RxEnDlyTargetValue[MAX_BYTELANES_PER_CHANNEL]; |
| UINT8 AllByteLanesOutOfRange; |
| UINT8 AllByteLanesSaved; |
| UINT8 TotalByteLanesCheckedForSaved; |
| UINT8 MemClkCycle; |
| MEM_NB_BLOCK *NBPtr; |
| CH_DEF_STRUCT *ChannelPtr; |
| NBPtr = TechPtr->NBPtr; |
| ChannelPtr = TechPtr->NBPtr->ChannelPtr; |
| NumBLWithTargetFound = 0; |
| status = FALSE; |
| EsbNoDqsPosSave = TechPtr->NBPtr->MCTPtr->ErrStatus[EsbNoDqsPos]; |
| NBPtr->RdDqsDlyRetrnStat = RDDQSDLY_RTN_SUSPEND; |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\nStart HW RxEn Seedless training\n\n"); |
| // 1. Program D18F2x9C_x0D0F_0[F,8:0]30_dct[1:0][BlockRxDqsLock] = 1. |
| NBPtr->SetBitField (NBPtr, BFBlockRxDqsLock, 0x0100); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\tChip Select: %02x \n", TechPtr->ChipSel); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tRxEn Orig: "); |
| // |
| // Start sweep loops for RxEn Seedless Training |
| // |
| MaxByteLanes = (TechPtr->NBPtr->MCTPtr->Status[SbEccDimms] && TechPtr->NBPtr->IsSupported[EccByteTraining]) ? 9 : 8; //dmach |
| // |
| //Initialialize BL variables |
| // |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| OutOfRange[ByteLane] = FALSE; |
| ByteLanePass[ByteLane] = FALSE; |
| ByteLaneFail[ByteLane] = FALSE; |
| // 2. RxEnOrig = D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] result |
| // from 2.10.6.8.2 [Phy Assisted DQS Receiver Enable Training] |
| RxOrig[ByteLane] = TechPtr->RxOrig[ByteLane]; // Original RxEn Dly based on PRE results |
| RxEnDlyTargetFound[ByteLane] = FALSE; |
| RxEnDlyTargetValue[ByteLane] = 0; |
| IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RxOrig[ByteLane]); |
| for (i = 0; i < MAX_POS_RX_EN_SEED_GROSS_RANGE; i++) { |
| RxEnMemClkTested[ByteLane][i] = FALSE; |
| } |
| } |
| // Start MemClk delay sweep |
| for (i = 0; i < MAX_POS_RX_EN_SEED_GROSS_RANGE; i++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\ti: %02x\n", i); |
| // Start direction sweep (0, - Positive, 1 - negative) |
| for (j = 0; j < MAX_POS_RX_EN_SEED_GROSS_DIR; j++) { |
| // Edge detect may run twice to see Pass to fail transition |
| // It is not run if the value are already saved |
| // Fail test is only done if pass is found |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tj: %02x\n", j); |
| // Reset Bytelane Flags for next sweep |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| ByteLaneFail[ByteLane] = FALSE; |
| ByteLanePass[ByteLane] = FALSE; |
| OutOfRange[ByteLane] = FALSE; |
| } |
| if (i == 0 && j == 1) { |
| continue; // Since i & j are the same skip |
| } |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Target BL Found: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", ((RxEnDlyTargetFound[ByteLane] == TRUE) ? 'Y' : 'N')); |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t Target BL Value: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RxEnDlyTargetValue[ByteLane]); |
| } |
| ); |
| // |
| // Find the RxEn Delay for the Pass condition in the Pass to Fail transition |
| // "PassTestRxEnDly" |
| // |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t Setting PassTestRxEnDly\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t PassTestRxEnDly: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| // Calculate "PassTestRxEnDly" from current "RxEnDly" |
| // 3. RxEnOffset = MOD(RxEnOrig + 0x10, 0x40) |
| RxEn = (j == 0) ? ((INT16)RxOrig[ByteLane] + 0x10 + (0x40*i)) : ((INT16)RxOrig[ByteLane] + 0x10 - (0x40*i)); |
| // Check if RxEnDly is in a valid range |
| if ((RxEn >= NBPtr->MinRxEnSeedGross) && (RxEn <= NBPtr->MaxRxEnSeedTotal)) { |
| PassTestRxEnDly[ByteLane] = (UINT16)RxEn; |
| // 4. For each DqsRcvEn value beginning from RxEnOffset incrementing by 1 MEMCLK: |
| // A. Program D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] with |
| // the current value. |
| MemTRdPosRxEnSeedSetDly3 (TechPtr, PassTestRxEnDly[ByteLane], ByteLane); |
| OutOfRange[ByteLane] = FALSE; |
| } else { |
| PassTestRxEnDly[ByteLane] = RxOrig[ByteLane]; |
| OutOfRange[ByteLane] = TRUE; |
| } |
| } else { |
| PassTestRxEnDly[ByteLane] = RxEnDlyTargetValue[ByteLane]; |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", PassTestRxEnDly[ByteLane]); |
| } |
| // Check if all BLs out of Range at "PassTestRxEnDly" |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t OutOfRange: "); |
| AllByteLanesOutOfRange = 0; |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (OutOfRange[ByteLane]) { |
| AllByteLanesOutOfRange++; |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (OutOfRange[ByteLane] == TRUE) ? 'Y' : 'N'); |
| } |
| if (AllByteLanesOutOfRange == MaxByteLanes) { |
| continue; // All BLs out of range, so skip |
| } |
| // Check if all BLs saved Results at "PassTestRxEnDly" |
| AllByteLanesSaved = 0; |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| MemClkCycle = (UINT8) (PassTestRxEnDly[ByteLane] >> 5); |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| if (!RxEnMemClkTested[ByteLane][MemClkCycle]) { |
| AllByteLanesSaved++; |
| } |
| } |
| } |
| // Check if "RxEnDlyValueForPassCond" passed |
| if (AllByteLanesSaved != 0) { |
| // At least one BL has not been saved, so check if "PassTestRxEnDly" passed |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t Checking if PassTestRxEnDly Passes?\n\n"); |
| // 4B. Perform 2.10.6.8.5 [DQS Position Training]. |
| // Record the result for the current DqsRcvEn setting as a pass or fail depending if a data eye is found. |
| MemTRdPosRxEnSeedCheckRxEndly3 (TechPtr); |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\t Err Status: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (TechPtr->ByteLaneError[ByteLane] == TRUE) ? 'F' : 'P'); |
| } |
| ); |
| } else { |
| // All BLs saved, so use saved results for "PassTestRxEnDly" |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tAll BLs Saved at PassTestRxEnDly\n"); |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Save Err Stat: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| MemClkCycle = (UINT8) (PassTestRxEnDly[ByteLane] >> 5); |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", ((RxEnMemClkSt[ByteLane][MemClkCycle] == TRUE) ? 'F' : 'P')); |
| } |
| ); |
| } |
| // Update Saved values for "PassTestRxEnDly" |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| if (OutOfRange[ByteLane] == FALSE) { |
| MemClkCycle = (UINT8) (PassTestRxEnDly[ByteLane] >> 5); |
| if (!RxEnMemClkTested[ByteLane][MemClkCycle]) { |
| RxEnMemClkTested[ByteLane][MemClkCycle] = TRUE; |
| RxEnMemClkSt[ByteLane][MemClkCycle] = TechPtr->ByteLaneError[ByteLane]; |
| } |
| } |
| } |
| } |
| // |
| // Find the RxEn Delay for the Fail condition in the Pass to Fail transition |
| // "FailTestRxEnDly" |
| // |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| DlyWrittenToReg[ByteLane] = FALSE; |
| } |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| FailTestRxEnDly[ByteLane] = PassTestRxEnDly[ByteLane] + 0x40; |
| } |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t FailTestRxEnDly: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", FailTestRxEnDly[ByteLane]); |
| } |
| ); |
| // Check if all BLs Saved Results at FailTestRxEnDly |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tSetting FailTestRxEnDly"); |
| AllByteLanesSaved = 0; |
| TotalByteLanesCheckedForSaved = 0; |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| MemClkCycle = (UINT8) (FailTestRxEnDly[ByteLane] >> 5); |
| // Check if RxEnDly + 40 is valid |
| if ((FailTestRxEnDly[ByteLane] >= NBPtr->MinRxEnSeedGross) && (FailTestRxEnDly[ByteLane] <= NBPtr->MaxRxEnSeedTotal)) { |
| if (RxEnMemClkTested[ByteLane][MemClkCycle]) { |
| AllByteLanesSaved++; |
| } |
| OutOfRange[ByteLane] = FALSE; |
| } else { |
| OutOfRange[ByteLane] = TRUE; |
| } |
| TotalByteLanesCheckedForSaved++; |
| } |
| } |
| // Check if all BLs out of Range condition at FailTestRxEnDly |
| AllByteLanesOutOfRange = 0; |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t OutOfRange: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (OutOfRange[ByteLane]) { |
| AllByteLanesOutOfRange++; |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (OutOfRange[ByteLane] == TRUE) ? 'Y' : 'N'); |
| } |
| if (AllByteLanesOutOfRange == MaxByteLanes) { |
| continue; // All BLs out of range, so skip |
| } |
| // Setting FailTestRxEnDly for any BL that was not saved |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t FailTestRxEnDly: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| MemClkCycle = (UINT8) (PassTestRxEnDly[ByteLane] >> 5); |
| // Check if New RxEnDly has Passed |
| if ((RxEnMemClkTested[ByteLane][MemClkCycle] ? RxEnMemClkSt[ByteLane][MemClkCycle] : TechPtr->ByteLaneError[ByteLane]) == FALSE) { |
| if (OutOfRange[ByteLane] == FALSE) { |
| // BL has passed at "New RxEnDly", so check if "New RxEnDly" + 0x40 fails |
| MemClkCycle = (UINT8) (FailTestRxEnDly[ByteLane] >> 5); |
| if (!RxEnMemClkTested[ByteLane][MemClkCycle]) { |
| // Only Set Delays for ByteLanes that have not been already tested |
| MemTRdPosRxEnSeedSetDly3 (TechPtr, FailTestRxEnDly[ByteLane], ByteLane); |
| DlyWrittenToReg[ByteLane] = TRUE; |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'Y'); |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'N'); |
| } |
| ByteLanePass[ByteLane] = TRUE; |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'O'); |
| } |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'F'); |
| } |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'N'); |
| } |
| } |
| // Check if BLs that passed at PassTestRxEnDly fail at FailTestRxEnDly |
| if (AllByteLanesSaved != TotalByteLanesCheckedForSaved) { |
| // At least one BL has not been saved, so check if FailTestRxEnDly passed |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\n\t\t Checking if FailTestRxEnDly Fails?\n"); |
| MemTRdPosRxEnSeedCheckRxEndly3 (TechPtr); |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Err Status: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (TechPtr->ByteLaneError[ByteLane] == TRUE) ? 'F' : 'P'); |
| } |
| ); |
| } else { |
| // All BLs saved, so use saved results for FailTestRxEnDly |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tAll BLs Saved at PassTestRxEnDly\n"); |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t Save Err Stat: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| MemClkCycle = (UINT8) (FailTestRxEnDly[ByteLane] >> 5); |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (RxEnMemClkSt[ByteLane][MemClkCycle] == TRUE) ? 'F' : 'P'); |
| } |
| ); |
| } |
| // |
| // If BL failes at "FailTestRxEnDly" set FinalRxEnCycle |
| // |
| // Setting FinalRxEnCycle for any BL that Failed at FailTestRxEnDly |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n Set FinalRxEnCycle: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| MemClkCycle = (UINT8) (FailTestRxEnDly[ByteLane] >> 5); |
| if (RxEnMemClkTested[ByteLane][MemClkCycle] ? RxEnMemClkSt[ByteLane][MemClkCycle] == TRUE : (TechPtr->ByteLaneError[ByteLane] && DlyWrittenToReg[ByteLane])) { |
| FinalRxEnCycle[ByteLane] = PassTestRxEnDly[ByteLane] - 0x10; |
| if (((UINT16) FinalRxEnCycle[ByteLane] >= NBPtr->MinRxEnSeedGross) && ((UINT16) FinalRxEnCycle[ByteLane] <= NBPtr->MaxRxEnSeedTotal)) { |
| // Since FailTestRxEnDly, we can set FinalRxEnCycle |
| MemTRdPosRxEnSeedSetDly3 (TechPtr, (UINT16) FinalRxEnCycle[ByteLane], ByteLane); |
| ByteLaneFail[ByteLane] = TRUE; |
| OutOfRange[ByteLane] = FALSE; |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'Y'); |
| } else { |
| OutOfRange[ByteLane] = TRUE; |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'N'); |
| } |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'F'); |
| OutOfRange[ByteLane] = FALSE; |
| } |
| } else { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", 'Y'); |
| } |
| } |
| // Update Saved values for FailTestRxEnDly |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| if (OutOfRange[ByteLane] == FALSE) { |
| MemClkCycle = (UINT8) (FailTestRxEnDly[ByteLane] >> 5); |
| if (!RxEnMemClkTested[ByteLane][MemClkCycle] && DlyWrittenToReg[ByteLane]) { |
| RxEnMemClkTested[ByteLane][MemClkCycle] = TRUE; |
| RxEnMemClkSt[ByteLane][MemClkCycle] = TechPtr->ByteLaneError[ByteLane]; |
| } |
| } |
| } |
| } |
| // Check for out of Range condition |
| AllByteLanesOutOfRange = 0; |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t OutOfRange: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (OutOfRange[ByteLane]) { |
| AllByteLanesOutOfRange++; |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (OutOfRange[ByteLane] == TRUE) ? 'Y' : 'N'); |
| } |
| if (AllByteLanesOutOfRange == MaxByteLanes) { |
| continue; // All BLs out of range so skip |
| } |
| IDS_HDT_CONSOLE_DEBUG_CODE ( |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n FinalRxEnCycle: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", (UINT16) FinalRxEnCycle[ByteLane]); |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n ByteLaneFail: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (ByteLaneFail[ByteLane] == TRUE) ? 'Y' : 'N'); |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n ByteLanePass: "); |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| IDS_HDT_CONSOLE (MEM_FLOW, " %c ", (ByteLanePass[ByteLane] == TRUE) ? 'Y' : 'N'); |
| } |
| ); |
| // |
| // Check for exit condition |
| // PassTestRxEnDly = Pass and FailTestRxEnDly[ByteLane] = Fail |
| // If found, use "FinalRxEnCycle" as final RxEnDly value |
| // |
| // 5. Process the array of results and determine a pass-to-fail transition. |
| NumBLWithTargetFound = 0; |
| for (ByteLane = 0; ByteLane < MaxByteLanes; ByteLane++) { |
| if (RxEnDlyTargetFound[ByteLane] == FALSE) { |
| // Check if the current BL has found its target |
| if (ByteLanePass[ByteLane] == TRUE && ByteLaneFail[ByteLane] == TRUE) { |
| RxEnDlyTargetFound[ByteLane] = TRUE; |
| NumBLWithTargetFound++; |
| RxEnDlyTargetValue[ByteLane] = FinalRxEnCycle[ByteLane]; |
| } else { |
| RxEnDlyTargetFound[ByteLane] = FALSE; |
| } |
| } else { |
| // BL has already failed and passed, so increment both flags |
| NumBLWithTargetFound++; |
| } |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n"); |
| // Check for exit condition |
| if (NumBLWithTargetFound == MaxByteLanes) { |
| // Exit condition found, so setting new RDQS based on RxEn-0x10 \n\n |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Setting new RDQS based on FinalRxEnCycle \n\n"); |
| // 5 A. DqsRcvEnCycle = the total delay value of the pass result. |
| // B. Program D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] = |
| // DqsRcvEnCycle - 0x10. |
| NBPtr->RdDqsDlyRetrnStat = RDDQSDLY_RTN_NEEDED; |
| MemTRdPosRxEnSeedCheckRxEndly3 (TechPtr); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n"); |
| status = TRUE; |
| break; |
| } else { |
| status = FALSE; |
| } |
| } |
| // Check for exit condition |
| if (NumBLWithTargetFound == MaxByteLanes) { |
| status = TRUE; |
| break; |
| } else { |
| status = FALSE; |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n"); |
| } |
| TechPtr->NBPtr->MCTPtr->ErrStatus[EsbNoDqsPos] = EsbNoDqsPosSave; |
| if (i == MAX_POS_RX_EN_SEED_GROSS_RANGE) { |
| TechPtr->NBPtr->MCTPtr->ErrStatus[EsbNoDqsPos] = TRUE; |
| } |
| |
| // 6. Program D18F2x9C_x0D0F_0[F,8:0]30_dct[1:0][BlockRxDqsLock] = 0. |
| NBPtr->SetBitField (NBPtr, BFBlockRxDqsLock, 0); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\nEnd HW RxEn Seedless training\n\n"); |
| return status; |
| } |