aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c')
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c996
1 files changed, 996 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c
new file mode 100644
index 0000000000..a568f9ec68
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Tech/mttRdDqs2DEyeRimSearch.c
@@ -0,0 +1,996 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttRdDqs2DEyeRimmSearch.c
+ *
+ * RD DQS 2 Dimentional Training using Eye Rim Sampling
+ *
+ * @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 "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 "Filecode.h"
+#include "OptionMemory.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTRDDQS2DEYERIMSEARCH_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+BOOLEAN
+MemTInitializeEyeRimSearch (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTEyeFill (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+CheckSaveResAtEdge (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN INT8 xdir
+ );
+
+UINT8
+DetermineSavedState (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ );
+
+UINT8
+GetPassFailValue (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ );
+
+VOID
+SetPassFailValue (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN UINT8 result
+ );
+
+VOID
+SetSavedState (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN UINT8 result
+ );
+
+INT8 MemTGet1DTrainedEyeCenter (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane
+ );
+
+BOOLEAN
+CheckForFail (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ );
+
+BOOLEAN
+AllocateSaveLaneStorage (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+INT8
+xlateY (
+ IN INT8 y
+ );
+
+BOOLEAN
+ClearSampledPassResults (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Initialize Eye Rim Search
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE
+ */
+BOOLEAN
+MemTInitializeEyeRimSearch (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 lane;
+ UINT8 vref;
+ MEM_2D_ENTRY *Data;
+ MEM_2D_RIM_ENTRY *RimData;
+ Data = TechPtr->Local2DData;
+ RimData = TechPtr->SavedData;
+ //
+ // Set Boundaries
+ //
+ RimData->xMax = Data->MaxRdDqsSweep - 1;
+ RimData->yMax = (TechPtr->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->RdDqsDlyUpdates = 0;
+ for (lane = 0; lane < MemT2DGetMaxLanes (TechPtr); lane ++ ) {
+ for ( vref = 0; vref < TechPtr->NBPtr->TotalMaxVrefRange; vref ++ ) {
+ // 00b = state not saved
+ // 01b = state saved
+ RimData->LaneSaved[lane].Vref[vref].PosRdDqsDly = 0;
+ RimData->LaneSaved[lane].Vref[vref].NegRdDqsDly = 0;
+ // 00b = Fail
+ // 01b = Pass
+ Data->Lane[lane].Vref[vref].PosRdDqsDly = 0;
+ Data->Lane[lane].Vref[vref].NegRdDqsDly = 0;
+ }
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ * This function collects data for Eye Rim Search
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No Errors occurred
+ * @return FALSE - Errors occurred
+ */
+BOOLEAN
+MemT2DRdDQSEyeRimSearch (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ 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_2D_ENTRY *Data;
+ MEM_2D_RIM_ENTRY RimData;
+ MEM_NB_BLOCK *NBPtr;
+ RD_DQS_2D *VrefPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ NBPtr = TechPtr->NBPtr;
+ Data = TechPtr->Local2DData;
+
+ //if (AllocateSaveLaneStorage(TechPtr)) {
+ // return FALSE;
+ //}
+ // Allocate Storage for Rim Search
+ AllocHeapParams.RequestedBufferSize = MemT2DGetMaxLanes (TechPtr) * TechPtr->NBPtr->TotalMaxVrefRange * sizeof (RD_DQS_2D);
+ AllocHeapParams.BufferHandle = AMD_MEM_2D_RDQS_RIM_HANDLE;
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, &TechPtr->NBPtr->MemPtr->StdHeader) == AGESA_SUCCESS) {
+ VrefPtr = (RD_DQS_2D *) AllocHeapParams.BufferPtr;
+ } else {
+ SetMemError (AGESA_FATAL, TechPtr->NBPtr->MCTPtr);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_2D, 0, 0, 0, 0, &TechPtr->NBPtr->MemPtr->StdHeader);
+ return FALSE;
+ }
+ for (lane = 0; lane < MemT2DGetMaxLanes (TechPtr); lane++) {
+ RimData.LaneSaved[lane].Vref = &VrefPtr[lane * TechPtr->NBPtr->TotalMaxVrefRange];
+ }
+ TechPtr->SavedData = &RimData;
+ MemTInitializeEyeRimSearch (TechPtr);
+ MemT2DProgramIntExtVrefSelect (TechPtr);
+ InitialCS = TechPtr->ChipSel;
+ NBPtr->FamilySpecificHook[Adjust2DPhaseMaskBasedOnEcc] (NBPtr, &NBPtr);
+ NBPtr->InitializeRdDqs2dVictimContinuousWrites (NBPtr);
+ //
+ // EnableDisable continuous writes on the agressor channels
+ //
+ IDS_HDT_CONSOLE (MEM_FLOW,"\n\tEye Rim Search, ParallelSampling: %c, BroadcastDelays: %c \n", (RimData.ParallelSampling == TRUE) ? 'Y' : 'N', (RimData.BroadcastDelays == TRUE) ? 'Y' : 'N');
+
+ for (Aggr = 0; Aggr < (NBPtr->MaxAggressorDimms[(NBPtr->Dct + 1) & 1] > 0 ? NBPtr->MaxAggressorDimms[(NBPtr->Dct + 1) & 1] : 1) ; Aggr += (NBPtr->IsSupported[PerDimmAggressors2D] ? 2 : NBPtr->CsPerDelay) ) {
+ ClearSampledPassResults (TechPtr);
+ //
+ // Enable continuous writes on the aggressors
+ //
+ NBPtr->AgressorContinuousWrites (NBPtr, Aggr, 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;
+ for (lane = 0; lane < MemT2DGetMaxLanes (TechPtr); 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 = MemTGet1DTrainedEyeCenter (TechPtr, 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) &&
+ CheckSaveResAtEdge (TechPtr, lane, y, x, xdir))
+ ) {
+ //
+ // Decide if result is already sampled, or need to take the sample
+ //
+ if (0 == DetermineSavedState (TechPtr, lane, y, x)) {
+ RimData.SampleCount++;
+ //
+ // Result for this point is not in the cache, sample it
+ //
+ for (slane = 0; slane < MemT2DGetMaxLanes (TechPtr); slane ++ ) {
+ if (!RimData.ParallelSampling && ( slane != lane)) {
+ continue;
+ }
+ //
+ // Calculate the relative offset from the initial trained position for this lane
+ //
+ xo = MemTGet1DTrainedEyeCenter (TechPtr, 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
+ //
+ TechPtr->SavedData->VrefUpdates++;
+ NBPtr->Vref = xlateY (yt);
+ MemT2DProgramVref (TechPtr, xlateY (yt));
+ }
+ }
+ if (RimData.BroadcastDelays) {
+ // When BroadcastDelays, only set RdDqs once
+ if (slane == lane) {
+ //
+ // If current lane
+ //
+ if ( NBPtr->RdDqsDly != (UINT8) (xt & RimData.xMax)) {
+ //
+ // If the not already set
+ // Account for rollover.
+ //
+ TechPtr->SavedData->RdDqsDlyUpdates++;
+ NBPtr->RdDqsDly = (UINT8) (xt & RimData.xMax);
+ MemT2DPrograRdDQSDly (TechPtr, (UINT8) (xt & RimData.xMax));
+ }
+ }
+ } else {
+ //
+ /// @todo: Set individual lanes
+ //
+ }
+ }
+ //
+ // Perform Memory RW test
+ //
+ InPhaseResult = 0;
+ PhaseResult180 = 0;
+ NBPtr->InitializeRdDqs2dVictimChipSelContinuousWrites (NBPtr);
+ for (SeedCount = 0; SeedCount < NBPtr->MaxSeedCount; SeedCount++) {
+ //
+ // Begin continuous reads and writes on the victim channels
+ //
+ NBPtr->StartRdDqs2dVictimContinuousWrites (NBPtr, SeedCount);
+ //
+ // Occasionally check if all trained lanes have already failed
+ //
+ if ((NBPtr->MaxSeedCount < 4) || ((SeedCount % (NBPtr->MaxSeedCount / 4)) == 0)) {
+ InPhaseResult |= NBPtr->InPhaseCompareRdDqs2DPattern (NBPtr, TechPtr->TestBufPtr, TechPtr->PatternBufPtr, TechPtr->PatternLength * 64);
+ PhaseResult180 |= NBPtr->Phase180CompareRdDqs2DPattern (NBPtr, TechPtr->TestBufPtr, TechPtr->PatternBufPtr, TechPtr->PatternLength * 64);
+ if (((InPhaseResult & NBPtr->PhaseLaneMask) == NBPtr->PhaseLaneMask) && ((PhaseResult180& NBPtr->PhaseLaneMask) == NBPtr->PhaseLaneMask)) {
+ break;
+ }
+ }
+ }
+ //
+ // Obtain the results
+ //
+ for (slane = 0; slane < MemT2DGetMaxLanes (TechPtr); slane ++ ) {
+ if (!RimData.ParallelSampling && (slane != lane)) {
+ continue;
+ }
+ //
+ // Calculate the relative offset from legacy trained
+ //
+ xo = MemTGet1DTrainedEyeCenter (TechPtr, 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 (TechPtr, slane, yt, xt)) {
+ //
+ // Don't overwrite a fail
+ //
+ if (xt > 0) {
+ if ((TechPtr->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 (TechPtr, slane, yt, xt, (UINT8) (Result & 0x0F));
+ SetSavedState (TechPtr, slane, yt, xt, (UINT8) (Result & 0x0F));
+ } else {
+ if ((TechPtr->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 (TechPtr, slane, yt, xt, (UINT8) (Result & 0x0F));
+ SetSavedState (TechPtr, slane, yt, xt, (UINT8) (Result & 0x0F));
+ }
+ }
+ }
+ }
+ // Decide the next sample point based on the result of the current lane
+ result = GetPassFailValue (TechPtr, 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
+ //
+ NBPtr->AgressorContinuousWrites (NBPtr, Aggr, FALSE);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW,"\n\tSampleCount:%d",TechPtr->SavedData->SampleCount);
+ IDS_HDT_CONSOLE (MEM_FLOW,"\t\tVref Updates:%d",TechPtr->SavedData->VrefUpdates);
+ IDS_HDT_CONSOLE (MEM_FLOW,"\t\tRdDqs Dly Updates:%d\n",TechPtr->SavedData->RdDqsDlyUpdates);
+ //
+ // Finilazing Victim Continuous writes
+ //
+ NBPtr->FinalizeRdDqs2dVictimContinuousWrites (NBPtr);
+ TechPtr->ChipSel = InitialCS;
+ //
+ // Fill eye based on Rim Search results
+ //
+ MemTEyeFill (TechPtr);
+ //
+ // Display the results the completed eye
+ //
+ MemT2DRdDqsDisplaySearch (TechPtr, Data);
+ //
+ // Restore environment settings after training
+ //
+ if (HeapDeallocateBuffer (AMD_MEM_2D_RDQS_RIM_HANDLE, &TechPtr->NBPtr->MemPtr->StdHeader) != AGESA_SUCCESS) {
+ SetMemError (AGESA_FATAL, TechPtr->NBPtr->MCTPtr);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_DEALLOCATE_FOR_2D, 0, 0, 0, 0, &TechPtr->NBPtr->MemPtr->StdHeader);
+ }
+ return TRUE;
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ * Fill the data eye
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return
+ */
+VOID
+MemTEyeFill (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ INT8 x;
+ INT8 y;
+ UINT8 lane;
+ UINT8 result;
+ INT8 yLastPass;
+ UINT8 xMax;
+ UINT8 yMax;
+ UINT8 xMin;
+ UINT8 yMin;
+ BOOLEAN FirstPassFound;
+
+ xMax = TechPtr->SavedData->xMax;
+ yMax = TechPtr->SavedData->yMax;
+ xMin = TechPtr->SavedData->xMin;
+ yMin = TechPtr->SavedData->yMin;
+ for (lane = 0; lane < MemT2DGetMaxLanes (TechPtr); 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 (TechPtr, 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 (TechPtr, 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 (TechPtr, 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 (TechPtr, 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 (TechPtr, lane, y, x, result);
+ FirstPassFound = TRUE;
+ } else {
+ ASSERT (FALSE);
+ }
+ } // y Loop
+ } //x Loop
+ } // Lane Loop
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Get the 1D trained center
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] lane - current lane
+ *
+ * @return
+ */
+INT8
+MemTGet1DTrainedEyeCenter (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane
+ )
+{
+ if ((TechPtr->NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) == 0) {
+ // Program Byte based for x8 and x16
+ return (INT8)TechPtr->NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / TechPtr->NBPtr->CsPerDelay) * MAX_DELAYS + lane];
+ } else {
+ return (INT8)TechPtr->NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / TechPtr->NBPtr->CsPerDelay) * MAX_DELAYS + (lane >> 1)];
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Determine if the saved value is at or close to the edge
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ * @param[in] xdir - x-direction
+ *
+ * @return TRUE - close to edge, FALSE - not close to edge
+ */
+BOOLEAN
+CheckSaveResAtEdge (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN INT8 xdir
+ )
+{
+ if (x > 0) {
+ if (((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-1 * xdir))) & 0x1) == 0) {
+ if (((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-1 * xdir))) & 0x1) == 1) {
+ if (((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-2 * xdir))) & 0x1) == 0) {
+ if (((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-2 * xdir))) & 0x1) == 1) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ if (((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-1 * xdir))) & 0x1) == 0) {
+ if (((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-1 * xdir))) & 0x1) == 1) {
+ if (((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-2 * xdir))) & 0x1) == 0) {
+ if (((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax) + (-2 * xdir))) & 0x1) == 1) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * determine if a BL has been saved
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ *
+ * @return 1 - value saved, 0 - value not saved
+ */
+UINT8
+DetermineSavedState (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ )
+{
+ if (x > 0) {
+ return (UINT8) (TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1);
+ } else {
+ return (UINT8) (TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1);
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Determine if a failure has occured
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ *
+ * @return 2 - Fail, 3 - Pass
+ */
+BOOLEAN
+CheckForFail (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ )
+{
+ if (x > 0) {
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // value not saved, so it is not fail
+ return TRUE;
+ } else {
+ // value saved, so examine result
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // result = fail
+ return FALSE;
+ } else {
+ // result = pass
+ return TRUE;
+ }
+ }
+ } else {
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // value not saved, so it is not fail
+ return TRUE;
+ } else {
+ // value saved, so examine result
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // result = fail
+ return FALSE;
+ } else {
+ // result = pass
+ return TRUE;
+ }
+ }
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Get pass fail state of lane
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ *
+ * @return 0 - Value not saved, 2 - Fail, 3 - Pass
+ */
+UINT8
+GetPassFailValue (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x
+ )
+{
+ if (x > 0) {
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // value not saved
+ return 0;
+ } else {
+ // value saved, so return pass/fail
+ return ((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].PosRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) ? 2 : 3;
+ }
+ } else {
+ if ((TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) {
+ // value not saved
+ return 0;
+ } else {
+ // value saved, so return pass/fail
+ return ((TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].NegRdDqsDly >> (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)) & 0x1) == 0) ? 2 : 3;
+ }
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Set the Pass/Fail state of lane
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ * @param[in] result - result value
+ *
+ * @return Saved Value
+ */
+VOID
+SetPassFailValue (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN UINT8 result
+ )
+{
+ if (x > 0) {
+ TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].PosRdDqsDly |= (result == 0) ? (1 << (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax))) : 0;
+ } else {
+ TechPtr->Local2DData->Lane[lane].Vref[xlateY (y)].NegRdDqsDly |= (result == 0) ? (1 << (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax))) : 0;
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Set the save state of lane
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *lane - current lane
+ * @param[in] y - vref value
+ * @param[in] x - RdDqs value
+ * @param[in] result - result value
+ *
+ * @return Saved Value
+ */
+VOID
+SetSavedState (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 lane,
+ IN INT8 y,
+ IN INT8 x,
+ IN UINT8 result
+ )
+{
+ if (x > 0) {
+ TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].PosRdDqsDly |= (1 << (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)));
+ } else {
+ TechPtr->SavedData->LaneSaved[lane].Vref[xlateY (y)].NegRdDqsDly |= (1 << (TechPtr->SavedData->xMax - (x & TechPtr->SavedData->xMax)));
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Allocate data storage
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return FALSE - No Errors occurred
+ * @return TRUE - Errors occurred
+ */
+BOOLEAN
+AllocateSaveLaneStorage (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ RD_DQS_2D *VrefPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ UINT8 Lane;
+
+ AllocHeapParams.RequestedBufferSize = MemT2DGetMaxLanes (TechPtr) * TechPtr->NBPtr->TotalMaxVrefRange * sizeof (RD_DQS_2D);
+ AllocHeapParams.BufferHandle = AMD_MEM_2D_RDQS_RIM_HANDLE;
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, &TechPtr->NBPtr->MemPtr->StdHeader) == AGESA_SUCCESS) {
+ VrefPtr = (RD_DQS_2D *) AllocHeapParams.BufferPtr;
+ } else {
+ SetMemError (AGESA_FATAL, TechPtr->NBPtr->MCTPtr);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_2D, 0, 0, 0, 0, &TechPtr->NBPtr->MemPtr->StdHeader);
+ return TRUE;
+ }
+ for (Lane = 0; Lane < MemT2DGetMaxLanes (TechPtr); Lane++) {
+ TechPtr->SavedData->LaneSaved[Lane].Vref = &VrefPtr[Lane * TechPtr->NBPtr->TotalMaxVrefRange];
+ }
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Translate Vref into a positive, linear value that can be used as an
+ * array index.
+ *
+ * @param[in] y - vref value
+ *
+ * @return Saved Value
+ */
+INT8
+xlateY (
+ IN INT8 y
+ )
+{
+ ASSERT ( y > -0x10);
+ ASSERT ( y < 0x10);
+ return (y + 0xF) & 0x1F;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Re-walking 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] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE
+ */
+BOOLEAN
+ClearSampledPassResults (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 lane;
+ UINT8 vref;
+ MEM_2D_ENTRY *Data;
+ MEM_2D_RIM_ENTRY *RimData;
+ Data = TechPtr->Local2DData;
+ RimData = TechPtr->SavedData;
+ for (lane = 0; lane < MemT2DGetMaxLanes (TechPtr); lane ++ ) {
+ for ( vref = 0; vref < TechPtr->NBPtr->TotalMaxVrefRange; vref ++ ) {
+ RimData->LaneSaved[lane].Vref[vref].PosRdDqsDly &= ~(Data->Lane[lane].Vref[vref].PosRdDqsDly);
+ Data->Lane[lane].Vref[vref].PosRdDqsDly = 0;
+ RimData->LaneSaved[lane].Vref[vref].NegRdDqsDly &= ~(Data->Lane[lane].Vref[vref].NegRdDqsDly);
+ Data->Lane[lane].Vref[vref].NegRdDqsDly = 0;
+ }
+ }
+ return TRUE;
+}