blob: 832e807647cba939c2bc2979d3767f963205604a [file] [log] [blame]
/* $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_MTRRDDQS2DEYERIMSEARCH_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;
}