aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c
diff options
context:
space:
mode:
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.c1112
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);
+}