summaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat
diff options
context:
space:
mode:
authorSiyuan Wang <wangsiyuanbuaa@gmail.com>2013-07-25 15:14:15 +0800
committerBruce Griffith <Bruce.Griffith@se-eng.com>2013-08-04 05:40:37 +0200
commitaffe85fbc8a13d35960aa92ae87cbb6330ad253f (patch)
tree9c1ace69f12b06b6544faf041994aa4288fb2e45 /src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat
parentae8d06969bdde9b1250bc3c4ad93f5db408dae98 (diff)
AMD Kabini: Add AGESA/PI code for new processor family
Change-Id: Icb6f64e2e3cfd678fb4fb4f13f0e4b678d5acc4a Signed-off-by: Siyuan Wang <SiYuan.Wang@amd.com> Signed-off-by: Siyuan Wang <wangsiyuanbuaa@gmail.com> Reviewed-by: Nick Dill <nick.dill@se-eng.com> Tested-by: Bruce Griffith <bruce.griffith@se-eng.com> Reviewed-on: http://review.coreboot.org/3836 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martin.roth@se-eng.com>
Diffstat (limited to 'src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat')
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CRAT/mfCrat.h95
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.c357
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.h80
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c721
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.c290
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.h80
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfemp.c177
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/EXCLUDIMM/mfdimmexclud.c206
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.c548
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.h72
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.c172
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.h78
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/MEMCLR/mfmemclr.c153
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.c179
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.h77
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfParallelTraining.c288
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfStandardTraining.c85
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/KB/mfRdWr2DKb.c348
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdDqs2DTraining.c115
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DEyeRimSearch.c1112
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DPatternGeneration.c424
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.c1368
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.h266
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/S3/mfs3.c718
-rw-r--r--src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/TABLE/mftds.c401
25 files changed, 8410 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CRAT/mfCrat.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CRAT/mfCrat.h
new file mode 100644
index 0000000000..e7f9267864
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CRAT/mfCrat.h
@@ -0,0 +1,95 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfCrat.h
+ *
+ * Feature CRAT table support
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+#ifndef _MFCRAT_H_
+#define _MFCRAT_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/// DCT Select Interleaving Address Mapping
+typedef struct {
+ UINT8 DctSelIntLvAddr; ///< F2x110 DctSelIntLvAddr
+ UINT8 DctSelFunctionBit; ///< Lowest function bit to select DCT for interleaving
+} DCTSELBIT_ENTRY;
+
+/// CRAT Memory Affinity Info Header
+typedef struct {
+ UINT8 NumOfMemAffinityInfoEntries; ///< Integer that represents the proximity domain to
+ UINT32 MemoryWidth; ///< Specifies the number of parallel bits of the memory interface
+} CRAT_MEMORY_AFFINITY_INFO_HEADER;
+
+/// CRAT Memory Affinity Info Entry
+typedef struct {
+ UINT8 Domain; ///< Integer that represents the proximity domain to
+ ///< which the memory belongs
+ UINT32 BaseAddressLow; ///< Low 32Bits of the Base Address of the memory range
+ UINT32 BaseAddressHigh; ///< High 32Bits of the Base Address of the memory range
+ UINT32 LengthLow; ///< Low 32Bits of the length of the memory range
+ UINT32 LengthHigh; ///< High 32Bits of the length of the memory range
+} CRAT_MEMORY_AFFINITY_INFO_ENTRY;
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#endif /* _MFCRAT_H_ */
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.c
new file mode 100644
index 0000000000..8baba277e6
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.c
@@ -0,0 +1,357 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfcsi.c
+ *
+ * Feature bank interleaving support (AKA Chip Select Interleaving )
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/Csintlv)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+/* This file contains functions for Chip Select interleaving */
+
+
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "mfcsi.h"
+#include "Ids.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_CSINTLV_MFCSI_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+STATIC
+MemFDctInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+VOID
+STATIC
+CsIntSwap (
+ IN OUT UINT32 *BaseMaskRegPtr,
+ IN UINT8 EnChipSels,
+ IN UINT8 LoBit,
+ IN UINT8 HiBit
+ );
+
+BOOLEAN
+MemFUndoInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+/*
+ *-----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function Applies DIMM bank (chip-select) interleaving if enabled
+ * and if all criteria are met. Interleaves chip-selects on page boundaries.
+ * This function calls subfunctions that sets up CS interleaving on multiple Sockets
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Dct;
+ BOOLEAN RetFlag;
+
+ ASSERT (NBPtr != NULL);
+
+ RetFlag = FALSE;
+ if (NBPtr->RefPtr->EnableBankIntlv) {
+ if (NBPtr->MCTPtr->NodeMemSize) {
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ RetFlag |= MemFDctInterleaveBanks (NBPtr);
+ }
+ }
+ }
+ return RetFlag;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function checks if bank interleaving has been enabled or not. If yes, it will
+ * undo bank interleaving. Otherwise, it does nothing.
+ *
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - Bank interleaving has been enabled.
+ * @return FALSE - Bank interleaving has not been enabled.
+ */
+
+BOOLEAN
+MemFUndoInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Cs;
+ UINT8 Dct;
+ UINT32 CSMask;
+ BOOLEAN CSIntlvEnabled;
+ BOOLEAN RetFlag;
+
+ ASSERT (NBPtr != NULL);
+
+ RetFlag = FALSE;
+
+ if (NBPtr->RefPtr->EnableBankIntlv) {
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.DctMemSize) {
+ CSIntlvEnabled = FALSE;
+ for (Cs = 0; Cs < MAX_CS_PER_CHANNEL; Cs++) {
+ if ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + Cs) & 1) != 0) {
+ CSMask = NBPtr->GetBitField (NBPtr, BFCSMask0Reg + (Cs / 2));
+ if (((CSMask >> 5) & 0x1FF) != 0x1FF) {
+ CSIntlvEnabled = TRUE;
+ break;
+ }
+ }
+ }
+ if (CSIntlvEnabled) {
+ MemFDctInterleaveBanks (NBPtr);
+ RetFlag = TRUE;
+ }
+ }
+ }
+ }
+ return RetFlag;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function Applies DIMM bank (chip-select) interleaving if enabled
+ * and if all criteria are met. Interleaves chip-selects on page boundaries.
+ * This function is run once per Socket
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - Register bits have been swapped.
+ * @return FALSE - Register bits have not been swapped.
+ *
+ */
+
+BOOLEAN
+STATIC
+MemFDctInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Cs;
+ UINT8 EnChipSels;
+ UINT8 BankEncd;
+ UINT8 BankEncd0;
+ UINT8 i;
+ UINT8 j;
+ UINT32 BankAddrReg;
+ UINT32 BaseRegS0;
+ UINT32 BaseRegS1;
+ UINT32 MaskReg;
+ UINT8 Offset;
+ UINT8 Dct;
+
+ ASSERT (NBPtr != NULL);
+
+ Dct = NBPtr->Dct;
+
+ // Check if CS interleaving can be enabled
+ EnChipSels = 0;
+ BankEncd0 = 0xFF;
+ Offset = 0;
+ for (Cs = 0; Cs < MAX_CS_PER_CHANNEL; Cs++) {
+ if ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + Cs) & 3) != 0) {
+ BankAddrReg = NBPtr->GetBitField (NBPtr, BFDramBankAddrReg);
+ BankEncd = (UINT8) ((BankAddrReg >> ((Cs / 2) * 4)) & 0xF);
+ if (BankEncd0 == 0xFF) {
+ BankEncd0 = BankEncd;
+ } else if (BankEncd0 != BankEncd) {
+ break;
+ }
+ if ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + Cs) & 1) != 0) {
+ EnChipSels++;
+ }
+ }
+ }
+
+ // Swap Dram Base/Mask Addr to enable CS interleaving
+ if ((Cs == MAX_CS_PER_CHANNEL) && ((EnChipSels == 2) || (EnChipSels == 4) || (EnChipSels == 8))) {
+ NBPtr->TechPtr->GetCSIntLvAddr (BankEncd0, &i, &j);
+ NBPtr->DCTPtr->BankAddrMap = BankEncd0;
+ NBPtr->DCTPtr->EnabledChipSels = EnChipSels;
+ // Family specific CS interleaving low address adjustment
+ NBPtr->FamilySpecificHook[AdjustCSIntLvLowAddr] (NBPtr, &i);
+
+ if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
+ i++;
+ j++;
+ }
+
+ for (Cs = 0; Cs < MAX_CS_PER_CHANNEL; Cs += 2) {
+ //
+ // LRDIMMS - Add an offset to the bit positions specified based on D18F2x[6C:60]_dct[1:0][RankDef] as follows:
+ // RankDef=0xb: 0 RankDef=10b: 1 RankDef=11b: 2
+ // Using RankMult information: Lo/HiBit <<= (Mult >> 1)
+ //
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ Offset = ((NBPtr->ChannelPtr->LrDimmRankMult[Cs >> 1]) >> 1);
+ }
+ BaseRegS0 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + Cs);
+ BaseRegS1 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + Cs + 1);
+ if (((BaseRegS0 | BaseRegS1) & 1) != 0) {
+ // Swap Mask register bits
+ MaskReg = NBPtr->GetBitField (NBPtr, BFCSMask0Reg + (Cs / 2));
+ CsIntSwap (&MaskReg, EnChipSels, (i + Offset), (j + Offset));
+ NBPtr->SetBitField (NBPtr, BFCSMask0Reg + (Cs / 2), MaskReg);
+
+ // Swap Base register bits
+ CsIntSwap (&BaseRegS0, EnChipSels, (i + Offset), (j + Offset));
+ NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + Cs, BaseRegS0);
+ CsIntSwap (&BaseRegS1, EnChipSels, (i + Offset), (j + Offset));
+ NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + Cs + 1, BaseRegS1);
+ }
+ }
+ //
+ // Bank Interleaving is requested and has been enabled as well
+ //
+ NBPtr->MCTPtr->DctData[Dct].BkIntDis = FALSE;
+ return TRUE;
+ } else {
+ //
+ // Bank Interleaving is requested but cannot be enabled
+ //
+ PutEventLog (AGESA_WARNING, MEM_WARNING_BANK_INTERLEAVING_NOT_ENABLED, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_WARNING, NBPtr->MCTPtr);
+ NBPtr->MCTPtr->DctData[Dct].BkIntDis = TRUE;
+ }
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This supporting function swaps Chip selects
+ *
+ * @param[in,out] *BaseMaskRegPtr - Pointer to the Mask Register
+ * @param[in] *EnChipSels - Chip Selects to Enable
+ * @param[in] *LoBit - Lowest Bit
+ * @param[in] *HiBit - Highest Bit
+ *
+ *
+ */
+
+VOID
+STATIC
+CsIntSwap (
+ IN OUT UINT32 *BaseMaskRegPtr,
+ IN UINT8 EnChipSels,
+ IN UINT8 LoBit,
+ IN UINT8 HiBit
+ )
+{
+ UINT8 BitDelta;
+ UINT32 TempHi;
+ UINT32 TempLo;
+ UINT32 AddrLoMask;
+ UINT32 AddrHiMask;
+
+ ASSERT (BaseMaskRegPtr != NULL);
+ ASSERT (HiBit > LoBit);
+
+ BitDelta = HiBit - LoBit;
+ AddrLoMask = (((UINT32)EnChipSels) - 1) << LoBit;
+ AddrHiMask = AddrLoMask << BitDelta;
+
+ TempHi = TempLo = *BaseMaskRegPtr;
+ TempLo &= AddrLoMask;
+ TempLo <<= BitDelta; // move lower bits to upper bit position
+ TempHi &= AddrHiMask;
+ TempHi >>= BitDelta; // move upper bits to lower bit position
+
+ *BaseMaskRegPtr &= ~AddrLoMask;
+ *BaseMaskRegPtr &= ~AddrHiMask;
+ *BaseMaskRegPtr |= TempLo | TempHi;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.h
new file mode 100644
index 0000000000..b660f05d55
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/CSINTLV/mfcsi.h
@@ -0,0 +1,80 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfcsi.h
+ *
+ * Memory Controller
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+#ifndef _MFCSI_H_
+#define _MFCSI_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemFInterleaveBanks (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+#endif /* _MFCSI_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c
new file mode 100644
index 0000000000..af7bdaf357
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c
@@ -0,0 +1,721 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfDMI.c
+ *
+ * Memory DMI table support.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Main)
+ * @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 "Ids.h"
+#include "heapManager.h"
+#include "cpuServices.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_DMI_MFDMI_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#define MAX_DCTS_PER_DIE 2
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+UINT64
+MemFGetNodeMemBase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 NodeLimit
+ );
+
+UINT64
+MemFGetDctMemBase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 DctLimit
+ );
+
+UINT64
+MemFGetDctInterleavedMemSize (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+UINT64
+MemFGetDctInterleavedLimit (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 Dct,
+ IN UINT64 DctMemBase,
+ IN UINT64 DctInterleavedMemSize
+ );
+
+BOOLEAN
+MemFDMISupport3 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function gets DDR3 DMI information from SPD buffer and stores the info into heap
+ *
+ * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
+ *
+ */
+BOOLEAN
+MemFDMISupport3 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ UINT8 Socket;
+ UINT8 NodeId;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 temp;
+ UINT16 LocalHandle;
+ UINT8 MaxPhysicalDimms;
+ UINT8 MaxLogicalDimms;
+ UINT8 NumLogicalDimms;
+ UINT32 *TotalMemSizePtr;
+ UINT8 *DmiTable;
+ UINT8 MaxChannelsPerSocket;
+ UINT8 MaxDimmsPerChannel;
+ UINT8 FormFactor;
+ UINT16 TotalWidth;
+ UINT16 Capacity;
+ UINT16 Width;
+ UINT16 Rank;
+ UINT16 BusWidth;
+ UINT64 ManufacturerIdCode;
+ UINT32 MaxSockets;
+ UINT32 Address;
+ UINT8 ChipSelectPairScale;
+ UINT32 TotalSize;
+ UINT32 DimmSize;
+ UINT32 CsBaseAddrReg0;
+ UINT32 CsBaseAddrReg1;
+ UINT64 AddrValue;
+ UINT64 DctMemBase;
+ UINT64 NodeMemBase;
+ UINT64 SysMemSize;
+ INT32 MTB_ps;
+ INT32 FTB_ps;
+ INT32 Value32;
+ BOOLEAN DctInterleaveEnabled;
+ UINT64 DctInterleavedMemSize;
+ BOOLEAN NodeInterleaveEnabled;
+ UINT16 T17HandleMatrix[MAX_SOCKETS_SUPPORTED][MAX_CHANNELS_PER_SOCKET][MAX_DIMMS_PER_CHANNEL];
+
+ MEM_NB_BLOCK *NBPtr;
+ MEM_PARAMETER_STRUCT *RefPtr;
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ SPD_DEF_STRUCT *SpdDataStructure;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ MEM_DMI_PHYSICAL_DIMM_INFO *DmiPhysicalDimmInfoTable;
+ MEM_DMI_LOGICAL_DIMM_INFO *DmiLogicalDimmInfoTable;
+ DMI_T17_MEMORY_TYPE *DmiType17MemTypePtr;
+
+ NBPtr = MemMainPtr->NBPtr;
+ MemPtr = MemMainPtr->MemPtr;
+ SpdDataStructure = MemPtr->SpdDataStructure;
+ MCTPtr = NBPtr->MCTPtr;
+ RefPtr = MemPtr->ParameterListPtr;
+
+ // Initialize local variables
+ LocalHandle = 1;
+ MaxPhysicalDimms = 0;
+ MaxLogicalDimms = 0;
+ NumLogicalDimms = 0;
+ TotalSize = 0;
+ NodeMemBase = 0;
+ SysMemSize = 0;
+
+ AGESA_TESTPOINT (TpProcMemDmi, &MemPtr->StdHeader);
+
+ ASSERT (NBPtr != NULL);
+
+ MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
+ temp = (UINT8) GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ MaxPhysicalDimms = MaxPhysicalDimms + temp;
+ MaxLogicalDimms += MAX_DIMMS_PER_CHANNEL;
+ }
+ }
+
+ // Allocate heap for memory DMI table 16, 17, 19, 20
+ AllocHeapParams.RequestedBufferSize = sizeof (UINT8) + // Storage for MaxPhysicalDimms
+ sizeof (UINT8) + // Storage for Type Detail
+ sizeof (UINT32) + // Storage for Total Memory Size
+ sizeof (DMI_T17_MEMORY_TYPE) +
+ MaxPhysicalDimms * sizeof (MEM_DMI_PHYSICAL_DIMM_INFO) +
+ sizeof (UINT8) + // Storage for MaxLogicalDimms
+ MaxLogicalDimms * sizeof (MEM_DMI_LOGICAL_DIMM_INFO);
+
+ AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
+ PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR3, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
+ SetMemError (AGESA_CRITICAL, MCTPtr);
+ // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR3
+ ASSERT (FALSE);
+ return FALSE;
+ }
+
+ DmiTable = (UINT8 *) AllocHeapParams.BufferPtr;
+ // Max number of physical DIMMs
+ *DmiTable = MaxPhysicalDimms;
+ DmiTable ++;
+ // Type Detail;
+ *DmiTable = 0;
+ DmiTable ++;
+ // Pointer to total memory size
+ TotalMemSizePtr = (UINT32 *) DmiTable;
+ DmiTable += sizeof (UINT32);
+ // Memory Type
+ DmiType17MemTypePtr = (DMI_T17_MEMORY_TYPE *) DmiTable;
+ *DmiType17MemTypePtr = Ddr3MemType;
+ DmiType17MemTypePtr ++;
+ DmiTable = (UINT8 *) DmiType17MemTypePtr;
+ // Pointer to DMI info of Physical DIMMs
+ DmiPhysicalDimmInfoTable = (MEM_DMI_PHYSICAL_DIMM_INFO *) DmiTable;
+
+ //
+ // Gather physical DIMM DMI info
+ //
+ for (Socket = 0; Socket < MaxSockets; Socket ++) {
+ MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
+ DctMemBase = 0;
+ for (Channel = 0; Channel < MaxChannelsPerSocket; Channel ++) {
+ //
+ // Get Node number and Dct number for this channel
+ //
+ ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
+ NodeId = ChannelPtr->MCTPtr->NodeId;
+ NBPtr = MemMainPtr->NBPtr;
+ Dct = ChannelPtr->Dct;
+ NBPtr = &NBPtr[NodeId];
+ NBPtr->SwitchDCT (NBPtr, Dct);
+
+ MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm ++, SpdDataStructure ++, LocalHandle++) {
+ //
+ // Initialize default value for DMI fields
+ //
+ DmiPhysicalDimmInfoTable->DimmPresent = 0;
+ DmiPhysicalDimmInfoTable->Socket = Socket;
+ DmiPhysicalDimmInfoTable->Channel = Channel;
+ DmiPhysicalDimmInfoTable->Dimm = Dimm;
+ DmiPhysicalDimmInfoTable->TotalWidth = 0xFFFF;
+ DmiPhysicalDimmInfoTable->DataWidth = 0xFFFF;
+ DmiPhysicalDimmInfoTable->MemorySize = 0;
+ DmiPhysicalDimmInfoTable->Speed = 0;
+ DmiPhysicalDimmInfoTable->ManufacturerIdCode = 0;
+ DmiPhysicalDimmInfoTable->Attributes = 0;
+ DmiPhysicalDimmInfoTable->ConfigSpeed = 0;
+ DmiPhysicalDimmInfoTable->ExtSize = 0;
+ DmiPhysicalDimmInfoTable->FormFactor = UnknowFormFactor;
+ DmiPhysicalDimmInfoTable->Handle = LocalHandle;
+ T17HandleMatrix[Socket][Channel][Dimm] = LocalHandle;
+
+ for (i = 0; i < 4; i++) {
+ DmiPhysicalDimmInfoTable->SerialNumber[i] = 0xFF;
+ }
+
+ for (i = 0; i < 18; i++) {
+ DmiPhysicalDimmInfoTable->PartNumber[i] = 0x0;
+ }
+
+ if (SpdDataStructure->DimmPresent) {
+ // Total Width (offset 08h) & Data Width (offset 0Ah)
+ TotalWidth = (UINT16) SpdDataStructure->Data[8];
+ if ((TotalWidth & 0x18) == 0) {
+ // non ECC
+ if ((TotalWidth & 0x07) == 0) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 8; // 8 bits
+ } else if ((TotalWidth & 0x07) == 1) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 16; // 16 bits
+ } else if ((TotalWidth & 0x07) == 2) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 32; // 32 bits
+ } else if ((TotalWidth & 0x07) == 3) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 64; // 64 bits
+ }
+ DmiPhysicalDimmInfoTable->DataWidth = DmiPhysicalDimmInfoTable->TotalWidth ;
+ } else {
+ // ECC
+ if ((TotalWidth & 0x07) == 0) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 8 + 8; // 8 bits
+ } else if ((TotalWidth & 0x07) == 1) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 16 + 8; // 16 bits
+ } else if ((TotalWidth & 0x07) == 2) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 32 + 8; // 32 bits
+ } else if ((TotalWidth & 0x07) == 3) {
+ DmiPhysicalDimmInfoTable->TotalWidth = 64 + 8; // 64 bits
+ }
+ DmiPhysicalDimmInfoTable->DataWidth = DmiPhysicalDimmInfoTable->TotalWidth - 8;
+ }
+
+ // Memory Size (offset 0Ch)
+ Capacity = 0;
+ BusWidth = 0;
+ Width = 0;
+ Rank = 0;
+ temp = (UINT8) SpdDataStructure->Data[4];
+ if ((temp & 0x0F) == 0) {
+ Capacity = 0x0100; // 256M
+ } else if ((temp & 0x0F) == 1) {
+ Capacity = 0x0200; // 512M
+ } else if ((temp & 0x0F) == 2) {
+ Capacity = 0x0400; // 1G
+ } else if ((temp & 0x0F) == 3) {
+ Capacity = 0x0800; // 2G
+ } else if ((temp & 0x0F) == 4) {
+ Capacity = 0x1000; // 4G
+ } else if ((temp & 0x0F) == 5) {
+ Capacity = 0x2000; // 8G
+ } else if ((temp & 0x0F) == 6) {
+ Capacity = 0x4000; // 16G
+ }
+
+ temp = (UINT8) SpdDataStructure->Data[8];
+ if ((temp & 0x07) == 0) {
+ BusWidth = 8; // 8 bits
+ } else if ((temp & 0x07) == 1) {
+ BusWidth = 16; // 16 bits
+ } else if ((temp & 0x07) == 2) {
+ BusWidth = 32; // 32 bits
+ } else if ((temp & 0x07) == 3) {
+ BusWidth = 64; // 64 bits
+ }
+
+ temp = (UINT8) SpdDataStructure->Data[7];
+ if ((temp & 0x07) == 0) {
+ Width = 4; // 4 bits
+ } else if ((temp & 0x07) == 1) {
+ Width = 8; // 8 bits
+ } else if ((temp & 0x07) == 2) {
+ Width = 16; // 16 bits
+ } else if ((temp & 0x07) == 3) {
+ Width = 32; // 32 bits
+ }
+
+ temp = (UINT8) SpdDataStructure->Data[7];
+ if (((temp >> 3) & 0x07) == 0) {
+ Rank = 1; // 4 bits
+ DmiPhysicalDimmInfoTable->Attributes = 1; // Single Rank Dimm
+ } else if (((temp >> 3) & 0x07) == 1) {
+ Rank = 2; // 8 bits
+ DmiPhysicalDimmInfoTable->Attributes = 2; // Dual Rank Dimm
+ } else if (((temp >> 3) & 0x07) == 2) {
+ Rank = 3; // 16 bits
+ } else if (((temp >> 3) & 0x07) == 3) {
+ Rank = 4; // 32 bits
+ DmiPhysicalDimmInfoTable->Attributes = 4; // Quad Rank Dimm
+ }
+
+ DimmSize = (UINT32) (Capacity / 8 * BusWidth / Width * Rank);
+ if (DimmSize < 0x7FFF) {
+ DmiPhysicalDimmInfoTable->MemorySize = (UINT16) DimmSize;
+ } else {
+ DmiPhysicalDimmInfoTable->MemorySize = 0x7FFF;
+ DmiPhysicalDimmInfoTable->ExtSize = DimmSize;
+ }
+
+ // Form Factor (offset 0Eh)
+ FormFactor = (UINT8) SpdDataStructure->Data[3];
+ if (((FormFactor & 0x0F) == 0x01) || ((FormFactor & 0x0F) == 0x02) || ((FormFactor & 0x0F) == 0x0B)) {
+ DmiPhysicalDimmInfoTable->FormFactor = 0x09; // RDIMM or UDIMM or LRDIMM
+ } else if ((FormFactor & 0x0F) == 0x03) {
+ DmiPhysicalDimmInfoTable->FormFactor = 0x0D; // SO-DIMM
+ } else {
+ DmiPhysicalDimmInfoTable->FormFactor = 0x02; // UNKNOWN
+ }
+
+ // DIMM Present
+ DmiPhysicalDimmInfoTable->DimmPresent = 1;
+
+ // Type Detail (offset 13h)
+ if (((FormFactor & 0x0F) == 0x01) || ((FormFactor & 0x0F) == 0x0B)) {
+ *((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 1; // Registered (Buffered)
+ } else {
+ *((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 2; // Unbuffered (Unregistered)
+ }
+
+ // Speed (offset 15h)
+ MTB_ps = ((INT32) SpdDataStructure->Data[10] * 1000) / SpdDataStructure->Data[11];
+ FTB_ps = (SpdDataStructure->Data[9] >> 4) / (SpdDataStructure->Data[9] & 0xF);
+ Value32 = (MTB_ps * SpdDataStructure->Data[12]) + (FTB_ps * (INT8) SpdDataStructure->Data[34]) ;
+ if (Value32 <= 938) {
+ DmiPhysicalDimmInfoTable->Speed = 1067; // DDR3-2133
+ } else if (Value32 <= 1071) {
+ DmiPhysicalDimmInfoTable->Speed = 933; // DDR3-1866
+ } else if (Value32 <= 1250) {
+ DmiPhysicalDimmInfoTable->Speed = 800; // DDR3-1600
+ } else if (Value32 <= 1500) {
+ DmiPhysicalDimmInfoTable->Speed = 667; // DDR3-1333
+ } else if (Value32 <= 1875) {
+ DmiPhysicalDimmInfoTable->Speed = 533; // DDR3-1066
+ } else if (Value32 <= 2500) {
+ DmiPhysicalDimmInfoTable->Speed = 400; // DDR3-800
+ }
+
+ // Manufacturer (offset 17h)
+ ManufacturerIdCode = (UINT64) SpdDataStructure->Data[118];
+ DmiPhysicalDimmInfoTable->ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure->Data[117]);
+
+ // Serial Number (offset 18h)
+ for (i = 0; i < 4; i++) {
+ DmiPhysicalDimmInfoTable->SerialNumber[i] = (UINT8) SpdDataStructure->Data[i + 122];
+ }
+ // Part Number (offset 1Ah)
+ for (i = 0; i < 18; i++) {
+ DmiPhysicalDimmInfoTable->PartNumber[i] = (UINT8) SpdDataStructure->Data[i + 128];
+ }
+
+ // Configured Memory Clock Speed (offset 20h)
+ DmiPhysicalDimmInfoTable->ConfigSpeed = NBPtr->DCTPtr->Timings.Speed;
+ } // Dimm present
+ TotalSize += (UINT32) DmiPhysicalDimmInfoTable->MemorySize;
+ DmiPhysicalDimmInfoTable ++;
+ } // Dimm loop
+ } // Channel loop
+ } // Socket loop
+
+ // Max number of logical DIMMs
+ DmiTable = (UINT8 *) DmiPhysicalDimmInfoTable;
+ *DmiTable = MaxLogicalDimms;
+ DmiTable ++;
+
+ // Pointer to DMI info of Logical DIMMs
+ DmiLogicalDimmInfoTable = (MEM_DMI_LOGICAL_DIMM_INFO *) DmiTable;
+
+ // Calculate the total memory size in the system
+ SysMemSize = MemFGetNodeMemBase (MemMainPtr->NBPtr, MemPtr->DieCount);
+ //
+ // Gather logical DIMM DMI info
+ //
+ for (Socket = 0; Socket < MaxSockets; Socket ++) {
+ MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
+ DctMemBase = 0;
+ for (Channel = 0; Channel < MaxChannelsPerSocket; Channel ++) {
+ MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ //
+ // Get Node number and Dct number for this channel
+ //
+ ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
+ NodeId = ChannelPtr->MCTPtr->NodeId;
+ NBPtr = MemMainPtr->NBPtr;
+ Dct = ChannelPtr->Dct;
+ NodeMemBase = MemFGetNodeMemBase (NBPtr, NodeId);
+ NBPtr = &NBPtr[NodeId];
+
+ DctMemBase = MemFGetDctMemBase (NBPtr, Dct);
+ DctInterleavedMemSize = MemFGetDctInterleavedMemSize (NBPtr);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ NodeInterleaveEnabled = (NBPtr->GetBitField (NBPtr, BFDramIntlvEn) == 0) ? FALSE : TRUE;
+ DctInterleaveEnabled = (NBPtr->GetBitField (NBPtr, BFDctSelIntLvEn) == 0) ? FALSE : TRUE;
+
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm ++, DmiLogicalDimmInfoTable ++) {
+ //
+ // Initialize default value for DMI fields
+ //
+ DmiLogicalDimmInfoTable->DimmPresent = 0;
+ DmiLogicalDimmInfoTable->Socket = Socket;
+ DmiLogicalDimmInfoTable->Channel = Channel;
+ DmiLogicalDimmInfoTable->Dimm = Dimm;
+ DmiLogicalDimmInfoTable->StartingAddr = 0;
+ DmiLogicalDimmInfoTable->EndingAddr = 0;
+ DmiLogicalDimmInfoTable->ExtStartingAddr = 0;
+ DmiLogicalDimmInfoTable->ExtEndingAddr = 0;
+ //
+ // Starting/Ending Address for each DIMM
+ //
+ // If Ending Address >= 0xFFFFFFFF, update Starting Address & Ending Address to 0xFFFFFFFF,
+ // and use the Extended Starting Address & Extended Ending Address instead.
+ //
+ CsBaseAddrReg0 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + 2 * Dimm);
+ CsBaseAddrReg1 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + 2 * Dimm + 1);
+ if ((CsBaseAddrReg0 & 1) != 0 || (CsBaseAddrReg1 & 1) != 0) {
+ ASSERT (NumLogicalDimms < MaxLogicalDimms);
+ NumLogicalDimms ++;
+ DmiLogicalDimmInfoTable->DimmPresent = 1;
+ if (Dimm < MaxDimmsPerChannel) {
+ // The logical DIMM is mapped from a SR/QR physical DIMM
+ DmiLogicalDimmInfoTable->MemoryDeviceHandle = T17HandleMatrix[Socket][Channel][Dimm];
+ } else {
+ // The logical DIMM is mapped from a QR physical DIMM
+ DmiLogicalDimmInfoTable->MemoryDeviceHandle = T17HandleMatrix[Socket][Channel][Dimm - 2];
+ }
+ //
+ // For DR and QR DIMMs, DIMM size should be scaled based on the CS pair presence
+ //
+ ChipSelectPairScale = ((CsBaseAddrReg0 & 1) != 0 && (CsBaseAddrReg1 & 1) != 0) ? 1 : 0;
+ Address = ((CsBaseAddrReg0 & 1) != 0 ? CsBaseAddrReg0 : CsBaseAddrReg1) & NBPtr->CsRegMsk;
+ Address = (Address & 0xFFFF0000) >> 2;
+ if (DctInterleaveEnabled) {
+ //
+ // When channel interleaving is enabled, all the DIMMs on the node share the same starting address
+ //
+ Address = (UINT32)NodeMemBase;
+ } else {
+ if (NBPtr->DCTPtr->BkIntDis == FALSE && NBPtr->RefPtr->EnableBankIntlv == TRUE) {
+ //
+ // When bank interleaving is enabled, all the chip selects share the same starting address
+ //
+ Address = (UINT32) (NodeMemBase + DctMemBase);
+ } else {
+ Address += (UINT32) (NodeMemBase + DctMemBase);
+ }
+ }
+ if (NodeInterleaveEnabled) {
+ //
+ // When node interleaving is enabled, all the DIMMs in the system share the same starting address
+ //
+ Address = 0;
+ }
+ DmiLogicalDimmInfoTable->StartingAddr = Address;
+ AddrValue = (UINT64) Address +
+ ((UINT64) ((NBPtr->GetBitField (NBPtr, BFCSMask0Reg + Dimm) & 0xFFFF0000) + 0x00080000) >>
+ (2 - ChipSelectPairScale) ) - 1;
+ if (NBPtr->DCTPtr->BkIntDis == FALSE && NBPtr->RefPtr->EnableBankIntlv == TRUE) {
+ //
+ // When bank interleaving is enabled, all the chip selects share the same ending address
+ //
+ AddrValue = NodeMemBase + DctMemBase + (NBPtr->DCTPtr->Timings.DctMemSize << 6) - 1;
+ }
+ if (DctInterleaveEnabled) {
+ //
+ // When channel interleaving is enabled, the interleaved range is accounted for in the ending address of each DCT
+ //
+ AddrValue = NodeMemBase + MemFGetDctInterleavedLimit (NBPtr, Dct, DctMemBase, DctInterleavedMemSize);
+ }
+ if (NodeInterleaveEnabled) {
+ //
+ // When node interleaving is enabled, all the DIMMs in the system share the same ending address
+ //
+ AddrValue = SysMemSize - 1;
+ }
+ if (AddrValue >= ((UINT64) 0xFFFFFFFF)) {
+ DmiLogicalDimmInfoTable->StartingAddr = 0xFFFFFFFFUL;
+ DmiLogicalDimmInfoTable->EndingAddr = 0xFFFFFFFFUL;
+ DmiLogicalDimmInfoTable->ExtStartingAddr = (UINT64) Address;
+ DmiLogicalDimmInfoTable->ExtEndingAddr = AddrValue;
+ } else {
+ DmiLogicalDimmInfoTable->EndingAddr = (UINT32) AddrValue;
+ }
+ }
+ } // Dimm loop
+ } // Channel loop
+ } // Socket loop
+
+ // Max Capacity
+ *TotalMemSizePtr = TotalSize;
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------------------
+ * L O C A L F U N C T I O N S
+ *---------------------------------------------------------------------------------------
+ */
+
+/**
+ *
+ *
+ * This function obtains the memory size RJ6 contributed by the previous nodes
+ *
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] NodeLimit - Node number
+ *
+ */
+UINT64
+MemFGetNodeMemBase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 NodeLimit
+ )
+{
+ UINT8 Node;
+ UINT64 NodeMemBase;
+
+ NodeMemBase = 0;
+ // Calculate the total memory size in the system
+ for (Node = 0; Node < NodeLimit; Node++) {
+ NodeMemBase += (NBPtr[Node].MCTPtr->NodeMemSize << 6);
+ }
+
+ return NodeMemBase;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function obtains the memory size RJ6 contributed by the previous dcts on
+ * the current node
+ *
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] DctLimit - Dct number
+ *
+ */
+UINT64
+MemFGetDctMemBase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 DctLimit
+ )
+{
+ UINT8 Dct;
+ UINT64 DctMemBase;
+
+ DctMemBase = 0;
+ // Calculate the total memory size in the system
+ for (Dct = 0; Dct < DctLimit; Dct++) {
+ MemNSwitchDCTNb (NBPtr, Dct);
+ DctMemBase += (NBPtr->DCTPtr->Timings.DctMemSize << 6);
+ }
+
+ return DctMemBase;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function obtains the interleaved memory size RJ6 contributed on the
+ * current dct
+ *
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ */
+UINT64
+MemFGetDctInterleavedMemSize (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Dct;
+ UINT64 DctInterleavedMemSize;
+
+ DctInterleavedMemSize = NBPtr->MCTPtr->NodeMemSize << 6;
+ // Find minimum memory size among the interleaved DCTs
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ MemNSwitchDCTNb (NBPtr, Dct);
+ if (DctInterleavedMemSize > (NBPtr->DCTPtr->Timings.DctMemSize << 6)) {
+ DctInterleavedMemSize = (NBPtr->DCTPtr->Timings.DctMemSize << 6);
+ }
+ }
+
+ return DctInterleavedMemSize;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function obtains the memory ending address RJ6 contributed by a dct
+ * under channel interleaving
+ *
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] Dct - Dct number
+ * @param[in] DctMemBase - Dct memory base
+ * @param[in] DctInterleavedMemSize - Dct interleaved memory size
+ *
+ */
+UINT64
+MemFGetDctInterleavedLimit (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 Dct,
+ IN UINT64 DctMemBase,
+ IN UINT64 DctInterleavedMemSize
+ )
+{
+ UINT64 DctMemLimit;
+ UINT8 i;
+
+ DctMemLimit = 0;
+ if (DctInterleavedMemSize == NBPtr->DCTPtr->Timings.DctMemSize << 6) {
+ // The whole memory range is interleaved for the DCTs with the minimum memory size
+ for (i = 0; i < NBPtr->DctCount; i++) {
+ DctMemLimit += DctInterleavedMemSize;
+ }
+ DctMemLimit -= 1;
+ } else {
+ // Part of the memory range is interleaved for the DCTs with memory size larger than
+ // the minimum. The remaining is treated as non-interleaved.
+ for (i = 0; i < NBPtr->DctCount - 1 - Dct; i++) {
+ DctMemLimit += DctInterleavedMemSize;
+ }
+ DctMemLimit += DctMemBase + (NBPtr->DCTPtr->Timings.DctMemSize << 6) - 1;
+ }
+
+ return DctMemLimit;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.c
new file mode 100644
index 0000000000..7ff3960971
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.c
@@ -0,0 +1,290 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfecc.c
+ *
+ * Feature ECC initialization functions
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/ECC)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mfecc.h"
+#include "Filecode.h"
+#include "mfmemclr.h"
+#include "GeneralServices.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_ECC_MFECC_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+STATIC
+InitECCOverriedeStruct (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT ECC_OVERRIDE_STRUCT *pecc_override_struct
+ );
+
+BOOLEAN
+MemFCheckECC (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+/*
+ *-----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+extern BUILD_OPT_CFG UserOptions;
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function checks to see if ECC can be enabled on all nodes
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFCheckECC (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ DIE_STRUCT *MCTPtr;
+ MEM_SHARED_DATA *SharedPtr;
+ BOOLEAN ErrorRecovery;
+
+ ASSERT (NBPtr != NULL);
+
+ MCTPtr = NBPtr->MCTPtr;
+ SharedPtr = NBPtr->SharedPtr;
+
+ ErrorRecovery = TRUE;
+ IDS_OPTION_HOOK (IDS_MEM_ERROR_RECOVERY, &ErrorRecovery, &NBPtr->MemPtr->StdHeader);
+
+ if (MCTPtr->NodeMemSize != 0) {
+ if (SharedPtr->AllECC && MCTPtr->Status[SbEccDimms] && (ErrorRecovery || (MCTPtr->ErrCode < AGESA_ERROR))) {
+ // Clear all MCA reports before using scrubber
+ // to initialize ECC check bits
+ //
+ NBPtr->McaNbCtlReg = NBPtr->GetBitField (NBPtr, BFMcaNbCtlReg);
+ NBPtr->SetBitField (NBPtr, BFMcaNbCtlReg, 0);
+ NBPtr->SetBitField (NBPtr, BFSyncOnUcEccEn, 0);
+ // In unganged mode, set DctDctIntlv
+ if (!NBPtr->Ganged) {
+ NBPtr->SetBitField (NBPtr, BFDctDatIntLv, 1);
+ }
+ //
+ // Set Ecc Symbol Size
+ //
+ NBPtr->SetEccSymbolSize (NBPtr);
+ // If ECC can be enabled on this node,
+ // set the master ECCen bit (according to setup)
+ //
+ NBPtr->SetBitField (NBPtr, BFDramEccEn, 1);
+ // Do mem clear on current node
+ MemFMctMemClr_Init (NBPtr);
+ return TRUE;
+ } else {
+ if (SharedPtr->AllECC) {
+ SharedPtr->AllECC = FALSE;
+ }
+ // ECC requested but cannot be enabled
+ MCTPtr->Status[SbEccDimms] = FALSE;
+ MCTPtr->ErrStatus[EsbDramECCDis] = TRUE;
+ PutEventLog (AGESA_WARNING, MEM_WARNING_ECC_DIS, NBPtr->Node, 0, 0, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_WARNING, MCTPtr);
+ }
+ }
+ return FALSE;
+}
+
+ /* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function initializes the ECC on all nodes
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFInitECC (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Node;
+ UINT32 ScrubAddrRJ16;
+ DIE_STRUCT *MCTPtr;
+ MEM_SHARED_DATA *SharedPtr;
+ ECC_OVERRIDE_STRUCT ecc_override_struct;
+ BOOLEAN Flag;
+
+ InitECCOverriedeStruct (NBPtr, &ecc_override_struct);
+ IDS_OPTION_HOOK (IDS_ECC, &ecc_override_struct, &(NBPtr->MemPtr->StdHeader));
+
+ ASSERT (NBPtr != NULL);
+
+ MCTPtr = NBPtr->MCTPtr;
+ Node = MCTPtr->NodeId;
+ SharedPtr = NBPtr->SharedPtr;
+ Flag = TRUE;
+
+ NBPtr->FamilySpecificHook[ScrubberErratum] (NBPtr, (VOID *) &Flag);
+
+ if ((MCTPtr->Status[SbEccDimms]) && (SharedPtr->AllECC)) {
+ // Check if the input dram scrub rate is supported or not
+ ASSERT (ecc_override_struct.CfgScrubDramRate <= 0x16);
+ if (ecc_override_struct.CfgScrubDramRate != 0) {
+ // Program scrub address,
+ // let the scrub Addr be the Base of this Node
+ // Only enable Dram scrubber when there is memory on current node
+ //
+ NBPtr->SetBitField (NBPtr, BFScrubReDirEn, 0);
+ ScrubAddrRJ16 = (NBPtr->GetBitField (NBPtr, BFDramBaseReg0 + Node) & 0xFFFF0000) >> 8;
+ ScrubAddrRJ16 |= NBPtr->GetBitField (NBPtr, BFDramBaseHiReg0 + Node) << 24;
+ NBPtr->SetBitField (NBPtr, BFScrubAddrLoReg, ScrubAddrRJ16 << 16);
+ NBPtr->SetBitField (NBPtr, BFScrubAddrHiReg, ScrubAddrRJ16 >> 16);
+ NBPtr->SetBitField (NBPtr, BFDramScrub, ecc_override_struct.CfgScrubDramRate);
+ NBPtr->IsSupported[ScrubberEn] = TRUE;
+ }
+ }
+ // Scrub CTL for Dcache, L2, L3
+ // Check if the input L2 scrub rate is supported or not
+ ASSERT (ecc_override_struct.CfgScrubL2Rate <= 0x16);
+ NBPtr->SetBitField (NBPtr, BFL2Scrub, ecc_override_struct.CfgScrubL2Rate);
+ // Check if the input Dcache scrub rate is supported or not
+ ASSERT (ecc_override_struct.CfgScrubDcRate <= 0x16);
+ NBPtr->SetBitField (NBPtr, BFDcacheScrub, ecc_override_struct.CfgScrubDcRate);
+ // Do not enable L3 Scrub if F3xE8[L3Capable] is 0 or F3x188[DisableL3] is 1
+ if ((NBPtr->GetBitField (NBPtr, BFL3Capable) == 1) && (NBPtr->GetBitField (NBPtr, BFDisableL3) == 0)) {
+ // Check if input L3 scrub rate is supported or not
+ ASSERT (ecc_override_struct.CfgScrubL3Rate <= 0x16);
+ NBPtr->SetBitField (NBPtr, BFL3Scrub, ecc_override_struct.CfgScrubL3Rate);
+ }
+
+ // Check if Dcache scrubber or L2 scrubber is enabled
+ if ((ecc_override_struct.CfgScrubL2Rate != 0) || (ecc_override_struct.CfgScrubDcRate!= 0)) {
+ // If ClkDivisor is deeper than divide-by-16
+ if (NBPtr->GetBitField (NBPtr, BFC1ClkDivisor) > 4) {
+ // Set it to divide-by-16
+ NBPtr->SetBitField (NBPtr, BFC1ClkDivisor, 4);
+ }
+ }
+
+ NBPtr->SetBitField (NBPtr, BFScrubReDirEn, ecc_override_struct.CfgEccRedirection);
+ NBPtr->SetBitField (NBPtr, BFSyncOnUcEccEn, ecc_override_struct.CfgEccSyncFlood);
+ // Restore MCA reports after scrubber is done
+ // with initializing ECC check bits
+ NBPtr->SetBitField (NBPtr, BFMcaNbCtlReg, NBPtr->McaNbCtlReg);
+
+ Flag = FALSE;
+ NBPtr->FamilySpecificHook[ScrubberErratum] (NBPtr, (VOID *) &Flag);
+
+ return TRUE;
+}
+
+VOID
+STATIC
+InitECCOverriedeStruct (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT ECC_OVERRIDE_STRUCT *pecc_override_struct
+ )
+{
+ //
+ // If (D18F3x44[DramEccEn]==1) THEN 1 ELSE 0 ENDIF
+ //
+ if (NBPtr->GetBitField (NBPtr, BFDramEccEn) == 1) {
+ pecc_override_struct->CfgEccRedirection = 1;
+ } else {
+ pecc_override_struct->CfgEccRedirection = 0;
+ }
+
+ pecc_override_struct->CfgEccSyncFlood = UserOptions.CfgEccSyncFlood;
+ pecc_override_struct->CfgScrubDcRate = UserOptions.CfgScrubDcRate;
+
+ if (UserOptions.CfgScrubDramRate != 0xFF) {
+ pecc_override_struct->CfgScrubDramRate = UserOptions.CfgScrubDramRate;
+ } else {
+ if (NBPtr->MCTPtr->NodeMemSize <= 0x4000) {
+ pecc_override_struct->CfgScrubDramRate = 0x12; // 1 ~ 1 GB
+ } else if (NBPtr->MCTPtr->NodeMemSize <= 0x8000) {
+ pecc_override_struct->CfgScrubDramRate = 0x11; // 1 GB + 1 ~ 2 GB
+ } else if (NBPtr->MCTPtr->NodeMemSize <= 0x10000) {
+ pecc_override_struct->CfgScrubDramRate = 0x10; // 2 GB + 1 ~ 4 GB
+ } else if (NBPtr->MCTPtr->NodeMemSize <= 0x20000) {
+ pecc_override_struct->CfgScrubDramRate = 0x0F; // 4 GB + 1 ~ 8 GB
+ } else if (NBPtr->MCTPtr->NodeMemSize <= 0x40000) {
+ pecc_override_struct->CfgScrubDramRate = 0x0E; // 8 GB + 1 ~ 16 GB
+ } else {
+ pecc_override_struct->CfgScrubDramRate = 0x0D; //16 GB + 1 above
+ }
+ }
+
+ pecc_override_struct->CfgScrubL2Rate = UserOptions.CfgScrubL2Rate;
+ pecc_override_struct->CfgScrubL3Rate = UserOptions.CfgScrubL3Rate;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.h
new file mode 100644
index 0000000000..a25b12e6ab
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfecc.h
@@ -0,0 +1,80 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfecc.h
+ *
+ * Feature ECC initialization functions
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+#ifndef _MFECC_H_
+#define _MFECC_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemFInitECC (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+#endif /* _MFECC_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfemp.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfemp.c
new file mode 100644
index 0000000000..54487d2a1b
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ECC/mfemp.c
@@ -0,0 +1,177 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfemp.c
+ *
+ * Feature EMP initialization functions
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/ECC)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+
+
+#include "AGESA.h"
+#include "mm.h"
+#include "mn.h"
+#include "Ids.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_ECC_MFEMP_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+IsPowerOfTwo (
+ IN UINT32 TestNumber
+ );
+
+BOOLEAN
+MemFInitEMP (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+/*
+ *-----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+extern BUILD_OPT_CFG UserOptions;
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function initializes EMP (Enhanced Memory Protection)
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFInitEMP (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ MEM_PARAMETER_STRUCT *RefPtr;
+ DIE_STRUCT *MCTPtr;
+
+ ASSERT (NBPtr != NULL);
+
+ RefPtr = NBPtr->RefPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ if (RefPtr->EnableEccFeature) {
+ if (NBPtr->GetBitField (NBPtr, BFEnhMemProtCap) == 0) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_EMP_NOT_SUPPORTED, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader);
+ MCTPtr->ErrStatus[EsbEMPNotSupported] = TRUE;
+ } else if (RefPtr->EnableChannelIntlv || RefPtr->EnableBankIntlv || RefPtr->EnableBankSwizzle) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_EMP_CONFLICT, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader);
+ MCTPtr->ErrStatus[EsbEMPConflict] = TRUE;
+ } else if ((!MCTPtr->GangedMode) &&
+ (!IsPowerOfTwo (MCTPtr->DctData[0].Timings.DctMemSize) &&
+ !IsPowerOfTwo (MCTPtr->DctData[1].Timings.DctMemSize))) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_EMP_NOT_ENABLED, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader);
+ MCTPtr->ErrStatus[EsbEMPDis] = TRUE;
+ } else {
+ // Reduce memory size to 7/8 of the original memory size
+ ASSERT ((MCTPtr->NodeMemSize % 8) == 0);
+ NBPtr->SetBitField (NBPtr, BFDramHoleValid, 0);
+ MCTPtr->NodeMemSize = (MCTPtr->NodeMemSize / 8) * 7;
+ NBPtr->HtMemMapInit (NBPtr);
+ NBPtr->CpuMemTyping (NBPtr);
+
+ // Enable EMP
+ NBPtr->SetBitField (NBPtr, BFDramEccEn, 1);
+
+ // Scrub CTL settings for Dcache, L2
+ NBPtr->SetBitField (NBPtr, BFL2Scrub, UserOptions.CfgScrubL2Rate);
+ NBPtr->SetBitField (NBPtr, BFDcacheScrub, UserOptions.CfgScrubDcRate);
+
+ NBPtr->SetBitField (NBPtr, BFSyncOnUcEccEn, UserOptions.CfgEccSyncFlood);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function checks to see if the input is power of two.
+ *
+ * @param[in] TestNumber - Value to check for power of two
+ *
+ * @return TRUE - is power of two
+ * FALSE - is not power of two
+ */
+BOOLEAN
+STATIC
+IsPowerOfTwo (
+ IN UINT32 TestNumber
+ )
+{
+ return (BOOLEAN) ((TestNumber & (TestNumber - 1)) == 0);
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/EXCLUDIMM/mfdimmexclud.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/EXCLUDIMM/mfdimmexclud.c
new file mode 100644
index 0000000000..475b04ffab
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/EXCLUDIMM/mfdimmexclud.c
@@ -0,0 +1,206 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfdimmexclud.c
+ *
+ * Feature DIMM exclude.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/EXCLUDIMM)
+ * @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 "OptionMemory.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "Ids.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_EXCLUDIMM_MFDIMMEXCLUD_FILECODE
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+MemFRASExcludeDIMM (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Check and disable Chip selects that fail training for each node.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+BOOLEAN
+MemFRASExcludeDIMM (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 ReserveDCT;
+ UINT8 q;
+ BOOLEAN Flag;
+ BOOLEAN IsCSIntlvEnabled;
+ UINT16 CsTestFail;
+ DIE_STRUCT *MCTPtr;
+ BOOLEAN RetVal;
+
+ ASSERT (NBPtr != NULL);
+ ReserveDCT = NBPtr->Dct;
+ CsTestFail = 0;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.CsTestFail != 0) {
+ // When there is no new failed dimm that needs to be excluded, then no need to go through the process.
+ switch (NBPtr->SharedPtr->DimmExcludeFlag) {
+ case NORMAL:
+ // See there is new dimm that needs to be excluded
+ if ((NBPtr->DCTPtr->Timings.CsTestFail & NBPtr->DCTPtr->Timings.CsEnabled) != 0) {
+ CsTestFail |= NBPtr->DCTPtr->Timings.CsTestFail;
+ }
+ break;
+ case TRAINING:
+ // Do not do any dimm excluding during training
+ // Dimm exclude will be done at the end of training
+ break;
+ case END_TRAINING:
+ // Exclude all dimms that have failures during training
+ if ((NBPtr->DCTPtr->Timings.CsTrainFail != 0) ||
+ ((NBPtr->DCTPtr->Timings.CsTestFail & NBPtr->DCTPtr->Timings.CsEnabled) != 0)) {
+ CsTestFail |= NBPtr->DCTPtr->Timings.CsTestFail;
+ }
+ break;
+ default:
+ IDS_ERROR_TRAP;
+ }
+ }
+ }
+
+ if (CsTestFail != 0) {
+ IsCSIntlvEnabled = FALSE;
+ MCTPtr = NBPtr->MCTPtr;
+ MCTPtr->NodeMemSize = 0;
+ NBPtr->SharedPtr->NodeMap[NBPtr->Node].IsValid = FALSE;
+ NBPtr->SharedPtr->NodeMap[NBPtr->Node].SysBase = 0;
+ NBPtr->SharedPtr->NodeMap[NBPtr->Node].SysLimit = 0;
+ NBPtr->SetBitField (NBPtr, BFDramBaseAddr, 0);
+ NBPtr->SetBitField (NBPtr, BFDramLimitAddr, 0);
+
+ if (MCTPtr->GangedMode) {
+ // if ganged mode, disable all pairs of CS that fail.
+ NBPtr->DCTPtr->Timings.CsTestFail |= CsTestFail;
+ }
+
+ // if chip select interleaving has been enabled, need to undo it before remapping memory
+ if (NBPtr->FeatPtr->UndoInterleaveBanks (NBPtr)) {
+ IsCSIntlvEnabled = TRUE;
+ }
+
+ Flag = TRUE;
+ NBPtr->FamilySpecificHook[BfAfExcludeDimm] (NBPtr, &Flag);
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (!MCTPtr->GangedMode || (MCTPtr->Dct == 0)) {
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ NBPtr->DCTPtr->Timings.DctMemSize = 0;
+
+ NBPtr->DCTPtr->Timings.CsEnabled = 0;
+ for (q = 0; q < MAX_CS_PER_CHANNEL; q++) {
+ NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + q, 0);
+ }
+
+ // Set F2x94[DisDramInterface] = 1 if all chip selects fail training on the DCT
+ if ((NBPtr->DCTPtr->Timings.CsPresent & ~NBPtr->DCTPtr->Timings.CsTestFail) == 0) {
+ NBPtr->DisableDCT (NBPtr);
+ }
+
+ Flag = NBPtr->StitchMemory (NBPtr);
+ ASSERT (Flag == TRUE);
+ }
+ }
+ }
+ Flag = FALSE;
+ NBPtr->FamilySpecificHook[BfAfExcludeDimm] (NBPtr, &Flag);
+
+ // Re-enable chip select interleaving when remapping is done.
+ if (IsCSIntlvEnabled) {
+ NBPtr->FeatPtr->InterleaveBanks (NBPtr);
+ }
+
+ RetVal = TRUE;
+ } else {
+ RetVal = FALSE;
+ }
+ NBPtr->SwitchDCT (NBPtr, ReserveDCT);
+ return RetVal;
+}
+
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.c
new file mode 100644
index 0000000000..6bd85214af
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.c
@@ -0,0 +1,548 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfidendimm.c
+ *
+ * Translate physical system address to dimm identification.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat)
+ * @e \$Revision: 84482 $ @e \$Date: 2012-12-16 22:48:10 -0600 (Sun, 16 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 "mm.h"
+#include "mn.h"
+#include "Ids.h"
+#include "OptionMemory.h"
+#include "heapManager.h"
+#include "mfidendimm.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_IDENDIMM_MFIDENDIMM_FILECODE
+extern MEM_NB_SUPPORT memNBInstalled[];
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+#define MAX_DCTS_PER_DIE 2 ///< Max DCTs per die
+#define MAX_CHLS_PER_DCT 1 ///< Max Channels per DCT
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+AGESA_STATUS
+STATIC
+MemFTransSysAddrToCS (
+ IN OUT AMD_IDENTIFY_DIMM *AmdDimmIdentify,
+ IN MEM_MAIN_DATA_BLOCK *mmPtr
+ );
+
+UINT32
+STATIC
+MemFGetPCI (
+ IN MEM_NB_BLOCK *NBPtr,
+ IN UINT8 NodeID,
+ IN UINT8 DctNum,
+ IN BIT_FIELD_NAME BitFieldName
+ );
+
+UINT8
+STATIC
+MemFUnaryXOR (
+ IN UINT32 address
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/*-----------------------------------------------------------------------------*/
+/**
+*
+* This function identifies the dimm on which the given memory address locates.
+*
+* @param[in, out] *AmdDimmIdentify - Pointer to the parameter structure AMD_IDENTIFY_DIMM
+*
+* @retval AGESA_SUCCESS - Successfully translate physical system address
+* to dimm identification.
+* AGESA_BOUNDS_CHK - Targeted address is out of bound.
+*
+*/
+
+AGESA_STATUS
+AmdIdentifyDimm (
+ IN OUT AMD_IDENTIFY_DIMM *AmdDimmIdentify
+ )
+{
+ UINT8 i;
+ AGESA_STATUS RetVal;
+ MEM_MAIN_DATA_BLOCK mmData; // Main Data block
+ MEM_NB_BLOCK *NBPtr;
+ MEM_DATA_STRUCT MemData;
+ LOCATE_HEAP_PTR LocHeap;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ UINT8 Node;
+ UINT8 Dct;
+ UINT8 Die;
+ UINT8 DieCount;
+
+ LibAmdMemCopy (&(MemData.StdHeader), &(AmdDimmIdentify->StdHeader), sizeof (AMD_CONFIG_PARAMS), &(AmdDimmIdentify->StdHeader));
+ mmData.MemPtr = &MemData;
+ RetVal = MemSocketScan (&mmData);
+ if (RetVal == AGESA_FATAL) {
+ return RetVal;
+ }
+ DieCount = mmData.DieCount;
+
+ // Search for AMD_MEM_AUTO_HANDLE on the heap first.
+ // Only apply for space on the heap if cannot find AMD_MEM_AUTO_HANDLE on the heap.
+ LocHeap.BufferHandle = AMD_MEM_AUTO_HANDLE;
+ if (HeapLocateBuffer (&LocHeap, &AmdDimmIdentify->StdHeader) == AGESA_SUCCESS) {
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ NBPtr = (MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ mmData.NBPtr = NBPtr;
+ } else {
+ AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK)));
+ AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (HeapAllocateBuffer (&AllocHeapParams, &AmdDimmIdentify->StdHeader) != AGESA_SUCCESS) {
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_IDENTIFY_DIMM_MEM_NB_BLOCK, 0, 0, 0, 0, &AmdDimmIdentify->StdHeader);
+ ASSERT(FALSE); // Could not allocate heap space for NB block for Identify DIMM
+ return AGESA_FATAL;
+ }
+ NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
+ mmData.NBPtr = NBPtr;
+ // Construct each die.
+ for (Die = 0; Die < DieCount; Die ++) {
+ i = 0;
+ while (memNBInstalled[i].MemIdentifyDimmConstruct != 0) {
+ if (memNBInstalled[i].MemIdentifyDimmConstruct (&NBPtr[Die], &MemData, Die)) {
+ break;
+ }
+ i++;
+ };
+ if (memNBInstalled[i].MemIdentifyDimmConstruct == 0) {
+ PutEventLog (AGESA_FATAL, MEM_ERROR_NO_CONSTRUCTOR_FOR_IDENTIFY_DIMM, Die, 0, 0, 0, &AmdDimmIdentify->StdHeader);
+ ASSERT(FALSE); // No Identify DIMM constructor found
+ return AGESA_FATAL;
+ }
+ }
+ }
+
+ if ((RetVal = MemFTransSysAddrToCS (AmdDimmIdentify, &mmData)) == AGESA_SUCCESS) {
+ // Translate Node, DCT and Chip select number to Socket, Channel and Dimm number.
+ Node = AmdDimmIdentify->SocketId;
+ Dct = AmdDimmIdentify->MemChannelId;
+ AmdDimmIdentify->SocketId = MemData.DiesPerSystem[Node].SocketId;
+ AmdDimmIdentify->MemChannelId = NBPtr[Node].GetSocketRelativeChannel (&NBPtr[Node], Dct, 0);
+ AmdDimmIdentify->DimmId /= 2;
+ }
+
+ return RetVal;
+}
+
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------*/
+/**
+*
+* This function translates the given physical system address to
+* a node, channel select, chip select, bank, row, and column address.
+*
+* @param[in, out] *AmdDimmIdentify - Pointer to the parameter structure AMD_IDENTIFY_DIMM
+* @param[in, out] *mmPtr - Pointer to the MEM_MAIN_DATA_BLOCK
+*
+* @retval AGESA_SUCCESS - The chip select address is found
+* @retval AGESA_BOUNDS_CHK - Targeted address is out of bound.
+*
+*/
+AGESA_STATUS
+STATIC
+MemFTransSysAddrToCS (
+ IN OUT AMD_IDENTIFY_DIMM *AmdDimmIdentify,
+ IN MEM_MAIN_DATA_BLOCK *mmPtr
+ )
+{
+ BOOLEAN CSFound;
+ BOOLEAN DctSelHiRngEn;
+ BOOLEAN DctSelIntLvEn;
+ BOOLEAN DctGangEn;
+ BOOLEAN HiRangeSelected;
+ BOOLEAN DramHoleValid;
+ BOOLEAN CSEn;
+ BOOLEAN SwapDone;
+ BOOLEAN IntLvRgnSwapEn;
+ UINT8 DctSelHi;
+ UINT8 DramEn;
+ UINT8 range;
+ UINT8 IntlvEn;
+ UINT8 IntlvSel;
+ UINT8 ILog;
+ UINT8 DctSelIntLvAddr;
+ UINT8 DctNum;
+ UINT8 cs;
+ UINT8 BadDramCs;
+ UINT8 spare;
+ UINT8 IntLvRgnBaseAddr;
+ UINT8 IntLvRgnLmtAddr;
+ UINT8 IntLvRgnSize;
+ UINT32 temp;
+ UINT32 DramHoleOffset;
+ UINT32 DramHoleBase;
+ UINT64 DramBase;
+ UINT64 DramLimit;
+ UINT64 DramLimitSysAddr;
+ UINT64 DctSelBaseAddr;
+ UINT64 DctSelBaseOffset;
+ UINT64 ChannelAddr;
+ UINT64 CSBase;
+ UINT64 CSMask;
+ UINT64 InputAddr;
+ UINT64 ChannelOffset;
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 Die;
+
+ UINT64 SysAddr;
+ UINT8 *NodeID;
+ UINT8 *ChannelSelect;
+ UINT8 *ChipSelect;
+
+ SysAddr = AmdDimmIdentify->MemoryAddress;
+ NodeID = &(AmdDimmIdentify->SocketId);
+ ChannelSelect = &(AmdDimmIdentify->MemChannelId);
+ ChipSelect = &(AmdDimmIdentify->DimmId);
+ CSFound = FALSE;
+ ILog = 0;
+ NBPtr = mmPtr->NBPtr;
+
+ NBPtr->FamilySpecificHook[FixupSysAddr] (NBPtr, &SysAddr);
+
+ // Loop to determine the dram range
+ for (Die = 0; Die < mmPtr->DieCount; Die ++) {
+ range = NBPtr[Die].Node;
+
+ // DRAM Base
+ temp = MemFGetPCI (NBPtr, 0, 0, BFDramBaseReg0 + range);
+ DramEn = (UINT8) (temp & 0x3);
+ IntlvEn = (UINT8) ((temp >> 8) & 0x7);
+
+ DramBase = ((UINT64) (MemFGetPCI (NBPtr, 0, 0, BFDramBaseHiReg0 + range) & 0xFF) << 40) |
+ (((UINT64) temp & 0xFFFF0000) << 8);
+
+ // DRAM Limit
+ temp = MemFGetPCI (NBPtr, 0, 0, BFDramLimitReg0 + range);
+ *NodeID = (UINT8) (temp & 0x7);
+ IntlvSel = (UINT8) ((temp >> 8) & 0x7);
+ DramLimit = ((UINT64) (MemFGetPCI (NBPtr, 0, 0, BFDramLimitHiReg0 + range) & 0xFF) << 40) |
+ (((UINT64) temp << 8) | 0xFFFFFF);
+ DramLimitSysAddr = (((UINT64) MemFGetPCI (NBPtr, *NodeID, 0, BFDramLimitAddr)) << 27) | 0x7FFFFFF;
+ ASSERT (DramLimit <= DramLimitSysAddr);
+
+ if ((DramEn != 0) && (DramBase <= SysAddr) && (SysAddr <= DramLimitSysAddr) &&
+ ((IntlvEn == 0) || (IntlvSel == ((SysAddr >> 12) & IntlvEn)))) {
+ // Determine the number of bit positions consumed by Node Interleaving
+ switch (IntlvEn) {
+
+ case 0x0:
+ ILog = 0;
+ break;
+
+ case 0x1:
+ ILog = 1;
+ break;
+
+ case 0x3:
+ ILog = 2;
+ break;
+
+ case 0x7:
+ ILog = 3;
+ break;
+
+ default:
+ IDS_ERROR_TRAP;
+ }
+
+ DramHoleOffset = MemFGetPCI (NBPtr, *NodeID, 0, BFDramHoleOffset) << 23;
+ DramHoleValid = (BOOLEAN) MemFGetPCI (NBPtr, *NodeID, 0, (mmPtr->DieCount == 1) ? BFDramMemHoistValid : BFDramHoleValid);
+ DramHoleBase = MemFGetPCI (NBPtr, *NodeID, 0, BFDramHoleBase) << 24;
+ // Address belongs to this node based on DramBase/Limit,
+ // but is in the memory hole so it doesn't map to DRAM
+ if (DramHoleValid && (DramHoleBase <= SysAddr) && (SysAddr < 0x100000000)) {
+ return AGESA_BOUNDS_CHK;
+ }
+
+ // F2x10C Swapped Interleaved Region
+ IntLvRgnSwapEn = (BOOLEAN) MemFGetPCI (NBPtr, *NodeID, 0, BFIntLvRgnSwapEn);
+ if (IntLvRgnSwapEn) {
+ IntLvRgnBaseAddr = (UINT8) MemFGetPCI (NBPtr, *NodeID, 0, BFIntLvRgnBaseAddr);
+ IntLvRgnLmtAddr = (UINT8) MemFGetPCI (NBPtr, *NodeID, 0, BFIntLvRgnLmtAddr);
+ IntLvRgnSize = (UINT8) MemFGetPCI (NBPtr, *NodeID, 0, BFIntLvRgnSize);
+ ASSERT (IntLvRgnSize == (IntLvRgnLmtAddr - IntLvRgnBaseAddr + 1));
+ if (((SysAddr >> 34) == 0) &&
+ ((((SysAddr >> 27) >= IntLvRgnBaseAddr) && ((SysAddr >> 27) <= IntLvRgnLmtAddr))
+ || ((SysAddr >> 27) < IntLvRgnSize))) {
+ SysAddr ^= (UINT64) IntLvRgnBaseAddr << 27;
+ }
+ }
+
+ // Extract variables from F2x110 DRAM Controller Select Low Register
+ DctSelHiRngEn = (BOOLEAN) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelHiRngEn);
+ DctSelHi = (UINT8) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelHi);
+ DctSelIntLvEn = (BOOLEAN) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelIntLvEn);
+ DctGangEn = (BOOLEAN) MemFGetPCI (NBPtr, *NodeID, 0, BFDctGangEn);
+ DctSelIntLvAddr = (UINT8) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelIntLvAddr);
+ DctSelBaseAddr = (UINT64) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelBaseAddr) << 27;
+ DctSelBaseOffset = (UINT64) MemFGetPCI (NBPtr, *NodeID, 0, BFDctSelBaseOffset) << 26;
+
+
+ // Determine if high DCT address range is being selected
+ if (DctSelHiRngEn && !DctGangEn && (SysAddr >= DctSelBaseAddr)) {
+ HiRangeSelected = TRUE;
+ } else {
+ HiRangeSelected = FALSE;
+ }
+
+ // Determine Channel
+ if (DctGangEn) {
+ *ChannelSelect = (UINT8) ((SysAddr >> 3) & 0x1);
+ } else if (HiRangeSelected) {
+ *ChannelSelect = DctSelHi;
+ } else if (DctSelIntLvEn && (DctSelIntLvAddr == 0)) {
+ *ChannelSelect = (UINT8) ((SysAddr >> 6) & 0x1);
+ } else if (DctSelIntLvEn && (((DctSelIntLvAddr >> 1) & 0x1) != 0)) {
+ temp = MemFUnaryXOR ((UINT32) ((SysAddr >> 16) & 0x1F));
+ if ((DctSelIntLvAddr & 0x1) != 0) {
+ *ChannelSelect = (UINT8) (((SysAddr >> 9) & 0x1) ^ temp);
+ } else {
+ *ChannelSelect = (UINT8) (((SysAddr >> 6) & 0x1) ^ temp);
+ }
+ } else if (DctSelIntLvEn) {
+ *ChannelSelect = (UINT8) ((SysAddr >> (12 + ILog)) & 0x1);
+ } else if (DctSelHiRngEn) {
+ *ChannelSelect = ~DctSelHi & 0x1;
+ } else {
+ *ChannelSelect = 0;
+ }
+ ASSERT (*ChannelSelect < NBPtr[*NodeID].DctCount);
+
+ // Determine base address offset
+ if (HiRangeSelected) {
+ if ((DctSelBaseAddr < DramHoleBase) && DramHoleValid && (SysAddr >= (UINT64) 0x100000000)) {
+ ChannelOffset = (UINT64) DramHoleOffset;
+ } else {
+ ChannelOffset = DctSelBaseOffset;
+ }
+ } else {
+ if (DramHoleValid && (SysAddr >= (UINT64) 0x100000000)) {
+ ChannelOffset = (UINT64) DramHoleOffset;
+ } else {
+ ChannelOffset = DramBase;
+ }
+ }
+
+ // Remove hoisting offset and normalize to DRAM bus addresses
+ ChannelAddr = SysAddr - ChannelOffset;
+
+ // Remove node interleaving
+ if (IntlvEn != 0) {
+ ChannelAddr = ((ChannelAddr >> (12 + ILog)) << 12) | (ChannelAddr & 0xFFF);
+ }
+
+ // Remove channel interleave
+ if (DctSelIntLvEn && !HiRangeSelected && !DctGangEn) {
+ if ((DctSelIntLvAddr & 1) != 1) {
+ // A[6] Select or Hash 6
+ ChannelAddr = ((ChannelAddr >> 7) << 6) | (ChannelAddr & 0x3F);
+ } else if (DctSelIntLvAddr == 1) {
+ // A[12]
+ ChannelAddr = ((ChannelAddr >> 13) << 12) | (ChannelAddr & 0xFFF);
+ } else {
+ // Hash 9
+ ChannelAddr = ((ChannelAddr >> 10) << 9) | (ChannelAddr & 0x1FF);
+ }
+ }
+
+ // Determine the Chip Select
+ for (cs = 0; cs < MAX_CS_PER_CHANNEL; ++ cs) {
+ DctNum = DctGangEn ? 0 : *ChannelSelect;
+
+ // Obtain the CS Base
+ temp = MemFGetPCI (NBPtr, *NodeID, DctNum, BFCSBaseAddr0Reg + cs);
+ CSEn = (BOOLEAN) (temp & 0x1);
+ CSBase = ((UINT64) temp & NBPtr->CsRegMsk) << 8;
+
+ // Obtain the CS Mask
+ CSMask = ((UINT64) MemFGetPCI (NBPtr, *NodeID, DctNum, BFCSMask0Reg + (cs >> 1)) & NBPtr->CsRegMsk) << 8;
+
+ // Adjust the Channel Addr for easy comparison
+ InputAddr = ((ChannelAddr >> 8) & NBPtr->CsRegMsk) << 8;
+
+ if (CSEn && ((InputAddr & ~CSMask) == (CSBase & ~CSMask))) {
+ CSFound = TRUE;
+
+ *ChipSelect = cs;
+
+ temp = MemFGetPCI (NBPtr, *NodeID, 0, BFOnLineSpareControl);
+ SwapDone = (BOOLEAN) ((temp >> (1 + 2 * (*ChannelSelect))) & 0x1);
+ BadDramCs = (UINT8) ((temp >> (4 + 4 * (*ChannelSelect))) & 0x7);
+ if (SwapDone && (cs == BadDramCs)) {
+ // Find the spare rank for the channel
+ for (spare = 0; spare < MAX_CS_PER_CHANNEL; ++spare) {
+ if ((MemFGetPCI (NBPtr, *NodeID, DctNum, BFCSBaseAddr0Reg + spare) & 0x2) != 0) {
+ *ChipSelect = spare;
+ break;
+ }
+ }
+ }
+ ASSERT (*ChipSelect < MAX_CS_PER_CHANNEL);
+
+ break;
+ }
+ }
+ }
+ if (CSFound) {
+ break;
+ }
+ }
+
+ // last ditch sanity check
+ ASSERT (!CSFound || ((*NodeID < mmPtr->DieCount) && (*ChannelSelect < NBPtr[*NodeID].DctCount) && (*ChipSelect < MAX_CS_PER_CHANNEL)));
+ if (CSFound) {
+ return AGESA_SUCCESS;
+ } else {
+ return AGESA_BOUNDS_CHK;
+ }
+
+}
+
+
+/*-----------------------------------------------------------------------------*/
+/**
+*
+* This function is the interface to call the PCI register access function
+* defined in NB block.
+*
+* @param[in] *NBPtr - Pointer to the parameter structure MEM_NB_BLOCK
+* @param[in] NodeID - Node ID number of the target Northbridge
+* @param[in] DctNum - DCT number if applicable, otherwise, put 0
+* @param[in] BitFieldName - targeted bitfield
+*
+* @retval UINT32 - 32 bits PCI register value
+*
+*/
+UINT32
+STATIC
+MemFGetPCI (
+ IN MEM_NB_BLOCK *NBPtr,
+ IN UINT8 NodeID,
+ IN UINT8 DctNum,
+ IN BIT_FIELD_NAME BitFieldName
+ )
+{
+ MEM_NB_BLOCK *LocalNBPtr;
+ UINT8 Die;
+
+ // Find NBBlock that associates with node NodeID
+ for (Die = 0; (Die < MAX_NODES_SUPPORTED) && (NBPtr[Die].Node != NodeID); Die ++);
+ ASSERT (Die < MAX_NODES_SUPPORTED);
+
+ // Get the northbridge pointer for the targeted node.
+ LocalNBPtr = &NBPtr[Die];
+ LocalNBPtr->FamilySpecificHook[DCTSelectSwitch] (LocalNBPtr, &DctNum);
+ LocalNBPtr->Dct = DctNum;
+ // The caller of this function will take care of the ganged/unganged situation.
+ // So Ganged is set to be false here, and do PCI read on the DCT specified by DctNum.
+ return LocalNBPtr->GetBitField (LocalNBPtr, BitFieldName);
+}
+
+/*-----------------------------------------------------------------------------*/
+/**
+*
+* This function returns an even parity bit (making the total # of 1's even)
+* {0, 1} = number of set bits in argument is {even, odd}.
+*
+* @param[in] address - the address on which the parity bit will be calculated
+*
+* @retval UINT8 - parity bit
+*
+*/
+
+UINT8
+STATIC
+MemFUnaryXOR (
+ IN UINT32 address
+ )
+{
+ UINT8 parity;
+ UINT8 index;
+ parity = 0;
+ for (index = 0; index < 32; ++ index) {
+ parity = (UINT8) (parity ^ (address & 0x1));
+ address = address >> 1;
+ }
+ return parity;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.h
new file mode 100644
index 0000000000..bf95ce0593
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/IDENDIMM/mfidendimm.h
@@ -0,0 +1,72 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfidendimm.h
+ *
+ * Header file for address to dimm identification translator.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+* ***************************************************************************
+*
+*/
+
+#ifndef _MFIDENDIMM_H_
+#define _MFIDENDIMM_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#endif //_MFIDENDIMM_H_
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.c
new file mode 100644
index 0000000000..9407f45b04
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.c
@@ -0,0 +1,172 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * lvddr3.c
+ *
+ * Voltage change for DDR3 DIMMs.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/LVDDR3)
+ * @e \$Revision: 84150 $ @e \$Date: 2012-12-12 15:46:25 -0600 (Wed, 12 Dec 2012) $
+ *
+ **/
+/*****************************************************************************
+*
+ * Copyright (c) 2008 - 2013, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Advanced Micro Devices, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+* ***************************************************************************
+*
+*/
+
+/*
+ *----------------------------------------------------------------------------
+ * MODULES USED
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_LVDDR3_MFLVDDR3_FILECODE
+/* features */
+#include "mflvddr3.h"
+
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculate the common lowest voltage supported by all DDR3
+ * DIMMs in the system. This function only needs to be called on BSP.
+ *
+ * @param[in, out] *NBPtr - Pointer to NB block
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFLvDdr3 (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_TECH_BLOCK *TechPtr;
+ MEM_SHARED_DATA *mmSharedPtr;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 Dimm;
+ UINT8 *SpdBufferPtr;
+ UINT8 VDDByte;
+ UINT8 VoltageMap;
+
+ mmSharedPtr = NBPtr->SharedPtr;
+ TechPtr = NBPtr->TechPtr;
+ VoltageMap = 0xFF;
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if (TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, Dimm)) {
+ // SPD byte 6: Module Nominal Voltage, VDD
+ // 1.5v - bit 0
+ // 1.35v - bit 1
+ // 1.2v - bit 2
+ VDDByte = SpdBufferPtr[MNVVDD];
+ IDS_HDT_CONSOLE (MEM_FLOW, "Node%d DCT%d Channel%d Dimm%d VDD Byte: 0x%02x\n", NBPtr->Node, Dct, Channel, Dimm, VDDByte);
+
+ // Reverse the 1.5V operable bit. So its encoding can be consistent
+ // with that of 1.35V and 1.25V operable bit.
+ VDDByte ^= 1;
+ ASSERT (VDDByte != 0);
+
+ if (mmSharedPtr->VoltageMap != 0) {
+ // Get the common supported voltage map
+ VoltageMap &= VDDByte;
+ } else {
+ // This is the second execution of all the loop as no common voltage is found
+ if (VDDByte == (1 << VOLT1_5_ENCODED_VAL)) {
+ // Always exclude 1.5V dimm if no common voltage is found
+ ChannelPtr->DimmExclude |= (UINT16) 1 << Dimm;
+ }
+ }
+ }
+ }
+ if (mmSharedPtr->VoltageMap == 0) {
+ NBPtr->DCTPtr->Timings.DimmExclude |= ChannelPtr->DimmExclude;
+ }
+ }
+ }
+
+ if (mmSharedPtr->VoltageMap != 0) {
+ mmSharedPtr->VoltageMap &= VoltageMap;
+ }
+
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.h
new file mode 100644
index 0000000000..93bc4f4aa4
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/LVDDR3/mflvddr3.h
@@ -0,0 +1,78 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mflvddr3.h
+ *
+ * Header file for DDR3 DIMMs voltage configuration.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+* ***************************************************************************
+*
+*/
+
+#ifndef _MFLVDDR3_H_
+#define _MFLVDDR3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+#define MNVVDD 6
+#define LOWEST_VOLT_BIT 2
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+MemFLvDdr3 (
+ IN OUT MEM_NB_BLOCK *NBPtr
+);
+
+#endif //_MFLVDDR3_H_
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/MEMCLR/mfmemclr.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/MEMCLR/mfmemclr.c
new file mode 100644
index 0000000000..5a0c67584a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/MEMCLR/mfmemclr.c
@@ -0,0 +1,153 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfmemclr.c
+ *
+ * Feature function for memory clear operation
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/Memclr)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+
+
+#include "AGESA.h"
+#include "mm.h"
+#include "mn.h"
+#include "mfmemclr.h"
+#include "Ids.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_MEMCLR_MFMEMCLR_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * Initiates memory clear operation on one node with Dram on it.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ */
+
+BOOLEAN
+MemFMctMemClr_Init (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ AGESA_TESTPOINT (TpProcMemMemClr, &NBPtr->MemPtr->StdHeader);
+ IDS_PERF_TIMESTAMP (TP_BEGINMEMFMCTMEMCLR_INIT, &(NBPtr->MemPtr->StdHeader));
+ if (NBPtr->RefPtr->EnableMemClr == TRUE) {
+ if (NBPtr->MCTPtr->NodeMemSize != 0) {
+ if (!NBPtr->MemCleared) {
+ NBPtr->PollBitField (NBPtr, BFMemClrBusy, 0, SPECIAL_PCI_ACCESS_TIMEOUT, FALSE);
+ if (NBPtr->GetBitField (NBPtr, BFDramEnabled) == 1) {
+ NBPtr->FamilySpecificHook[BeforeMemClr] (NBPtr, NBPtr);
+ NBPtr->SetBitField (NBPtr, BFDramBaseAddr, 0);
+ NBPtr->SetBitField (NBPtr, BFMemClrInit, 1);
+ }
+ }
+ }
+ }
+ IDS_PERF_TIMESTAMP (TP_ENDNMEMFMCTMEMCLR_INIT, &(NBPtr->MemPtr->StdHeader));
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * Ensures memory clear operation has completed on one node with Dram on it.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ */
+
+BOOLEAN
+MemFMctMemClr_Sync (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT32 MicroSecondToWait;
+
+ MicroSecondToWait = 0;
+ if (NBPtr->RefPtr->EnableMemClr == TRUE) {
+ if (NBPtr->MCTPtr->NodeMemSize != 0) {
+ // Calculate Timeout value:
+ // Timeout (in microsecond) = Memory Size * 1.5 ns / 8 Byte * 4 (Margin) * 1000 (change millisecond to us)
+ // NodeMemSize is system address right shifted by 16, so shift it 4 bits to right to convert it to MB.
+ // 1.5 / 8 * 4 * 1000 = 750
+ MicroSecondToWait = (NBPtr->MCTPtr->NodeMemSize >> 4) * 750;
+
+ if (!NBPtr->MemCleared) {
+ NBPtr->PollBitField (NBPtr, BFMemClrBusy, 0, MicroSecondToWait, FALSE);
+ NBPtr->PollBitField (NBPtr, BFMemCleared, 1, MicroSecondToWait, FALSE);
+ NBPtr->SetBitField (NBPtr, BFDramBaseAddr, NBPtr->MCTPtr->NodeSysBase >> (27 - 16));
+ NBPtr->MemCleared = TRUE;
+ }
+ }
+ }
+ return TRUE;
+}
+
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.c
new file mode 100644
index 0000000000..41a14ae3f3
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.c
@@ -0,0 +1,179 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfodthermal.c
+ *
+ * On Dimm thermal management.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat)
+ * @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 "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "Ids.h"
+#include "mfodthermal.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_ODTHERMAL_MFODTHERMAL_FILECODE
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/*-----------------------------------------------------------------------------*/
+/**
+ *
+ * This function does On-Dimm thermal management.
+ *
+ * @param[in, out] *NBPtr - Pointer to the MEM_NB_BLOCK.
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+
+BOOLEAN
+MemFOnDimmThermal (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ UINT8 i;
+ UINT8 Dct;
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_DATA_STRUCT *MemPtr;
+ UINT8 *SpdBufferPtr;
+ UINT8 ThermalOp;
+ BOOLEAN ODTSEn;
+ BOOLEAN ExtendTmp;
+ BOOLEAN FirstLoop;
+
+ ODTSEn = FALSE;
+ ExtendTmp = FALSE;
+ FirstLoop = TRUE;
+
+ ASSERT (NBPtr != NULL);
+ MemPtr = NBPtr->MemPtr;
+ AGESA_TESTPOINT (TpProcMemOnDimmThermal, &MemPtr->StdHeader);
+ if (NBPtr->MCTPtr->NodeMemSize != 0) {
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ // Only go through the DCT if it is not disabled.
+ if (NBPtr->GetBitField (NBPtr, BFDisDramInterface) == 0) {
+ ChannelPtr = NBPtr->ChannelPtr;
+ // If Ganged mode is enabled, need to go through all dram devices on both DCTs.
+ if (!NBPtr->Ganged || (NBPtr->Dct != 1)) {
+ if (!(NBPtr->IsSupported[CheckSetSameDctODTsEn]) || (NBPtr->IsSupported[CheckSetSameDctODTsEn] && (NBPtr->Dct != 1)) ||
+ ((NBPtr->Dct != 0) && (FirstLoop == TRUE))) {
+ ODTSEn = TRUE;
+ ExtendTmp = TRUE;
+ }
+ }
+ for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i ++) {
+ if (NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, i)) {
+ // Check byte 31: thermal and refresh option.
+ ThermalOp = SpdBufferPtr[THERMAL_OPT];
+ // Bit 3: ODTS readout
+ if (!((ThermalOp >> 3) & 1)) {
+ ODTSEn = FALSE;
+ }
+ // Bit 0: Extended Temperature Range.
+ if (!(ThermalOp & 1)) {
+ ExtendTmp = FALSE;
+ }
+ }
+ }
+
+ if (!NBPtr->Ganged || (NBPtr->Dct == 1)) {
+ // If in ganged mode, need to switch back to DCT0 to set the registers.
+ if (NBPtr->Ganged || NBPtr->IsSupported[CheckSetSameDctODTsEn]) {
+ NBPtr->SwitchDCT (NBPtr, 0);
+ ChannelPtr = NBPtr->ChannelPtr;
+ }
+ // If all dram devices on support ODTS
+ NBPtr->SetBitField (NBPtr, BFODTSEn, (ODTSEn == TRUE) ? 1 : 0);
+ ChannelPtr->ExtendTmp = ExtendTmp;
+ }
+ FirstLoop = FALSE;
+ } else {
+ ODTSEn = FALSE;
+ ExtendTmp = FALSE;
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\tDct %d\n", Dct);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tODTSEn = %d\n", ODTSEn);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tExtendTmp = %d\n", ExtendTmp);
+ }
+ }
+ return TRUE;
+}
+
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.h
new file mode 100644
index 0000000000..50945f3124
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/ODTHERMAL/mfodthermal.h
@@ -0,0 +1,77 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfodthermal.h
+ *
+ * Header file for On-Dimm thermal management.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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.
+* ***************************************************************************
+*
+*/
+
+#ifndef _MFODTHERMAL_H_
+#define _MFODTHERMAL_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemFOnDimmThermal (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+#endif //_MFODTHERMAL_H_
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfParallelTraining.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfParallelTraining.c
new file mode 100644
index 0000000000..2fd10c5e07
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfParallelTraining.c
@@ -0,0 +1,288 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfParallelTraining.c
+ *
+ * This is the parallel training feature
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/PARTRN)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "OptionMemory.h"
+#include "mm.h"
+#include "mn.h"
+#include "Ids.h"
+#include "cpuRegisters.h"
+#include "cpuApicUtilities.h"
+#include "mfParallelTraining.h"
+#include "heapManager.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_PARTRN_MFPARALLELTRAINING_FILECODE
+
+/*-----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+extern MEM_TECH_CONSTRUCTOR* memTechInstalled[];
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This is the main function to perform parallel training on all nodes.
+ * This is the routine which will run on the remote AP.
+ *
+ * @param[in,out] *EnvPtr - Pointer to the Training Environment Data
+ * @param[in,out] *StdHeader - Pointer to the Standard Header of the AP
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+BOOLEAN
+MemFParallelTraining (
+ IN OUT REMOTE_TRAINING_ENV *EnvPtr,
+ IN OUT AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ MEM_PARAMETER_STRUCT ParameterList;
+ MEM_NB_BLOCK NB;
+ MEM_TECH_BLOCK TB;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ UINT8 p;
+ UINT8 i;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 *BufferPtr;
+ UINT8 DctCount;
+ UINT8 ChannelCount;
+ UINT8 RowCount;
+ UINT8 ColumnCount;
+ UINT16 SizeOfNewBuffer;
+ AP_DATA_TRANSFER ReturnData;
+
+ //
+ // Initialize Parameters
+ //
+ ReturnData.DataPtr = NULL;
+ ReturnData.DataSizeInDwords = 0;
+ ReturnData.DataTransferFlags = 0;
+
+ ASSERT (EnvPtr != NULL);
+ //
+ // Replace Standard header of a AP
+ //
+ LibAmdMemCopy (StdHeader, &(EnvPtr->StdHeader), sizeof (AMD_CONFIG_PARAMS), &(EnvPtr->StdHeader));
+
+
+ //
+ // Allocate buffer for training data
+ //
+ BufferPtr = (UINT8 *) (&EnvPtr->DieStruct);
+ DctCount = EnvPtr->DieStruct.DctCount;
+ BufferPtr += sizeof (DIE_STRUCT);
+ ChannelCount = ((DCT_STRUCT *) BufferPtr)->ChannelCount;
+ BufferPtr += DctCount * sizeof (DCT_STRUCT);
+ RowCount = ((CH_DEF_STRUCT *) BufferPtr)->RowCount;
+ ColumnCount = ((CH_DEF_STRUCT *) BufferPtr)->ColumnCount;
+
+ SizeOfNewBuffer = sizeof (DIE_STRUCT) +
+ DctCount * (
+ sizeof (DCT_STRUCT) + (
+ ChannelCount * (
+ sizeof (CH_DEF_STRUCT) + sizeof (MEM_PS_BLOCK) + (
+ RowCount * ColumnCount * NUMBER_OF_DELAY_TABLES +
+ (MAX_BYTELANES_PER_CHANNEL * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES) +
+ (MAX_DIMMS_PER_CHANNEL * MAX_NUMBER_LANES)
+ )
+ )
+ )
+ );
+ AllocHeapParams.RequestedBufferSize = SizeOfNewBuffer;
+ AllocHeapParams.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_PAR_TRN_HANDLE, 0, 0, 0);
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
+ BufferPtr = AllocHeapParams.BufferPtr;
+ LibAmdMemCopy ( BufferPtr,
+ &(EnvPtr->DieStruct),
+ sizeof (DIE_STRUCT) + DctCount * (sizeof (DCT_STRUCT) + ChannelCount * (sizeof (CH_DEF_STRUCT) + sizeof (MEM_PS_BLOCK))),
+ StdHeader
+ );
+
+ //
+ // Fix up pointers
+ //
+ MCTPtr = (DIE_STRUCT *) BufferPtr;
+ BufferPtr += sizeof (DIE_STRUCT);
+ MCTPtr->DctData = (DCT_STRUCT *) BufferPtr;
+ BufferPtr += MCTPtr->DctCount * sizeof (DCT_STRUCT);
+ for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
+ MCTPtr->DctData[Dct].ChData = (CH_DEF_STRUCT *) BufferPtr;
+ BufferPtr += MCTPtr->DctData[Dct].ChannelCount * sizeof (CH_DEF_STRUCT);
+ for (Channel = 0; Channel < MCTPtr->DctData[Dct].ChannelCount; Channel++) {
+ MCTPtr->DctData[Dct].ChData[Channel].MCTPtr = MCTPtr;
+ MCTPtr->DctData[Dct].ChData[Channel].DCTPtr = &MCTPtr->DctData[Dct];
+ }
+ }
+ NB.PSBlock = (MEM_PS_BLOCK *) BufferPtr;
+ BufferPtr += DctCount * ChannelCount * sizeof (MEM_PS_BLOCK);
+
+ ReturnData.DataPtr = AllocHeapParams.BufferPtr;
+ ReturnData.DataSizeInDwords = (SizeOfNewBuffer + 3) / 4;
+ ReturnData.DataTransferFlags = 0;
+
+ //
+ // Allocate Memory for the MEM_DATA_STRUCT we will use
+ //
+ AllocHeapParams.RequestedBufferSize = sizeof (MEM_DATA_STRUCT);
+ AllocHeapParams.BufferHandle = AMD_MEM_DATA_HANDLE;
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
+ MemPtr = (MEM_DATA_STRUCT *)AllocHeapParams.BufferPtr;
+
+ LibAmdMemCopy (&(MemPtr->StdHeader), &(EnvPtr->StdHeader), sizeof (AMD_CONFIG_PARAMS), StdHeader);
+
+ //
+ // Copy Parameters from environment
+ //
+ ParameterList.HoleBase = EnvPtr->HoleBase;
+ ParameterList.BottomIo = EnvPtr->BottomIo;
+ ParameterList.UmaSize = EnvPtr->UmaSize;
+ ParameterList.SysLimit = EnvPtr->SysLimit;
+ ParameterList.TableBasedAlterations = EnvPtr->TableBasedAlterations;
+ ParameterList.PlatformMemoryConfiguration = EnvPtr->PlatformMemoryConfiguration;
+ MemPtr->ParameterListPtr = &ParameterList;
+
+ for (p = 0; p < MAX_PLATFORM_TYPES; p++) {
+ MemPtr->GetPlatformCfg[p] = EnvPtr->GetPlatformCfg[p];
+ }
+
+ MemPtr->ErrorHandling = EnvPtr->ErrorHandling;
+ //
+ // Create Local NBBlock and Tech Block
+ //
+ EnvPtr->NBBlockCtor (&NB, MCTPtr, EnvPtr->FeatPtr);
+ NB.RefPtr = &ParameterList;
+ NB.MemPtr = MemPtr;
+ i = 0;
+ while (memTechInstalled[i] != NULL) {
+ if (memTechInstalled[i] (&TB, &NB)) {
+ break;
+ }
+ i++;
+ }
+ NB.TechPtr = &TB;
+ NB.TechBlockSwitch (&NB);
+
+ //
+ // Setup CPU Mem Type MSRs on the AP
+ //
+ NB.CpuMemTyping (&NB);
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "Node %d\n", NB.Node);
+ //
+ // Call Technology Specific Training routine
+ //
+ NB.TrainingFlow (&NB);
+ //
+ // Copy training data to ReturnData buffer
+ //
+ LibAmdMemCopy ( BufferPtr,
+ MCTPtr->DctData[0].ChData[0].RcvEnDlys,
+ ((DctCount * ChannelCount) * (
+ (RowCount * ColumnCount * NUMBER_OF_DELAY_TABLES) +
+ (MAX_BYTELANES_PER_CHANNEL * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES) +
+ (MAX_DIMMS_PER_CHANNEL * MAX_NUMBER_LANES)
+ )
+ ),
+ StdHeader);
+
+ HeapDeallocateBuffer (AMD_MEM_DATA_HANDLE, StdHeader);
+ //
+ // Restore pointers
+ //
+ for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
+ for (Channel = 0; Channel < MCTPtr->DctData[Dct].ChannelCount; Channel++) {
+ MCTPtr->DctData[Dct].ChData[Channel].MCTPtr = &EnvPtr->DieStruct;
+ MCTPtr->DctData[Dct].ChData[Channel].DCTPtr = &EnvPtr->DieStruct.DctData[Dct];
+
+ MCTPtr->DctData[Dct].ChData[Channel].RcvEnDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RcvEnDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].WrDqsDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].WrDqsDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RdDqsDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RdDqsDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].WrDatDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqs2dDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RdDqs2dDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsMinDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RdDqsMinDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsMaxDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].RdDqsMaxDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatMinDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].WrDatMinDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatMaxDlys = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].WrDatMaxDlys;
+ MCTPtr->DctData[Dct].ChData[Channel].FailingBitMask = EnvPtr->DieStruct.DctData[Dct].ChData[Channel].FailingBitMask;
+ }
+ MCTPtr->DctData[Dct].ChData = EnvPtr->DieStruct.DctData[Dct].ChData;
+ }
+ MCTPtr->DctData = EnvPtr->DieStruct.DctData;
+ }
+
+ //
+ // Signal to BSP that training is complete and Send Results
+ //
+ ASSERT (ReturnData.DataPtr != NULL);
+ ApUtilTransmitBuffer (EnvPtr->BspSocket, EnvPtr->BspCore, &ReturnData, StdHeader);
+
+ //
+ // Clean up and exit.
+ //
+ HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_PAR_TRN_HANDLE, 0, 0, 0), StdHeader);
+ } else {
+ MCTPtr = &EnvPtr->DieStruct;
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_TRAINING_DATA, MCTPtr->NodeId, 0, 0, 0, StdHeader);
+ SetMemError (AGESA_FATAL, MCTPtr);
+ ASSERT(FALSE); // Could not allocate heap for buffer for parallel training data
+ }
+ return TRUE;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfStandardTraining.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfStandardTraining.c
new file mode 100644
index 0000000000..654af0e235
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/PARTRN/mfStandardTraining.c
@@ -0,0 +1,85 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfStandardTraining.c
+ *
+ * This is the standard training routine which performs all training from the BSP
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/PARTRN)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+
+
+#include "AGESA.h"
+#include "mm.h"
+#include "mn.h"
+#include "Ids.h"
+#include "mfStandardTraining.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_FEAT_PARTRN_MFSTANDARDTRAINING_FILECODE
+/*-----------------------------------------------------------------------------
+* EXPORTED FUNCTIONS
+*
+*-----------------------------------------------------------------------------
+*/
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This is the main function to perform memory training on all nodes from
+ * the BSP only.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return TRUE - This feature is enabled.
+ * @return FALSE - This feature is not enabled.
+ */
+BOOLEAN
+MemFStandardTraining (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ ASSERT (NBPtr != NULL);
+
+ NBPtr->TrainingFlow (NBPtr);
+ return TRUE;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/KB/mfRdWr2DKb.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/KB/mfRdWr2DKb.c
new file mode 100644
index 0000000000..b355d6b093
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/KB/mfRdWr2DKb.c
@@ -0,0 +1,348 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfRdWr2DKb.c
+ *
+ * KB - Specific funtion for 2D Read and write training feature
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/RdWr2DTraining/Kb)
+ * @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_KB_MFRDWR2DKB_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemFRdWr2DTrainingInitKB (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+BOOLEAN
+STATIC
+MemFRdWr2DProgramVrefKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *VrefPtr
+ );
+
+BOOLEAN
+STATIC
+MemFRdWr2DScaleVrefKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *Vref
+ );
+
+BOOLEAN
+STATIC
+MemFRdWr2DProgramIntExtVrefSelectKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+STATIC
+MemFRdWr2DProgramDataPatternKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID* PatternIndexPtr
+ );
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initializes the 2D Read/Write Training Feature Hooks for KB
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return BOOLEAN
+ * TRUE - Function was implemented
+ *
+ */
+
+BOOLEAN
+MemFRdWr2DTrainingInitKB (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ ASSERT (NBPtr != NULL);
+ NBPtr->FamilySpecificHook[RdWr2DTraining] = MemFAmdRdWr2DTraining;
+ NBPtr->FamilySpecificHook[CheckRdWr2DTrainingPerConfig] = MemFCheckRdWr2DTrainingPerConfig;
+ NBPtr->FamilySpecificHook[RdWr2DSelectIntExtVref] = MemFRdWr2DProgramIntExtVrefSelectKB;
+ NBPtr->FamilySpecificHook[RdWr2DProgramVref] = MemFRdWr2DProgramVrefKB;
+ NBPtr->FamilySpecificHook[RdWr2DScaleVref] = MemFRdWr2DScaleVrefKB;
+ NBPtr->FamilySpecificHook[RdWr2DProgramDelays] = MemFRdWr2DProgramDelays;
+ NBPtr->FamilySpecificHook[RdWr2DDataCollection] = MemFRdWr2DEyeRimSearch;
+ NBPtr->FamilySpecificHook[RdWr2DInitVictim] = MemFRdWr2DInitVictim;
+ NBPtr->FamilySpecificHook[RdWr2DInitVictimChipSel] = MemFRdWr2DInitVictimChipSel;
+ NBPtr->FamilySpecificHook[RdWr2DStartVictim] = MemFRdWr2DStartVictim;
+ NBPtr->FamilySpecificHook[RdWr2DFinalizeVictim] = MemFRdWr2DFinalizeVictim;
+ NBPtr->FamilySpecificHook[RdWr2DCompareInPhase] = MemFRdWr2DCompareInPhase;
+ NBPtr->FamilySpecificHook[RdWr2DCompare180Phase] = MemFRdWr2DCompare180Phase;
+ NBPtr->FamilySpecificHook[RdWr2DProgramDataPattern] = MemFRdWr2DProgramDataPatternKB;
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs Vref for 2D Read/Write Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *VrefPtr - Pointer to Vref value
+ *
+ * @return BOOLEAN
+ * TRUE - Success
+ * FAIL (External Callout only)
+ *
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DProgramVrefKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *VrefPtr
+ )
+{
+ AGESA_STATUS Status;
+ MEM_DATA_STRUCT *MemPtr;
+ ID_INFO CallOutIdInfo;
+ VOLTAGE_ADJUST Va;
+ UINT8 Vref;
+
+ ASSERT (NBPtr != NULL);
+ ASSERT (VrefPtr != NULL);
+ MemPtr = NBPtr->MemPtr;
+ Vref = *(UINT8*)VrefPtr;
+ CallOutIdInfo.IdField.SocketId = NBPtr->MCTPtr->SocketId;
+ CallOutIdInfo.IdField.ModuleId = NBPtr->MCTPtr->DieId;
+ LibAmdMemCopy ((VOID *)&Va, (VOID *)MemPtr, (UINTN)sizeof (Va.StdHeader), &MemPtr->StdHeader);
+ Va.MemData = MemPtr;
+ Status = AGESA_SUCCESS;
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ if (NBPtr->RefPtr->ExternalVrefCtl == FALSE) {
+ //
+ // Internal vref control
+ //
+ ASSERT (Vref < 61);
+ if (Vref < 30) {
+ Vref = (62 - Vref);
+ } else {
+ Vref = (Vref - 30);
+ }
+ NBPtr->SetBitField (NBPtr, BFVrefDAC, Vref << 3);
+ } else {
+ //
+ // External vref control
+ //
+ AGESA_TESTPOINT (TpProcMemBefore2dTrainExtVrefChange, &(NBPtr->MemPtr->StdHeader));
+ NBPtr->MemPtr->ParameterListPtr->ExternalVrefValue = Vref;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n2D Read Training External CPU Vref Callout \n");
+ Va.VoltageType = VTYPE_CPU_VREF;
+ Va.AdjustValue = Vref = (Vref - 15) << 1;
+ Status = AgesaExternalVoltageAdjust ((UINTN)CallOutIdInfo.IdInformation, &Va);
+ AGESA_TESTPOINT (TpProcMemAfter2dTrainExtVrefChange, &(NBPtr->MemPtr->StdHeader));
+ }
+ } else {
+ //
+ // DIMM Vref Control
+ //
+ Va.VoltageType = VTYPE_DIMM_VREF;
+ //
+ // Offset by 15 and multiply by 2.
+ //
+ Va.AdjustValue = Vref = (Vref - 15) << 1;
+ Status = AgesaExternalVoltageAdjust ((UINTN)CallOutIdInfo.IdInformation, &Va);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDimm Vref = %c%d% ", (Va.AdjustValue < 0) ? '-':'+', (Va.AdjustValue < 0) ? (0 - Va.AdjustValue) : Va.AdjustValue );
+ if (Status != AGESA_SUCCESS) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "* Dimm Vref Callout Failed *");
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ }
+ return (Status == AGESA_SUCCESS) ? TRUE : FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function scales Vref from the range used in Data Collection to
+ * the range that is programmed into the register.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *Vref - Pointer to UINT8 Vref Value to scale.
+ *
+ * @return BOOLEAN
+ * TRUE Function was implemented
+ *
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DScaleVrefKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *Vref
+ )
+{
+ *(UINT8*)Vref = *(UINT8*)Vref * 2;
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs Vref to internal or external control for 2D Read
+ * or Write Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE - External Vref was selected
+ * FALSE - Internal Vref was selected
+ *
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DProgramIntExtVrefSelectKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ NBPtr->SetBitField (NBPtr, BFVrefSel, (NBPtr->RefPtr->ExternalVrefCtl ? 0x0002 : 0x0001));
+ }
+ return NBPtr->RefPtr->ExternalVrefCtl;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs the Data Pattern that will be sent and compared
+ * against.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *PatternIndexPtr - Pointer to a generic index used to
+ * determine which pattern to program.
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DProgramDataPatternKB (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID* PatternIndexPtr
+ )
+{
+ UINT8 SeedCount;
+ UINT32 PrbsSeed;
+ CONST STATIC UINT32 CmdStreamLenTbl[4] = {13, 61, 127, 251};
+
+ ASSERT (NBPtr != 0);
+ ASSERT (PatternIndexPtr != NULL);
+ SeedCount = *(UINT8*)PatternIndexPtr;
+ ASSERT (SeedCount <= (NBPtr->MaxSeedCount - 1));
+ MemNSetBitFieldNb (NBPtr, BFCmdStreamLen, CmdStreamLenTbl[SeedCount]);
+ PrbsSeed = 0x7EA05;
+ switch (SeedCount) {
+ case 0:
+ MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x01);
+ PrbsSeed = 0x7FFFF;
+ break;
+ case 1:
+ MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x04);
+ MemNSetBitFieldNb (NBPtr, BFXorPatOvr, 0xFF);
+ PrbsSeed = 0x7EA05;
+ break;
+ case 2:
+ MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x03);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern0, 0x55555549);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern1, 0x55555555);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern2, 0x55555555);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern3, 0x55555555);
+ break;
+ case 3:
+ MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x03);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern0, 0xA5A5A55A);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern1, 0xA5A5A5A5);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern2, 0xA5A5A5A5);
+ MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern3, 0xA5A5A5A5);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ ASSERT (PrbsSeed != 0);
+ //
+ // Program the PRBS Seed
+ //
+ NBPtr->SetBitField (NBPtr, BFDataPrbsSeed, PrbsSeed);
+ return TRUE;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdDqs2DTraining.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdDqs2DTraining.c
new file mode 100644
index 0000000000..62bfb82366
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdDqs2DTraining.c
@@ -0,0 +1,115 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfRdDqs2DTraining.c
+ *
+ * RD DQS 2 dimensional 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 "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mt.h"
+#include "mport.h"
+#include "mfRdWr2DTraining.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_FEAT_RDWR2DTRAINING_MFRDDQS2DTRAINING_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+ /*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes 2D training for Read DQS
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors occurred
+ *
+ */
+
+BOOLEAN
+MemFAmdRdDqs2DTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemFAmdRdDqs2DTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ IDS_HDT_CONSOLE (MEM_STATUS, "\n\nStart Read DQS 2D training.\n\n");
+ TechPtr->Direction = DQS_READ_DIR;
+ return TechPtr->NBPtr->FamilySpecificHook[RdWr2DTraining] (TechPtr->NBPtr, NULL);
+}
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);
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DPatternGeneration.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DPatternGeneration.c
new file mode 100644
index 0000000000..b8d8429822
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DPatternGeneration.c
@@ -0,0 +1,424 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfRdWr2DPatternGeneration.c
+ *
+ * Common Northbridge features
+ *
+ * @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 "AdvancedApi.h"
+#include "amdlib.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mport.h"
+#include "PlatformMemoryConfiguration.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_MFRDWR2DPATTERNGENERATION_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+ /* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function Initializes the Victim for 2D RdDqs Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE
+ */
+BOOLEAN
+MemFRdWr2DInitVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ RRW_SETTINGS *Rrw;
+ UINT8 InitialCS;
+ UINT8 ChipSel;
+ UINT8 SeedCount;
+ BOOLEAN OptPatWr2D;
+
+ OptPatWr2D = (NBPtr->IsSupported[OptimizedPatternWrite2D]) && (NBPtr->TechPtr->Direction == DQS_READ_DIR);
+ InitialCS = NBPtr->TechPtr->ChipSel;
+ Rrw = &NBPtr->RrwSettings;
+ // Program the Bubble Count and CmdStreamLen
+ NBPtr->SetBitField (NBPtr, BFBubbleCnt, 32);
+ NBPtr->SetBitField (NBPtr, BFBubbleCnt2, 0);
+ NBPtr->SetBitField (NBPtr, BFCmdStreamLen, 63);
+ // Set Comparison Masks
+ NBPtr->SetBitField (NBPtr, BFDramDqMaskLow, Rrw->CompareMaskLow);
+ NBPtr->SetBitField (NBPtr, BFDramDqMaskHigh, Rrw->CompareMaskHigh);
+ // If All Dimms are ECC Capable Test ECC. Otherwise, mask it off
+ NBPtr->SetBitField (NBPtr, BFDramEccMask, (NBPtr->MCTPtr->Status[SbEccDimms] == TRUE) ? Rrw->CompareMaskEcc : 0xFF);
+ // Program the Starting Address
+ NBPtr->SetBitField (NBPtr, BFTgtBankA, Rrw->TgtBankAddressA);
+ NBPtr->SetBitField (NBPtr, BFTgtAddressA, Rrw->TgtColAddressA);
+ NBPtr->SetBitField (NBPtr, BFTgtBankB, Rrw->TgtBankAddressB);
+ NBPtr->SetBitField (NBPtr, BFTgtAddressB, Rrw->TgtColAddressB);
+ NBPtr->SetBitField (NBPtr, BFCmdTgt, CMD_TGT_AB);
+ // Wait for RRW Engine to be ready and turn it on
+ NBPtr->PollBitField (NBPtr, BFCmdSendInProg, 0, PCI_ACCESS_TIMEOUT, FALSE);
+ NBPtr->SetBitField (NBPtr, BFCmdTestEnable, 1);
+ for (ChipSel = InitialCS; ChipSel < (InitialCS + NBPtr->CsPerDelay); ChipSel++) {
+ // Ensure that Odd and Even CS are trained
+ if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) == 0) {
+ continue;
+ }
+ NBPtr->TechPtr->ChipSel = ChipSel;
+ for (SeedCount = 0; SeedCount < (OptPatWr2D ? NBPtr->MaxSeedCount : 1 ); SeedCount++) {
+ if (OptPatWr2D) {
+ //
+ // Set BankAddress according to seed
+ //
+ ASSERT (NBPtr->MaxSeedCount <= 4);
+ Rrw->TgtBankAddressA = (SeedCount * 2) + CPG_BANK_ADDRESS_A;
+ Rrw->TgtBankAddressB = (SeedCount * 2) + CPG_BANK_ADDRESS_B;
+ }
+ //
+ // Send ACTIVATE to all Banks
+ //
+ // Set Chip select
+ MemNSetBitFieldNb (NBPtr, BFCmdChipSelect, (1 << NBPtr->TechPtr->ChipSel));
+ // Set Bank Address
+ MemNSetBitFieldNb (NBPtr, BFCmdBank, Rrw->TgtBankAddressA);
+ // Set Row Address
+ MemNSetBitFieldNb (NBPtr, BFCmdAddress, Rrw->TgtRowAddressA);
+ // Send the command
+ MemNSetBitFieldNb (NBPtr, BFSendActCmd, 1);
+ // Wait for command complete
+ MemNPollBitFieldNb (NBPtr, BFSendActCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
+ // Set Chip select
+ MemNSetBitFieldNb (NBPtr, BFCmdChipSelect, (1 << NBPtr->TechPtr->ChipSel));
+ // Set Bank Address
+ MemNSetBitFieldNb (NBPtr, BFCmdBank, Rrw->TgtBankAddressB);
+ // Set Row Address
+ MemNSetBitFieldNb (NBPtr, BFCmdAddress, Rrw->TgtRowAddressB);
+ // Send the command
+ MemNSetBitFieldNb (NBPtr, BFSendActCmd, 1);
+ // Wait for command complete
+ MemNPollBitFieldNb (NBPtr, BFSendActCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
+
+ if (OptPatWr2D) {
+ //
+ // Write the Pattern to the bank pairs for each seed.
+ //
+ NBPtr->FamilySpecificHook[RdWr2DInitVictimChipSel] (NBPtr, NULL);
+ NBPtr->SetBitField (NBPtr, BFTgtBankA, Rrw->TgtBankAddressA);
+ NBPtr->SetBitField (NBPtr, BFTgtBankB, Rrw->TgtBankAddressB);
+ // Program the PRBS Seed
+ NBPtr->FamilySpecificHook[RdWr2DProgramDataPattern] (NBPtr, &SeedCount);
+ //
+ // Enable continuous writes on the victim channels
+ //
+ // Set the Command Count
+ NBPtr->SetBitField (NBPtr, BFCmdCount, 256);
+ NBPtr->SetBitField (NBPtr, BFCmdType, CMD_TYPE_WRITE);
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 1);
+ // Wait for TestStatus = 1 and CmdSendInProg = 0.
+ NBPtr->PollBitField (NBPtr, BFTestStatus, 1, PCI_ACCESS_TIMEOUT, FALSE);
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 0);
+ }
+ }
+ }
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ //
+ // Do not use LFSR Rollover during Wr Training
+ //
+ NBPtr->SetBitField (NBPtr, BFLfsrRollOver, 1);
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function Initializes the Victim chipSelects for 2D Read or Write
+ * Training Continuous Writes
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE
+ */
+BOOLEAN
+MemFRdWr2DInitVictimChipSel (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ NBPtr->SetBitField (NBPtr, BFTgtChipSelectA, NBPtr->TechPtr->ChipSel);
+ NBPtr->SetBitField (NBPtr, BFTgtChipSelectB, NBPtr->TechPtr->ChipSel);
+ NBPtr->SetBitField (NBPtr, BFResetAllErr, 1);
+ return TRUE;
+}
+
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function checks the In Phase Error status bits for comparison
+ * results for RD/WR 2D training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[out] *Result - Pointer to UINT32 for storing results
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+BOOLEAN
+MemFRdWr2DCompareInPhase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ OUT VOID *Result
+ )
+{
+ *(UINT32*)Result = NBPtr->GetBitField (NBPtr, BFNibbleErrSts);
+ return TRUE;
+}
+
+ /*-----------------------------------------------------------------------------*/
+/**
+ *
+ * This function checks the 180 Error status bits for RD/WR 2D training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[out] *Result - Pointer to UINT32 for storing results
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+BOOLEAN
+MemFRdWr2DCompare180Phase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ OUT VOID *Result
+ )
+{
+ *(UINT32*)Result = NBPtr->GetBitField (NBPtr, BFNibbleErr180Sts);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function starts the Victim for 2D RdDqs Training Continuous Writes
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] SeedCountPtr - UINT8 Pointer to Seed count
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+BOOLEAN
+MemFRdWr2DStartVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *SeedCountPtr
+ )
+{
+ BOOLEAN OptPatWr2D;
+ UINT32 CommandCount;
+ UINT8 SeedCount;
+
+ ASSERT (NBPtr != NULL);
+ ASSERT (SeedCountPtr != NULL);
+
+ SeedCount = *(UINT8*)SeedCountPtr;
+
+ OptPatWr2D = FALSE;
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ OptPatWr2D = (NBPtr->IsSupported[OptimizedPatternWrite2D]);
+ CommandCount = NBPtr->TotalBitTimes2DRdTraining / (8 * NBPtr->MaxSeedCount * NBPtr->MaxAggressorDimms[NBPtr->Dct]);
+ } else {
+ CommandCount = 256;
+ }
+
+ // Program the PRBS Seed
+ NBPtr->FamilySpecificHook[RdWr2DProgramDataPattern] (NBPtr, &SeedCount);
+ if (OptPatWr2D) {
+ //
+ // Set BankAddress according to seed
+ //
+ NBPtr->SetBitField (NBPtr, BFTgtBankA, (SeedCount * 2) + CPG_BANK_ADDRESS_A);
+ NBPtr->SetBitField (NBPtr, BFTgtBankB, (SeedCount * 2) + CPG_BANK_ADDRESS_B);
+ } else {
+ //
+ // Enable continuous writes on the victim channels
+ //
+ // Set the Command Count
+ NBPtr->SetBitField (NBPtr, BFCmdCount, 256);
+ NBPtr->SetBitField (NBPtr, BFCmdType, CMD_TYPE_WRITE);
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 1);
+ // Wait for TestStatus = 1 and CmdSendInProg = 0.
+ NBPtr->PollBitField (NBPtr, BFTestStatus, 1, PCI_ACCESS_TIMEOUT, FALSE);
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 0);
+ }
+ //
+ // Enable continuous reads on the victim channels
+ //
+ // Set the Command Count
+ ASSERT (NBPtr->MaxAggressorDimms[NBPtr->Dct] != 0);
+ //
+ NBPtr->SetBitField (NBPtr, BFCmdCount, CommandCount );
+ // Reset All Errors and Disable StopOnErr
+ NBPtr->SetBitField (NBPtr, BFCmdType, CMD_TYPE_READ);
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 1);
+ // Wait for TestStatus = 1 and CmdSendInProg = 0
+ NBPtr->PollBitField (NBPtr, BFTestStatus, 1, PCI_ACCESS_TIMEOUT, FALSE);
+ //}
+ NBPtr->SetBitField (NBPtr, BFSendCmd, 0);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finalizes the Victim for 2D RdDqs Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE - Success
+ */
+BOOLEAN
+MemFRdWr2DFinalizeVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ UINT8 InitialCS;
+ UINT8 ChipSel;
+ InitialCS = NBPtr->TechPtr->ChipSel;
+ NBPtr->SetBitField (NBPtr, BFLfsrRollOver, 0);
+ for (ChipSel = InitialCS; ChipSel < (InitialCS + NBPtr->CsPerDelay); ChipSel++) {
+ // Ensure that Odd and Even CS are precharged
+ if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) == 0) {
+ continue;
+ }
+ NBPtr->TechPtr->ChipSel = ChipSel;
+ // Send the Precharge All Command
+ MemNRrwPrechargeCmd (NBPtr, ChipSel, PRECHARGE_ALL_BANKS);
+ }
+ // Turn Off the RRW Engine
+ NBPtr->SetBitField (NBPtr, BFCmdTestEnable, 0);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs the Data Pattern that will be sent and compared
+ * against.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *PatternIndexPtr - Pointer to a generic index used to
+ * determine which pattern to program.
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+BOOLEAN
+MemFRdWr2DProgramDataPattern (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID* PatternIndexPtr
+ )
+{
+ UINT8 SeedCount;
+ UINT32 PrbsSeed;
+ CONST STATIC UINT32 PrbsSeedTbl[4] = {0x7ea05, 0x44443, 0x22b97, 0x3f167};
+ CONST STATIC UINT32 CmdStreamLenTbl[4] = {13, 61, 127, 251};
+
+ ASSERT (NBPtr != 0);
+ ASSERT (PatternIndexPtr != NULL);
+ SeedCount = *(UINT8*)PatternIndexPtr;
+ ASSERT (SeedCount <= (NBPtr->MaxSeedCount - 1));
+ //
+ // Program the Command Stream Length
+ //
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ NBPtr->SetBitField (NBPtr, BFCmdStreamLen, CmdStreamLenTbl[SeedCount]);
+ } else {
+ NBPtr->SetBitField (NBPtr, BFCmdStreamLen, 63);
+ }
+ PrbsSeed = PrbsSeedTbl[SeedCount % GET_SIZE_OF (PrbsSeedTbl)];
+ ASSERT (PrbsSeed != 0);
+ //
+ // Program the PRBS Seed
+ //
+ NBPtr->SetBitField (NBPtr, BFDataPrbsSeed, PrbsSeed);
+ return TRUE;
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.c
new file mode 100644
index 0000000000..6a9e873e94
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.c
@@ -0,0 +1,1368 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfRdWr2DTraining.c
+ *
+ * Common Read/Write 2D Training Feature Function
+ *
+ * @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 "Ids.h"
+#include "AdvancedApi.h"
+#include "GeneralServices.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_MFRDWR2DTRAINING_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DScaleVref (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *Vref
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+ extern MEM_PSC_FLOW_BLOCK* memPlatSpecFlowArray[];
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initializes the 2D Read/Write Training Feature Hooks.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return BOOLEAN
+ * TRUE - Function was implemented
+ */
+
+BOOLEAN
+MemFRdWr2DTrainingInit (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ ASSERT (NBPtr != NULL);
+ NBPtr->FamilySpecificHook[RdWr2DTraining] = MemFAmdRdWr2DTraining;
+ NBPtr->FamilySpecificHook[CheckRdWr2DTrainingPerConfig] = MemFCheckRdWr2DTrainingPerConfig;
+ NBPtr->FamilySpecificHook[RdWr2DSelectIntExtVref] = MemFRdWr2DProgramIntExtVrefSelect;
+ NBPtr->FamilySpecificHook[RdWr2DProgramVref] = MemFRdWr2DProgramVref;
+ NBPtr->FamilySpecificHook[RdWr2DScaleVref] = MemFRdWr2DScaleVref;
+ NBPtr->FamilySpecificHook[RdWr2DProgramDelays] = MemFRdWr2DProgramDelays;
+ NBPtr->FamilySpecificHook[RdWr2DDataCollection] = MemFRdWr2DEyeRimSearch;
+ NBPtr->FamilySpecificHook[RdWr2DInitVictim] = MemFRdWr2DInitVictim;
+ NBPtr->FamilySpecificHook[RdWr2DInitVictimChipSel] = MemFRdWr2DInitVictimChipSel;
+ NBPtr->FamilySpecificHook[RdWr2DStartVictim] = MemFRdWr2DStartVictim;
+ NBPtr->FamilySpecificHook[RdWr2DFinalizeVictim] = MemFRdWr2DFinalizeVictim;
+ NBPtr->FamilySpecificHook[RdWr2DCompareInPhase] = MemFRdWr2DCompareInPhase;
+ NBPtr->FamilySpecificHook[RdWr2DCompare180Phase] = MemFRdWr2DCompare180Phase;
+ NBPtr->FamilySpecificHook[RdWr2DProgramDataPattern] = MemFRdWr2DProgramDataPattern;
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes 2D training for Read DQS or Write DQ
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors occurred
+ */
+
+BOOLEAN
+MemFAmdRdWr2DTraining (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID* OptParam
+ )
+{
+ MEM_TECH_BLOCK *TechPtr;
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_RD_WR_2D_ENTRY Data;
+ RD_WR_2D *VrefPtr;
+ PSO_TABLE *PsoTable;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ UINT8 Dct;
+ UINT8 ChipSel;
+ UINT8 Lane;
+ UINT8 Vref;
+ UINT8 MaxLanes;
+ UINT8 TmpLanes;
+ UINT8 TotalDlyRange;
+ BOOLEAN Status;
+ //
+ // Initialize Pointers
+ //
+ ASSERT (NBPtr != NULL);
+ TechPtr = NBPtr->TechPtr;
+ MemPtr = NBPtr->MemPtr;
+ PsoTable = MemPtr->ParameterListPtr->PlatformMemoryConfiguration;
+ //
+ // Set environment settings before training
+ //
+ AGESA_TESTPOINT (TpProcMem2dRdDqsTraining, &(MemPtr->StdHeader));
+ MemTBeginTraining (TechPtr);
+ //
+ // Allocate heap for the 2D RdWR/Vref Data structure
+ //
+ MaxLanes = 0;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ TmpLanes = MemFRdWr2DGetMaxLanes (NBPtr);
+ MaxLanes = MAX (MaxLanes, TmpLanes);
+ }
+
+ AllocHeapParams.RequestedBufferSize = MaxLanes * NBPtr->TotalMaxVrefRange * sizeof (RD_WR_2D);
+ AllocHeapParams.BufferHandle = AMD_MEM_2D_RD_WR_HANDLE;
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, &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, &MemPtr->StdHeader);
+ return TRUE;
+ }
+ for (Lane = 0; Lane < MaxLanes; Lane++) {
+ Data.Lane[Lane].Vref = &VrefPtr[Lane * NBPtr->TotalMaxVrefRange];
+ }
+ //
+ // Setup hardware training engine
+ //
+ TechPtr->TrainingType = TRN_DQS_POSITION;
+ NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType);
+
+ Data.Vnom = NBPtr->TotalMaxVrefRange / 2; // Set Nominal Vref
+ TotalDlyRange = (TechPtr->Direction == DQS_READ_DIR) ? NBPtr->TotalRdDQSDlyRange : NBPtr->TotalWrDatDlyRange;
+ Data.MaxRdWrSweep = TotalDlyRange / 2; // Set Max Sweep Size
+ ASSERT (TotalDlyRange <= MAX_RD_WR_DLY_ENTRIES);
+ //
+ // Execute 2d Rd DQS training for all Dcts/Chipselects
+ //
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ NBPtr->Vref = 0xFF;
+ Status = FALSE;
+ if (NBPtr->FamilySpecificHook[CheckRdWr2DTrainingPerConfig] (NBPtr, NULL)) {
+ for (ChipSel = 0; ChipSel < NBPtr->CsPerChannel; ChipSel = ChipSel + NBPtr->CsPerDelay ) {
+ if ( (NBPtr->MCTPtr->Status[SbLrdimms]) ? ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << (ChipSel >> 1))) != 0) :
+ ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) != 0) ) {
+ //
+ //Initialize storage
+ //
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ for (Vref = 0; Vref < NBPtr->TotalMaxVrefRange; Vref++) {
+ Data.Lane[Lane].Vref[Vref].PosRdWrDly = 0;
+ Data.Lane[Lane].Vref[Vref].NegRdWrDly = 0;
+ }
+ }
+ TechPtr->ChipSel = ChipSel;
+ IDS_HDT_CONSOLE (MEM_FLOW,"\tChip Select: %02x \n", TechPtr->ChipSel);
+ //
+ // 1. Sample the data eyes for each channel:
+ //
+ TechPtr->RdWr2DData = &Data;
+ if (NBPtr->FamilySpecificHook[RdWr2DDataCollection] (NBPtr, NULL)) {
+ //
+ // 2. Process the array of results with a diamond convolution mask, summing the number passing sample points.
+ //
+ // Determine Diamond Mask Height
+ if (MemFRdWr2DHeight (NBPtr, &Data)) {
+ //
+ // Apply Mask
+ //
+ if (MemFRdWr2DApplyMask (NBPtr, &Data)) {
+ //
+ // Convolution
+ //
+ if (MemFRdWr2DProcessConvolution (NBPtr, &Data)) {
+ //
+ // 3. Program the final DQS delay values.
+ //
+ if (MemFRdWr2DProgramMaxDelays (NBPtr, &Data)) {
+ //
+ // Find the Smallest Positive or Negative Margin for current CS
+ //
+ if (MemFRdWr2DFindCsVrefMargin (NBPtr, &Data)) {
+ Status = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (Status == FALSE) {
+ SetMemError (AGESA_ERROR, NBPtr->MCTPtr);
+ PutEventLog (AGESA_ERROR, (TechPtr->Direction == DQS_READ_DIR) ? MEM_ERROR_2D_DQS_ERROR : MEM_ERROR_2D_WRDAT_ERROR, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ }
+ }
+ }
+ //
+ // Find the Max and Min Vref values for each DCT
+ //
+ if (Status == TRUE) {
+ if (MemFRdWr2DFinalVrefMargin (NBPtr, &Data)) {
+ //
+ // Program the Max Vref value
+ //
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tProgramming Final Vref for channel\n");
+ NBPtr->FamilySpecificHook[RdWr2DProgramVref] (NBPtr, &NBPtr->ChannelPtr->MaxVref);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tActual Vref programmed = %02x\n",
+ ( NBPtr->GetBitField (NBPtr, BFVrefDAC) >> TSEFO_END (NBPtr->NBRegTable[BFVrefDAC])) );
+ Status = TRUE;
+ } else {
+ SetMemError (AGESA_ERROR, NBPtr->MCTPtr);
+ PutEventLog (AGESA_ERROR, (TechPtr->Direction == DQS_READ_DIR) ? MEM_ERROR_2D_DQS_VREF_MARGIN_ERROR: MEM_ERROR_2D_WRDAT_VREF_MARGIN_ERROR, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ }
+ }
+ }
+ }
+ //
+ // Restore environment settings after training
+ //
+ if (HeapDeallocateBuffer (AMD_MEM_2D_RD_WR_HANDLE, &MemPtr->StdHeader) != AGESA_SUCCESS) {
+ SetMemError (AGESA_FATAL, NBPtr->MCTPtr);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_DEALLOCATE_FOR_2D, 0, 0, 0, 0, &MemPtr->StdHeader);
+ }
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tEnd\n");
+ MemTEndTraining (TechPtr);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\nEnd %s 2D training\n\n",(TechPtr->Direction == DQS_READ_DIR) ? "Read DQS":"Write DQ");
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines whether the current configuration is a valid
+ * config for applying 2D Training
+ * @todo: Update to work for 2D WR and 2D RD training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE - Configuration valid
+ * FALSE - Configuration invalid
+ *
+ */
+BOOLEAN
+MemFCheckRdWr2DTrainingPerConfig (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ UINT8 i;
+ if (NBPtr->RefPtr->ForceTrainMode == FORCE_TRAIN_AUTO) {
+ i = 0;
+ while (memPlatSpecFlowArray[i] != NULL) {
+ if ((memPlatSpecFlowArray[i])->S2D (NBPtr, (memPlatSpecFlowArray[i])->EntryOfTables)) {
+ return TRUE;
+ }
+ i++;
+ }
+ }
+ return FALSE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines the maximum number of lanes for puposes of 2D
+ * Read or Write training.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ *
+ * @return UINT8 - Max Number of Lanes
+ *
+ */
+UINT8
+MemFRdWr2DGetMaxLanes (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ MEM_TECH_BLOCK *TechPtr;
+ UINT8 MaxLanes;
+
+ TechPtr = NBPtr->TechPtr;
+ if ((TechPtr->Direction == DQS_READ_DIR) && ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) != 0)) {
+ // Per Nibble
+ MaxLanes = (NBPtr->MCTPtr->Status[SbEccDimms] && (NBPtr->IsSupported[EccByteTraining] == TRUE)) ? 18 : 16;
+ } else {
+ // Per Byte
+ MaxLanes = (NBPtr->MCTPtr->Status[SbEccDimms] && (NBPtr->IsSupported[EccByteTraining] == TRUE)) ? 9 : 8;
+ }
+ return MaxLanes;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs Vref to internal or external control for 2D Read
+ * or Write Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *OptParam - Unused
+ *
+ * @return BOOLEAN
+ * TRUE - External Vref was selected
+ * FALSE - Internal Vref was selected
+ *
+ */
+BOOLEAN
+MemFRdWr2DProgramIntExtVrefSelect (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ NBPtr->SetBitField (NBPtr, BFVrefSel, (NBPtr->RefPtr->ExternalVrefCtl ? 0x0000 : 0x0001));
+ }
+ return NBPtr->RefPtr->ExternalVrefCtl;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function scales Vref from the range used in Data Collection to
+ * the range that is programmed into the register.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *Vref - Pointer to UINT8 Vref Value to scale.
+ *
+ * @return BOOLEAN
+ * TRUE Function was implemented
+ *
+ */
+BOOLEAN
+STATIC
+MemFRdWr2DScaleVref (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *Vref
+ )
+{
+ *(UINT8*)Vref = *(UINT8*)Vref * 2;
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs Vref for 2D Read/Write Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *VrefPtr - Pointer to Vref value
+ *
+ * @return BOOLEAN
+ * TRUE - Success
+ * FAIL (External Callout only)
+ *
+ */
+BOOLEAN
+MemFRdWr2DProgramVref (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *VrefPtr
+ )
+{
+ AGESA_STATUS Status;
+ MEM_DATA_STRUCT *MemPtr;
+ ID_INFO CallOutIdInfo;
+ VOLTAGE_ADJUST Va;
+ UINT8 Vref;
+
+ ASSERT (NBPtr != NULL);
+ ASSERT (VrefPtr != NULL);
+ MemPtr = NBPtr->MemPtr;
+ Vref = *(UINT8*)VrefPtr;
+ CallOutIdInfo.IdField.SocketId = NBPtr->MCTPtr->SocketId;
+ CallOutIdInfo.IdField.ModuleId = NBPtr->MCTPtr->DieId;
+ LibAmdMemCopy ((VOID *)&Va, (VOID *)MemPtr, (UINTN)sizeof (Va.StdHeader), &MemPtr->StdHeader);
+ Va.MemData = MemPtr;
+ Status = AGESA_SUCCESS;
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ if (NBPtr->RefPtr->ExternalVrefCtl == FALSE) {
+ //
+ // Internal vref control
+ //
+ // This is 1/2 VrefDAC value Sign bit is shifted into place.
+ //
+ ASSERT (Vref < 32);
+ if (Vref < 15) {
+ Vref = (31 - Vref) << 1;
+ } else {
+ Vref = (Vref - 15) << 1;
+ }
+ NBPtr->SetBitField (NBPtr, BFVrefDAC, Vref << 2);
+ } else {
+ // External vref control
+ AGESA_TESTPOINT (TpProcMemBefore2dTrainExtVrefChange, &(NBPtr->MemPtr->StdHeader));
+ NBPtr->MemPtr->ParameterListPtr->ExternalVrefValue = Vref;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n2D Read Training External CPU Vref Callout \n");
+ Va.VoltageType = VTYPE_CPU_VREF;
+ Va.AdjustValue = Vref = (Vref - 15) << 1;
+ Status = AgesaExternalVoltageAdjust ((UINTN)CallOutIdInfo.IdInformation, &Va);
+ AGESA_TESTPOINT (TpProcMemAfter2dTrainExtVrefChange, &(NBPtr->MemPtr->StdHeader));
+ }
+ } else {
+ //
+ // DIMM Vref Control
+ //
+ Va.VoltageType = VTYPE_DIMM_VREF;
+ //
+ // Offset by 15 and multiply by 2.
+ //
+ Va.AdjustValue = Vref = (Vref - 15) << 1;
+ Status = AgesaExternalVoltageAdjust ((UINTN)CallOutIdInfo.IdInformation, &Va);
+ if (Status != AGESA_SUCCESS) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "* Dimm Vref Callout Failed *");
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ }
+ return (Status == AGESA_SUCCESS) ? TRUE : FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs Read DQS or Write DQ Delay values for Read/Write
+ * Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Delay - Pointer to UINT8 containing Delay value
+ *
+ * @return BOOLEAN
+ * TRUE
+ *
+ */
+
+BOOLEAN
+MemFRdWr2DProgramDelays (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *Delay
+ )
+{
+ UINT32 RdDqsTime;
+ UINT8 RdWrDly;
+
+ ASSERT (NBPtr != 0);
+ ASSERT (Delay != 0);
+ RdWrDly = *(UINT8*) Delay;
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ // This function should only be used for read training
+ ASSERT (NBPtr->TechPtr->Direction == DQS_READ_DIR);
+ // Program BL registers for both nibble (x4) and bytes (x8, x16)
+ RdDqsTime = 0;
+ RdDqsTime = (RdWrDly & 0x1F) << 8;
+ RdDqsTime = RdDqsTime | (RdWrDly & 0x1F);
+ if ((NBPtr->TechPtr->ChipSel / NBPtr->CsPerDelay) == 0) {
+ NBPtr->SetBitField (NBPtr, BFDataByteRxDqsDLLDimm0Broadcast, RdDqsTime);
+ } else if ((NBPtr->TechPtr->ChipSel / NBPtr->CsPerDelay) == 1) {
+ NBPtr->SetBitField (NBPtr, BFDataByteRxDqsDLLDimm1Broadcast, RdDqsTime);
+ } else if ((NBPtr->TechPtr->ChipSel / NBPtr->CsPerDelay) == 2) {
+ NBPtr->SetBitField (NBPtr, BFDataByteRxDqsDLLDimm2Broadcast, RdDqsTime);
+ } else if ((NBPtr->TechPtr->ChipSel / NBPtr->CsPerDelay) == 3) {
+ NBPtr->SetBitField (NBPtr, BFDataByteRxDqsDLLDimm3Broadcast, RdDqsTime);
+ }
+ } else {
+ MemTSetDQSDelayAllCSR (NBPtr->TechPtr, RdWrDly);
+ }
+ return TRUE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function stores data for 2D Read DQS and Write DQ Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ * @param[in] *InPhaseResult[] - Array of inphase results
+ * @param[in] *PhaseResult180[] - Array of Phase 180 results
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ */
+VOID
+MemFRdWr2DStoreResult (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data,
+ IN UINT32 InPhaseResult[],
+ IN UINT32 PhaseResult180[]
+ )
+{
+ UINT8 Lane;
+ UINT8 Vref;
+ UINT8 RdWrDly;
+ UINT32 Result;
+ UINT32 Result180;
+ UINT8 Index;
+ Vref = NBPtr->Vref;
+ RdWrDly = Data->RdWrDly;
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ for (RdWrDly = 0; RdWrDly < Data->MaxRdWrSweep; RdWrDly++) {
+ if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (NBPtr->TechPtr->ChipSel >> 1))) == 0) {
+ // x8, so combine "Nibble X" and "Nibble X+1" results
+ Index = Lane * 2;
+ Result = (InPhaseResult[RdWrDly] >> Index) & 0x03;
+ Result180 = (PhaseResult180[RdWrDly] >> Index) & 0x03;
+ } else {
+ // x4, so use "Nibble" results
+ Result = (InPhaseResult[RdWrDly] >> Lane) & 0x01;
+ Result180 = (PhaseResult180[RdWrDly] >> Lane) & 0x01;
+ }
+ Data->Lane[Lane].Vref[Vref].PosRdWrDly |= (Result == 0) ? (1 << (Data->MaxRdWrSweep - 1 - RdWrDly)) : 0;
+ Data->Lane[Lane].Vref[Vref].NegRdWrDly |= (Result180 == 0) ? (1 << (Data->MaxRdWrSweep - 1 - RdWrDly)) : 0;
+ }
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines the height of data for 2D Read and Write training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ */
+BOOLEAN
+MemFRdWr2DHeight (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ UINT8 Lane;
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ Data->Lane[Lane].HalfDiamondHeight = 0x0F;
+ }
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t Lane: ");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Lane);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tHeight: ");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", (2*(Data->Lane[Lane].HalfDiamondHeight) + 1));
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ );
+ return TRUE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function gets the width for 2D RdDQS and WrDat training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return UINT8 Width
+ */
+UINT8
+MemFGetRdWr2DWidth (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ return NBPtr->DiamondWidthRd;
+ } else {
+ return NBPtr->DiamondWidthWr;
+ }
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function gets the step height for the diamond mask for 2D RdDQS or
+ * WrDat Training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ * @param[in] Vref - current Vref value
+ * @param[in] Lane - current Lane
+ *
+ * @return BOOLEAN
+ * TRUE - Step found and value should be updated
+ * FALSE - Step not found and value should not be updated
+ *
+ */
+BOOLEAN
+MemFCheckRdWr2DDiamondMaskStep (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data,
+ IN UINT8 Vref,
+ IN UINT8 Lane
+ )
+{
+ UINT8 M;
+ UINT8 VrefVal;
+ UINT8 width;
+ UINT8 i;
+ BOOLEAN status;
+ // m = -1 * height/width
+ // (y-b)/m = x
+ status = FALSE;
+ if (Vref > (Data->Vnom - 1)) {
+ VrefVal = (Vref + 1) - Data->Vnom;
+ } else {
+ VrefVal = Vref;
+ }
+ width = (MemFGetRdWr2DWidth (NBPtr, Data) - 1) / 2;
+ M = Data->Lane[Lane].HalfDiamondHeight / width;
+ i = 1;
+ while (i <= Data->Lane[Lane].HalfDiamondHeight) {
+ i = i + M;
+ if (VrefVal == i) {
+ status = TRUE;
+ }
+ }
+ return status;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function applies a mask for 2D RdDQS or WrDat training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ *
+ */
+BOOLEAN
+MemFRdWr2DApplyMask (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ MEM_TECH_BLOCK *TechPtr;
+ UINT8 RdWrDly;
+ UINT8 Lane;
+ UINT8 Height;
+ UINT8 Width;
+ UINT32 PosNegData;
+ UINT8 Vref;
+ UINT8 count;
+ UINT8 Dly;
+ UINT8 endWidth;
+ UINT8 startWidth;
+ UINT8 origEndWidth;
+ UINT8 origStartWidth;
+ UINT8 maxOverLapWidth;
+ UINT8 startOverLapWidth;
+ UINT8 TotalDlyRange;
+ BOOLEAN maxHeightExceeded;
+ BOOLEAN negVrefComplete;
+ BOOLEAN PosRdWrToNegRdWr;
+ BOOLEAN NegRdWrToPosRdWr;
+
+ TechPtr = NBPtr->TechPtr;
+ TotalDlyRange = (TechPtr->Direction == DQS_READ_DIR) ? NBPtr->TotalRdDQSDlyRange : NBPtr->TotalWrDatDlyRange;
+ //
+ // Initialize Convolution
+ //
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ for (RdWrDly = 0; RdWrDly < TotalDlyRange; RdWrDly++) {
+ Data->Lane[Lane].Convolution[RdWrDly] = 0;
+ NBPtr->FamilySpecificHook[Adjust2DDelayStepSize] (NBPtr, &RdWrDly);
+ }
+ }
+ endWidth = 0;
+ startWidth = 0;
+ origEndWidth = 0;
+ origStartWidth = 0;
+ startOverLapWidth = 0;
+ maxOverLapWidth = 0;
+ maxHeightExceeded = FALSE;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tDetermining Width");
+ //
+ // Get the Width of Diamond
+ //
+ Width = MemFGetRdWr2DWidth (NBPtr, Data);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWidth: %02x\n", Width);
+ ASSERT (Width != 0);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tExecuting convolution function\n");
+ //
+ // Perform the convolution by sweeping the mask function centered at nominal Vref. Results in a one
+ // dimensional array with FOM values at each delay for each lane. Choose the delay setting at the peak
+ // FOM value.
+ //
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ Height = Data->Lane[Lane].HalfDiamondHeight;
+ ASSERT (Height < Data->Vnom);
+ //
+ // RdWrDly is divided around "Data->MaxRdWrSweep" into positive and negative directions
+ // Positive direction -> RdWrDly = 0 to (Data->MaxRdWrSweep - 1)
+ // Negative direction -> RdWrDly = Data->MaxRdWrSweep to (TotalDlyRange - 1)
+ //
+ for (RdWrDly = 0; RdWrDly < TotalDlyRange; RdWrDly++) {
+ // Vref loop is divided around "Data->Vnom - 1" into positive and negative directions
+ // Negative direction -> Vref = 0 ("Data->Vnom - 1") to Height("Data->Vnom - 1" - Height)
+ // Positive direction -> Vref = "Data->Vnom" to Height("Data->Vnom" + Height)
+ //
+ negVrefComplete = FALSE;
+ PosRdWrToNegRdWr = FALSE;
+ NegRdWrToPosRdWr = FALSE;
+ for (Vref = 0; Vref < (NBPtr->TotalMaxVrefRange - 1); Vref++) {
+ // Initial negative direction where Vref = 0 ("Data->Vnom - 1"), so we need to set
+ // initial startWidth and endWidth for +/- RdDqs
+ //
+ // Create common delay based on +/- RdDqs
+ if (RdWrDly > (Data->MaxRdWrSweep - 1)) {
+ Dly = RdWrDly - Data->MaxRdWrSweep;
+ } else {
+ Dly = RdWrDly;
+ }
+ if (Vref == 0 ) {
+ // Initialize -Vref
+ maxHeightExceeded = FALSE; // reset for start of -Vref
+ // Case 1: if +RdDqs - Check for lower bound (Width/2 > RdDqs > 0)
+ // : if -RdDqs - Check for lower bound (Width/2 + Data->MaxRdDqsSweep > RdDqs > Data->MaxRdDqsSweep)
+ if (Dly < Width / 2) {
+ endWidth = Dly + Width / 2 + 1;
+ startWidth = 0;
+ } else if ((Dly + Width / 2) > (Data->MaxRdWrSweep - 1)) {
+ // Case 2: if +RdWr - Check for upper bound ((Data->MaxRdWrSweep - 1) < RdWr < ((Data->MaxRdWrSweep - 1) - Width/2))
+ // : if -RdWr - Check for lower bound ((DatNBPtr->TotalRdWrDlyRange - 1) < RdWr < ((NBPtr->TotalRdWrDlyRange - 1) - Width/2))
+ endWidth = Data->MaxRdWrSweep;
+ startWidth = Dly - Width / 2;
+ } else {
+ // Set the initial "startWidth" and "endWidth" for +/- RdDqs
+ endWidth = Dly + Width / 2 + 1;
+ startWidth = Dly - Width / 2;
+ }
+ origEndWidth = endWidth;
+ origStartWidth = startWidth;
+ } else if (Vref == Data->Vnom) {
+ // Initialize +Vref
+ endWidth = origEndWidth;
+ startWidth = origStartWidth;
+ maxHeightExceeded = FALSE; // reset for start of +Vref
+ negVrefComplete = TRUE;
+ } else if ((Vref > (Data->Vnom + Height)) && negVrefComplete == TRUE) {
+ break; //switch to next RdDqs Dly if height exceeded for +vref and -vref complete
+ } else {
+ if (startWidth >= endWidth) {
+ if (RdWrDly == (TotalDlyRange - 1)) {
+ // Special condition for end of -RdDqs range
+ startWidth = Data->MaxRdWrSweep - 1;
+ endWidth = Data->MaxRdWrSweep;
+ } else {
+ // Width = 0, but Height not reached,
+ startWidth = Dly;
+ endWidth = Dly + 1;
+ }
+ } else {
+ // Check for Case 1 and Case 2 above
+ if ((RdWrDly + Width / 2) > (TotalDlyRange - 1)) {
+ endWidth = origEndWidth;
+ }
+ }
+ maxHeightExceeded = FALSE;
+ }
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ if (Lane == 0) {
+ if (RdWrDly == (Data->MaxRdWrSweep - (Width / 2)) ) {
+ Data->DiamondLeft[Vref] = startWidth;
+ Data->DiamondRight[Vref] = endWidth - 1;
+ }
+ }
+ );
+ //
+ // Determine the correct Delay (+/-) and Vref (+/-)direction
+ //
+ if (maxHeightExceeded == FALSE) {
+ if (RdWrDly < Data->MaxRdWrSweep) {
+ if (Vref > (Data->Vnom - 1)) {
+ PosNegData = Data->Lane[Lane].Vref[Vref].PosRdWrDly; // +RdWr Dly, +Vref
+ } else {
+ PosNegData = Data->Lane[Lane].Vref[(Data->Vnom - 1) - Vref].PosRdWrDly; // +RdDqs Dly, -Vref
+ }
+ } else {
+ if (Vref > (Data->Vnom - 1)) {
+ PosNegData = Data->Lane[Lane].Vref[Vref].NegRdWrDly; // -RdWr Dly, +Vref
+ } else {
+ PosNegData = Data->Lane[Lane].Vref[(Data->Vnom - 1) - Vref].NegRdWrDly; // -RdWr Dly, -Vref
+ }
+ }
+ //
+ // Case 1: Non-overlap condition:
+ // Count the number of passes from "startWidth" to "endWidth"
+ //
+ for (count = startWidth; count < endWidth; count++) {
+ Data->Lane[Lane].Convolution[RdWrDly] = (UINT8) ((PosNegData >> count) & 0x1) + Data->Lane[Lane].Convolution[RdWrDly];
+ }
+ // Case 2: Overlay between +RdWr and -RdWr starting from +RdWr
+ // Count the number of passes from "startWidth" to "endWidth"
+ //
+ if ((RdWrDly <= (Data->MaxRdWrSweep - 1) && (RdWrDly > ((Data->MaxRdWrSweep - 1) - Width / 2)))) {
+ startOverLapWidth = 0;
+ if (Vref == 0 || Vref == Data->Vnom) {
+ maxOverLapWidth = (RdWrDly + Width / 2) - (Data->MaxRdWrSweep - 1); // Initial overlap max width size
+ } else if (maxOverLapWidth == 0) {
+ maxOverLapWidth = startOverLapWidth; // Stop counting after overlap region complete
+ }
+ // Ensure that +/- vref is set correctly
+ if (Vref > (Data->Vnom - 1)) {
+ PosNegData = Data->Lane[Lane].Vref[Vref].NegRdWrDly;
+ } else {
+ PosNegData = Data->Lane[Lane].Vref[(Data->Vnom - 1) - Vref].NegRdWrDly;
+ }
+ // Need to count the number of passes when range extends from Pos RdDqs to Neg RdDqs
+ for (count = startOverLapWidth; count < maxOverLapWidth; count++) {
+ Data->Lane[Lane].Convolution[RdWrDly] = (UINT8) ((PosNegData >> count) & 0x1) + Data->Lane[Lane].Convolution[RdWrDly];
+ }
+ if (maxOverLapWidth > 0) {
+ if (MemFCheckRdWr2DDiamondMaskStep (NBPtr, Data, Vref, Lane) || (Vref == 1) || (Vref == Data->Vnom)) {
+ maxOverLapWidth--; // Reduce overlap width outside of diamond mask
+ }
+ PosRdWrToNegRdWr = TRUE;
+ }
+ }
+ if (((RdWrDly - Data->MaxRdWrSweep) < Width / 2) && (RdWrDly > (Data->MaxRdWrSweep - 1))) {
+ //
+ // Case 3: Overlay between -RdDqs and +RdDqs starting from -RdDqs
+ // Count the number of passes from "startWidth" to "endWidth"
+ //
+ maxOverLapWidth = Data->MaxRdWrSweep;
+ if (Vref == 0 || Vref == Data->Vnom) {
+ startOverLapWidth = RdWrDly - Width / 2; // Initial overlap start point
+ } else if (startOverLapWidth > maxOverLapWidth) {
+ maxOverLapWidth = maxOverLapWidth - 1; // Continue to count until MaxHeight excceded
+ }
+ // Ensure that vref + or - is set correctly
+ if (Vref > (Data->Vnom - 1)) {
+ PosNegData = Data->Lane[Lane].Vref[Vref].PosRdWrDly;
+ } else {
+ PosNegData = Data->Lane[Lane].Vref[(Data->Vnom - 1) - Vref].PosRdWrDly;
+ }
+ // Need to count the number of passes when range extends from Pos RdDqs to Neg RdDqs
+ for (count = startOverLapWidth; count < maxOverLapWidth; count++) {
+ Data->Lane[Lane].Convolution[RdWrDly] = (UINT8) ((PosNegData >> count) & 0x1) + Data->Lane[Lane].Convolution[RdWrDly];
+ }
+ if (startOverLapWidth < maxOverLapWidth) {
+ if (MemFCheckRdWr2DDiamondMaskStep (NBPtr, Data, Vref, Lane) || (Vref == 1) || (Vref == Data->Vnom)) {
+ startOverLapWidth++; // Reduce overlap width outside of diamond mask
+ }
+ NegRdWrToPosRdWr = TRUE;
+ }
+ }
+ }
+ if (MemFCheckRdWr2DDiamondMaskStep (NBPtr, Data, Vref, Lane) || (Vref == 1) || (Vref == Data->Vnom)) {
+ if (PosRdWrToNegRdWr) {
+ startWidth++;
+ endWidth = Data->MaxRdWrSweep;
+ PosRdWrToNegRdWr = FALSE;
+ } else if (NegRdWrToPosRdWr) {
+ startWidth = 0;
+ endWidth--;
+ NegRdWrToPosRdWr = FALSE;
+ } else {
+ startWidth++;
+ endWidth--;
+ }
+ }
+ NBPtr->FamilySpecificHook[Adjust2DVrefStepSize] (NBPtr, &Vref);
+ }
+ NBPtr->FamilySpecificHook[Adjust2DDelayStepSize] (NBPtr, &RdWrDly);
+ }
+ }
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t Diamond Shape: \n");
+ for (Vref = 0; Vref < (NBPtr->TotalMaxVrefRange - 1); Vref++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ for (RdWrDly = (Data->MaxRdWrSweep - Width); RdWrDly < Data->MaxRdWrSweep; RdWrDly++) {
+ if (Vref < (Data->Vnom - 1)) {
+ if (RdWrDly == Data->DiamondLeft[(NBPtr->TotalMaxVrefRange - 2) - Vref]) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " | ");
+ } else if (RdWrDly == Data->DiamondRight[(NBPtr->TotalMaxVrefRange - 2) - Vref]) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " | -> Width = %02x", (Data->DiamondRight[(NBPtr->TotalMaxVrefRange - 2) - Vref]) - (Data->DiamondLeft[(NBPtr->TotalMaxVrefRange - 2) - Vref]));
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, " ");
+ }
+ } else {
+ if (RdWrDly == Data->DiamondLeft[Vref - (Data->Vnom - 1)]) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " | ");
+ } else if (RdWrDly == Data->DiamondRight[Vref - (Data->Vnom - 1)]) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " | -> Width = %02x", (Data->DiamondRight[Vref - (Data->Vnom - 1)]) - (Data->DiamondLeft[Vref - (Data->Vnom - 1)]));
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, " ");
+ }
+ }
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t Convolution results after processing raw data:\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t Delay: ");
+ for (RdWrDly = 0; RdWrDly < TotalDlyRange; RdWrDly++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x ", RdWrDly <= (Data->MaxRdWrSweep - 1) ? (Data->MaxRdWrSweep - 1) - RdWrDly : (TotalDlyRange - 1) - RdWrDly);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tLane: %02x\n", Lane);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tConv: ");
+ for (RdWrDly = 0; RdWrDly < TotalDlyRange; RdWrDly++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", Data->Lane[Lane].Convolution[RdWrDly]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ }
+ );
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function Examines the convolution function and determines the Max Delay
+ * for 2D RdDQS and WrDat training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ */
+
+BOOLEAN
+MemFRdWr2DProcessConvolution (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ MEM_TECH_BLOCK *TechPtr;
+ UINT8 RdWrDly;
+ UINT8 Lane;
+ UINT16 MaxFOM;
+ UINT8 MaxRange;
+ UINT8 CurrRange;
+ UINT8 TotalDlyRange;
+ BOOLEAN status;
+
+ ASSERT (NBPtr != NULL);
+ TechPtr = NBPtr->TechPtr;
+ TotalDlyRange = (TechPtr->Direction == DQS_READ_DIR) ? NBPtr->TotalRdDQSDlyRange : NBPtr->TotalWrDatDlyRange;
+ status = TRUE;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tDetermining Delay based on Convolution function\n");
+ // Determine the Max RdDqs or WrDat Dly for the convolution function
+ // - Choose the delay setting at the peak FOM value.
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ // Find largest value as MaxFOM
+ MaxFOM = 0;
+ for (RdWrDly = 0; RdWrDly < TotalDlyRange; RdWrDly++) {
+ if (Data->Lane[Lane].Convolution[RdWrDly] > MaxFOM) {
+ MaxFOM = Data->Lane[Lane].Convolution[RdWrDly];
+ }
+ }
+ status = MaxFOM > 0 ? TRUE : FALSE; // It is an error if all convolution points are zero
+
+ // Then find the midpoint of the largest consecutive window w/ that MaxFOM
+ // In cases of an even number of consecutive points w/ that MaxFOM exists,
+ // choose the midpoint to the right
+ // All things being equal, favor the right side of a bi-modal eye
+ // Stressful SSO patterns shift the eye right!
+ MaxRange = 0;
+ CurrRange = 0;
+ for (RdWrDly = 0; (MaxFOM > 0) && RdWrDly < TotalDlyRange; RdWrDly++) {
+ if (Data->Lane[Lane].Convolution[RdWrDly] == MaxFOM) {
+ CurrRange++;
+ if (CurrRange >= MaxRange) {
+ Data->Lane[Lane].MaxRdWrDly = RdWrDly - ((CurrRange - 1) / 2);
+ MaxRange = CurrRange;
+ }
+ } else {
+ CurrRange = 0;
+ }
+ }
+
+ if (Data->Lane[Lane].MaxRdWrDly > Data->MaxRdWrSweep) {
+ status = FALSE; // Error
+ }
+ // Set Actual register value
+ if (Data->Lane[Lane].MaxRdWrDly < Data->MaxRdWrSweep) {
+ Data->Lane[Lane].MaxRdWrDly = (Data->MaxRdWrSweep - 1) - Data->Lane[Lane].MaxRdWrDly;
+ } else {
+ status = FALSE; // Error
+ }
+ }
+
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Cs %d Lane: ", TechPtr->ChipSel);
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Lane);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t Max %s Delay: ", TechPtr->Direction == DQS_READ_DIR ? "Rd Dqs" : "Wr DQ");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Data->Lane[Lane].MaxRdWrDly);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t1D Trained %s Delay: ", TechPtr->Direction == DQS_READ_DIR ? "Rd Dqs" : "Wr DQ");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + Lane]);
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", (NBPtr->ChannelPtr->WrDatDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + Lane] - \
+ NBPtr->ChannelPtr->WrDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + Lane]));
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ );
+
+ if (status == FALSE) {
+ SetMemError (AGESA_FATAL, NBPtr->MCTPtr);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_INVALID_2D_RDDQS_VALUE, 0, 0, 0, 0, &TechPtr->NBPtr->MemPtr->StdHeader);
+ }
+ return status;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs the Max Rd Dqs or Max Wr DQ for 2D training from
+ * convolution
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ */
+BOOLEAN
+MemFRdWr2DProgramMaxDelays (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ MEM_TECH_BLOCK *TechPtr;
+ UINT8 Lane;
+ UINT8 LaneHighRdDqs2dDlys;
+ UINT8 LaneLowRdDqs2dDlys;
+ UINT8 MaxWrDatDly;
+ TechPtr = NBPtr->TechPtr;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tProgramming Max %s Delay per Lane\n\n", TechPtr->Direction == DQS_READ_DIR ? "Rd Dqs" : "Wr DQ");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ if ( TechPtr->Direction == DQS_WRITE_DIR || (NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) == 0) {
+ // Program Byte based for x8 and x16
+ if ( TechPtr->Direction == DQS_READ_DIR) {
+ //
+ // Read DQS Training
+ //
+ NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS ((TechPtr->ChipSel / NBPtr->CsPerDelay), Lane), (UINT16)Data->Lane[Lane].MaxRdWrDly);
+ NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + Lane] = Data->Lane[Lane].MaxRdWrDly;
+ } else {
+ //
+ // Write DQ Training
+ //
+ MaxWrDatDly = (UINT8) (Data->Lane[Lane].MaxRdWrDly + TechPtr->NBPtr->ChannelPtr->WrDqsDlys[(TechPtr->ChipSel / TechPtr->NBPtr->CsPerDelay) * MAX_DELAYS + Lane]);
+ NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS ((TechPtr->ChipSel / NBPtr->CsPerDelay), Lane), MaxWrDatDly);
+ NBPtr->ChannelPtr->WrDatDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + Lane] = MaxWrDatDly;
+ }
+ } else {
+ ASSERT (TechPtr->Direction == DQS_READ_DIR);
+ // Program nibble based x4, so use "Nibble"
+ NBPtr->SetTrainDly (NBPtr, AccessRdDqs2dDly, DIMM_NBBL_ACCESS ((TechPtr->ChipSel / NBPtr->CsPerDelay), Lane), (UINT16)Data->Lane[Lane].MaxRdWrDly);
+ NBPtr->ChannelPtr->RdDqs2dDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_NUMBER_LANES + Lane] = Data->Lane[Lane].MaxRdWrDly;
+ // For each pair of nibbles (high (Odd Nibble) and Low (Even nibble)), find the largest and use that as the RdDqsDly value
+ if ((Lane & 0x1) == 0) {
+ LaneHighRdDqs2dDlys = Data->Lane[Lane + 1].MaxRdWrDly;
+ LaneLowRdDqs2dDlys = Data->Lane[Lane].MaxRdWrDly;
+ if (LaneHighRdDqs2dDlys > LaneLowRdDqs2dDlys) {
+ NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + (Lane >> 1)] = LaneHighRdDqs2dDlys;
+ } else {
+ NBPtr->ChannelPtr->RdDqsDlys[(TechPtr->ChipSel / NBPtr->CsPerDelay) * MAX_DELAYS + (Lane >> 1)] = LaneLowRdDqs2dDlys;
+ }
+ }
+ NBPtr->DctCachePtr->Is2Dx4 = TRUE;
+ }
+ }
+ return TRUE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the Positive and negative Vref Margin for the current CS
+ * for 2D RdDQS or WrDat training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ */
+BOOLEAN
+MemFRdWr2DFindCsVrefMargin (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ UINT8 SmallestMaxVrefNeg;
+ UINT8 Lane;
+ UINT8 RdWrDly;
+ UINT8 Vref;
+ UINT8 MaxVrefPositive;
+ UINT8 MaxVrefNegative;
+ UINT8 SmallestMaxVrefPos;
+ UINT32 PosNegData;
+ SmallestMaxVrefPos = 0xFF;
+ SmallestMaxVrefNeg = 0;
+ MaxVrefPositive = 0;
+ MaxVrefNegative = 0xFF;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFinding Smallest Max Positive and Negative Vref\n\n");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ RdWrDly = (Data->MaxRdWrSweep - 1) - Data->Lane[Lane].MaxRdWrDly;
+ for (Vref = 0; Vref < (Data->Vnom - 1); Vref++) {
+ // Neg Vref - (searching from top of array down)
+ PosNegData = Data->Lane[Lane].Vref[Vref].PosRdWrDly;
+ if ((UINT8) ((PosNegData >> RdWrDly) & 0x1) == 1) {
+ MaxVrefNegative = Vref;
+ break;
+ }
+ NBPtr->FamilySpecificHook[Adjust2DVrefStepSize] (NBPtr, &Vref);
+ }
+ for (Vref = (Data->Vnom - 1); Vref < (NBPtr->TotalMaxVrefRange - 1); Vref++) {
+ // Pos Vref - (searching from Vnom + 1 of array down)
+ PosNegData = Data->Lane[Lane].Vref[Vref].PosRdWrDly;
+ if ((UINT8) ((PosNegData >> RdWrDly) & 0x1) == 0) {
+ // Convert to register setting
+ MaxVrefPositive = Vref - 1;// - Data->Vnom;
+ break;
+ } else {
+ // If Vref = 1F passes, then smallest Vref = 0x1F
+ if (Vref == ((NBPtr->TotalMaxVrefRange - 1) - 1)) {
+ MaxVrefPositive = 0x1E;
+ break;
+ }
+ }
+ NBPtr->FamilySpecificHook[Adjust2DVrefStepSize] (NBPtr, &Vref);
+ }
+ if (MaxVrefPositive < SmallestMaxVrefPos) {
+ // Find the smallest Max Pos Vref
+ SmallestMaxVrefPos = MaxVrefPositive;
+ }
+ if (MaxVrefNegative > SmallestMaxVrefNeg) {
+ // Find the largest Max Neg Vref
+ SmallestMaxVrefNeg = MaxVrefNegative;
+ }
+ }
+ if (SmallestMaxVrefPos != (Data->Vnom - 2)) {
+ Data->SmallestPosMaxVrefperCS[NBPtr->TechPtr->ChipSel] = SmallestMaxVrefPos - Data->Vnom + 1;
+ } else {
+ Data->SmallestPosMaxVrefperCS[NBPtr->TechPtr->ChipSel] = 0;
+ }
+ Data->SmallestNegMaxVrefperCS[NBPtr->TechPtr->ChipSel] = (Data->Vnom - 1) - SmallestMaxVrefNeg;
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSmallest Max Positive Vref Offset from V-Nom for ChipSel %02x = + %02x\n", NBPtr->TechPtr->ChipSel, Data->SmallestPosMaxVrefperCS[NBPtr->TechPtr->ChipSel]);
+ if (Data->SmallestPosMaxVrefperCS[NBPtr->TechPtr->ChipSel] == 0) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSmallest Max Negative Vref Offset from V-Nom for ChipSel %02x = 00\n");
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSmallest Max Negative Vref Offset from V-Nom for ChipSel %02x = - %02x\n", NBPtr->TechPtr->ChipSel, Data->SmallestNegMaxVrefperCS[NBPtr->TechPtr->ChipSel]);
+ }
+ );
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the final Vref Margin for 2D RdDQS or WrDat training
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ * @return BOOLEAN
+ * TRUE - No Errors occurred
+ * FALSE - Errors ccurred
+ */
+BOOLEAN
+MemFRdWr2DFinalVrefMargin (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ UINT8 ChipSel;
+ UINT8 SmallestMaxPosVref;
+ UINT8 SmallestMaxNegVref;
+ UINT8 OffsetFromVref;
+ UINT8 Vnom;
+ SmallestMaxNegVref = 0x7F;
+ SmallestMaxPosVref = 0x7F;
+ Vnom = (Data->Vnom - 1);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFinding Final Vref for channel\n\n");
+ for (ChipSel = 0; ChipSel < NBPtr->CsPerChannel; ChipSel = ChipSel + NBPtr->CsPerDelay ) {
+ if ( (NBPtr->MCTPtr->Status[SbLrdimms]) ? ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << (ChipSel >> 1))) != 0) :
+ ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) != 0) ) {
+ if (Data->SmallestPosMaxVrefperCS[ChipSel] < SmallestMaxPosVref) {
+ SmallestMaxPosVref = Data->SmallestPosMaxVrefperCS[ChipSel];
+ }
+ if (Data->SmallestNegMaxVrefperCS[ChipSel] < SmallestMaxNegVref) {
+ SmallestMaxNegVref = Data->SmallestNegMaxVrefperCS[ChipSel];
+ }
+ }
+ }
+ //
+ // Synchronize minimum and Maximums with other Vref values
+ //
+ if (NBPtr->TechPtr->Direction == DQS_WRITE_DIR) {
+ if (NBPtr->SharedPtr->CommonSmallestMaxNegVref < SmallestMaxNegVref) {
+ SmallestMaxNegVref = NBPtr->SharedPtr->CommonSmallestMaxNegVref;
+ } else {
+ NBPtr->SharedPtr->CommonSmallestMaxNegVref = SmallestMaxNegVref;
+ }
+ if (NBPtr->SharedPtr->CommonSmallestMaxPosVref < SmallestMaxPosVref) {
+ SmallestMaxPosVref = NBPtr->SharedPtr->CommonSmallestMaxPosVref;
+ } else {
+ NBPtr->SharedPtr->CommonSmallestMaxPosVref = SmallestMaxPosVref;
+ }
+ }
+ NBPtr->FamilySpecificHook[RdWr2DScaleVref] (NBPtr, &SmallestMaxPosVref);
+ NBPtr->FamilySpecificHook[RdWr2DScaleVref] (NBPtr, &SmallestMaxNegVref);
+ NBPtr->FamilySpecificHook[RdWr2DScaleVref] (NBPtr, &Vnom);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tScaled Smallest Max Positive = + %02x\n", SmallestMaxPosVref);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tScaled Smallest Max Negative =%s%02x\n", ((SmallestMaxNegVref != 0) ? " - " : " "), SmallestMaxNegVref);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tScaled Vnom = %02x\n", Vnom);
+
+ if (SmallestMaxPosVref > SmallestMaxNegVref) {
+ OffsetFromVref = (SmallestMaxPosVref - SmallestMaxNegVref) / 2;
+ NBPtr->ChannelPtr->MaxVref = Vnom + OffsetFromVref;
+ } else {
+ OffsetFromVref = (SmallestMaxNegVref - SmallestMaxPosVref) / 2;
+ NBPtr->ChannelPtr->MaxVref = Vnom - OffsetFromVref;
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tFinal Vref Offset From Vnom =%s%02x\n",
+ ((OffsetFromVref != 0) ? ((SmallestMaxPosVref > SmallestMaxNegVref) ? " + ":" - "):" "), OffsetFromVref);
+ return TRUE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function displays ther results of the 2D search
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] *Data - Pointer to Result data structure
+ *
+ */
+VOID
+MemFRdWr2DDisplaySearch (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ )
+{
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ UINT8 Lane;
+ INT8 Vref;
+ // Display data collected
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDisplaying Data collected\n\n");
+ for (Lane = 0; Lane < MemFRdWr2DGetMaxLanes (NBPtr); Lane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tLane: %02x\n", Lane);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t Vref %s\n", (NBPtr->TechPtr->Direction == DQS_READ_DIR) ? "NegRdDqs PosRdDqs" : "PosWrDat");
+ for (Vref = NBPtr->TotalMaxVrefRange - 2; Vref >= 0; Vref--) {
+ if (Vref < (Data->Vnom - 1)) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t - ");
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", ((Data->Vnom -1) - Vref));
+ } else if (Vref == (Data->Vnom - 1)) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t 00 ");
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t + ");
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Vref - (Data->Vnom - 1));
+ }
+ if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%08x", Data->Lane[Lane].Vref[Vref].NegRdWrDly);
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, " ");
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "%08x \n", Data->Lane[Lane].Vref[Vref].PosRdWrDly);
+ NBPtr->FamilySpecificHook[Adjust2DVrefStepSize] (NBPtr, &Vref);
+ }
+ }
+ )
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.h b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.h
new file mode 100644
index 0000000000..a2a4b02dda
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/RDWR2DTRAINING/mfRdWr2DTraining.h
@@ -0,0 +1,266 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mf2DRdWrTraining.h
+ *
+ * Common Definitions ot support 2D Read/Write Training
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/2DRdWrTraining)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+#ifndef _MFRDWR2DTRAINING_H_
+#define _MFRDWR2DTRAINING_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+#define MAX_2D_VREF_ENTRIES 0x20 ///< Maximum number of vref entries
+#define MAX_RD_WR_DLY_ENTRIES 0x40 ///< Maximum number of RD/WR Delay Entries
+#define VREF_ADDITIONAL_STEP_SIZE 0x0 ///< Vref Additional Step size
+#define RDDQS_ADDITIONAL_STEP_SIZE 0x0 ///< RdDqs Additional Step size
+#define MAX_2D_RD_SEED_COUNT 4 ///< Max Seed count
+#define MAX_2D_RD_WR_CS_PER_CHANNEL 8 ///< Max CS per Rd Wr delay group
+
+#define EYERIM_PARALLEL_SAMPLING TRUE
+#define EYERIM_BROADCAST_DELAYS TRUE
+
+/// Structure for RD DQS 2D training RDDQS delays.
+typedef struct {
+ UINT32 PosRdWrDly; ///< Positive RdDQS Delay
+ UINT32 NegRdWrDly; ///< Negative RdDQS Delay
+} RD_WR_2D;
+
+/// Structure for RD DQS 2D training Vref delays
+typedef struct {
+ RD_WR_2D *Vref; ///< Pointer to Vref Entries
+ UINT16 Convolution[MAX_RD_WR_DLY_ENTRIES]; ///< Total number of passes in each mask
+ UINT8 PosHeight[MAX_RD_WR_DLY_ENTRIES / 2]; ///< Positive Vref height Height per Delay
+ UINT8 NegHeight[MAX_RD_WR_DLY_ENTRIES / 2]; ///< Negative Vref height Height per Delay
+ UINT8 HalfDiamondHeight; ///< Half of the Height per BL (height of pos/neg vref)
+ UINT8 MaxRdWrDly; ///< Max RdWrDly from convolution function
+} VREF_RD_WR_2D;
+
+/// Structure for RD DQS 2D training Nibbles
+typedef struct {
+ VREF_RD_WR_2D Lane[MAX_NUMBER_LANES]; ///< Bytelane or Nibble
+ UINT8 Vnom; ///< Nominal Vref value
+ UINT8 MaxRdWrSweep; ///< Maximum RdDqs or WrDat Sweep size
+ UINT8 SmallestPosMaxVrefperCS[MAX_2D_RD_WR_CS_PER_CHANNEL]; ///< Smallest Positive Max Vref per CS
+ UINT8 SmallestNegMaxVrefperCS[MAX_2D_RD_WR_CS_PER_CHANNEL]; ///< Smallest Negative Max Vref per CS
+ UINT8 DiamondLeft[MAX_2D_VREF_ENTRIES]; ///< Left edge of Diamond for shape display
+ UINT8 DiamondRight[MAX_2D_VREF_ENTRIES]; ///< Left edge of Diamond for shape display
+ UINT8 RdWrDly; ///< RdDQS or WrDat Dly setting
+ VOID* SavedData; ///< Algorithm-specific saved data
+} MEM_RD_WR_2D_ENTRY;
+
+/// Structure used for RD WR 2D Eye Rim Search Algorithm
+typedef struct {
+ VREF_RD_WR_2D LaneSaved[MAX_NUMBER_LANES]; ///< Bytelane or Nibble that was saved
+ INT8 xMin; ///< Minimum value for RdDqs delays
+ INT8 xMax; ///< Maximum value for RdDqs delays
+ INT8 yMin; ///< Minimum value for vref delays
+ INT8 yMax; ///< Maximum value for vref delays
+ BOOLEAN ParallelSampling; ///< Flag to indicate parallel sampling feature
+ BOOLEAN BroadcastDelays; ///< Flag to indicate if delays will be broadcast
+ UINT32 SampleCount; ///< Count of samples taken
+ UINT32 VrefUpdates; ///< Count of updates to Vref
+ UINT32 RdWrDlyUpdates; ///< Count of updates to RdWrDly
+ INT8 Dirs[2]; ///< List of directions to search for each axis
+} MEM_RD_WR_2D_RIM_ENTRY;
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+BOOLEAN
+MemFAmdRdWr2DTraining (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID* OptParam
+ );
+
+BOOLEAN
+MemFCheckRdWr2DTrainingPerConfig (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+MemFRdWr2DProgramIntExtVrefSelect (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+MemFRdWr2DProgramVref (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *VrefPtr
+ );
+
+BOOLEAN
+MemFRdWr2DProgramDelays (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *Delay
+ );
+
+VOID
+MemFRdWr2DStoreResult (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data,
+ IN UINT32 InPhaseResult[],
+ IN UINT32 PhaseResult180[]
+ );
+
+BOOLEAN
+MemFRdWr2DHeight (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+UINT8
+MemFGetRdWr2DWidth (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+BOOLEAN
+MemFCheckRdWr2DDiamondMaskStep (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data,
+ IN UINT8 Vref,
+ IN UINT8 Lane
+ );
+BOOLEAN
+MemFRdWr2DApplyMask (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+BOOLEAN
+MemFRdWr2DProcessConvolution (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+BOOLEAN
+MemFRdWr2DProgramMaxDelays (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+BOOLEAN
+MemFRdWr2DFindCsVrefMargin (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+BOOLEAN
+MemFRdWr2DFinalVrefMargin (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+UINT8
+MemFRdWr2DGetMaxLanes (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+BOOLEAN
+MemFRdWr2DTrainingInit (
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+BOOLEAN
+MemFRdWr2DEyeRimSearch (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *OptParam
+ );
+
+VOID
+MemFRdWr2DDisplaySearch (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_RD_WR_2D_ENTRY *Data
+ );
+
+/*******************************
+* Pattern Generation Functions
+*******************************/
+BOOLEAN
+MemFRdWr2DCompareInPhase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ OUT VOID *Result
+ );
+
+BOOLEAN
+MemFRdWr2DCompare180Phase (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ OUT VOID *Result
+ );
+
+BOOLEAN
+MemFRdWr2DInitVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+MemFRdWr2DInitVictimChipSel (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+MemFRdWr2DStartVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID *SeedCountPtr
+ );
+
+BOOLEAN
+MemFRdWr2DFinalizeVictim (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+MemFRdWr2DProgramDataPattern (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN VOID* PatternIndexPtr
+ );
+
+#endif /* _MFRDWR2DTRAINING_H_ */
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/S3/mfs3.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/S3/mfs3.c
new file mode 100644
index 0000000000..e6914a7d5a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/S3/mfs3.c
@@ -0,0 +1,718 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfs3.c
+ *
+ * Main S3 resume memory Entrypoint file
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/FEAT/S3)
+ * @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 "Ids.h"
+#include "cpuRegisters.h"
+#include "OptionMemory.h"
+#include "mm.h"
+#include "mn.h"
+#include "S3.h"
+#include "mfs3.h"
+#include "heapManager.h"
+#include "amdlib.h"
+#include "GeneralServices.h"
+#include "cpuFamilyTranslation.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_S3_MFS3_FILECODE
+
+extern MEM_NB_SUPPORT memNBInstalled[];
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function is the main memory entry point for the S3 resume sequence
+ * Requirements:
+ *
+ * Run-Time Requirements:
+ * 1. Complete Hypertransport Bus Configuration
+ * 4. BSP in Big Real Mode
+ * 5. Stack available
+ *
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+AmdMemS3Resume (
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ MEM_MAIN_DATA_BLOCK mmData;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ MEM_DATA_STRUCT *MemData;
+ UINT8 Die;
+ UINT8 DieCount;
+
+ //---------------------------------------------
+ // Creation of NB Block for S3 resume
+ //---------------------------------------------
+ RetVal = MemS3InitNB (&S3NBPtr, &MemData, &mmData, StdHeader);
+ if (RetVal == AGESA_FATAL) {
+ return RetVal;
+ }
+ DieCount = mmData.DieCount;
+
+ //---------------------------------------------
+ //1. Errata Before resume sequence
+ //2. S3 Resume sequence
+ //3. Errata After resume sequence
+ //---------------------------------------------
+ for (Die = 0; Die < DieCount; Die ++) {
+ if (!S3NBPtr[Die].MemS3Resume (&S3NBPtr[Die], Die)) {
+ return AGESA_FATAL;
+ }
+ S3NBPtr[Die].MemS3RestoreScrub (S3NBPtr[Die].NBPtr, Die);
+ }
+
+ HeapDeallocateBuffer (AMD_MEM_S3_DATA_HANDLE, StdHeader);
+ return AGESA_SUCCESS;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function deallocates heap space allocated in memory S3 resume.
+ *
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemS3Deallocate (
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ AGESA_STATUS tempRetVal;
+ UINT8 Tab;
+
+ RetVal = AGESA_SUCCESS;
+ for (Tab = 0; Tab < NumberOfNbRegTables; Tab++) {
+ HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Tab, 0, 0), StdHeader);
+ }
+
+ tempRetVal = HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_DIE_STRUCT_HANDLE, 0, 0, 0), StdHeader);
+ if (tempRetVal > RetVal) {
+ RetVal = tempRetVal;
+ }
+ tempRetVal = HeapDeallocateBuffer (AMD_MEM_AUTO_HANDLE, StdHeader);
+ if (tempRetVal > RetVal) {
+ RetVal = tempRetVal;
+ }
+ RetVal = HeapDeallocateBuffer (AMD_MEM_S3_NB_HANDLE, StdHeader);
+ if (tempRetVal > RetVal) {
+ RetVal = tempRetVal;
+ }
+ RetVal = HeapDeallocateBuffer (AMD_MEM_DATA_HANDLE, StdHeader);
+ if (tempRetVal > RetVal) {
+ RetVal = tempRetVal;
+ }
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function is the entrance to get device list for memory registers.
+ *
+ * @param[in, out] **DeviceBlockHdrPtr - Pointer to the memory containing the
+ * device descriptor list
+ * @param[in] *StdHeader - Config handle for library and services
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemFS3GetDeviceList (
+ IN OUT DEVICE_BLOCK_HEADER **DeviceBlockHdrPtr,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ UINT8 i;
+ UINT16 BufferSize;
+ UINT64 BufferOffset;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ MEM_DATA_STRUCT *MemData;
+ MEM_MAIN_DATA_BLOCK mmData;
+ UINT8 Die;
+ UINT8 DieCount;
+ AGESA_STATUS RetVal;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ DESCRIPTOR_GROUP DeviceDescript[MAX_NODES_SUPPORTED];
+ BufferSize = 0;
+
+ //---------------------------------------------
+ // Creation of NB Block for S3 resume
+ //---------------------------------------------
+ RetVal = MemS3InitNB (&S3NBPtr, &MemData, &mmData, StdHeader);
+ if (RetVal == AGESA_FATAL) {
+ return RetVal;
+ }
+ DieCount = mmData.DieCount;
+
+ // Get the mask bit and the register list for node that presents
+ for (Die = 0; Die < DieCount; Die ++) {
+ S3NBPtr->MemS3GetConPCIMask (S3NBPtr[Die].NBPtr, (VOID *)&DeviceDescript[Die]);
+ S3NBPtr->MemS3GetConMSRMask (S3NBPtr[Die].NBPtr, (VOID *)&DeviceDescript[Die]);
+ BufferSize = BufferSize + S3NBPtr->MemS3GetRegLstPtr (S3NBPtr[Die].NBPtr, (VOID *)&DeviceDescript[Die]);
+ }
+
+ // Base on the size of the device list, apply for a buffer for it.
+ AllocHeapParams.RequestedBufferSize = BufferSize + sizeof (DEVICE_BLOCK_HEADER);
+ AllocHeapParams.BufferHandle = AMD_S3_NB_INFO_BUFFER_HANDLE;
+ AllocHeapParams.Persist = HEAP_S3_RESUME;
+ AGESA_TESTPOINT (TpIfBeforeAllocateMemoryS3SaveBuffer, StdHeader);
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) != AGESA_SUCCESS) {
+ return AGESA_FATAL;
+ }
+ AGESA_TESTPOINT (TpIfAfterAllocateMemoryS3SaveBuffer, StdHeader);
+
+ *DeviceBlockHdrPtr = (DEVICE_BLOCK_HEADER *) AllocHeapParams.BufferPtr;
+ (*DeviceBlockHdrPtr)->RelativeOrMaskOffset = (UINT16) AllocHeapParams.RequestedBufferSize;
+
+ // Copy device list on the stack to the heap.
+ BufferOffset = sizeof (DEVICE_BLOCK_HEADER) + (UINT64) (UINTN) AllocHeapParams.BufferPtr;
+ for (Die = 0; Die < DieCount; Die ++) {
+ for (i = PRESELFREF; i <= POSTSELFREF; i ++) {
+ // Copy PCI device descriptor to the heap if it exists.
+ if (DeviceDescript[Die].PCIDevice[i].RegisterListID != 0xFFFFFFFF) {
+ LibAmdMemCopy ((VOID *) (UINTN) BufferOffset, &(DeviceDescript[Die].PCIDevice[i]), sizeof (PCI_DEVICE_DESCRIPTOR), StdHeader);
+ (*DeviceBlockHdrPtr)->NumDevices ++;
+ BufferOffset += sizeof (PCI_DEVICE_DESCRIPTOR);
+ }
+ // Copy conditional PCI device descriptor to the heap if it exists.
+ if (DeviceDescript[Die].CPCIDevice[i].RegisterListID != 0xFFFFFFFF) {
+ LibAmdMemCopy ((VOID *) (UINTN) BufferOffset, &(DeviceDescript[Die].CPCIDevice[i]), sizeof (CONDITIONAL_PCI_DEVICE_DESCRIPTOR), StdHeader);
+ (*DeviceBlockHdrPtr)->NumDevices ++;
+ BufferOffset += sizeof (CONDITIONAL_PCI_DEVICE_DESCRIPTOR);
+ }
+ // Copy MSR device descriptor to the heap if it exists.
+ if (DeviceDescript[Die].MSRDevice[i].RegisterListID != 0xFFFFFFFF) {
+ LibAmdMemCopy ((VOID *) (UINTN) BufferOffset, &(DeviceDescript[Die].MSRDevice[i]), sizeof (MSR_DEVICE_DESCRIPTOR), StdHeader);
+ (*DeviceBlockHdrPtr)->NumDevices ++;
+ BufferOffset += sizeof (MSR_DEVICE_DESCRIPTOR);
+ }
+ // Copy conditional MSR device descriptor to the heap if it exists.
+ if (DeviceDescript[Die].CMSRDevice[i].RegisterListID != 0xFFFFFFFF) {
+ LibAmdMemCopy ((VOID *) (UINTN) BufferOffset, &(DeviceDescript[Die].PCIDevice[i]), sizeof (CONDITIONAL_MSR_DEVICE_DESCRIPTOR), StdHeader);
+ (*DeviceBlockHdrPtr)->NumDevices ++;
+ BufferOffset += sizeof (CONDITIONAL_MSR_DEVICE_DESCRIPTOR);
+ }
+ }
+ }
+
+ return RetVal;
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function initialize the northbridge block and apply for heap space
+ * before any function call is made to memory component during S3 resume.
+ *
+ * @param[in] *StdHeader - Config handle for library and services
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemS3ResumeInitNB (
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ MEM_MAIN_DATA_BLOCK mmData;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ MEM_DATA_STRUCT *MemData;
+ UINT8 Die;
+ UINT8 DieCount;
+ UINT8 SpecialCaseHeapSize;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ S3_SPECIAL_CASE_HEAP_HEADER SpecialHeapHeader[MAX_NODES_SUPPORTED];
+
+ SpecialCaseHeapSize = 0;
+
+ //---------------------------------------------
+ // Creation of NB Block for S3 resume
+ //---------------------------------------------
+ RetVal = MemS3InitNB (&S3NBPtr, &MemData, &mmData, StdHeader);
+ if (RetVal == AGESA_FATAL) {
+ return RetVal;
+ }
+ DieCount = mmData.DieCount;
+
+ //--------------------------------------------------
+ // Apply for heap space for special case registers
+ //--------------------------------------------------
+ for (Die = 0; Die < DieCount; Die ++) {
+ // Construct the header for the special case heap.
+ SpecialHeapHeader[Die].Node = S3NBPtr[Die].NBPtr->Node;
+ SpecialHeapHeader[Die].Offset = SpecialCaseHeapSize + (DieCount * (sizeof (S3_SPECIAL_CASE_HEAP_HEADER)));
+ SpecialCaseHeapSize = SpecialCaseHeapSize + S3NBPtr->MemS3SpecialCaseHeapSize;
+ }
+ AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (S3_SPECIAL_CASE_HEAP_HEADER))) + SpecialCaseHeapSize;
+ AllocHeapParams.BufferHandle = AMD_MEM_S3_DATA_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) != AGESA_SUCCESS) {
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_S3_SPECIAL_CASE_REGISTERS, S3NBPtr[Die].NBPtr->Node, 0, 0, 0, StdHeader);
+ SetMemError (AGESA_FATAL, S3NBPtr[Die].NBPtr->MCTPtr);
+ ASSERT(FALSE); // Could not allocate heap space for "S3_SPECIAL_CASE_HEAP_HEADER"
+ return AGESA_FATAL;
+ }
+ LibAmdMemCopy ((VOID *) AllocHeapParams.BufferPtr, (VOID *) SpecialHeapHeader, (sizeof (S3_SPECIAL_CASE_HEAP_HEADER) * DieCount), StdHeader);
+ return AGESA_SUCCESS;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function returns the PCI device register list according to the register
+ * list ID.
+ *
+ * @param[in] *Device - pointer to the PCI_DEVICE_DESCRIPTOR
+ * @param[out] **RegisterHdr - pointer to the address of the register list
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemFS3GetPciDeviceRegisterList (
+ IN PCI_DEVICE_DESCRIPTOR *Device,
+ OUT PCI_REGISTER_BLOCK_HEADER **RegisterHdr,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ VOID *RegisterHeader;
+ LOCATE_HEAP_PTR LocHeap;
+ AGESA_BUFFER_PARAMS LocBufferParams;
+ LocHeap.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+
+ LibAmdMemCopy (&LocBufferParams.StdHeader, StdHeader, sizeof (AMD_CONFIG_PARAMS), StdHeader);
+ LocBufferParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+
+ AGESA_TESTPOINT (TpIfBeforeLocateS3PciBuffer, StdHeader);
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ S3NBPtr = (S3_MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ ASSERT(FALSE) ; // No match for heap status, but could not locate "AMD_MEM_S3_NB_HANDLE" in heap for S3GetMsr
+ return AGESA_FATAL;
+ }
+ AGESA_TESTPOINT (TpIfAfterLocateS3PciBuffer, StdHeader);
+
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ RetVal = S3NBPtr[Device->Node].MemS3GetDeviceRegLst (Device->RegisterListID, &RegisterHeader);
+ *RegisterHdr = (PCI_REGISTER_BLOCK_HEADER *)RegisterHeader;
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function returns the conditional PCI device register list according
+ * to the register list ID.
+ *
+ * @param[in] *Device - pointer to the CONDITIONAL_PCI_DEVICE_DESCRIPTOR
+ * @param[out] **RegisterHdr - pointer to the address of the register list
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemFS3GetCPciDeviceRegisterList (
+ IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
+ OUT CPCI_REGISTER_BLOCK_HEADER **RegisterHdr,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ VOID *RegisterHeader;
+ LOCATE_HEAP_PTR LocHeap;
+ AGESA_BUFFER_PARAMS LocBufferParams;
+
+ LibAmdMemCopy (&LocBufferParams.StdHeader, StdHeader, sizeof (AMD_CONFIG_PARAMS), StdHeader);
+ LocHeap.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+ LocBufferParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+
+ AGESA_TESTPOINT (TpIfBeforeLocateS3CPciBuffer, StdHeader);
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ S3NBPtr = (S3_MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ ASSERT(FALSE) ; // No match for heap status, but could not locate "AMD_MEM_S3_NB_HANDLE" in heap for S3GetMsr
+ return AGESA_FATAL;
+ }
+ AGESA_TESTPOINT (TpIfAfterLocateS3CPciBuffer, StdHeader);
+
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ RetVal = S3NBPtr[Device->Node].MemS3GetDeviceRegLst (Device->RegisterListID, &RegisterHeader);
+ *RegisterHdr = (CPCI_REGISTER_BLOCK_HEADER *)RegisterHeader;
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function returns the MSR device register list according to the register
+ * list ID.
+ *
+ * @param[in] *Device - pointer to the MSR_DEVICE_DESCRIPTOR
+ * @param[out] **RegisterHdr - pointer to the address of the register list
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemFS3GetMsrDeviceRegisterList (
+ IN MSR_DEVICE_DESCRIPTOR *Device,
+ OUT MSR_REGISTER_BLOCK_HEADER **RegisterHdr,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ VOID *RegisterHeader;
+ LOCATE_HEAP_PTR LocHeap;
+ AGESA_BUFFER_PARAMS LocBufferParams;
+
+ LibAmdMemCopy (&LocBufferParams.StdHeader, StdHeader, sizeof (AMD_CONFIG_PARAMS), StdHeader);
+ LocHeap.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+ LocBufferParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+
+ AGESA_TESTPOINT (TpIfBeforeLocateS3MsrBuffer, StdHeader);
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ S3NBPtr = (S3_MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ ASSERT(FALSE) ; // No match for heap status, but could not locate "AMD_MEM_S3_NB_HANDLE" in heap for S3GetMsr
+ return AGESA_FATAL;
+ }
+ AGESA_TESTPOINT (TpIfAfterLocateS3MsrBuffer, StdHeader);
+
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ RetVal = S3NBPtr[BSP_DIE].MemS3GetDeviceRegLst (Device->RegisterListID, &RegisterHeader);
+ *RegisterHdr = (MSR_REGISTER_BLOCK_HEADER *)RegisterHeader;
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function returns the conditional MSR device register list according
+ * to the register list ID.
+ *
+ * @param[in] *Device - pointer to the CONDITIONAL_PCI_DEVICE_DESCRIPTOR
+ * @param[out] **RegisterHdr - pointer to the address of the register list
+ * @param[in] *StdHeader - Config handle for library and services
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemFS3GetCMsrDeviceRegisterList (
+ IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
+ OUT CMSR_REGISTER_BLOCK_HEADER **RegisterHdr,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ AGESA_STATUS RetVal;
+ S3_MEM_NB_BLOCK *S3NBPtr;
+ VOID *RegisterHeader;
+ LOCATE_HEAP_PTR LocHeap;
+ AGESA_BUFFER_PARAMS LocBufferParams;
+
+ LibAmdMemCopy (&LocBufferParams.StdHeader, StdHeader, sizeof (AMD_CONFIG_PARAMS), StdHeader);
+ LocHeap.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+ LocBufferParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+
+
+ AGESA_TESTPOINT (TpIfBeforeLocateS3CMsrBuffer, StdHeader);
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ S3NBPtr = (S3_MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ ASSERT(FALSE) ; // No match for heap status, but could not locate "AMD_MEM_S3_NB_HANDLE" in heap for S3GetMsr
+ return AGESA_FATAL;
+ }
+ AGESA_TESTPOINT (TpIfAfterLocateS3CMsrBuffer, StdHeader);
+
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ RetVal = S3NBPtr[BSP_DIE].MemS3GetDeviceRegLst (Device->RegisterListID, &RegisterHeader);
+ *RegisterHdr = (CMSR_REGISTER_BLOCK_HEADER *)RegisterHeader;
+ return RetVal;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function initialize needed data structures for S3 resume.
+ *
+ * @param[in, out] **S3NBPtr - Pointer to the pointer of northbridge block.
+ * @param[in, out] *MemPtr - Pointer to MEM_DATA_STRUCT.
+ * @param[in, out] *mmData - Pointer to MEM_MAIN_DATA_BLOCK.
+ * @param[in] *StdHeader - Config handle for library and services.
+ *
+ * @return AGESA_STATUS
+ * - AGESA_ALERT
+ * - AGESA_FATAL
+ * - AGESA_SUCCESS
+ * - AGESA_WARNING
+ */
+AGESA_STATUS
+MemS3InitNB (
+ IN OUT S3_MEM_NB_BLOCK **S3NBPtr,
+ IN OUT MEM_DATA_STRUCT **MemPtr,
+ IN OUT MEM_MAIN_DATA_BLOCK *mmData,
+ IN AMD_CONFIG_PARAMS *StdHeader
+ )
+{
+ UINT8 i;
+ AGESA_STATUS RetVal;
+ LOCATE_HEAP_PTR LocHeap;
+ MEM_NB_BLOCK *NBPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ UINT8 Die;
+ UINT8 DieCount;
+ BOOLEAN SkipScan;
+ CPU_SPECIFIC_SERVICES *FamilySpecificServices;
+
+ SkipScan = FALSE;
+ LocHeap.BufferHandle = AMD_MEM_DATA_HANDLE;
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ *MemPtr = (MEM_DATA_STRUCT *)LocHeap.BufferPtr;
+ SkipScan = TRUE;
+ } else {
+ AllocHeapParams.RequestedBufferSize = sizeof (MEM_DATA_STRUCT);
+ AllocHeapParams.BufferHandle = AMD_MEM_DATA_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) != AGESA_SUCCESS) {
+ ASSERT(FALSE); // Allocate failed for MEM_DATA_STRUCT
+ return AGESA_FATAL;
+ }
+ *MemPtr = (MEM_DATA_STRUCT *)AllocHeapParams.BufferPtr;
+ LibAmdMemCopy (&(*MemPtr)->StdHeader, StdHeader, sizeof (AMD_CONFIG_PARAMS), StdHeader);
+
+ GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &(*MemPtr)->StdHeader);
+ FamilySpecificServices->GetTscRate (FamilySpecificServices, &(*MemPtr)->TscRate, &(*MemPtr)->StdHeader);
+
+ }
+ mmData->MemPtr = *MemPtr;
+
+ if (!SkipScan) {
+ RetVal = MemSocketScan (mmData);
+ if (RetVal == AGESA_FATAL) {
+ return RetVal;
+ }
+ } else {
+ // We already have initialize data block, no need to do it again.
+ mmData->DieCount = mmData->MemPtr->DieCount;
+ }
+ DieCount = mmData->DieCount;
+
+ //---------------------------------------------
+ // Creation of NB Block for S3 resume
+ //---------------------------------------------
+ // Search for AMD_MEM_AUTO_HANDLE on the heap first.
+ // Only apply for space on the heap if cannot find AMD_MEM_AUTO_HANDLE on the heap.
+ LocHeap.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ *S3NBPtr = (S3_MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (S3_MEM_NB_BLOCK)));
+ AllocHeapParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) != AGESA_SUCCESS) {
+ ASSERT(FALSE); // Could not allocate space for "S3_MEM_NB_BLOCK"
+ return AGESA_FATAL;
+ }
+ *S3NBPtr = (S3_MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
+
+ LocHeap.BufferHandle = AMD_MEM_AUTO_HANDLE;
+ if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
+ // NB block has already been constructed by main block.
+ // No need to construct it here.
+ NBPtr = (MEM_NB_BLOCK *)LocHeap.BufferPtr;
+ } else {
+ AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK)));
+ AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) != AGESA_SUCCESS) {
+ ASSERT(FALSE); // Allocate failed for "MEM_NB_BLOCK"
+ return AGESA_FATAL;
+ }
+ NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
+ }
+ // Construct each die.
+ for (Die = 0; Die < DieCount; Die ++) {
+ i = 0;
+ ((*S3NBPtr)[Die]).NBPtr = &NBPtr[Die];
+ while (memNBInstalled[i].MemS3ResumeConstructNBBlock != 0) {
+ if (memNBInstalled[i].MemS3ResumeConstructNBBlock ((VOID *)&((*S3NBPtr)[Die]), *MemPtr, Die)) {
+ break;
+ }
+ i++;
+ };
+ if (memNBInstalled[i].MemS3ResumeConstructNBBlock == 0) {
+ ASSERT(FALSE); // S3 resume NB constructor not found
+ return AGESA_FATAL;
+ }
+ }
+ }
+ return AGESA_SUCCESS;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Waits specified number of 10ns cycles
+ * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
+ * @param[in] Count - Number of 10ns cycles to wait
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+VOID
+MemFS3Wait10ns (
+ IN UINT32 Count,
+ IN OUT MEM_DATA_STRUCT *MemPtr
+ )
+{
+ UINT64 TargetTsc;
+ UINT64 CurrentTsc;
+
+ ASSERT (Count <= 1000000);
+
+ LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
+ TargetTsc = CurrentTsc + ((Count * MemPtr->TscRate + 99) / 100);
+ do {
+ LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
+ } while (CurrentTsc < TargetTsc);
+}
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/TABLE/mftds.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/TABLE/mftds.c
new file mode 100644
index 0000000000..accc96b0ec
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/TABLE/mftds.c
@@ -0,0 +1,401 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mftds.c
+ *
+ * Northbridge table drive support file for DR
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Feat/TABLE)
+ * @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.
+ * ***************************************************************************
+ *
+ */
+
+
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "mftds.h"
+#include "Ids.h"
+#include "OptionMemory.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_TABLE_MFTDS_FILECODE
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+#define MAX_BYTELANES_PER_CHANNEL (8 + 1) ///< Max Bytelanes per channel
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+SetTableValues (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_TABLE_ALIAS MTPtr
+ );
+
+VOID
+SetTableValuesLoop (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_TABLE_ALIAS *MTPtr,
+ IN UINT8 time
+ );
+
+/*-----------------------------------------------------------------------------
+ *
+ * This function initializes bit field translation table
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_TABLE_ALIAS structure
+ * @param[in] time - Indicate the timing for the register which is written.
+ *
+ * @return None
+ * ----------------------------------------------------------------------------
+ */
+VOID
+MemFInitTableDrive (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN UINT8 time
+ )
+{
+ MEM_TABLE_ALIAS *MTPtr;
+ MEM_TABLE_ALIAS *IdsMTPtr;
+
+ ASSERT (NBPtr != NULL);
+ IdsMTPtr = NULL;
+ IDS_HDT_CONSOLE (MEM_FLOW, "MemFInitTableDrive [%X] Start\n", time);
+ MTPtr = (MEM_TABLE_ALIAS *) NBPtr->RefPtr->TableBasedAlterations;
+
+ IDS_SKIP_HOOK (IDS_GET_DRAM_TABLE, &IdsMTPtr, &(NBPtr->MemPtr->StdHeader)) {
+ IDS_OPTION_HOOK (IDS_INIT_DRAM_TABLE, NBPtr, &(NBPtr->MemPtr->StdHeader));
+ IDS_OPTION_HOOK (IDS_GET_DRAM_TABLE, &IdsMTPtr, &(NBPtr->MemPtr->StdHeader));
+ }
+
+ SetTableValuesLoop (NBPtr, MTPtr, time);
+ SetTableValuesLoop (NBPtr, IdsMTPtr, time);
+
+ IDS_OPTION_HOOK (IDS_MT_BASE + time, NBPtr, &(NBPtr->MemPtr->StdHeader));
+ IDS_HDT_CONSOLE (MEM_FLOW, "MemFInitTableDrive End\n");
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * This function initializes bit field translation table
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *MTPtr - Pointer to the MEM_TABLE_ALIAS structure
+ * @param[in] time - Indicate the timing for the register which is written.
+ *
+ * @return None
+ * ----------------------------------------------------------------------------
+ */
+VOID
+SetTableValuesLoop (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_TABLE_ALIAS *MTPtr,
+ IN UINT8 time
+ )
+{
+ UINT8 i;
+ UINT8 CurDct;
+
+ if (MTPtr != NULL) {
+ CurDct = NBPtr->Dct;
+ for (i = 0; MTPtr[i].time != MTEnd; i++) {
+ if ((MTPtr[i].attr != MTAuto) && (MTPtr[i].time == time)) {
+ SetTableValues (NBPtr, MTPtr[i]);
+ }
+ }
+ NBPtr->SwitchDCT (NBPtr, CurDct);
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * Engine for setting Table Value.
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in] MTPtr - Pointer to the MEM_TABLE_ALIAS structure
+ *
+ * @return None
+ * ----------------------------------------------------------------------------
+ */
+VOID
+SetTableValues (
+ IN OUT MEM_NB_BLOCK *NBPtr,
+ IN MEM_TABLE_ALIAS MTPtr
+ )
+{
+ UINT8 AccessType;
+ UINT16 ByteLane;
+ UINT8 Dct;
+ UINT8 i;
+ UINT8 j;
+ UINT32 TempVal[36];
+ UINT32 Temp2Val[72];
+ UINT8 *DqsSavePtr;
+ UINT8 DqsOffset;
+ BOOLEAN SaveDqs;
+
+ AccessType = 0;
+ DqsSavePtr = NULL;
+ SaveDqs = TRUE;
+
+ ASSERT (MTPtr.time <= MTValidTimePointLimit);
+ ASSERT (MTPtr.attr <= MTOr);
+ ASSERT (MTPtr.node <= MTNodes);
+ ASSERT (MTPtr.dct <= MTDcts);
+ ASSERT (MTPtr.dimm <= MTDIMMs);
+ ASSERT (MTPtr.data.s.bytelane <= MTBLs);
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ if ((MTPtr.dct == MTDcts) || (MTPtr.dct == Dct)) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ switch (MTPtr.bfindex) {
+ case BFRcvEnDly:
+ AccessType = AccessRcvEnDly;
+ DqsSavePtr = NULL;
+ break;
+ case BFWrDatDly:
+ AccessType = AccessWrDatDly;
+ DqsSavePtr = NBPtr->ChannelPtr->WrDatDlys;
+ break;
+ case BFRdDqsDly:
+ AccessType = AccessRdDqsDly;
+ DqsSavePtr = NBPtr->ChannelPtr->RdDqsDlys;
+ break;
+ case BFWrDqsDly:
+ AccessType = AccessWrDqsDly;
+ DqsSavePtr = NBPtr->ChannelPtr->WrDqsDlys;
+ break;
+ case BFRdDqs2dDly:
+ AccessType = AccessRdDqs2dDly;
+ DqsSavePtr = NBPtr->ChannelPtr->RdDqs2dDlys;
+ break;
+ case BFPhRecDly:
+ AccessType = AccessPhRecDly;
+ SaveDqs = FALSE;
+ break;
+ default:
+ AccessType = 0xFF;
+ break;
+ }
+ if (AccessType == 0xFF) {
+ if (MTPtr.attr == MTOverride) {
+ NBPtr->SetBitField (NBPtr, MTPtr.bfindex, MTPtr.data.s.value);
+ }
+ if (MTPtr.attr == MTSubtract) {
+ NBPtr->SetBitField (NBPtr, MTPtr.bfindex, NBPtr->GetBitField (NBPtr, MTPtr.bfindex) - MTPtr.data.s.value);
+ }
+ if (MTPtr.attr == MTAdd) {
+ NBPtr->SetBitField (NBPtr, MTPtr.bfindex, NBPtr->GetBitField (NBPtr, MTPtr.bfindex) + MTPtr.data.s.value);
+ }
+ if (MTPtr.attr == MTAnd) {
+ NBPtr->SetBitField (NBPtr, MTPtr.bfindex, (NBPtr->GetBitField (NBPtr, MTPtr.bfindex) & MTPtr.data.s.value));
+ }
+ if (MTPtr.attr == MTOr) {
+ NBPtr->SetBitField (NBPtr, MTPtr.bfindex, (NBPtr->GetBitField (NBPtr, MTPtr.bfindex) | MTPtr.data.s.value));
+ }
+ } else {
+ // Store the DQS data first
+ for (i = 0; i < NBPtr->CsPerChannel; i = i + NBPtr->CsPerDelay) {
+ if (AccessType == AccessRdDqs2dDly) {
+ for (j = 0; j < MAX_NUMBER_LANES; j++) {
+ Temp2Val[i * MAX_NUMBER_LANES + j] = NBPtr->GetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j));
+ }
+ } else {
+ for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
+ TempVal[i / NBPtr->CsPerDelay * MAX_BYTELANES_PER_CHANNEL + j] = NBPtr->GetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i / NBPtr->CsPerDelay, j));
+ }
+ }
+ }
+ //
+ // Single Value with Bytleane mask option
+ // Indicated by the vtype flag
+ //
+ if (MTPtr.vtype == VT_MSK_VALUE) {
+ // set the value which defined in Memory table.
+ for (i = 0; i < NBPtr->CsPerChannel; i = i + NBPtr->CsPerDelay) {
+ ByteLane = MTPtr.data.s.bytelane;
+ if ((MTPtr.dimm == MTDIMMs) || ((MTPtr.dimm * NBPtr->CsPerDelay) == i)) {
+ if (AccessType == AccessRdDqs2dDly) {
+ for (j = 0; j < MAX_NUMBER_LANES; j++) {
+ DqsOffset = (i * MAX_NUMBER_LANES + j);
+ if ((ByteLane & (UINT16)1) != 0) {
+ if (MTPtr.attr == MTOverride) {
+ Temp2Val[DqsOffset] = (UINT16)MTPtr.data.s.value;
+ }
+ if (MTPtr.attr == MTSubtract) {
+ Temp2Val[DqsOffset] -= (UINT16)MTPtr.data.s.value;
+ }
+ if (MTPtr.attr == MTAdd) {
+ Temp2Val[DqsOffset] += (UINT16)MTPtr.data.s.value;
+ }
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[DqsOffset]);
+ if (SaveDqs) {
+ if (DqsSavePtr == NULL) {
+ NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)Temp2Val[DqsOffset];
+ } else {
+ DqsSavePtr[DqsOffset] = (UINT8)Temp2Val[DqsOffset];
+ }
+ }
+ }
+ ByteLane = ByteLane >> (UINT16)1;
+ }
+ } else {
+ for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
+ DqsOffset = (i / NBPtr->CsPerDelay * MAX_BYTELANES_PER_CHANNEL + j);
+ if ((ByteLane & (UINT16)1) != 0) {
+ if (MTPtr.attr == MTOverride) {
+ TempVal[DqsOffset] = (UINT16)MTPtr.data.s.value;
+ }
+ if (MTPtr.attr == MTSubtract) {
+ TempVal[DqsOffset] -= (UINT16)MTPtr.data.s.value;
+ }
+ if (MTPtr.attr == MTAdd) {
+ TempVal[DqsOffset] += (UINT16)MTPtr.data.s.value;
+ }
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i / NBPtr->CsPerDelay, j), (UINT16)TempVal[DqsOffset]);
+ if (SaveDqs) {
+ if (DqsSavePtr == NULL) {
+ NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)TempVal[DqsOffset];
+ } else {
+ DqsSavePtr[DqsOffset] = (UINT8)TempVal[DqsOffset];
+ }
+ }
+ }
+ ByteLane = ByteLane >> (UINT16)1;
+ }
+ }
+ }
+ }
+ } else {
+ // Multiple values specified in a byte array
+ for (i = 0; i < NBPtr->CsPerChannel; i = i + NBPtr->CsPerDelay) {
+ if ((MTPtr.dimm == MTDIMMs) || ((MTPtr.dimm * NBPtr->CsPerDelay) == i)) {
+ if (AccessType == AccessRdDqs2dDly) {
+ for (j = 0; j < MAX_NUMBER_LANES; j++) {
+ DqsOffset = (i * MAX_NUMBER_LANES + j);
+ if (MTPtr.attr == MTOverride) {
+ Temp2Val[DqsOffset] = MTPtr.data.bytelanevalue[j];
+ }
+ if (MTPtr.attr == MTSubtract) {
+ Temp2Val[DqsOffset] -= MTPtr.data.bytelanevalue[j];
+ }
+ if (MTPtr.attr == MTAdd) {
+ Temp2Val[DqsOffset] += MTPtr.data.bytelanevalue[j];
+ }
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[DqsOffset]);
+ if (SaveDqs) {
+ if (DqsSavePtr == NULL) {
+ NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)Temp2Val[DqsOffset];
+ } else {
+ DqsSavePtr[DqsOffset] = (UINT8)Temp2Val[DqsOffset];
+ }
+ }
+ }
+ } else {
+ for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
+ DqsOffset = (i / NBPtr->CsPerDelay * MAX_BYTELANES_PER_CHANNEL + j);
+ if (MTPtr.attr == MTOverride) {
+ TempVal[DqsOffset] = MTPtr.data.bytelanevalue[j];
+ }
+ if (MTPtr.attr == MTSubtract) {
+ TempVal[DqsOffset] -= MTPtr.data.bytelanevalue[j];
+ }
+ if (MTPtr.attr == MTAdd) {
+ TempVal[DqsOffset] += MTPtr.data.bytelanevalue[j];
+ }
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i / NBPtr->CsPerDelay, j), (UINT16)TempVal[DqsOffset]);
+ if (SaveDqs) {
+ if (DqsSavePtr == NULL) {
+ NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)TempVal[DqsOffset];
+ } else {
+ DqsSavePtr[DqsOffset] = (UINT8)TempVal[DqsOffset];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // set the DQS value to left DIMMs.
+ i = MTPtr.dimm;
+ if (i != MTDIMMs) {
+ i = i * NBPtr->CsPerDelay + NBPtr->CsPerDelay;
+ while (i < NBPtr->CsPerChannel) {
+ if (AccessType == AccessRdDqs2dDly) {
+ for (j = 0; j < MAX_NUMBER_LANES; j++) {
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[i * MAX_BYTELANES_PER_CHANNEL + j]);
+ }
+ } else {
+ for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
+ NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i / NBPtr->CsPerDelay, j), (UINT16)TempVal[i / NBPtr->CsPerDelay * MAX_BYTELANES_PER_CHANNEL + j]);
+ }
+ }
+ i = i + NBPtr->CsPerDelay;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+