diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c | 1112 |
1 files changed, 1112 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c new file mode 100644 index 0000000000..090a9379a9 --- /dev/null +++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c @@ -0,0 +1,1112 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mfRdWr2DEyeRimSearch.c + * + * Eye Rim Sampling Algorithm for use in 2D Read DQS or 2D Write Data Training + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Feat/RdWr2DTraining) + * @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 "AdvancedApi.h" +#include "GeneralServices.h" +#include "Ids.h" +#include "heapManager.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mport.h" +#include "merrhdl.h" +#include "OptionMemory.h" +#include "mfRdWr2DTraining.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +#define FILECODE PROC_MEM_FEAT_RDWR2DTRAINING_MFRDWR2DEYERIMSEARCH_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +BOOLEAN +STATIC +MemFInitializeEyeRimSearch ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +VOID +STATIC +MemTEyeFill ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +UINT8 +STATIC +DetermineSavedState ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ); + +UINT8 +STATIC +GetPassFailValue ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ); + +VOID +STATIC +SetPassFailValue ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x, + IN UINT8 result + ); + +VOID +STATIC +SetSavedState ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x, + IN UINT8 result + ); + +INT8 +STATIC +Get1DTrainedEyeCenter ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane + ); + +BOOLEAN +STATIC +CheckForFail ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ); + + +INT8 +STATIC +xlateY ( + IN INT8 y + ); + +BOOLEAN +STATIC +ClearSampledPassResults ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +UINT32 +STATIC +CompareInPhase ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +UINT32 +STATIC +Compare180Phase ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +VOID +STATIC +ProgramVref ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 Vref + ); + +VOID +STATIC +StartAggressors ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN BOOLEAN TurnOn + ); + +/* -----------------------------------------------------------------------------*/ +/** + * + * Initialize Eye Rim Search + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return BOOLEAN + * TRUE + */ +BOOLEAN +STATIC +MemFInitializeEyeRimSearch ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + MEM_TECH_BLOCK *TechPtr; + UINT8 lane; + UINT8 vref; + MEM_RD_WR_2D_ENTRY *Data; + MEM_RD_WR_2D_RIM_ENTRY *RimData; + + ASSERT (NBPtr != NULL); + TechPtr = NBPtr->TechPtr; + Data = TechPtr->RdWr2DData; + RimData = Data->SavedData; + // + // Set Boundaries + // + RimData->xMax = Data->MaxRdWrSweep - 1; + RimData->yMax = (NBPtr->TotalMaxVrefRange / 2) - 1; + RimData->xMin = RimData->xMax * -1; + RimData->yMin = RimData->yMax * -1; + + RimData->ParallelSampling = EYERIM_PARALLEL_SAMPLING; + RimData->BroadcastDelays = EYERIM_BROADCAST_DELAYS; + RimData->Dirs[0] = 1; + RimData->Dirs[1] = -1; + + RimData->SampleCount = 0; + RimData->VrefUpdates = 0; + RimData->RdWrDlyUpdates = 0; + for (lane = 0; lane < MemFRdWr2DGetMaxLanes (NBPtr); lane ++ ) { + for ( vref = 0; vref < NBPtr->TotalMaxVrefRange; vref ++ ) { + // 00b = state not saved + // 01b = state saved + RimData->LaneSaved[lane].Vref[vref].PosRdWrDly = 0; + RimData->LaneSaved[lane].Vref[vref].NegRdWrDly = 0; + // 00b = Fail + // 01b = Pass + Data->Lane[lane].Vref[vref].PosRdWrDly = 0; + Data->Lane[lane].Vref[vref].NegRdWrDly = 0; + } + } + if (TechPtr->Direction == DQS_READ_DIR) { + NBPtr->MaxSeedCount = MAX_2D_RD_SEED_COUNT; + } else { + // + // Set the seed count in terms of the Total desired bit times + // + NBPtr->MaxSeedCount = (UINT8) (NBPtr->TotalBitTimes2DWrTraining / (256 * 8 * MIN ( 1, NBPtr->MaxAggressorDimms[NBPtr->Dct]))); + }; + TechPtr->DqsRdWrPosSaved = 0; + IDS_HDT_CONSOLE (MEM_FLOW, "\n\tTotal Bit Times: %d Max Seed Count: %d\n",(TechPtr->Direction == DQS_READ_DIR) ? NBPtr->TotalBitTimes2DRdTraining:NBPtr->TotalBitTimes2DWrTraining,NBPtr->MaxSeedCount); + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * This function collects data for Eye Rim Search + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] *OptParam - Not Used + * + * @return BOOLEAN + * TRUE - No Errors occurred + * FALSE - Errors occurred + * + */ +BOOLEAN +MemFRdWr2DEyeRimSearch ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN VOID * OptParam + ) +{ + UINT8 lane; + UINT8 j; + UINT8 k; + INT8 ydir; + INT8 xdir; + INT8 xi; + INT8 yi; + INT8 x; + INT8 y; + INT8 xmax; + INT8 ymax; + INT8 xmin; + INT8 ymin; + INT8 xo; + INT8 xt; + INT8 yo; + INT8 yt; + UINT8 slane; + UINT8 result; + INT8 states[2]; + UINT8 InitialCS; + UINT8 ChipSel; + UINT8 Aggr; + UINT8 SeedCount; + UINT32 InPhaseResult; + UINT32 PhaseResult180; + UINT32 Result; + MEM_RD_WR_2D_ENTRY *Data; + MEM_RD_WR_2D_RIM_ENTRY RimData; + MEM_TECH_BLOCK *TechPtr; + RD_WR_2D *VrefPtr; + ALLOCATE_HEAP_PARAMS AllocHeapParams; + + ASSERT (NBPtr != NULL); + TechPtr = NBPtr->TechPtr; + Data = TechPtr->RdWr2DData; + // + // Allocate Storage for Rim Search + // + AllocHeapParams.RequestedBufferSize = MemFRdWr2DGetMaxLanes (NBPtr) * NBPtr->TotalMaxVrefRange * sizeof (RD_WR_2D); + AllocHeapParams.BufferHandle = AMD_MEM_2D_RD_WR_RIM_HANDLE; + AllocHeapParams.Persist = HEAP_LOCAL_CACHE; + if (HeapAllocateBuffer (&AllocHeapParams, &NBPtr->MemPtr->StdHeader) == AGESA_SUCCESS) { + VrefPtr = (RD_WR_2D *) AllocHeapParams.BufferPtr; + } else { + SetMemError (AGESA_FATAL, NBPtr->MCTPtr); + PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_2D, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader); + return FALSE; + } + for (lane = 0; lane < MemFRdWr2DGetMaxLanes (NBPtr); lane++) { + RimData.LaneSaved[lane].Vref = &VrefPtr[lane * NBPtr->TotalMaxVrefRange]; + } + Data->SavedData = &RimData; + + MemFInitializeEyeRimSearch (NBPtr); + NBPtr->FamilySpecificHook[RdWr2DSelectIntExtVref] (NBPtr, NULL); + InitialCS = TechPtr->ChipSel; + NBPtr->FamilySpecificHook[Adjust2DPhaseMaskBasedOnEcc] (NBPtr, &NBPtr); + NBPtr->FamilySpecificHook[RdWr2DInitVictim] (NBPtr, NULL); + // + // EnableDisable continuous writes on the agressor channels + // + + for (Aggr = 0; Aggr < MAX (1 , NBPtr->MaxAggressorDimms[NBPtr->Dct]) ; Aggr += (NBPtr->IsSupported[PerDimmAggressors2D] ? 2 : NBPtr->CsPerDelay) ) { + ClearSampledPassResults (NBPtr); + // + // Enable continuous writes on the aggressors + // + StartAggressors (NBPtr, TRUE); + for (ChipSel = InitialCS; ChipSel < (InitialCS + NBPtr->CsPerDelay); ChipSel++) { + xmax = RimData.xMax; + xmin = RimData.xMin; + ymax = RimData.yMax; + ymin = RimData.yMin; + if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) != 0) { + TechPtr->ChipSel = ChipSel; + Data->RdWrDly = Data->MaxRdWrSweep; + for (lane = 0; lane < MemFRdWr2DGetMaxLanes (NBPtr); lane ++ ) { + // + // Two loops to handle each quadrant from the trained point + // + for ( j = 0; j < 2; j++) { + ydir = RimData.Dirs[j]; + for ( k = 0; k < 2; k++) { + xdir = RimData.Dirs[k]; + // + // Sample Loops - stay w/n the defined quadrant + // assume xmax = -1 * xmin, ymax = -1 * ymin + // initial point must always pass + // end point - boundary or two consecutive fails along the y-axis + // + // Initial dx, dy step state + // Starting dy at 8 to reduce samples necessary searching for the eye height + states[0] = 0; + states[1] = 8; + // xi and yi are inital trained points, assumed to be inside the eye + // These set the coordinate syst em for the quadrants + xi = Get1DTrainedEyeCenter (NBPtr, lane); + yi = 0; // Initial center is always at Vref nominal + x = xi; + y = yi; + while ( + ((xdir > 0 && x >= xi && x <= xmax) || + (xdir < 0 && x <= xi && x >= xmin)) && + ((ydir > 0 && y >= yi && y <= ymax) || + (ydir < 0 && y <= yi && y >= ymin)) && + !(y == yi && (xdir * (xi - x) >= 2)) + ) { + // + // Decide if result is already sampled, or need to take the sample + // + if (0 == DetermineSavedState (NBPtr, lane, y, x)) { + RimData.SampleCount++; + // + // Result for this point is not in the cache, sample it + // + for (slane = 0; slane < MemFRdWr2DGetMaxLanes (NBPtr); slane ++ ) { + if (!RimData.ParallelSampling && ( slane != lane)) { + continue; + } + // + // Calculate the relative offset from the initial trained position for this lane + // + xo = Get1DTrainedEyeCenter (NBPtr, slane); + yo = 0; + xt = xo + (x - xi); + yt = yo + (y - yi); + if (xt > xmax || xt < xmin || yt > ymax || yt < ymin) { + continue; + } + // + // Update the vref and lane delays (yt, xt) + // + if (slane == lane) { + // + // For processors w/ a single Vref per channel, only set Vref once + // + if ( NBPtr->Vref != xlateY (yt)) { + // + // If not already set + // + RimData.VrefUpdates++; + NBPtr->Vref = xlateY (yt); + ProgramVref (NBPtr, NBPtr->Vref); + } + } + if (RimData.BroadcastDelays) { + // + // When BroadcastDelays, only set RdDqs once + // + if (slane == lane) { + // + // If current lane + // + if ( Data->RdWrDly != (UINT8) (xt & RimData.xMax)) { + // + // If the not already set + // Account for rollover. + // + RimData.RdWrDlyUpdates++; + Data->RdWrDly = (UINT8) (xt & RimData.xMax); + NBPtr->FamilySpecificHook[RdWr2DProgramDelays] (NBPtr, &Data->RdWrDly); + } + } + } else { + // + // For Reads, Program all RdDqs Delay Values the same + // For Writes, Program all WrDat Values with same value offset by WrDqs for that lane. + // + if ( Data->RdWrDly != (UINT8) (xt & RimData.xMax)) { + // + // If the not already set + // Account for rollover. + // + RimData.RdWrDlyUpdates++; + Data->RdWrDly = (UINT8) (xt & RimData.xMax); + MemTSetDQSDelayAllCSR (TechPtr, (UINT8) (xt & RimData.xMax)); + } + } + } + // + // Perform Memory RW test + // + InPhaseResult = 0; + PhaseResult180 = 0; + NBPtr->FamilySpecificHook[RdWr2DInitVictimChipSel] (NBPtr, NULL); + for (SeedCount = 0; SeedCount < NBPtr->MaxSeedCount; SeedCount++) { + // + // Begin continuous reads and writes on the victim channels + // + NBPtr->FamilySpecificHook[RdWr2DStartVictim] (NBPtr, &SeedCount); + // + // Occasionally check if all trained lanes have already failed + // + if ((NBPtr->MaxSeedCount < 4) || ((SeedCount % (NBPtr->MaxSeedCount / 4)) == 0)) { + InPhaseResult |= CompareInPhase (NBPtr); + PhaseResult180 |= Compare180Phase (NBPtr); + if (((InPhaseResult & NBPtr->PhaseLaneMask) == NBPtr->PhaseLaneMask) && + ((PhaseResult180& NBPtr->PhaseLaneMask) == NBPtr->PhaseLaneMask)) { + break; + } + } + } + // + // Obtain the results + // + for (slane = 0; slane < MemFRdWr2DGetMaxLanes (NBPtr); slane ++ ) { + if (!RimData.ParallelSampling && (slane != lane)) { + continue; + } + // + // Calculate the relative offset from legacy trained + // + xo = Get1DTrainedEyeCenter (NBPtr, RimData.BroadcastDelays?lane:slane); + yo = 0; + xt = xo + (x - xi); + yt = yo + (y - yi); + if (xt > xmax || xt < xmin || yt > ymax || yt < ymin) { + continue; + } + // + // In this example, data{}{}{} = 1 is a Fail, 0 is a Pass + // In-Phase Results + // + if (CheckForFail (NBPtr, slane, yt, xt)) { + // + // Don't overwrite a fail + // + if (xt >= 0) { + if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) == 0) { + // x8, so combine "Nibble X" and "Nibble X+1" results + Result = (InPhaseResult >> (slane * 2)) & 0x03; + } else { + // x4, so use "Nibble" results + Result = (InPhaseResult >> slane) & 0x01; + } + SetPassFailValue (NBPtr, slane, yt, xt, (UINT8) (Result & 0x0F)); + SetSavedState (NBPtr, slane, yt, xt, (UINT8) (Result & 0x0F)); + } else { + if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) == 0) { + // x8, so combine "Nibble X" and "Nibble X+1" results + Result = (PhaseResult180 >> (slane * 2)) & 0x03; + } else { + // x4, so use "Nibble" results + Result = (PhaseResult180 >> slane) & 0x01; + } + SetPassFailValue (NBPtr, slane, yt, xt, (UINT8) (Result & 0x0F)); + SetSavedState (NBPtr, slane, yt, xt, (UINT8) (Result & 0x0F)); + } + } + } + } + // Decide the next sample point based on the result of the current lane + result = GetPassFailValue (NBPtr, lane, y, x); + InPhaseResult = 0; + PhaseResult180 = 0; + // States && comments are relative to the ++ Quadrant + if (result == 3) { + // Current Pass + if (states[0] > 0 || states[1] > 0) { + if (states[1] > 1 && y * ydir <= ymax - states[1]) { + // Current Pass, Continue searching up by leaps + states[0] = 0; + } else if (states[1] > 1 && y * ydir <= ymax - 4) { + // Current Pass, Continue searching up by leaps + states[0] = 0; + states[1] = 4; + } else if (states[1] > 1 && y * ydir <= ymax - 2) { + // Current Pass, Continue searching up by leaps + states[0] = 0; + states[1] = 2; + } else if (y * ydir <= ymax - 1) { + // Current Pass, Continue searching up by one + states[0] = 0; + states[1] = 1; + } else if (y * ydir == ymax) { + // Current Pass and at the top edge, Move right + states[0] = 1; + states[1] = 0; + } else { + ASSERT (FALSE); + } + } else { + // Move right one + states[0] = 1; + states[1] = 0; + } + } else if (result == 2) { + // Current Fail + if (states[0] > 0) { + // Search down and left + states[0] = -1; + states[1] = -1; + } else if (states[1] > 1 || states[1] < 0) { + // Search down + states[0] = 0; + states[1] = -1; + } else if (states[1] == 1) { + // Move down and right + states[0] = 1; + states[1] = -1; + } else { + ASSERT (FALSE); + } + } else { + ASSERT (FALSE); + } + // Update the coordinates based on the new state and quadrant direction + x += xdir * states[0]; + y += ydir * states[1]; + } + } + } + } + } + } + // + // Disable continuous writes on the agressor channels + // + StartAggressors (NBPtr, FALSE); + } + IDS_HDT_CONSOLE (MEM_FLOW,"\n\tSampleCount:%d",RimData.SampleCount); + IDS_HDT_CONSOLE (MEM_FLOW,"\t\tVref Updates:%d",RimData.VrefUpdates); + IDS_HDT_CONSOLE (MEM_FLOW,"\t\tRdDqs Dly Updates:%d\n",RimData.RdWrDlyUpdates); + // + // Finilazing Victim Continuous writes + // + NBPtr->FamilySpecificHook[RdWr2DFinalizeVictim] (NBPtr, NULL); + TechPtr->ChipSel = InitialCS; + // + // Fill eye based on Rim Search results + // + MemTEyeFill (NBPtr); + // + // Display the results the completed eye + // + MemFRdWr2DDisplaySearch (NBPtr, Data); + // + // Restore environment settings after training + // + if (HeapDeallocateBuffer (AMD_MEM_2D_RD_WR_RIM_HANDLE, &NBPtr->MemPtr->StdHeader) != AGESA_SUCCESS) { + SetMemError (AGESA_FATAL, NBPtr->MCTPtr); + PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_DEALLOCATE_FOR_2D, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader); + } + return TRUE; +} + + +/* -----------------------------------------------------------------------------*/ +/** + * Fill the data eye + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ +VOID +STATIC +MemTEyeFill ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + INT8 x; + INT8 y; + UINT8 lane; + UINT8 result; + INT8 yLastPass; + UINT8 xMax; + UINT8 yMax; + UINT8 xMin; + UINT8 yMin; + BOOLEAN FirstPassFound; + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + SavedData = ((MEM_RD_WR_2D_ENTRY*)NBPtr->TechPtr->RdWr2DData)->SavedData; + + xMax = SavedData->xMax; + yMax = SavedData->yMax; + xMin = SavedData->xMin; + yMin = SavedData->yMin; + for (lane = 0; lane < MemFRdWr2DGetMaxLanes (NBPtr); lane++) { + for (x = xMin ; x <= xMax ; x++) { + FirstPassFound = FALSE; + yLastPass = yMin; + // + // Scan for the last passing value + // + for (y = yMax ; y >= yLastPass ; y--) { + result = GetPassFailValue (NBPtr, lane, y, x); + if (result == 0) { + // + // Not Saved, Mark it as FAIL. (Should already be cleared) + // + } else if (result == 2) { + // + // FAIL, so Mark as FAIL (Do nothing) + // + } else if (result == 3) { + // + // PASS, Mark it and save y value (This will end the loop) + // + SetPassFailValue (NBPtr, lane, y, x, result); + yLastPass = y; + } else { + ASSERT (FALSE); + } + } + // + // Scan for the first pass, the fill until the last pass + // + for (y = yMin ; y < yLastPass ; y++) { + result = GetPassFailValue (NBPtr, lane, y, x); + if (result == 0) { + // + // Not Saved, if we've already found a first Passing value, mark it as a PASS + // otherwise, mark it as FAIL. (Should already be cleared) + // + if (FirstPassFound == TRUE) { + SetPassFailValue (NBPtr, lane, y, x, result); + } + } else if (result == 2) { + // + // FAIL, so Mark as FAIL (Do nothing) + // + } else if (result == 3) { + // + // PASS, Mark it and set FirstPassFound + // + SetPassFailValue (NBPtr, lane, y, x, result); + FirstPassFound = TRUE; + } else { + ASSERT (FALSE); + } + } // y Loop + } //x Loop + } // Lane Loop +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Get the 1D trained center + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in] lane - UINT8 of current lane + * + * @return INT8 - Eye Center + */ +INT8 +STATIC +Get1DTrainedEyeCenter ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane + ) +{ + MEM_TECH_BLOCK *TechPtr; + ASSERT (NBPtr != NULL); + TechPtr = NBPtr->TechPtr; + if (TechPtr->Direction == DQS_READ_DIR) { + if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) == 0) { + // Program Byte based for x8 and x16 + return (INT8)NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + lane]; + } else { + return (INT8)NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + (lane >> 1)]; + } + } else { + return (INT8) (NBPtr->ChannelPtr->WrDatDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + lane] - + NBPtr->ChannelPtr->WrDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + lane]); + } +} + + +/* -----------------------------------------------------------------------------*/ +/** + * + * Determine if a Byte Lane result has been saved + * + * @param[in,out] *NBPtr - Pointer to MEM_NB_BLOCK + * @param[in] lane - Current lane + * @param[in] y - Vref value + * @param[in] x - Delay + * + * @return UINT8 + * 1 - value saved + * 0 - value not saved + */ +UINT8 +STATIC +DetermineSavedState ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ) +{ + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + SavedData = ((MEM_RD_WR_2D_ENTRY*)NBPtr->TechPtr->RdWr2DData)->SavedData; + + if (x >= 0) { + return (UINT8) (SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1); + } else { + return (UINT8) (SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1); + } +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Determine if a failure has occured + * + * @param[in,out] *NBPtr - Pointer to MEM_NB_BLOCK + * @param[in] lane - Current lane + * @param[in] y - Vref value + * @param[in] x - Delay Value + * + * @return BOOLEAN + * FALSE - Fail + * TRUE - Pass + */ +BOOLEAN +STATIC +CheckForFail ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ) +{ + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + SavedData = ((MEM_RD_WR_2D_ENTRY*)NBPtr->TechPtr->RdWr2DData)->SavedData; + + if (x >= 0) { + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // value not saved, so it is not fail + return TRUE; + } else { + // value saved, so examine result + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // result = fail + return FALSE; + } else { + // result = pass + return TRUE; + } + } + } else { + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // value not saved, so it is not fail + return TRUE; + } else { + // value saved, so examine result + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // result = fail + return FALSE; + } else { + // result = pass + return TRUE; + } + } + } +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Get pass fail state of lane + * + * @param[in,out] *NBPtr - Pointer to MEM_NB_BLOCK + * @param[in] lane - Current lane + * @param[in] y - Vref value + * @param[in] x - Delay Value + * + * @return UINT8 + * 0 - Value not saved, + * 2 - Fail, + * 3 - Pass + */ +UINT8 +STATIC +GetPassFailValue ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x + ) +{ + MEM_TECH_BLOCK *TechPtr; + MEM_RD_WR_2D_ENTRY* RdWr2DData; + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + TechPtr = NBPtr->TechPtr; + RdWr2DData = TechPtr->RdWr2DData; + SavedData = RdWr2DData->SavedData; + + if (x >= 0) { + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // value not saved + return 0; + } else { + // value saved, so return pass/fail + return ((RdWr2DData->Lane[lane].Vref[xlateY (y)].PosRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) ? 2 : 3; + } + } else { + if ((SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) { + // value not saved + return 0; + } else { + // value saved, so return pass/fail + return ((RdWr2DData->Lane[lane].Vref[xlateY (y)].NegRdWrDly >> (SavedData->xMax - (x & SavedData->xMax)) & 0x1) == 0) ? 2 : 3; + } + } +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Set the Pass/Fail state of lane + * + * @param[in,out] *NBPtr - Pointer to MEM_NB_BLOCK + * @param[in] lane - Current lane + * @param[in] y - Vref value + * @param[in] x - Delay Value + * @param[in] result - result value + * + */ +VOID +STATIC +SetPassFailValue ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x, + IN UINT8 result + ) +{ + MEM_TECH_BLOCK *TechPtr; + MEM_RD_WR_2D_ENTRY* RdWr2DData; + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + TechPtr = NBPtr->TechPtr; + RdWr2DData = TechPtr->RdWr2DData; + SavedData = RdWr2DData->SavedData; + + if (x >= 0) { + RdWr2DData->Lane[lane].Vref[xlateY (y)].PosRdWrDly |= (result == 0) ? (1 << (SavedData->xMax - (x & SavedData->xMax))) : 0; + } else { + RdWr2DData->Lane[lane].Vref[xlateY (y)].NegRdWrDly |= (result == 0) ? (1 << (SavedData->xMax - (x & SavedData->xMax))) : 0; + } +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Set the save state of lane + * + * @param[in,out] *NBPtr - Pointer to MEM_NB_BLOCK + * @param[in] lane - Current lane + * @param[in] y - Vref value + * @param[in] x - Delay Value + * @param[in] result - result value + * + */ +VOID +STATIC +SetSavedState ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 lane, + IN INT8 y, + IN INT8 x, + IN UINT8 result + ) +{ + MEM_RD_WR_2D_RIM_ENTRY *SavedData; + + ASSERT (NBPtr != NULL); + SavedData = ((MEM_RD_WR_2D_ENTRY*)NBPtr->TechPtr->RdWr2DData)->SavedData; + + if (x >= 0) { + SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdWrDly |= (1 << (SavedData->xMax - (x & SavedData->xMax))); + } else { + SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdWrDly |= (1 << (SavedData->xMax - (x & SavedData->xMax))); + } +} +/* -----------------------------------------------------------------------------*/ +/** + * + * Translate Vref into a positive, linear value that can be used as an + * array index. + * + * @param[in] y - INT8 of the (signed) Vref value + * + * @return UINT8 - Translated Value + */ +INT8 +STATIC +xlateY ( + IN INT8 y + ) +{ + ASSERT ( y > -0x10); + ASSERT ( y < 0x10); + return (y + 0xF) & 0x1F; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * Re-walk the eye rim for each aggressor combination, which invalidates + * previous Passes in the sample array. Previous Fails in the sample array + * remain valid. Knowledge of previous fails and speeds sampling for the + * subsequent walks, esp. when used in conjunction w/ ParallelSampling. + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return BOOLEAN + * TRUE + */ +BOOLEAN +STATIC +ClearSampledPassResults ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 lane; + UINT8 vref; + MEM_RD_WR_2D_ENTRY *Data; + MEM_RD_WR_2D_RIM_ENTRY *RimData; + + ASSERT (NBPtr != NULL); + + Data = (MEM_RD_WR_2D_ENTRY*)NBPtr->TechPtr->RdWr2DData; + RimData = Data->SavedData; + + for (lane = 0; lane < MemFRdWr2DGetMaxLanes (NBPtr); lane ++ ) { + for ( vref = 0; vref < NBPtr->TotalMaxVrefRange; vref ++ ) { + RimData->LaneSaved[lane].Vref[vref].PosRdWrDly &= ~(Data->Lane[lane].Vref[vref].PosRdWrDly); + Data->Lane[lane].Vref[vref].PosRdWrDly = 0; + RimData->LaneSaved[lane].Vref[vref].NegRdWrDly &= ~(Data->Lane[lane].Vref[vref].NegRdWrDly); + Data->Lane[lane].Vref[vref].NegRdWrDly = 0; + } + } + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * Perform in-phase comparison + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return UINT32 - Bitmap of results of comparison + * 1 = FAIL + * 0 = PASS + */ + +UINT32 +STATIC +CompareInPhase ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT32 Result; + Result = 0; + NBPtr->FamilySpecificHook[RdWr2DCompareInPhase] (NBPtr, &Result); + return Result; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * Perform 180 Degree out-of-phase comparison + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return UINT32 - Bitmap of results of comparison + * 1 = FAIL + * 0 = PASS + */ + +UINT32 +STATIC +Compare180Phase ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT32 Result; + Result = 0; + NBPtr->FamilySpecificHook[RdWr2DCompare180Phase] (NBPtr, &Result); + return Result; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * Program Vref after scaling to accomodate the register definition + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in] Vref - UINT8 value of Vref relative to the sample point + * + */ + +VOID +STATIC +ProgramVref ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT8 Vref + ) +{ + UINT8 ScaledVref; + ScaledVref = Vref; + NBPtr->FamilySpecificHook[RdWr2DScaleVref] (NBPtr, &ScaledVref); + NBPtr->FamilySpecificHook[RdWr2DProgramVref] (NBPtr, &ScaledVref); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * Turn Aggressor Channels On or Off + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in] TurnOn - BOOLEAN + * TRUE - Turn On, False = Turn Off. + */ + +VOID +STATIC +StartAggressors ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN BOOLEAN TurnOn + ) +{ + NBPtr->FamilySpecificHook[TurnOnAggressorChannels] (NBPtr, &TurnOn); +} |