summaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3')
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c237
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h136
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c1102
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h127
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c170
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h92
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c297
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h89
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c493
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h98
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c1153
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h177
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c166
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c686
14 files changed, 5023 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c
new file mode 100644
index 0000000000..b1ab754103
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c
@@ -0,0 +1,237 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mt3.c
+ *
+ * Common Technology functions for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 36765 $ @e \$Date: 2010-08-25 23:06:36 +0800 (Wed, 25 Aug 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mt3.h"
+#include "mtspd3.h"
+#include "mtot3.h"
+#include "OptionMemory.h"
+#include "PlatformMemoryConfiguration.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+/* features */
+#define FILECODE PROC_MEM_TECH_DDR3_MT3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function Constructs the technology block
+ *
+ * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+BOOLEAN
+MemConstructTechBlock3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT MEM_NB_BLOCK *NBPtr
+ )
+{
+ TECHNOLOGY_TYPE *TechTypePtr;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 i;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ UINT8 DimmSlots;
+
+
+ TechTypePtr = (TECHNOLOGY_TYPE *) FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEM_TECH, NBPtr->MCTPtr->SocketId, 0);
+ if (TechTypePtr != NULL) {
+ // Ensure the platform override value is valid
+ ASSERT ((*TechTypePtr == DDR3_TECHNOLOGY) || (*TechTypePtr == DDR2_TECHNOLOGY));
+ if (*TechTypePtr != DDR3_TECHNOLOGY) {
+ return FALSE;
+ }
+ }
+
+ TechPtr->NBPtr = NBPtr;
+ TechPtr->RefPtr = NBPtr->RefPtr;
+ MCTPtr = NBPtr->MCTPtr;
+
+ TechPtr->SendAllMRCmds = MemTSendAllMRCmds3;
+ TechPtr->FreqChgCtrlWrd = FreqChgCtrlWrd3;
+ TechPtr->SetDramMode = MemTSetDramMode3;
+ TechPtr->DimmPresence = MemTDIMMPresence3;
+ TechPtr->SpdCalcWidth = MemTSPDCalcWidth3;
+ TechPtr->SpdGetTargetSpeed = MemTSPDGetTargetSpeed3;
+ TechPtr->AutoCycTiming = MemTAutoCycTiming3;
+ TechPtr->SpdSetBanks = MemTSPDSetBanks3;
+ TechPtr->SetDqsEccTmgs = MemTSetDQSEccTmgs;
+ TechPtr->GetCSIntLvAddr = MemTGetCSIntLvAddr3;
+ TechPtr->AdjustTwrwr = MemTAdjustTwrwr3;
+ TechPtr->AdjustTwrrd = MemTAdjustTwrrd3;
+ TechPtr->GetDimmSpdBuffer = MemTGetDimmSpdBuffer3;
+ TechPtr->GetLD = MemTGetLD3;
+ TechPtr->MaxFilterDly = 0;
+
+ //
+ // Map the Logical Dimms on this channel to the SPD that should be used for that logical DIMM.
+ // The pointers to the DIMM SPD information is as follows (2 Dimm/Ch and 3 Dimm/Ch examples).
+ //
+ // DIMM Spd Buffer Current Channel DimmSpdPtr[MAX_DIMMS_PER_CHANNEL] array
+ // (Number of dimms varies by platform) (Array size is determined in AGESA.H) Dimm operations loop
+ // on this array only)
+ // 2 DIMMS PER CHANNEL
+ //
+ // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0]
+ // Dimm 1 SR/DR DIMM <--------------DimmSpdPtr[1]
+ // DimmSpdPtr[2]------->NULL
+ // DimmSpdPtr[3]------->NULL
+ //
+ // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0]
+ // Dimm 1 QR DIMM <---------+----DimmSpdPtr[1]
+ // | DimmSpdPtr[2]------->NULL
+ // +----DimmSpdPtr[3]
+ //
+ // Socket N Channel N Dimm 0 QR DIMM <-----+--------DimmSpdPtr[0]
+ // Dimm 1 QR DIMM <-----|---+----DimmSpdPtr[1]
+ // +-- | ---DimmSpdPtr[2]
+ // +----DimmSpdPtr[3]
+ //
+ // 3 DIMMS PER CHANNEL
+ //
+ // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0]
+ // Dimm 1 SR/DR DIMM <--------------DimmSpdPtr[1]
+ // Dimm 3 SR/DR DIMM <--------------DimmSpdPtr[2]
+ // DimmSpdPtr[3]------->NULL
+ //
+ // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0]
+ // Dimm 1 QR DIMM <---------+----DimmSpdPtr[1]
+ // Dimm 3 SR/DR DIMM <-------- | ---DimmSpdPtr[2]
+ // +----DimmSpdPtr[3]
+ //
+ //
+ // FOR LRDIMMS
+ //
+ // This code will assign SPD pointers on the basis of Physical ranks, even though
+ // an LRDIMM may only use one or two logical ranks, that determination will have to
+ // be made from downstream code. An LRDIMM with greater than 2 Physical ranks will have
+ // its DimmSpdPtr[] mapped as if it were a QR in the above diagrams.
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ ChannelPtr->TechType = DDR3_TECHNOLOGY;
+ ChannelPtr->MCTPtr = MCTPtr;
+ ChannelPtr->DCTPtr = DCTPtr;
+
+ DimmSlots = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
+ MCTPtr->SocketId,
+ NBPtr->GetSocketRelativeChannel (NBPtr, Dct, Channel)
+ );
+ //
+ // Initialize the SPD pointers for each Dimm
+ //
+ for (i = 0 ; i < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0])) ; i++) {
+ ChannelPtr->DimmSpdPtr[i] = NULL;
+ }
+ for (i = 0 ; i < DimmSlots; i++) {
+ ChannelPtr->DimmSpdPtr[i] = &(ChannelPtr->SpdPtr[i]);
+ if ( (i + 2) < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0]))) {
+ if (ChannelPtr->DimmSpdPtr[i]->DimmPresent) {
+ if ((((ChannelPtr->DimmSpdPtr[i]->Data[SPD_RANKS] >> 3) & 0x07) + 1) > 2) {
+ ChannelPtr->DimmSpdPtr[i + 2] = &(ChannelPtr->SpdPtr[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+ // Initialize Common technology functions
+ MemTCommonTechInit (TechPtr);
+
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h
new file mode 100644
index 0000000000..6769da03ab
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h
@@ -0,0 +1,136 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mt3.h
+ *
+ * Common Technology
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MT3_H_
+#define _MT3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemConstructTechBlock3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+BOOLEAN
+MemTSetDramMode3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTDIMMPresence3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDCalcWidth3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDGetTargetSpeed3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTAutoCycTiming3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDSetBanks3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTGetCSIntLvAddr3 (
+ IN UINT8 BankEnc,
+ OUT UINT8 *LowBit,
+ OUT UINT8 *HiBit
+ );
+
+VOID
+MemTSendAllMRCmds3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel
+ );
+
+VOID
+FreqChgCtrlWrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+
+BOOLEAN
+MemTGetDimmSpdBuffer3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 **SpdBuffer,
+ IN UINT8 Dimm
+ );
+#endif /* _MT3_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c
new file mode 100644
index 0000000000..4775def8a2
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c
@@ -0,0 +1,1102 @@
+/**
+ * @file
+ *
+ * mtlrdimm3.c
+ *
+ * Technology initialization and control workd support for DDR3 LRDIMMS
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 23714 $ @e \$Date: 2009-12-09 17:28:37 -0600 (Wed, 09 Dec 2009) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mu.h"
+#include "mt.h"
+#include "mt3.h"
+#include "mtspd3.h"
+#include "mtrci3.h"
+#include "mtsdi3.h"
+#include "mtlrdimm3.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+#define FILECODE PROC_MEM_TECH_DDR3_MTLRDIMM3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+STATIC
+MemTSendMBCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Fn,
+ IN UINT8 Rcw,
+ IN UINT8 Value
+ );
+
+UINT8
+STATIC
+MemTGetSpecialMBCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Fn,
+ IN UINT8 Rc
+ );
+
+BOOLEAN
+STATIC
+MemTLrDimmControlRegInit3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+STATIC
+MemTLrDimmFreqChgCtrlWrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+STATIC
+MemTWLPrepareLrdimm3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *Wl
+ );
+
+BOOLEAN
+STATIC
+MemTSendAllMRCmdsLR3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *CsPtr
+ );
+
+VOID
+STATIC
+MemTEMRS1Lr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel,
+ IN UINT8 PhyRank
+ );
+
+VOID
+STATIC
+MemTEMRS2Lr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel
+ );
+
+
+BOOLEAN
+STATIC
+MemTLrdimmRankMultiplication (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *DimmID
+ );
+
+BOOLEAN
+STATIC
+MemTLrdimmBuf2DramTrain3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ );
+
+BOOLEAN
+STATIC
+MemTLrdimmSyncTrainedDlys (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initializes LRDIMM functions.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+BOOLEAN
+MemTLrdimmConstructor3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] = MemTSendAllMRCmdsLR3;
+ TechPtr->TechnologySpecificHook[LrdimmControlRegInit] = MemTLrDimmControlRegInit3;
+ TechPtr->TechnologySpecificHook[LrdimmFreqChgCtrlWrd] = MemTLrDimmFreqChgCtrlWrd3;
+ TechPtr->TechnologySpecificHook[WlTrainingPrepareLrdimm] = MemTWLPrepareLrdimm3;
+ TechPtr->TechnologySpecificHook[LrdimmRankMultiplication] = MemTLrdimmRankMultiplication;
+ TechPtr->TechnologySpecificHook[LrdimmBuf2DramTrain] = MemTLrdimmBuf2DramTrain3;
+ TechPtr->TechnologySpecificHook[LrdimmSyncTrainedDlys] = MemTLrdimmSyncTrainedDlys;
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends a Control word command to an LRDIMM Memory Buffer
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Fn - control word function
+ * @param[in] Rcw - control word number
+ * @param[in] Value - value to send
+ *
+ */
+
+VOID
+STATIC
+MemTSendMBCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Fn,
+ IN UINT8 Rcw,
+ IN UINT8 Value
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ ASSERT (Rcw != RCW_FN_SELECT); // RC7 can only be used for function select
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tF%dRC%d = %x\n", Fn, Rcw, Value);
+ //
+ // Select the MB Function by sending the Fn number
+ // to the Function Select Control Word
+ //
+ MemUWait10ns (800, NBPtr->MemPtr);
+ MemTSendCtlWord3 (TechPtr, RCW_FN_SELECT, Fn);
+ //
+ // Send the value to the control word
+ //
+ MemUWait10ns (800, NBPtr->MemPtr);
+ MemTSendCtlWord3 (TechPtr, Rcw, Value);
+
+
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function gets the value of special RCW
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dimm - Physical LR DIMM number
+ * @param[in] Fn - control word function
+ * @param[in] Rc - control word number
+ *
+ * @return Special RCW value
+ *
+ */
+
+UINT8
+STATIC
+MemTGetSpecialMBCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Fn,
+ IN UINT8 Rc
+ )
+{
+ CONST UINT8 F0RC13PhyRankTab[] = {3, 2, 0, 1, 0};
+ UINT8 PhyRanks;
+ UINT8 LogRanks;
+ UINT8 DramCap;
+ UINT8 Value8;
+ UINT8 *SpdBufferPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
+
+ Value8 = 0;
+ switch (Fn) {
+ case 0:
+ switch (Rc) {
+ case 8:
+ // F0RC8
+ Value8 = NBPtr->PsPtr->F0RC8;
+ break;
+ case 10:
+ // F0RC10
+ // 2:0 OperatingSpeed: operating speed. BIOS: Table 88.
+ if (NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) {
+ Value8 = 0;
+ } else {
+ Value8 = (UINT8) (NBPtr->DCTPtr->Timings.Speed / 133) - 3;
+ }
+ break;
+ case 11:
+ // F0RC11
+ // 3:2 ParityCalculation: partiy calculation. BIOS: Table.
+ // 1:0 OperatingVoltage: operating voltage. BIOS: IF(VDDIO == 1.5) THEN 00b ELSEIF (VDDIO ==
+ // 1.35) THEN 01b ELSE 10b ENDIF.
+ DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF;
+ if ((NBPtr->ChannelPtr->LrDimmRankMult[Dimm] + DramCap * 2) > 8) {
+ Value8 = 8;
+ } else {
+ Value8 = 4;
+ }
+ Value8 |= NBPtr->RefPtr->DDR3Voltage;
+ break;
+ case 13:
+ // F0RC13
+ // 3:2 NumLogicalRanks: partiy calculation. BIOS: Table 90.
+ // 1:0 NumPhysicalRanks: operating voltage. BIOS: Table 89.
+ LogRanks = NBPtr->ChannelPtr->LrDimmLogicalRanks[Dimm] >> 1;
+ PhyRanks = F0RC13PhyRankTab[(SpdBufferPtr[SPD_RANKS] >> 3) & 7];
+ Value8 = (LogRanks << 2) | PhyRanks;
+ break;
+ case 14:
+ // F0RC14
+ // 3 DramBusWidth: DRAM bus width. BIOS: IF (DeviceWidth==0) THEN 0 ELSE 1 ENDIF.
+ // 2 MRSCommandControl: MRS command control. BIOS: IF (F0RC15[RankMultiplicationControl]
+ // > 0) THEN 1 ELSE 0 ENDIF.
+ // 1 RefreshPrechargeCommandControl: refresh and precharge command control. BIOS: IF
+ // (F0RC15[RankMultiplicationControl] > 0) THEN D18F2xA8_dct[1:0][LrDimmEnhRefEn] ELSE 0 ENDIF.
+ // 0 AddressMirror: address mirror. BIOS: RankMap. See D18F2x[5C:40]_dct[1:0][OnDimmMirror].
+ if ((SpdBufferPtr[SPD_DEV_WIDTH] & 7) != 0) {
+ Value8 |= 8;
+ }
+ if (NBPtr->ChannelPtr->LrDimmRankMult[Dimm] > 1) {
+ Value8 |= 4;
+ if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 1) {
+ Value8 |= 2;
+ }
+ }
+ if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
+ Value8 |= 1;
+ }
+ break;
+ case 15:
+ // F0RC15
+ // 3:0 RankMultiplicationControl: rank multiplication control. BIOS: Table 91.
+ DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF;
+ ASSERT ((DramCap >= 2) && (DramCap <= 4)); // BKDG only lists 1Gb, 2Gb, and 4Gb
+ switch (NBPtr->ChannelPtr->LrDimmRankMult[Dimm]) {
+ case 1:
+ Value8 = 0;
+ break;
+ case 2:
+ Value8 = DramCap - 1;
+ break;
+ case 4:
+ Value8 = DramCap + 3;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ break;
+ case 1:
+ switch (Rc) {
+ case 0:
+ // F1RC0
+ Value8 = NBPtr->PsPtr->F1RC0;
+ Value8 |= (UINT8) NBPtr->GetBitField (NBPtr, BFCSTimingMux67) << 3;
+ break;
+ case 1:
+ // F1RC1
+ Value8 = NBPtr->PsPtr->F1RC1;
+ break;
+ case 2:
+ // F1RC2
+ Value8 = NBPtr->PsPtr->F1RC2;
+ break;
+ case 9:
+ // F1RC9
+ if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 0) {
+ Value8 = 1;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ break;
+ case 3:
+ switch (Rc) {
+ case 0:
+ // F3RC0
+ // 3 TDQSControl: TDQS control. BIOS: 0.
+ // 2:0 RttNom: RttNom. BIOS: Table 57, Table 60
+ Value8 = NBPtr->PsPtr->RttNom[Dimm << 1];
+ break;
+ case 1:
+ // F3RC1
+ // 3 Vref: Vref. BIOS: 0.
+ // 2:0 RttWr: RttWr. BIOS: Table 57, Table 60.
+ Value8 = NBPtr->PsPtr->RttWr[Dimm << 1];
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return Value8;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends LRDIMM Control Words to all LRDIMMS
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] OptParam - Optional parameter
+ *
+ * @return TRUE
+ */
+
+BOOLEAN
+STATIC
+MemTLrDimmControlRegInit3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ CONST UINT8 RCWInitTable[] = {
+ // RCW, Mask, SPD
+ F0, RC0, 0x00, SPD_NONE,
+ F0, RC1, 0x00, SPD_NONE,
+ F0, RC2, 0x03, SPD_67,
+ F0, RC10, 0x00, SPECIAL_CASE,
+ F0, RC11, 0x00, SPECIAL_CASE,
+
+ F1, RC8, 0x0F, SPD_69,
+ F1, RC11, 0xF0, SPD_69,
+ F1, RC12, 0x0F, SPD_70,
+ F1, RC13, 0xF0, SPD_70,
+ F1, RC14, 0x0F, SPD_71,
+ F1, RC15, 0xF0, SPD_71,
+
+ WAIT_6US, 0, 0, 0,
+
+ F0, RC3, 0xF0, SPD_67,
+ F0, RC4, 0x0F, SPD_68,
+ F0, RC5, 0xF0, SPD_68,
+
+ F0, RC6, 0x00, SPD_NONE,
+ F0, RC8, 0x00, SPECIAL_CASE,
+ F0, RC9, 0x0C, SPD_NONE,
+ F0, RC13, 0x00, SPECIAL_CASE,
+ F0, RC14, 0x00, SPECIAL_CASE,
+ F0, RC15, 0x00, SPECIAL_CASE,
+
+ F1, RC0, 0x00, SPECIAL_CASE,
+ F1, RC1, 0x00, SPECIAL_CASE,
+ F1, RC2, 0x00, SPECIAL_CASE,
+ F1, RC3, 0x00, SPD_NONE,
+ F1, RC9, 0x00, SPECIAL_CASE,
+ F1, RC10, 0x00, SPD_NONE,
+
+ F2, RC0, 0x00, SPD_NONE,
+ F2, RC1, 0x00, SPD_NONE,
+ F2, RC2, 0x0F, SPD_NONE,
+ F2, RC3, 0x00, SPD_NONE,
+
+ F3, RC0, 0x00, SPECIAL_CASE,
+ F3, RC1, 0x00, SPECIAL_CASE,
+ F3, RC2, 0x01, SPD_NONE,
+ F3, RC6, 0x08, SPD_NONE
+
+ // F3 RC[8,9] are programmed in MDQ RC loop
+
+ // F[10:3] RC[11,10] are programmed in QxODT RC loop
+
+ // F[15,14] RC[15:0] are programmed in personality RC loop
+ };
+
+ UINT8 Dimm;
+ UINT16 i;
+ UINT16 DimmMask;
+ UINT8 Fn;
+ UINT8 Rc;
+ UINT8 Mask;
+ UINT8 Spd;
+ UINT8 *SpdBufferPtr;
+ UINT8 FreqDiffOffset;
+ UINT8 Value8;
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ DimmMask = (UINT16)1 << Dimm;
+ if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSending LRDIMM Control Words: Dimm %02x\n", Dimm);
+ //
+ // Select the Target Chipselects
+ //
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
+ NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
+
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
+ for (i = 0; i < sizeof (RCWInitTable) ; i += 4) {
+ Fn = RCWInitTable[i];
+ Rc = RCWInitTable[i + 1];
+ Mask = RCWInitTable[i + 2];
+ Spd = RCWInitTable[i + 3];
+
+ if (Fn == WAIT_6US) {
+ MemUWait10ns (600, MemPtr); // wait 6us for TSTAB
+ } else {
+ if (Spd == SPD_NONE) {
+ Value8 = Mask;
+ } else if (Spd == SPECIAL_CASE) {
+ Value8 = MemTGetSpecialMBCtlWord3 (TechPtr, Dimm, Fn, Rc);
+ } else {
+ Value8 = (Mask > 0x0F) ? ((SpdBufferPtr[Spd] & Mask) >> 4) : (SpdBufferPtr[Spd] & Mask);
+ }
+ MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8);
+ }
+ }
+
+ FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
+ //
+ // Send RCW to program MDQ termination and drive strength
+ //
+ for (Rc = 8; Rc <= 9; Rc++) {
+ Value8 = SpdBufferPtr[SPD_MDQ_800_1066 + FreqDiffOffset];
+ Value8 = (Rc == 9) ? (Value8 >> 4) : Value8;
+ MemTSendMBCtlWord3 (TechPtr, 3, Rc, Value8 & 0x07);
+ }
+
+ //
+ // Send RCW to program QxODT
+ //
+ for (Fn = 3; Fn <= 10; Fn ++) {
+ for (Rc = 10; Rc <= 11; Rc++) {
+ Value8 = SpdBufferPtr[SPD_QXODT_800_1066 + FreqDiffOffset + ((Fn - 3) >> 1)];
+ Value8 = (Rc == 11) ? (Value8 >> 4) : (Value8 & 0x0F);
+ Value8 = ((Fn & 1) == 0) ? (Value8 >> 2) : (Value8 & 0x03);
+ MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8);
+ }
+ }
+
+ //
+ // Send Personality bytes from SPD
+ //
+ for (Fn = 14; Fn < 16; Fn ++) {
+ for (Rc = 0; Rc < 16 ; Rc++) {
+ Value8 = SpdBufferPtr[SPD_PERSONALITY_BYTE + ((Fn - 14) << 3) + (Rc >> 1)];
+ if ((Fn == 14) && (Rc == 0)) {
+ Value8 |= 0x01; // Write global enable
+ }
+ if (Rc != 0x07) {
+ MemTSendMBCtlWord3 (TechPtr, Fn, Rc, ((Rc & 1) != 0) ? (Value8 >> 4) : (Value8 & 0x0F));
+ }
+ }
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends LRDIMM Control Words to all LRDIMMS
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] OptParam - Optional parameter
+ *
+ * @return FALSE - The current channel does not have LRDIMM populated
+ * TRUE - The current channel has LRDIMM populated
+ */
+
+BOOLEAN
+STATIC
+MemTLrDimmFreqChgCtrlWrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ UINT8 Dct;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ MemNSwitchDCTNb (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ MemTLrDimmControlRegInit3 (TechPtr, NULL);
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ *
+ * This function prepares LRDIMMs for WL training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *Wl - Indicates if WL mode should be enabled
+ *
+ * @return TRUE - LRDIMMs present
+ * ----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemTWLPrepareLrdimm3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *Wl
+ )
+{
+ UINT8 Dimm;
+ UINT8 Value8;
+ UINT16 MrsAddress;
+ MEM_NB_BLOCK *NBPtr;
+ NBPtr = TechPtr->NBPtr;
+ MrsAddress = 0;
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if (*(BOOLEAN *) Wl == TRUE) {
+ // Program WrLvOdt
+ NBPtr->SetBitField (NBPtr, BFWrLvOdt, NBPtr->ChannelPtr->PhyWLODT[Dimm]);
+ }
+ if ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0) {
+ if (Dimm == TechPtr->TargetDIMM) {
+ if (*(BOOLEAN *) Wl == TRUE) {
+ //
+ // Select the Target Chipselects
+ //
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
+ NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
+
+ // Program F0RC12 to 1h
+ MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x01);
+ if (NBPtr->ChannelPtr->Dimms >= 2) {
+ // For two or more LRDIMMs per channel program the buffer RttNom to the
+ // corresponding specifed RttWr termination
+ Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, Dimm << 2);
+ } else {
+ // Program RttNom as normal
+ Value8 = NBPtr->MemNGetDramTerm (NBPtr, Dimm << 2);
+ }
+ if ((Value8 & ((UINT8) 1 << 2)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 9);
+ }
+ if ((Value8 & ((UINT8) 1 << 1)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 6);
+ }
+ if ((Value8 & ((UINT8) 1 << 0)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 2);
+ }
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
+ } else {
+ // Program F0RC12 to 0h
+ MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x00);
+ }
+ }
+ }
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This send all MR commands to all physical ranks of an LRDIMM
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *CsPtr - Target Chip Select
+ *
+ * @return FALSE - The current channel does not have LRDIMM populated
+ * TRUE - The current channel has LRDIMM populated
+ */
+
+BOOLEAN
+STATIC
+MemTSendAllMRCmdsLR3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *CsPtr
+ )
+{
+ UINT8 *SpdBufferPtr;
+ BOOLEAN Skip;
+ UINT8 Rank;
+ UINT8 PhyRank;
+ UINT8 ChipSel;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChipSel = *((UINT8 *) CsPtr);
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ //
+ // LRDIMM: MR0, MR2, and MR3 can be broadcasted.
+ // MR1[Rtt_Nom] needs to be programmed differently per physical ranks.
+ //
+ // CS 0 1 2 3 4 5 6 7
+ // MR[0,2,3] x x ?
+ // MR1 x x x x x x x x
+ //
+ // ? If 3 DIMMs/ch, need to send to CS4 since it is on the 3rd physical DIMM.
+ //
+ Skip = TRUE;
+ switch (ChipSel) {
+ case 0:
+ case 2:
+ Skip = FALSE;
+ break;
+ case 4:
+ if (GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
+ NBPtr->MCTPtr->SocketId,
+ NBPtr->ChannelPtr->ChannelID) == 3) {
+ Skip = FALSE;
+ }
+ break;
+ }
+
+ // Select target chip select
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
+
+ if (!Skip) {
+ // 13.Send EMRS(2)
+ MemTEMRS2Lr3 (TechPtr, ChipSel);
+ NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
+ NBPtr->SendMrsCmd (NBPtr);
+
+ // 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b
+ MemTEMRS33 (TechPtr);
+ NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
+ NBPtr->SendMrsCmd (NBPtr);
+ }
+
+ // 15.Send EMRS(1). Send to each physical rank.
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
+ for (Rank = 0; Rank < NBPtr->ChannelPtr->LrDimmRankMult[ChipSel >> 1]; Rank++) {
+ PhyRank = (((ChipSel >> 1) & 2) | (ChipSel & 1)) + (Rank * NBPtr->ChannelPtr->LrDimmLogicalRanks[ChipSel >> 1]);
+ MemTEMRS1Lr3 (TechPtr, ChipSel, PhyRank);
+ // Set Address bit 14, 15, 16, or 17 to select physical rank according to the device size
+ NBPtr->SetBitField (NBPtr, BFMrsAddressHi, Rank << (SpdBufferPtr[SPD_DENSITY] & 0xF));
+ NBPtr->SendMrsCmd (NBPtr);
+ }
+
+ if (!Skip) {
+ // 16.Send MRS with MrsAddress[8]=1(reset the DLL)
+ MemTMRS3 (TechPtr);
+ NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
+ NBPtr->SendMrsCmd (NBPtr);
+ }
+
+ // If LRDIMM, return TRUE to skip sending regular MR commands.
+ return TRUE;
+ }
+ // If not LRDIMM, send regular MR commands.
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the EMRS1 value for an LRDIMM
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ChipSel - Chip select number
+ * @param[in] PhyRank - Physical rank number
+ */
+
+VOID
+STATIC
+MemTEMRS1Lr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel,
+ IN UINT8 PhyRank
+ )
+{
+ UINT16 MrsAddress;
+ UINT8 Value8;
+ UINT8 *SpdBufferPtr;
+ UINT8 FreqDiffOffset;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
+ FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
+
+ // BA2=0,BA1=0,BA0=1
+ NBPtr->SetBitField (NBPtr, BFMrsBank, 1);
+
+ MrsAddress = 0;
+
+ // program MrsAddress[5,1]=output driver impedance control (DIC): 01b
+ MrsAddress |= ((UINT16) 1 << 1);
+
+ // program MrsAddress[5,1]=output driver impedance control (DIC):
+ // DIC is read from SPD byte 77, 83, or 89 depending on DDR speed
+ Value8 = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] & 3;
+ if ((Value8 & ((UINT8) 1 << 1)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 5);
+ }
+ if ((Value8 & ((UINT8) 1 << 0)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 1);
+ }
+
+ // program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
+ // RttNom is read from SPD byte 77, 83, or 89 depending on DDR speed
+ if (PhyRank <= 1) {
+ Value8 = (SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 2) & 7;
+ if ((Value8 & ((UINT8) 1 << 2)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 9);
+ }
+ if ((Value8 & ((UINT8) 1 << 1)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 6);
+ }
+ if ((Value8 & ((UINT8) 1 << 0)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 2);
+ }
+ }
+
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the EMRS2 value for an LRDIMM
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ChipSel - Chip select number
+ */
+
+VOID
+STATIC
+MemTEMRS2Lr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel
+ )
+{
+ UINT8 RttWr;
+ UINT8 *SpdBufferPtr;
+ UINT8 FreqDiffOffset;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ // Save default RttWr
+ RttWr = NBPtr->PsPtr->RttWr[ChipSel];
+
+ // Override RttWr with the value read from SPD byte 77, 83, or 89 depending on DDR speed
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
+ FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
+ NBPtr->PsPtr->RttWr[ChipSel] = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 6;
+
+ // Call EMRS2 calculation
+ MemTEMRS23 (TechPtr);
+
+ // Restore RttWr
+ NBPtr->PsPtr->RttWr[ChipSel] = RttWr;
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ *
+ * This function to determine the Rank Multiplication to use for an LRDIMM
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *DimmID - Dimm ID
+ *
+ * @return TRUE - LRDIMM Support is installed and LRDIMMs are present
+ * ----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemTLrdimmRankMultiplication (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *DimmID
+ )
+{
+ BOOLEAN RetVal;
+ UINT8 *SpdBufferPtr;
+ UINT8 Dimm;
+ UINT8 NumDimmslots;
+ UINT8 DramCapacity;
+ UINT8 Ranks;
+ UINT8 Rows;
+ UINT8 RankMult;
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (TechPtr != NULL);
+ ASSERT (DimmID != NULL);
+
+ Dimm = *(UINT8*)DimmID;
+ ASSERT (Dimm < MAX_DIMMS_PER_CHANNEL);
+
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = NBPtr->ChannelPtr;
+ RetVal = FALSE;
+ RankMult = 0;
+
+ if (!MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm)) {
+ ASSERT (FALSE);
+ }
+
+ NumDimmslots = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
+ NBPtr->MCTPtr->SocketId,
+ ChannelPtr->ChannelID);
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ RetVal = TRUE;
+ //
+ // Determine LRDIMM Rank Multiplication
+ //
+ Ranks = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
+ if (Ranks == 5) {
+ Ranks = 8;
+ }
+ DramCapacity = (SpdBufferPtr[SPD_DENSITY] & 0x0F);
+ Rows = 12 + (SpdBufferPtr[SPD_ROW_SZ] >> 3) & 0x7;
+
+ if (Ranks < 4) {
+ RankMult = 1;
+ } else if (Ranks == 4) {
+ RankMult = (NumDimmslots < 3) ? 1 : 2;
+ } else if (Ranks == 8) {
+ RankMult = ((NumDimmslots < 3) && (DramCapacity < 4)) ? 2 : 4;
+ }
+ //
+ // Save Rank Information
+ //
+ ChannelPtr->LrDimmRankMult[Dimm] = RankMult;
+ ChannelPtr->LrDimmLogicalRanks[Dimm] = Ranks / RankMult;
+ NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] = Rows + (RankMult >> 1);
+ //
+ // Program RankDef
+ //
+ NBPtr->SetBitField (NBPtr, BFRankDef0 + Dimm, (RankMult == 4) ? 3 : RankMult);
+ //
+ // If LrdimmRowAddressBits > 16, then we must be useing some CS signals for rank
+ // multiplication. If this is the case, then we want to clear the CSPresent bits
+ // that correspond to those chipselects.
+ // If there are 3 DIMMs per channel, then it will always be CS67, if there are
+ // 2DPCH, then DIMM0 will use CS45, adn DIMM1 will use CS67.
+ //
+ if (NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] > 16) {
+ NBPtr->DCTPtr->Timings.CsPresent &= ~(0x30 << ((NumDimmslots > 2) ? 1 : Dimm) );
+ }
+ }
+
+ return RetVal;
+
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function performs buffer to DRAM training for LRDIMMs
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] OptParam - Optional parameter
+ *
+ * @return TRUE
+ */
+
+BOOLEAN
+STATIC
+MemTLrdimmBuf2DramTrain3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ UINT8 Dct;
+ UINT8 Dimm;
+ UINT8 ChipSel;
+ UINT16 DimmMask;
+ UINT8 i;
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\nStart Buffer to DRAM training\n");
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+
+ //
+ // ODM needs to be set after Dram Init
+ //
+ if (NBPtr->StartupSpeed == NBPtr->DCTPtr->Timings.Speed) {
+ for (ChipSel = 1; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
+ if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
+ if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
+ NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel, ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel)) | ((UINT32)1 << BFOnDimmMirror )));
+ }
+ }
+ }
+ }
+
+ //
+ // Buffer to DRAM training
+ //
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ DimmMask = (UINT16)1 << Dimm;
+ if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\nDimm %d\n", Dimm);
+ // Select the Target Chipselects
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
+ NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
+
+ // Send F0RC12 with data = 0010b.
+ MemTSendMBCtlWord3 (TechPtr, F0, RC12, 2);
+
+ // Wait until D18F2xA0_dct[1:0][RcvParErr]=0 or tCAL * the number of physical ranks expires.
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tWaiting %d ms...\n", 10 * NBPtr->ChannelPtr->LrDimmRankMult[Dimm]);
+ for (i = 0; i < (NBPtr->ChannelPtr->LrdimmPhysicalRanks[Dimm] * 10); i++) {
+ MemUWait10ns (1000000, MemPtr);
+ }
+
+ // Configure for normal operation: Send F0RC12 with data = 0000b.
+ MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0);
+ }
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\nEnd Buffer to DRAM training\n");
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function copies trained delays of the first rank of a QR LRDIMM to the third rank
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] OptParam - Optional parameter
+ *
+ * @return TRUE
+ */
+
+BOOLEAN
+STATIC
+MemTLrdimmSyncTrainedDlys (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = NBPtr->ChannelPtr;
+
+ if (NBPtr->MCTPtr->Status[SbLrdimms]) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ for (i = 0; i < TechPtr->DlyTableWidth (); i++) {
+ if (ChannelPtr->LrDimmLogicalRanks[Dimm] > 2) {
+ // If logical QR LRDIMM, copy trained delays from first rank to third rank
+ NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i),
+ ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + i]);
+ NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm + 2, i),
+ ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i]);
+ NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i),
+ ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + i]);
+ NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i),
+ ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + i]);
+ }
+ }
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h
new file mode 100644
index 0000000000..ebbec4782a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h
@@ -0,0 +1,127 @@
+/**
+ * @file
+ *
+ * mtlrdimm3.h
+ *
+ * Definitions and declarations for DDR3 LRDIMM support
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @e \$Revision: 27045 $ @e \$Date: 2010-02-22 17:21:31 -0600 (Mon, 22 Feb 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MTLRDIMM3_H_
+#define _MTLRDIMM3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+#define RCW_FN_SELECT 7
+
+#define F0 0
+#define F1 1
+#define F2 2
+#define F3 3
+#define F4 4
+#define F5 5
+#define F6 6
+#define F7 7
+#define F8 8
+#define F9 9
+#define F10 10
+#define F11 11
+#define F12 12
+#define F13 13
+#define F14 14
+#define F15 15
+
+#define RC0 0
+#define RC1 1
+#define RC2 2
+#define RC3 3
+#define RC4 4
+#define RC5 5
+#define RC6 6
+#define RC7 7
+#define RC8 8
+#define RC9 9
+#define RC10 10
+#define RC11 11
+#define RC12 12
+#define RC13 13
+#define RC14 14
+#define RC15 15
+
+#define SPD_NONE 0
+#define SPD_67 67
+#define SPD_68 68
+#define SPD_69 69
+#define SPD_70 70
+#define SPD_71 71
+
+#define SPD_MDQ_800_1066 72
+#define SPD_QXODT_800_1066 73
+#define SPD_MR1_MR2_800_1066 77
+#define SPD_PERSONALITY_BYTE 150
+
+#define SPD_FREQ_DIFF_OFFSET 6
+
+#define SPECIAL_CASE 0xFF
+
+#define WAIT_6US 0xF6
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#endif /* _MTLRDIMM3_H_ */
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c
new file mode 100644
index 0000000000..2163ccf919
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c
@@ -0,0 +1,170 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtot3.c
+ *
+ * Technology Non-SPD Timings for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mtot3.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR3_MTOT3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function adjusts the Twrwr value for DDR3.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTAdjustTwrwr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ DCT_STRUCT *DCTPtr;
+
+ DCTPtr = TechPtr->NBPtr->DCTPtr;
+
+ // For DDR3, value 0000b-0001b and >= 1011b of Twrwr is reserved.
+ if (DCTPtr->Timings.Twrwr < 2) {
+ DCTPtr->Timings.Twrwr = 2;
+ } else if (DCTPtr->Timings.Twrwr > 10) {
+ DCTPtr->Timings.Twrwr = 10;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function adjusts the Twrrd value for DDR3.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTAdjustTwrrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ DCT_STRUCT *DCTPtr;
+
+ DCTPtr = TechPtr->NBPtr->DCTPtr;
+
+ // For DDR3, value 0000b, 0001b, and > 1010b of Twrrd is reserved.
+ if (DCTPtr->Timings.Twrrd < 2) {
+ DCTPtr->Timings.Twrrd = 2;
+ } else if (DCTPtr->Timings.Twrrd > 10) {
+ DCTPtr->Timings.Twrrd = 10;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function gets the LD value for DDR3.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return Value of LD
+ */
+
+INT8
+MemTGetLD3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ INT8 LD;
+ MEM_NB_BLOCK *NBPtr;
+ NBPtr = TechPtr->NBPtr;
+ //
+ // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
+ // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
+ // value.
+ //
+ LD = ((INT8) NBPtr->GetBitField (NBPtr, BFTcl) + 4) - ((INT8) NBPtr->GetBitField (NBPtr, BFTcwl) + 5);
+
+ return LD;
+}
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h
new file mode 100644
index 0000000000..8cdb9be480
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h
@@ -0,0 +1,92 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtot3.h
+ *
+ * Technology Non-SPD timings for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MTOT3_H_
+#define _MTOT3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+VOID
+MemTAdjustTwrwr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTAdjustTwrrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+INT8
+MemTGetLD3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+#endif /* _MTOT3_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c
new file mode 100644
index 0000000000..106f501948
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c
@@ -0,0 +1,297 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtrci3.c
+ *
+ * Technology Control word initialization for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mtrci3.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR3_MTRCI3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends control words
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTDramControlRegInit3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 ChipSel;
+ UINT8 i;
+ UINT8 RawCard;
+ UINT8 Data;
+ UINT16 CsPresent;
+
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
+
+ MemUWait10ns (800, MemPtr); // wait 8us TACT must be changed to optimize to 8 MEM CLKs
+
+ // Set EnDramInit to start DRAM initialization
+
+ MemUWait10ns (600, MemPtr); // wait 6us for PLL LOCK
+
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
+ //
+ // If chip select present
+ //
+ if ((CsPresent & ((UINT16)3 << ChipSel)) != 0) {
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
+
+ // 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects.
+ NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (ChipSel & 0xFE));
+
+ RawCard = NBPtr->ChannelPtr->RefRawCard[ChipSel >> 1];
+
+ for (i = 0; i <= 15; i++) {
+ // wait 8us for TMRD, must be changed to optimize to 8 MEM CLKs
+ MemUWait10ns (800, MemPtr);
+ if ((i != 6) && (i != 7)) {
+ Data = MemTGetCtlWord3 (TechPtr, i, RawCard, ChipSel);
+ MemTSendCtlWord3 (TechPtr, i, Data);
+ }
+ }
+ }
+ }
+ MemUWait10ns (600, MemPtr); // wait 6us for TSTAB
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the ControlRC value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] CtrlWordNum - control Word number.
+ * @param[in] RawCard - Raw Card
+ * @param[in] ChipSel - Target Chip Select
+ * @return Control Word value
+ */
+
+UINT8
+MemTGetCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 CtrlWordNum,
+ IN UINT8 RawCard,
+ IN UINT8 ChipSel
+ )
+{
+ UINT8 Data;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ DCTPtr = TechPtr->NBPtr->DCTPtr;
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ Data = 0; //Default value for all control words is 0
+ switch (CtrlWordNum) {
+ case 0:
+ Data = 0x02; // DA4=1
+ break;
+ case 1:
+ if (DCTPtr->Timings.DimmSRPresent & ((UINT16) 1 << (ChipSel >> 1))) {
+ Data = 0x0C; // if single rank, set DBA1 and DBA0
+ }
+ break;
+ case 2:
+ Data = ChannelPtr->CtrlWrd02[ChipSel >> 1];
+ break;
+ case 3:
+ Data = ChannelPtr->CtrlWrd03[ChipSel >> 1];
+ break;
+ case 4:
+ Data = ChannelPtr->CtrlWrd04[ChipSel >> 1];
+ break;
+ case 5:
+ Data = ChannelPtr->CtrlWrd05[ChipSel >> 1];
+ break;
+ case 8:
+ Data = ChannelPtr->CtrlWrd08[ChipSel >> 1];
+ break;
+ case 9:
+ Data = 0x0D;
+ break;
+ default:;
+ }
+
+ return (Data & 0x0F);
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends control word command
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] CmdNum - control number.
+ * @param[in] Value - value to send
+ *
+ */
+
+VOID
+MemTSendCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 CmdNum,
+ IN UINT8 Value
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ // 1. Program MrsBank and MrsAddress.
+ // n = [BA2, A2, A1, A0].
+ // data = [BA1, BA0, A4, A3].
+ // Set all other bits in MrsAddress to zero.
+ //
+ NBPtr->SetBitField (NBPtr, BFMrsBank, ((CmdNum & 8) >> 1) | (Value >> 2));
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, ((Value & 3) << 3) | (CmdNum & 7));
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d RC%02d %04x\n", (MemNGetBitFieldNb (NBPtr, BFMrsChipSel) & 7), CmdNum, Value);
+
+ // 2.Set SendCtrlWord=1
+ NBPtr->SetBitField (NBPtr, BFSendCtrlWord, 1);
+ // 3.Wait for BFSendCtrlWord=0
+ NBPtr->PollBitField (NBPtr, BFSendCtrlWord, 0, PCI_ACCESS_TIMEOUT, FALSE);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sends specific control words commands before frequency change for certain DRAM buffers.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+FreqChgCtrlWrd3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 ChipSel;
+ UINT16 Speed;
+ UINT16 CsPresent;
+
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ Speed = NBPtr->DCTPtr->Timings.Speed;
+ CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
+
+
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
+ //
+ // If chip select present.
+ //
+ if ((CsPresent & ((UINT16)3 << ChipSel)) != 0) {
+
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
+ // program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects.
+ NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (ChipSel & 0xFE));
+
+ //wait 8us for TMRD, must be changed to optimize to 8 MEM CLKs
+ MemUWait10ns (800, MemPtr);
+ if (Speed == DDR1066_FREQUENCY) {
+ MemTSendCtlWord3 (TechPtr, 0x0A, 1);
+ } else if (Speed == DDR1333_FREQUENCY) {
+ MemTSendCtlWord3 (TechPtr, 0x0A, 2);
+ } else if (Speed == DDR1600_FREQUENCY) {
+ MemTSendCtlWord3 (TechPtr, 0x0A, 3);
+ }
+ }
+ }
+}
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h
new file mode 100644
index 0000000000..d5fdfeec7f
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h
@@ -0,0 +1,89 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtrci3.h
+ *
+ * Technology control word init for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MTRCI3_H_
+#define _MTRCI3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+UINT8
+MemTGetCtlWord3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 CtrlWordNum,
+ IN UINT8 RawCard,
+ IN UINT8 ChipSel
+ );
+
+VOID
+MemTDramControlRegInit3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+#endif /* _MTRCI3_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c
new file mode 100644
index 0000000000..48dc007b10
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c
@@ -0,0 +1,493 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtsdi3.c
+ *
+ * Technology Software DRAM Init for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 37303 $ @e \$Date: 2010-09-02 03:43:36 +0800 (Thu, 02 Sep 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mt3.h"
+#include "mtsdi3.h"
+#include "mtrci3.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+#define FILECODE PROC_MEM_TECH_DDR3_MTSDI3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initiates software DRAM init for both DCTs
+ * at the same time.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+BOOLEAN
+MemTDramInitSw3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 ChipSel;
+ UINT32 Dummy;
+
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ MCTPtr = NBPtr->MCTPtr;
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Dram Init\n");
+ // 3.Program F2x[1,0]7C[EnDramInit]=1
+ IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
+ NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 1);
+ NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE);
+
+ // 4.wait 200us
+ MemUWait10ns (20000, MemPtr);
+
+ // 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1.
+ NBPtr->BrdcstSet (NBPtr, BFDeassertMemRstX, 1);
+
+ // 6.wait 500us
+ MemUWait10ns (50000, MemPtr);
+
+ // Do Phy Fence training before sending MRS commands
+ if (!NBPtr->IsSupported[FenceTrnBeforeDramInit]) {
+ AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->PhyFenceTraining (NBPtr);
+ }
+ }
+ }
+
+ // 7.NOP or deselect & take CKE high
+ NBPtr->BrdcstSet (NBPtr, BFAssertCke, 1);
+
+ // 8.wait 360ns
+ MemUWait10ns (36, MemPtr);
+
+ // The following steps are performed once for each channel with unbuffered DIMMs
+ // and once for each chip select on registered DIMMs:
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+
+ // Enable Dram Parity if appropriate.
+ NBPtr->FamilySpecificHook[EnableParityAfterMemRst] (NBPtr, NULL);
+
+ // The following steps are performed with registered DIMMs only and
+ // must be done for each chip select pair:
+ if (MCTPtr->Status[SbRegistered]) {
+ MemTDramControlRegInit3 (TechPtr);
+ }
+
+ // Initialize LRDIMM's register
+ TechPtr->TechnologySpecificHook[LrdimmControlRegInit] (TechPtr, NULL);
+
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
+ if (NBPtr->GetSysAddr (NBPtr, ChipSel, &Dummy)) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
+ // if chip select present
+ if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
+ MemTSendAllMRCmds3 (TechPtr, ChipSel);
+ }
+ // NOTE: wait 512 clocks for DLL-relock
+ MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
+ if (!(MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])) {
+ break;
+ }
+ }
+ }
+
+ // 17.Send two ZQCL commands (to even then odd chip select)
+ NBPtr->sendZQCmd (NBPtr);
+ NBPtr->sendZQCmd (NBPtr);
+ }
+ }
+
+ // 18.Program F2x[1,0]7C[EnDramInit]=0
+ NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 0);
+ NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE);
+ //
+ // For Unbuffered Dimms, Issue MRS for remaining CS without EnDramInit
+ //
+ NBPtr->FamilySpecificHook[SendMrsCmdsPerCs] (NBPtr, NBPtr);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "End Dram Init\n\n");
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the EMRS1 value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Wl - Indicates if WL mode should be enabled
+ * @param[in] TargetDIMM - DIMM target for WL
+ */
+
+VOID
+MemTEMRS13 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN BOOLEAN Wl,
+ IN UINT8 TargetDIMM
+ )
+{
+ UINT16 MrsAddress;
+ UINT8 MaxDimmPerCH;
+ UINT8 ChipSel;
+ UINT8 Value8;
+
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
+ NBPtr->MCTPtr->SocketId,
+ NBPtr->ChannelPtr->ChannelID);
+ ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel));
+
+ // BA2=0,BA1=0,BA0=1
+ NBPtr->SetBitField (NBPtr, BFMrsBank, 1);
+
+ MrsAddress = 0;
+
+ // program MrsAddress[5,1]=output driver impedance control (DIC):
+ // based on F2x[1,0]84[DrvImpCtrl]
+ if (!(NBPtr->IsSupported[CheckDrvImpCtrl])) {
+ Value8 = (UINT8)NBPtr->GetBitField (NBPtr, BFDrvImpCtrl);
+ if ((Value8 & ((UINT8) 1 << 1)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 5);
+ }
+ if ((Value8 & ((UINT8) 1 << 0)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 1);
+ }
+ } else {
+ MrsAddress |= ((UINT16) 1 << 1);
+ }
+ // program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
+ // Different CS may have different RTT.
+ //
+ Value8 = NBPtr->MemNGetDramTerm (NBPtr, ChipSel);
+
+ //
+ // If Write Leveling this DIMM
+ //
+ if (Wl) {
+ if ((ChipSel >> 1) == TargetDIMM) {
+ // Program MrsAddress[7] = 1 for Write leveling enable
+ MrsAddress |= ((UINT16) 1 << 7);
+ if (ChipSel & 1) {
+ // Output buffer disabled, MrsAddress[7] (Qoff = 1)
+ MrsAddress |= ((UINT16) 1 << 12);
+ }
+ // Set Rtt_Nom = Rtt_Wr if there are 2 or more dimms
+ if ((NBPtr->ChannelPtr->DimmQrPresent != 0) || (NBPtr->ChannelPtr->Dimms >= 2)) {
+ Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel);
+ }
+ }
+ }
+ //
+ // Turn off Rtt_Nom (DramTerm=0) for certain CS in certain configs.
+ //
+ // All odd CS for 4 Dimm Systems
+ if (MaxDimmPerCH == 4) {
+ if (ChipSel & 0x01) {
+ Value8 = 0;
+ }
+ // CS 1 and 5 for 3 Dimm configs
+ } else if (MaxDimmPerCH == 3) {
+ if ((ChipSel == 1) || (ChipSel == 5)) {
+ Value8 = 0;
+ }
+ }
+ // All odd CS of any QR Dimms
+ if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) {
+ if (ChipSel & 0x01) {
+ Value8 = 0;
+ }
+ }
+ if ((Value8 & ((UINT8) 1 << 2)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 9);
+ }
+ if ((Value8 & ((UINT8) 1 << 1)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 6);
+ }
+ if ((Value8 & ((UINT8) 1 << 0)) != 0) {
+ MrsAddress |= ((UINT16) 1 << 2);
+ }
+
+ // program MrsAddress[12]=output disable (QOFF):
+ // based on F2x[1,0]84[Qoff]
+
+ if (!NBPtr->IsSupported[CheckQoff]) {
+ if (NBPtr->GetBitField (NBPtr, BFQoff) != 0) {
+ MrsAddress |= ((UINT16) 1 << 12);
+ }
+ }
+
+ // program MrsAddress[11]=TDQS:
+ // based on F2x[1,0]94[RDqsEn]
+
+ if ((NBPtr->DCTPtr->Timings.Dimmx4Present != 0) && (NBPtr->DCTPtr->Timings.Dimmx8Present != 0)) {
+ MrsAddress |= ((UINT16) 1 << 11);
+ }
+
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the EMRS2 value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTEMRS23 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT32 MrsAddress;
+ UINT8 DramTermDyn;
+ UINT8 MaxDimmPerCH;
+ UINT8 ChipSel;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID );
+ ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel));
+
+ // BA2=0,BA1=1,BA0=0
+ NBPtr->SetBitField (NBPtr, BFMrsBank, 2);
+
+ // program MrsAddress[5:3]=CAS write latency (CWL):
+ MrsAddress = NBPtr->MemNGetMR2CWL (NBPtr);
+
+ // program MrsAddress[6]=auto self refresh method (ASR):
+ // program MrsAddress[7]=self refresh temperature range (SRT):
+ MrsAddress |= 1 << 6;
+ MrsAddress &= ( ~ (1 << 7));
+
+ // program MrsAddress[10:9]=dynamic termination during writes (RTT_WR):
+ DramTermDyn = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel);
+ // Special Case for 1 DR Unbuffered Dimm in 3 Dimm/Ch
+ if (!(NBPtr->MCTPtr->Status[SbRegistered])) {
+ if (MaxDimmPerCH == 3) {
+ if (NBPtr->ChannelPtr->Dimms == 1) {
+ if ((NBPtr->ChannelPtr->DimmDrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) {
+ DramTermDyn = 1;
+ }
+ }
+ }
+ }
+ MrsAddress |= (UINT16) DramTermDyn << 9;
+
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the EMRS3 value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTEMRS33 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ // BA2=0,BA1=1,BA0=1
+ NBPtr->SetBitField (NBPtr, BFMrsBank, 3);
+
+ // program MrsAddress[1:0]=multi purpose register address location
+ // (MPR Location):based on F2x[1,0]84[MprLoc]
+ // program MrsAddress[2]=multi purpose register
+ // (MPR):based on F2x[1,0]84[MprEn]
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, (NBPtr->GetBitField (NBPtr, BFDramMRSReg) >> 24) & 0x0007);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This sets MRS value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTMRS3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT32 MrsAddress;
+ MEM_NB_BLOCK *NBPtr;
+ UINT32 Ppd;
+
+ NBPtr = TechPtr->NBPtr;
+
+ // BA2=0,BA1=0,BA0=0
+ NBPtr->SetBitField (NBPtr, BFMrsBank, 0);
+
+ // program MrsAddress[1:0]=burst length and control method
+ // (BL):based on F2x[1,0]84[BurstCtrl]
+ MrsAddress = NBPtr->GetBitField (NBPtr, BFBurstCtrl);
+
+ // program MrsAddress[3]=1 (BT):interleaved
+ MrsAddress |= (UINT16) 1 << 3;
+
+ // program MrsAddress[6:4,2]=read CAS latency
+ MrsAddress |= NBPtr->MemNGetMR0CL (NBPtr);
+
+ // program MrsAddress[11:9]=write recovery for auto-precharge
+ MrsAddress |= NBPtr->MemNGetMR0WR (NBPtr);
+
+ // program MrsAddress[12] (PPD):based on F2x[1,0]84[PChgPDModeSel]
+ Ppd = NBPtr->GetBitField (NBPtr, BFPchgPDModeSel);
+ NBPtr->FamilySpecificHook[MR0_PPD] (NBPtr, &Ppd);
+ IDS_OPTION_HOOK (IDS_MEM_MR0, &Ppd, &TechPtr->NBPtr->MemPtr->StdHeader);
+ MrsAddress |= Ppd << 12;
+
+ // program MrsAddress[8]=1 (DLL):DLL reset
+ MrsAddress |= (UINT32) 1 << 8;
+
+ NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This send all MR commands to a rank in sequence 2-3-1-0
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ChipSel - Target Chip Select
+ */
+
+VOID
+MemTSendAllMRCmds3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
+
+ // 13.Send EMRS(2)
+ MemTEMRS23 (TechPtr);
+ NBPtr->SendMrsCmd (NBPtr);
+
+ // 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b
+ MemTEMRS33 (TechPtr);
+ NBPtr->SendMrsCmd (NBPtr);
+
+ // 15.Send EMRS(1).
+ MemTEMRS13 (TechPtr, FALSE, (ChipSel >> 1));
+ NBPtr->SendMrsCmd (NBPtr);
+
+ // 16.Send MRS with MrsAddress[8]=1(reset the DLL)
+ MemTMRS3 (TechPtr);
+ NBPtr->SendMrsCmd (NBPtr);
+}
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h
new file mode 100644
index 0000000000..5715a22d27
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h
@@ -0,0 +1,98 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtsdi3.h
+ *
+ * Technology software DRAM init for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 34985 $ @e \$Date: 2010-07-15 04:48:28 +0800 (Thu, 15 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MTSDI3_H_
+#define _MTSDI3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+MemTEMRS33 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTMRS3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTEMRS13 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN BOOLEAN Wl,
+ IN UINT8 TargetDIMM
+ );
+
+VOID
+MemTEMRS23 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+#endif /* _MTSDI3_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c
new file mode 100644
index 0000000000..c2f93724f8
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c
@@ -0,0 +1,1153 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtspd3.c
+ *
+ * Technology SPD supporting functions for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 36054 $ @e \$Date: 2010-08-10 05:26:12 +0800 (Tue, 10 Aug 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "Ids.h"
+#include "mport.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "mt3.h"
+#include "mu.h"
+#include "mtspd3.h"
+#include "mftds.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR3_MTSPD3_FILECODE
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemTCRCCheck3 (
+ IN OUT UINT8 *SPDPtr
+ );
+
+UINT8
+STATIC
+MemTSPDGetTCL3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+STATIC
+MemTCheckBankAddr3 (
+ IN UINT8 Encode,
+ OUT UINT8 *Index
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+extern BUILD_OPT_CFG UserOptions;
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the DRAM mode
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that the DRAM mode is set to DDR3
+ */
+
+BOOLEAN
+MemTSetDramMode3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
+ TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFDdr3Mode, 1);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that a FATAL error has not occurred
+ * @return FALSE - indicates that a FATAL error has occurred
+ */
+
+BOOLEAN
+MemTDIMMPresence3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 i;
+ MEM_PARAMETER_STRUCT *RefPtr;
+ UINT8 *SpdBufferPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_NB_BLOCK *NBPtr;
+ BOOLEAN SPDCtrl;
+ UINT8 Devwidth;
+ UINT8 MaxDimms;
+ UINT8 Value8;
+ UINT16 DimmMask;
+
+ NBPtr = TechPtr->NBPtr;
+ RefPtr = NBPtr->RefPtr;
+ MCTPtr = NBPtr->MCTPtr;
+
+ SPDCtrl = UserOptions.CfgIgnoreSpdChecksum;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ ChannelPtr->DimmQrPresent = 0;
+ //
+ // Get the maximum number of DIMMs
+ //
+ MaxDimms = MAX_DIMMS_PER_CHANNEL;
+ for (i = 0; i < MaxDimms; i++) {
+ // Bitmask representing dimm #i.
+ DimmMask = (UINT16)1 << i;
+ //
+ if (MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, i)) {
+ MCTPtr->DimmPresent |= DimmMask;
+ //
+ // Check for valid checksum value
+ //
+ AGESA_TESTPOINT (TpProcMemSPDChecking, &(NBPtr->MemPtr->StdHeader));
+ if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
+ ChannelPtr->ChDimmValid |= DimmMask;
+ MCTPtr->DimmValid |= DimmMask;
+ } else {
+ // Current socket is set up to only support DDR3 dimms.
+ IDS_ERROR_TRAP;
+ }
+ if (!MemTCRCCheck3 (SpdBufferPtr) && !SPDCtrl) {
+ //
+ // NV_SPDCHK_RESTRT is set to 0,
+ // cannot ignore faulty SPD checksum
+ //
+ // Indicate checksum error
+ ChannelPtr->DimmSpdCse |= DimmMask;
+ PutEventLog (AGESA_ERROR, MEM_ERROR_CHECKSUM_NV_SPDCHK_RESTRT_ERROR, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ }
+ //
+ // Check module type information.
+ //
+ if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_LRDIMM) {
+ //
+ // LRDIMMS
+ //
+ ChannelPtr->LrDimmPresent |= DimmMask;
+ MCTPtr->LrDimmPresent |= DimmMask;
+ if (!UserOptions.CfgMemoryLRDimmCapable) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_LRDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ IDS_ERROR_TRAP;
+ }
+ }
+ if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
+ //
+ // RDIMMS
+ //
+ ChannelPtr->RegDimmPresent |= DimmMask;
+ MCTPtr->RegDimmPresent |= DimmMask;
+ if (!UserOptions.CfgMemoryRDimmCapable) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_RDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ IDS_ERROR_TRAP;
+ }
+ }
+ if ((SpdBufferPtr[SPD_DIMM_TYPE] == JED_UDIMM) && !UserOptions.CfgMemoryUDimmCapable) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_UDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ IDS_ERROR_TRAP;
+ }
+ if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
+ ChannelPtr->SODimmPresent |= DimmMask;
+ if (!UserOptions.CfgMemorySODimmCapable) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_SODIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ IDS_ERROR_TRAP;
+ }
+ }
+ //
+ // Check error correction type
+ //
+ if ((SpdBufferPtr[SPD_ECCBITS] & JED_ECC) != 0) {
+ MCTPtr->DimmEccPresent |= DimmMask; // Dimm has ECC
+ }
+ //
+ // Get the Dimm width data
+ //
+ Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0x7;
+ switch (Devwidth) {
+ case 0:
+ ChannelPtr->Dimmx4Present |= DimmMask;
+ Devwidth = 4;
+ break;
+ case 1:
+ ChannelPtr->Dimmx8Present |= DimmMask;
+ Devwidth = 8;
+ break;
+ case 2:
+ ChannelPtr->Dimmx16Present |= DimmMask;
+ Devwidth = 16;
+ break;
+ default:
+ IDS_ERROR_TRAP;
+ }
+ //
+ // Check for 'analysis probe installed'
+ // if (SpdBufferPtr[SPD_ATTRIB] & JED_PROBE_MSK)
+ //
+ // Determine the geometry of the DIMM module
+ // if (SpdBufferPtr[SPD_DM_BANKS] & SP_DPL_BIT)
+ //
+ // specify the number of ranks
+ //
+ Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
+ if (Value8 == 5) {
+ // Octal Rank
+ Value8 = 8;
+ }
+ //
+ // For LRDIMMS we will assume that if there are at least 4 Physical ranks, then it Could be used
+ // as a QR RDIMM with a rank Mux of x1 and therefore all four CS will be used. So an 8R LRDIMM will
+ // be marked as a QR even if Rank multiplication allows it to use only 2 logical ranks.
+ //
+ if (ChannelPtr->LrDimmPresent |= DimmMask) {
+ //
+ // LRDIMM Physical Ranks
+ //
+ ChannelPtr->LrdimmPhysicalRanks[i] = Value8;
+ }
+ if (Value8 > 2) {
+ if (!UserOptions.CfgMemoryQuadRankCapable) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_QRDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ }
+ //
+ // Mark this Dimm as Quad Rank
+ //
+ ChannelPtr->DimmQrPresent |= DimmMask;
+ Value8 = 2;
+ } else if (Value8 == 2) {
+ ChannelPtr->DimmDrPresent |= DimmMask; // Dual rank dimms
+ } else {
+ ChannelPtr->DimmSRPresent |= DimmMask; // Single rank dimms
+ }
+ //
+ // Calculate bus loading per Channel
+ if (Devwidth == 16) {
+ Devwidth = 4;
+ } else if (Devwidth == 4) {
+ Devwidth = 16;
+ }
+ //
+ // Double Addr bus load value for dual rank DIMMs (Unless LRDIMM)
+ //
+ if ( ((ChannelPtr->LrDimmPresent |= DimmMask) == 0) && (Value8 == 2) ) {
+ Devwidth = Devwidth << 1;
+ }
+ //
+ ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
+ ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
+ if ((i < 2) || ((ChannelPtr->DimmQrPresent & DimmMask) == 0)) {
+ ChannelPtr->Dimms++;
+ }
+ //
+ // Check address mirror support for Unbuffered Dimms or LRDimms
+ //
+ if ((ChannelPtr->RegDimmPresent & DimmMask) == 0) {
+ if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
+ ChannelPtr->DimmMirrorPresent |= DimmMask;
+ }
+ }
+ //
+ // Get byte62: Reference Raw Card information
+ //
+ ChannelPtr->RefRawCard[i] = SpdBufferPtr[SPD_RAWCARD] & 0x1F;
+ //
+ // Get control word values for RC3, RC4 and RC5
+ //
+ ChannelPtr->CtrlWrd03[i] = SpdBufferPtr[SPD_CTLWRD03] >> 4;
+ ChannelPtr->CtrlWrd04[i] = SpdBufferPtr[SPD_CTLWRD04] & 0x0F;
+ ChannelPtr->CtrlWrd05[i] = SpdBufferPtr[SPD_CTLWRD05] >> 4;
+ //
+ // Temporarily store info. of SPD byte 63 into CtrlWrd02(s),
+ // and they will be used late to calculate real RC2 and RC8 value
+ //
+ ChannelPtr->CtrlWrd02[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
+ //
+ // Copy the number of registers to the Ps Block to persist across frequency changes
+ //
+ NBPtr->PsPtr->NumOfReg[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
+ //
+ } // if DIMM present
+ } // Dimm loop
+
+ if (Channel == 0) {
+ DCTPtr->Timings.DctDimmValid = ChannelPtr->ChDimmValid;
+ DCTPtr->Timings.DimmMirrorPresent = ChannelPtr->DimmMirrorPresent;
+ DCTPtr->Timings.DimmSpdCse = ChannelPtr->DimmSpdCse;
+ DCTPtr->Timings.DimmQrPresent = ChannelPtr->DimmQrPresent;
+ DCTPtr->Timings.DimmDrPresent = ChannelPtr->DimmDrPresent;
+ DCTPtr->Timings.DimmSRPresent = ChannelPtr->DimmSRPresent;
+ DCTPtr->Timings.Dimmx4Present = ChannelPtr->Dimmx4Present;
+ DCTPtr->Timings.Dimmx8Present = ChannelPtr->Dimmx8Present;
+ DCTPtr->Timings.Dimmx16Present = ChannelPtr->Dimmx16Present;
+ }
+ if ((Channel != 1) || (Dct != 1)) {
+ MCTPtr->DimmPresent <<= 8;
+ MCTPtr->DimmValid <<= 8;
+ MCTPtr->RegDimmPresent <<= 8;
+ MCTPtr->LrDimmPresent <<= 8;
+ MCTPtr->DimmEccPresent <<= 8;
+ MCTPtr->DimmParPresent <<= 8;
+ }
+ } // Channel loop
+ } // DCT loop
+
+ // If we have DIMMs, some further general characteristics checking
+ if (MCTPtr->DimmValid != 0) {
+ // If there are registered dimms, all the dimms must be registered
+ if (MCTPtr->RegDimmPresent == MCTPtr->DimmValid) {
+ // All dimms registered
+ MCTPtr->Status[SbRegistered] = TRUE;
+ MCTPtr->Status[SbParDimms] = TRUE; // All DDR3 RDIMMs are parity capable
+ TechPtr->SetDqsEccTmgs = MemTSetDQSEccTmgsRDdr3; // Change the function pointer for DQS ECC timing
+ } else if (MCTPtr->RegDimmPresent != 0) {
+ // We have an illegal DIMM mismatch
+ PutEventLog (AGESA_FATAL, MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_FATAL, MCTPtr);
+ }
+ // If there are LrDimms, all the dimms must be LrDimms
+ if (MCTPtr->LrDimmPresent == MCTPtr->DimmValid) {
+ // All dimms LRDIMMs
+ MCTPtr->Status[SbLrdimms] = TRUE;
+ } else if (MCTPtr->LrDimmPresent != 0) {
+ // We have an illegal DIMM mismatch
+ PutEventLog (AGESA_FATAL, MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_FATAL, MCTPtr);
+ }
+
+ // check the ECC capability of the DIMMs
+ if (MCTPtr->DimmEccPresent == MCTPtr->DimmValid) {
+ MCTPtr->Status[SbEccDimms] = TRUE; // All dimms ECC capable
+ }
+ } else {
+ }
+
+ NBPtr->SwitchDCT (NBPtr, 0);
+ NBPtr->SwitchChannel (NBPtr, 0);
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the maximum frequency that each channel is capable to run at.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that a FATAL error has not occurred
+ * @return FALSE - indicates that a FATAL error has occurred
+ */
+
+BOOLEAN
+MemTSPDGetTargetSpeed3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 *SpdBufferPtr;
+ UINT8 Dimm;
+ UINT8 Dct;
+ UINT8 Channel;
+ INT32 MTB_ps;
+ INT32 FTB_ps;
+ INT32 TCKmin_ps;
+ INT32 Value32;
+ MEM_NB_BLOCK *NBPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+ TCKmin_ps = 0;
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if ((ChannelPtr->ChDimmValid & ((UINT8)1 << Dimm)) != 0) {
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
+
+ // Determine tCKmin(all) which is the largest tCKmin
+ // value for all modules on the memory Channel (SPD byte 12).
+ //
+ MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
+ FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
+ Value32 = (MTB_ps * SpdBufferPtr[SPD_TCK]) + (FTB_ps * (INT8) SpdBufferPtr[SPD_TCK_FTB]) ;
+ if (TCKmin_ps < Value32) {
+ TCKmin_ps = Value32;
+ }
+ }
+ }
+ }
+ if (TCKmin_ps <= 1071) {
+ DCTPtr->Timings.TargetSpeed = DDR1866_FREQUENCY;
+ } else if (TCKmin_ps <= 1250) {
+ DCTPtr->Timings.TargetSpeed = DDR1600_FREQUENCY;
+ } else if (TCKmin_ps <= 1500) {
+ DCTPtr->Timings.TargetSpeed = DDR1333_FREQUENCY;
+ } else if (TCKmin_ps <= 1875) {
+ DCTPtr->Timings.TargetSpeed = DDR1066_FREQUENCY;
+ } else if (TCKmin_ps <= 2500) {
+ DCTPtr->Timings.TargetSpeed = DDR800_FREQUENCY;
+ } else {
+ DCTPtr->Timings.TargetSpeed = DDR667_FREQUENCY;
+ }
+ }
+
+ // Ensure the target speed can be applied to all channels of the current node
+ NBPtr->SyncTargetSpeed (NBPtr);
+
+ // Set the start-up frequency
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ NBPtr->DCTPtr->Timings.Speed = TechPtr->NBPtr->StartupSpeed;
+ }
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function check the symmetry of DIMM pairs (DIMM on Channel A matching with
+ * DIMM on Channel B), the overall DIMM population, and determine the width mode:
+ * 64-bit, 64-bit muxed, 128-bit.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that a FATAL error has not occurred
+ * @return FALSE - indicates that a FATAL error has occurred
+ */
+
+BOOLEAN
+MemTSPDCalcWidth3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 *SpdBufferAPtr;
+ UINT8 *SpdBufferBPtr;
+ MEM_NB_BLOCK *NBPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ UINT8 i;
+ UINT16 DimmMask;
+ UINT8 UngangMode;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ DCTPtr = NBPtr->DCTPtr;
+ UngangMode = UserOptions.CfgMemoryModeUnganged;
+ // Does not support ganged mode for DDR3 dimms
+ ASSERT (UngangMode);
+ IDS_OPTION_HOOK (IDS_GANGING_MODE, &UngangMode, &(NBPtr->MemPtr->StdHeader));
+
+ // Check symmetry of channel A and channel B dimms for 128-bit mode
+ // capability.
+ //
+ AGESA_TESTPOINT (TpProcMemModeChecking, &(NBPtr->MemPtr->StdHeader));
+ i = 0;
+ if (!UngangMode) {
+ if (MCTPtr->DctData[0].Timings.DctDimmValid == MCTPtr->DctData[1].Timings.DctDimmValid) {
+ for (; i < MAX_DIMMS_PER_CHANNEL; i++) {
+ DimmMask = (UINT16)1 << i;
+ if ((DCTPtr->Timings.DctDimmValid & DimmMask) != 0) {
+ NBPtr->SwitchDCT (NBPtr, 0);
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferAPtr, i);
+ NBPtr->SwitchDCT (NBPtr, 1);
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferBPtr, i);
+ // compare rows and columns
+ if ((SpdBufferAPtr[SPD_ROW_SZ]&0x3F) != (SpdBufferBPtr[SPD_ROW_SZ]&0x3F)) {
+ break;
+ }
+ if ((SpdBufferAPtr[SPD_DENSITY]&0x0F) != (SpdBufferBPtr[SPD_DENSITY]&0x0F)) {
+ break;
+ }
+ // compare ranks and devwidth
+ if ((SpdBufferAPtr[SPD_DEV_WIDTH]&0x7F) != (SpdBufferBPtr[SPD_DEV_WIDTH]&0x7F)) {
+ break;
+ }
+ }
+ }
+ }
+ if (i < MAX_DIMMS_PER_CHANNEL) {
+ PutEventLog (AGESA_ALERT, MEM_ALERT_ORG_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ALERT, MCTPtr);
+ } else {
+ NBPtr->Ganged = TRUE;
+ MCTPtr->GangedMode = TRUE;
+ MCTPtr->Status[Sb128bitmode] = TRUE;
+ NBPtr->SetBitField (NBPtr, BFDctGangEn, 1);
+ }
+ }
+
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Initialize DCT Timing registers as per DIMM SPD.
+ * For primary timing (T, CL) use best case T value.
+ * For secondary timing params., use most aggressive settings
+ * of slowest DIMM.
+ *
+ * Note:
+ * There are three components to determining "maximum frequency": SPD component,
+ * Bus load component, and "Preset" max frequency component.
+ * The SPD component is a function of the min cycle time specified by each DIMM,
+ * and the interaction of cycle times from all DIMMs in conjunction with CAS
+ * latency. The SPD component only applies when user timing mode is 'Auto'.
+ *
+ * The Bus load component is a limiting factor determined by electrical
+ * characteristics on the bus as a result of varying number of device loads. The
+ * Bus load component is specific to each platform but may also be a function of
+ * other factors. The bus load component only applies when user timing mode is
+ * ' Auto'.
+ *
+ * The Preset component is subdivided into three items and is the minimum of
+ * the set: Silicon revision, user limit setting when user timing mode is 'Auto' and
+ * memclock mode is 'Limit', OEM build specification of the maximum frequency.
+ * The Preset component only applies when user timing mode is 'Auto'.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that a FATAL error has not occurred
+ * @return FALSE - indicates that a FATAL error has occurred
+ */
+
+BOOLEAN
+MemTAutoCycTiming3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ CONST UINT8 SpdIndexes[] = {
+ SPD_TRCD,
+ SPD_TRP,
+ SPD_TRTP,
+ SPD_TRAS,
+ SPD_TRC,
+ SPD_TWR,
+ SPD_TRRD,
+ SPD_TWTR,
+ SPD_TFAW
+ };
+
+ CONST UINT8 SpdFTBIndexes[] = {
+ SPD_TRCD_FTB,
+ SPD_TRP_FTB,
+ 0,
+ 0,
+ SPD_TRC_FTB,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ UINT8 *SpdBufferPtr;
+ INT32 MiniMaxTmg[GET_SIZE_OF (SpdIndexes)];
+ UINT8 MiniMaxTrfc[4];
+
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT16 DimmMask;
+ INT32 Value32;
+ INT32 MTB_ps;
+ INT32 FTB_ps;
+ INT32 TCK_ps;
+ UINT8 i;
+ UINT8 j;
+ UINT8 Value8;
+ UINT8 *StatTmgPtr;
+ UINT16 *StatDimmTmgPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ DCTPtr = NBPtr->DCTPtr;
+ // initialize mini-max arrays
+ for (j = 0; j < GET_SIZE_OF (MiniMaxTmg); j++) {
+ MiniMaxTmg[j] = 0;
+ }
+ for (j = 0; j < GET_SIZE_OF (MiniMaxTrfc); j++) {
+ MiniMaxTrfc[j] = 0;
+ }
+
+ // ======================================================================
+ // Get primary timing (CAS Latency and Cycle Time)
+ // ======================================================================
+ // Get OEM specific load variant max
+ //
+
+ //======================================================================
+ // Gather all DIMM mini-max values for cycle timing data
+ //======================================================================
+ //
+ DimmMask = 1;
+ for (i = 0; i < (MAX_CS_PER_CHANNEL / 2); i++) {
+ if ((DCTPtr->Timings.DctDimmValid & DimmMask) != 0) {
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, i);
+ MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
+ FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
+
+ for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
+ Value32 = (UINT16)SpdBufferPtr[SpdIndexes[j]];
+ if (SpdIndexes[j] == SPD_TRC) {
+ Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TRC] & 0xF0) << 4;
+ } else if (SpdIndexes[j] == SPD_TRAS) {
+ Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TRAS] & 0x0F) << 8;
+ } else if (SpdIndexes[j] == SPD_TFAW) {
+ Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TFAW] & 0x0F) << 8;
+ }
+
+ Value32 *= MTB_ps;
+ if (SpdFTBIndexes[j] != 0) {
+ Value32 += (FTB_ps * (INT8) SpdBufferPtr[SpdFTBIndexes[j]]) ;
+ }
+ if (MiniMaxTmg[j] < Value32) {
+ MiniMaxTmg[j] = Value32;
+ }
+ }
+
+ // get Trfc0 - Trfc3 values
+ Value8 = SpdBufferPtr[SPD_DENSITY] & 0x0F;
+ if (MiniMaxTrfc[i] < Value8) {
+ MiniMaxTrfc[i] = Value8;
+ }
+ }
+ DimmMask <<= 1;
+ }
+
+ // ======================================================================
+ // Convert DRAM CycleTiming values and store into DCT structure
+ // ======================================================================
+ //
+ TCK_ps = 1000500 / DCTPtr->Timings.Speed;
+
+ StatDimmTmgPtr = &DCTPtr->Timings.DIMMTrcd;
+ StatTmgPtr = &DCTPtr->Timings.Trcd;
+ for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
+ Value32 = MiniMaxTmg[j];
+
+ MiniMaxTmg[j] = (MiniMaxTmg[j] + TCK_ps - 1) / TCK_ps;
+
+ StatDimmTmgPtr[j] = (UINT16) (Value32 / (1000 / 40));
+ StatTmgPtr[j] = (UINT8) MiniMaxTmg[j];
+ }
+ DCTPtr->Timings.Trfc0 = MiniMaxTrfc[0];
+ DCTPtr->Timings.Trfc1 = MiniMaxTrfc[1];
+ DCTPtr->Timings.Trfc2 = MiniMaxTrfc[2];
+ DCTPtr->Timings.Trfc3 = MiniMaxTrfc[3];
+
+ DCTPtr->Timings.CasL = MemTSPDGetTCL3 (TechPtr);
+
+ //======================================================================
+ // Program DRAM Timing values
+ //======================================================================
+ //
+ NBPtr->ProgramCycTimings (NBPtr);
+
+ MemFInitTableDrive (NBPtr, MTAfterAutoCycTiming);
+
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the bank addressing, program Mask values and build a chip-select population map.
+ * This routine programs PCI 0:24N:2x80 config register.
+ * This routine programs PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3)
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - indicates that a FATAL error has not occurred
+ * @return FALSE - indicates that a FATAL error has occurred
+ */
+
+BOOLEAN
+MemTSPDSetBanks3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 *SpdBufferPtr;
+ UINT8 i;
+ UINT8 ChipSel;
+ UINT8 DimmID;
+ UINT8 Value8;
+ UINT8 Rows;
+ UINT8 Cols;
+ UINT8 Ranks;
+ UINT8 Banks;
+ UINT32 BankAddrReg;
+ UINT32 CsMask;
+ UINT16 CSSpdCSE;
+ UINT16 CSExclude;
+ UINT16 DimmQRDR;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ DCTPtr = NBPtr->DCTPtr;
+ BankAddrReg = 0;
+ CSSpdCSE = 0;
+ CSExclude = 0;
+
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
+ DimmID = ChipSel >> 1;
+
+ DimmQRDR = (DCTPtr->Timings.DimmQrPresent) | (DCTPtr->Timings.DimmDrPresent);
+ if ((DCTPtr->Timings.DimmSpdCse & ((UINT16) 1 << DimmID)) != 0) {
+ CSSpdCSE |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3 : 1) << ChipSel;
+ }
+ if ((DCTPtr->Timings.DimmExclude & ((UINT16) 1 << DimmID)) != 0) {
+ CSExclude |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3: 1) << ChipSel;
+ }
+
+ if ((DCTPtr->Timings.DctDimmValid & ((UINT16)1 << DimmID)) != 0) {
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, DimmID);
+
+ // Get the basic data
+ Rows = (SpdBufferPtr[SPD_ROW_SZ] >> 3) & 0x7;
+ Cols = SpdBufferPtr[SPD_COL_SZ] & 0x7;
+ Banks = (SpdBufferPtr[SPD_L_BANKS] >> 4) & 0x7;
+ Ranks = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
+ if (Ranks == 5) {
+ Ranks = 8;
+ }
+
+ //
+ // Configure the bank encoding
+ // Use a 6-bit key into a lookup table.
+ // Key (index) = RRRBCC, where CC is the number of Columns minus 9,
+ // RRR is the number of Rows minus 12, and B is the number of banks
+ // minus 3.
+ //
+ Value8 = Cols;
+ Value8 |= (Banks == 1) ? 4 : 0;
+ Value8 |= Rows << 3;
+
+ if (MemTCheckBankAddr3 (Value8, &i)) {
+ BankAddrReg |= ((UINT32)i << (ChipSel << 1));
+
+ // Mask value=(2pow(rows+cols+banks+3)-1)>>8,
+ // or 2pow(rows+cols+banks-5)-1
+ //
+ Value8 = (Rows + 12) + (Cols + 9) + (Banks + 3) + 3 - 8;
+ if (MCTPtr->Status[Sb128bitmode]) {
+ Value8++;
+ }
+
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
+
+ if (Ranks >= 2) {
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
+ }
+ //
+ // Determine LRDIMM Rank Multiplication
+ //
+ if (TechPtr->TechnologySpecificHook[LrdimmRankMultiplication] (TechPtr, &DimmID)) {
+ //
+ // Increase the CS Size by the rank multiplication factor
+ //
+ Value8 += ((NBPtr->ChannelPtr->LrDimmRankMult[DimmID]) >> 1);
+ }
+
+ CsMask = ((UINT32)1 << Value8) - 1;
+ // Update the DRAM CS Mask for this chipselect
+ NBPtr->SetBitField (NBPtr, BFCSMask0Reg + (ChipSel >> 1), (CsMask & 0x1FF83FE0));
+ } else {
+ // Dimm is not supported, as no address mapping is found.
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
+ DCTPtr->Timings.CsTestFail |= (UINT16)1 << ChipSel;
+ if (Ranks >= 2) {
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
+ DCTPtr->Timings.CsTestFail |= (UINT16)1 << (ChipSel + 1);
+ }
+ PutEventLog (AGESA_ERROR, MEM_ERROR_NO_ADDRESS_MAPPING, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, DimmID, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ }
+ }
+ }
+ // For ranks that need to be excluded, the loading of this rank should be considered
+ // in timing, so need to set CsPresent before setting CsTestFail
+ if ((CSSpdCSE != 0) || (CSExclude != 0)) {
+ NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, (CSSpdCSE | CSExclude), &NBPtr->MemPtr->StdHeader);
+ }
+
+ // If there are no chip selects, we have an error situation.
+ if (DCTPtr->Timings.CsPresent == 0) {
+ PutEventLog (AGESA_ERROR, MEM_ERROR_NO_CHIPSELECT, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ }
+
+ NBPtr->SetBitField (NBPtr, BFDramBankAddrReg, BankAddrReg);
+
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns the low bit that will be swapped to enable CS interleaving
+ *
+ * @param[in] BankEnc - AddrMap Bank encoding from F2x80
+ * @param[in] *LowBit - pointer to low bit
+ * @param[in] *HiBit - pointer hight bit
+ *
+ */
+
+VOID
+MemTGetCSIntLvAddr3 (
+ IN UINT8 BankEnc,
+ OUT UINT8 *LowBit,
+ OUT UINT8 *HiBit
+ )
+{
+ CONST UINT8 ArrCodesLo[] = {0, 8, 8, 0, 0, 8, 9, 8, 9, 9, 8, 9};
+ CONST UINT8 ArrCodesHi[] = {0, 20, 21, 0, 0, 22, 22, 23, 23, 24, 24, 25};
+ ASSERT (BankEnc < GET_SIZE_OF (ArrCodesLo));
+ ASSERT (BankEnc < GET_SIZE_OF (ArrCodesHi));
+ // return ArrCodes[BankEnc];
+ *LowBit = ArrCodesLo[BankEnc];
+ *HiBit = ArrCodesHi[BankEnc];
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines if the checksum is correct
+ *
+ * @param[in] *SPDPtr - Pointer to SPD data
+ *
+ * @return TRUE - CRC check passes
+ * @return FALSE - CRC check fails
+ */
+
+BOOLEAN
+STATIC
+MemTCRCCheck3 (
+ IN OUT UINT8 *SPDPtr
+ )
+{
+ UINT16 Crc;
+ INT16 i;
+ INT16 j;
+ INT16 Count;
+
+ if (SPDPtr[SPD_TYPE] == JED_DDR3SDRAM) {
+ Count = (SPDPtr[SPD_BYTE_USED] & 0x80) ? 117 : 126;
+ Crc = 0;
+ for (j = 0; j < Count; j++) {
+ Crc = Crc ^ ((UINT16)SPDPtr[j] << 8);
+ for (i = 0; i < 8; i++) {
+ if (Crc & 0x8000) {
+ Crc = (Crc << 1) ^ 0x1021;
+ } else {
+ Crc = (Crc << 1);
+ }
+ }
+ }
+ if (*(UINT16 *) (SPDPtr + 126) == Crc) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns the CAS latency of the current frequency (DCTPtr->Timings.Speed).
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return CAS Latency
+ */
+
+UINT8
+STATIC
+MemTSPDGetTCL3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 *SpdBufferPtr;
+ UINT8 CLdesired;
+ UINT8 CLactual;
+ UINT8 Dimm;
+ UINT8 Channel;
+ UINT16 CASLat;
+ UINT16 Mask16;
+ INT32 MTB_ps;
+ INT32 FTB_ps;
+ INT32 TAAmin_ps;
+ INT32 TCKproposed_ps;
+ INT32 Value32;
+ BOOLEAN CltFail;
+ MEM_NB_BLOCK *NBPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ DCTPtr = NBPtr->DCTPtr;
+
+ CASLat = 0xFFFF;
+ TAAmin_ps = 0;
+ CltFail = FALSE;
+
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if ((ChannelPtr->ChDimmValid & ((UINT8)1 << Dimm)) != 0) {
+ MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
+
+ // Step 1: Determine the common set of supported CAS Latency
+ // values for all modules on the memory Channel using the CAS
+ // Latencies Supported in SPD bytes 14 and 15.
+ //
+ CASLat &= ((UINT16)SpdBufferPtr[SPD_CASHI] << 8) | SpdBufferPtr[SPD_CASLO];
+
+ // Step 2: Determine tAAmin(all) which is the largest tAAmin
+ // value for all modules on the memory Channel (SPD byte 16).
+ //
+ MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
+ FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
+ Value32 = (MTB_ps * SpdBufferPtr[SPD_TAA]) + (FTB_ps * (INT8) SpdBufferPtr[SPD_TAA_FTB]) ;
+ if (TAAmin_ps < Value32) {
+ TAAmin_ps = Value32;
+ }
+
+ // Step 3: Determine tCKmin(all) which is the largest tCKmin
+ // value for all modules on the memory Channel (SPD byte 12).
+ // * This step has been done in SPDGetTargetSpeed
+ }
+ }
+ }
+
+ TCKproposed_ps = 1000500 / DCTPtr->Timings.Speed;
+
+ // Step 4: For a proposed tCK value (tCKproposed) between tCKmin(all) and tCKmax,
+ // determine the desired CAS Latency. If tCKproposed is not a standard JEDEC
+ // value (2.5, 1.875, 1.5, or 1.25 ns) then tCKproposed must be adjusted to the
+ // next lower standard tCK value for calculating CLdesired.
+ // CLdesired = ceiling ( tAAmin(all) / tCKproposed )
+ // where tAAmin is defined in Byte 16. The ceiling function requires that the
+ // quotient be rounded up always.
+ //
+ CLdesired = (UINT8) ((TAAmin_ps + TCKproposed_ps - 1) / TCKproposed_ps);
+
+ // Step 5: Choose an actual CAS Latency (CLactual) that is greater than or equal
+ // to CLdesired and is supported by all modules on the memory Channel as
+ // determined in step 1. If no such value exists, choose a higher tCKproposed
+ // value and repeat steps 4 and 5 until a solution is found.
+ //
+ CLactual = 4;
+ for (Mask16 = 1; Mask16 < 0x8000; Mask16 <<= 1) {
+ if (CASLat & Mask16) {
+ if (CLdesired <= CLactual) {
+ break;
+ }
+ }
+ CLactual++;
+ }
+ if (Mask16 == 0x8000) {
+ CltFail = TRUE;
+ }
+
+ // Step 6: Once the calculation of CLactual is completed, the BIOS must also
+ // verify that this CAS Latency value does not exceed tAAmax, which is 20 ns
+ // for all DDR3 speed grades, by multiplying CLactual times tCKproposed. If
+ // not, choose a lower CL value and repeat steps 5 and 6 until a solution is found.
+ //
+ if ((TCKproposed_ps * CLactual) > 20000) {
+ CltFail = TRUE;
+ }
+
+ if (!CltFail) {
+ DCTPtr->Timings.CasL = CLactual;
+ } else {
+ // Fail to find supported Tcl, use 6 clocks since it is required for all DDR3 speed bin.
+ DCTPtr->Timings.CasL = 6;
+ }
+
+ return DCTPtr->Timings.CasL;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns the encoded value of bank address.
+ *
+ * @param[in] Encode - RRRBCC, where CC is the number of Columns minus 9,
+ * RRR is the number of Rows minus 12, and B is the number of banks
+ * minus 3.
+ * @param[out] *Index - index in bank address table
+ * @return TRUE - encoded value is found.
+ * FALSE - encoded value is not found.
+ */
+
+BOOLEAN
+STATIC
+MemTCheckBankAddr3 (
+ IN UINT8 Encode,
+ OUT UINT8 *Index
+ )
+{
+ UINT8 i;
+ CONST UINT8 TabBankAddr[] = {
+ 0x3F, 0x01, 0x09, 0x3F, 0x3F, 0x11,
+ 0x0A, 0x19, 0x12, 0x1A, 0x21, 0x22
+ };
+
+ for (i = 0; i < GET_SIZE_OF (TabBankAddr); i++) {
+ if (Encode == TabBankAddr[i]) {
+ *Index = i;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns a pointer to the SPD Buffer of a specific dimm on
+ * the current channel.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] **SpdBuffer - Pointer to a pointer to a UINT8 Buffer
+ * @param[in] Dimm - Dimm number
+ *
+ *
+ * @return BOOLEAN - Value of DimmPresent
+ * TRUE = Dimm is present, pointer is valid
+ * FALSE = Dimm is not present, pointer has not been modified.
+ */
+
+BOOLEAN
+MemTGetDimmSpdBuffer3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 **SpdBuffer,
+ IN UINT8 Dimm
+ )
+{
+ CH_DEF_STRUCT *ChannelPtr;
+ SPD_DEF_STRUCT *SPDPtr;
+ BOOLEAN DimmPresent;
+
+ DimmPresent = FALSE;
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+ ASSERT (Dimm < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0])))
+ SPDPtr = ChannelPtr->DimmSpdPtr[Dimm];
+
+
+ if (SPDPtr != NULL) {
+ DimmPresent = SPDPtr->DimmPresent;
+ if (DimmPresent) {
+ *SpdBuffer = SPDPtr->Data;
+ }
+ }
+ return DimmPresent;
+}
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h
new file mode 100644
index 0000000000..97f768335c
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h
@@ -0,0 +1,177 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtspd3.h
+ *
+ * Technology SPD support for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 35415 $ @e \$Date: 2010-07-22 06:10:32 +0800 (Thu, 22 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 _MTSPD3_H_
+#define _MTSPD3_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*===============================================================================
+ * Jedec DDR III
+ *===============================================================================
+ */
+#define SPD_BYTE_USED 0
+#define SPD_TYPE 2 /* SPD byte read location */
+#define JED_DDR_SDRAM 7 /* Jedec defined bit field */
+#define JED_DDR2_SDRAM 8 /* Jedec defined bit field */
+#define JED_DDR3SDRAM 0xB /* Jedec defined bit field */
+
+#define SPD_DIMM_TYPE 3
+#define SPD_ATTRIB 21
+#define JED_DIF_CK_MSK 0x20 /* Differential Clock Input */
+#define JED_RDIMM 1
+#define JED_MINIRDIMM 5
+#define JED_UDIMM 2
+#define JED_SODIMM 3
+#define JED_LRDIMM 0xB
+
+#define SPD_L_BANKS 4 /* [7:4] number of [logical] banks on each device */
+#define SPD_DENSITY 4 /* bit 3:0 */
+#define SPD_ROW_SZ 5 /* bit 5:3 */
+#define SPD_COL_SZ 5 /* bit 2:0 */
+#define SPD_RANKS 7 /* bit 5:3 */
+#define SPD_DEV_WIDTH 7 /* bit 2:0 */
+#define SPD_ECCBITS 8 /* bit 4:3 */
+#define JED_ECC 8
+#define SPD_RAWCARD 62 /* bit 2:0 */
+#define SPD_ADDRMAP 63 /* bit 0 */
+
+#define SPD_CTLWRD03 70 /* bit 7:4 */
+#define SPD_CTLWRD04 71 /* bit 3:0 */
+#define SPD_CTLWRD05 71 /* bit 7:4 */
+
+#define SPD_FTB 9
+
+#define SPD_DIVIDENT 10
+#define SPD_DIVISOR 11
+
+#define SPD_TCK 12
+#define SPD_CASLO 14
+#define SPD_CASHI 15
+#define SPD_TAA 16
+
+#define SPD_TRP 20
+#define SPD_TRRD 19
+#define SPD_TRCD 18
+#define SPD_TRAS 22
+#define SPD_TWR 17
+#define SPD_TWTR 26
+#define SPD_TRTP 27
+#define SPD_TRC 23
+#define SPD_UPPER_TRC 21 /* bit 7:4 */
+#define SPD_UPPER_TRAS 21 /* bit 3:0 */
+#define SPD_TFAW 29
+#define SPD_UPPER_TFAW 28 /* bit 3:0 */
+
+#define SPD_TCK_FTB 34
+#define SPD_TAA_FTB 35
+#define SPD_TRCD_FTB 36
+#define SPD_TRP_FTB 37
+#define SPD_TRC_FTB 38
+
+/*-----------------------------
+ * Jedec DDR II related equates
+ *-----------------------------
+ */
+
+#define CL_DEF 4 /* Default value for failsafe operation. 4=CL 6.0 T */
+#define T_DEF 4 /* Default value for failsafe operation. 4=2.5ns (cycle time) */
+
+#define BIAS_TRTP_T 4
+#define BIAS_TRCD_T 5
+#define BIAS_TRAS_T 15
+#define BIAS_TRC_T 11
+#define BIAS_TRRD_T 4
+#define BIAS_TWR_T 4
+#define BIAS_TRP_T 5
+#define BIAS_TWTR_T 4
+#define BIAS_TFAW_T 14
+
+#define MIN_TRTP_T 4
+#define MAX_TRTP_T 7
+#define MIN_TRCD_T 5
+#define MAX_TRCD_T 12
+#define MIN_TRAS_T 15
+#define MAX_TRAS_T 30
+#define MIN_TRC_T 11
+#define MAX_TRC_T 42
+#define MIN_TRRD_T 4
+#define MAX_TRRD_T 7
+#define MIN_TWR_T 5
+#define MAX_TWR_T 12
+#define MIN_TRP_T 5
+#define MAX_TRP_T 12
+#define MIN_TWTR_T 4
+#define MAX_TWTR_T 7
+#define MIN_TFAW_T 16
+#define MAX_TFAW_T 32
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+#endif /* _MTSPD3_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c
new file mode 100644
index 0000000000..5f948733a7
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c
@@ -0,0 +1,166 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttecc3.c
+ *
+ * Technology ECC byte support for registered DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mu.h"
+#include "mt.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR3_MTTECC3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the DQS ECC timings for registered DDR3
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTSetDQSEccTmgsRDdr3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 Dimm;
+ UINT8 i;
+ UINT8 *WrDqsDly;
+ UINT16 *RcvEnDly;
+ UINT8 *RdDqsDly;
+ UINT8 *WrDatDly;
+ UINT8 EccByte;
+ INT16 TempValue;
+
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ EccByte = TechPtr->MaxByteLanes ();
+ NBPtr = TechPtr->NBPtr;
+
+ if (NBPtr->MCTPtr->NodeMemSize) {
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if (NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm * 2))) {
+ i = Dimm * TechPtr->DlyTableWidth ();
+ WrDqsDly = &ChannelPtr->WrDqsDlys[i];
+ RcvEnDly = &ChannelPtr->RcvEnDlys[i];
+ RdDqsDly = &ChannelPtr->RdDqsDlys[i];
+ WrDatDly = &ChannelPtr->WrDatDlys[i];
+ // Receiver DQS Enable:
+ // Receiver DQS enable for ECC bytelane = Receiver DQS enable for bytelane 3 -
+ // [write DQS for bytelane 3 - write DQS for ECC]
+
+ TempValue = (INT16) RcvEnDly[3] - (INT16) (WrDqsDly[3] - WrDqsDly[EccByte]);
+ if (TempValue < 0) {
+ TempValue = 0;
+ }
+ RcvEnDly[EccByte] = (UINT16) TempValue;
+
+ // Read DQS:
+ // Read DQS for ECC bytelane = read DQS of byte lane 3
+ //
+ RdDqsDly[EccByte] = RdDqsDly[3];
+
+ // Write Data:
+ // Write Data for ECC bytelane = Write DQS for ECC +
+ // [write data for bytelane 3 - Write DQS for bytelane 3]
+ TempValue = (INT16) (WrDqsDly[EccByte] + (INT8) (WrDatDly[3] - WrDqsDly[3]));
+ if (TempValue < 0) {
+ TempValue = 0;
+ }
+ WrDatDly[EccByte] = (UINT8) TempValue;
+
+ NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RcvEnDly[EccByte]);
+ NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RdDqsDly[EccByte]);
+ NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, EccByte), WrDatDly[EccByte]);
+ }
+ }
+ }
+ }
+ }
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+} \ No newline at end of file
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c
new file mode 100644
index 0000000000..34e0927640
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c
@@ -0,0 +1,686 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttwl3.c
+ *
+ * Technology Phy assisted write levelization for DDR3
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR3)
+ * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 2010) $
+ *
+ **/
+/*
+ *****************************************************************************
+ *
+ * Copyright (c) 2011, 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 "mtsdi3.h"
+#include "merrhdl.h"
+#include "OptionMemory.h"
+#include "PlatformMemoryConfiguration.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+#include "mtlrdimm3.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR3_MTTWL3_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+STATIC
+MemTWriteLevelizationHw3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ );
+
+VOID
+STATIC
+MemTWLPerDimmHw3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Pass
+ );
+
+VOID
+STATIC
+MemTPrepareDIMMs3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 TargetDIMM,
+ IN BOOLEAN Wl
+ );
+
+VOID
+STATIC
+MemTProcConfig3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Pass
+ );
+
+VOID
+STATIC
+MemTBeginWLTrain3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes first pass of Phy assisted write levelization
+ * for a specific node (DDR800).
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTWriteLevelizationHw3Pass1 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return MemTWriteLevelizationHw3 (TechPtr, 1);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes second pass of Phy assisted write levelization
+ * for a specific node (DDR1066 and above).
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTWriteLevelizationHw3Pass2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ // If current speed is higher than start-up speed, do second pass of WL
+ if (TechPtr->NBPtr->DCTPtr->Timings.Speed > TechPtr->NBPtr->StartupSpeed) {
+ return MemTWriteLevelizationHw3 (TechPtr, 2);
+ }
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function prepares for Phy assisted training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTPreparePhyAssistedTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ // Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1.
+ TechPtr->NBPtr->BrdcstSet (TechPtr->NBPtr, BFDisAutoRefresh, 1);
+ // Disable ZQ calibration short command by configuring F2x[1, 0]94[ZqcsInterval] = 00b.
+ TechPtr->NBPtr->BrdcstSet (TechPtr->NBPtr, BFZqcsInterval, 0);
+ return (BOOLEAN) (TechPtr->NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function revert to normal settings when exiting from Phy assisted training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTExitPhyAssistedTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ NBPtr = TechPtr->NBPtr;
+
+ // 13.Program F2x[1, 0]8C[DisAutoRefresh] = 0.
+ NBPtr->BrdcstSet (NBPtr, BFDisAutoRefresh, 0);
+ // 14.Program F2x[1, 0]94[ZqcsInterval] to the proper interval for the current memory configuration.
+ NBPtr->BrdcstSet (NBPtr, BFZqcsInterval, 2);
+ NBPtr->FamilySpecificHook[ExitPhyAssistedTraining] (NBPtr, NBPtr);
+
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executed hardware based write levelization for a specific die
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Pass - Pass number (1 (400Mhz) or 2 (>400Mhz))
+ *
+ * @pre Auto refresh and ZQCL must be disabled
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+STATIC
+MemTWriteLevelizationHw3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ DCT_STRUCT *DCTPtr;
+ UINT8 Dct;
+ UINT8 Dimm;
+
+ NBPtr = TechPtr->NBPtr;
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart write leveling\n");
+ AGESA_TESTPOINT (TpProcMemWriteLevelizationTraining, &(NBPtr->MemPtr->StdHeader));
+ // Begin DQS Write timing training
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ DCTPtr = NBPtr->DCTPtr;
+
+ TechPtr->WLCriticalDelay = 0x00;
+
+ //training for each Dimm
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if ((DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm << 1))) != 0) {
+ if (!(NBPtr->MCTPtr->Status[SbLrdimms]) || ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0)) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Dimm << 1);
+ MemTWLPerDimmHw3 (TechPtr, Dimm, Pass);
+ }
+ }
+ }
+
+ NBPtr->FamilySpecificHook[CalcWrDqDqsEarly] (NBPtr, NULL);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "End write leveling\n\n");
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initializes per DIMM write levelization
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dimm - DIMM to be trained
+ * @param[in] Pass - Pass number (1 (400Mhz) or 2 (>400Mhz))
+ *
+ */
+
+VOID
+STATIC
+MemTWLPerDimmHw3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Pass
+ )
+{
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+
+ ASSERT (Dimm < MAX_DIMMS_PER_CHANNEL);
+
+ // 1. A. Specify the target Dimm that is to be trained by programming
+ // F2x[1, 0]9C_x08[TrDimmSel].
+ NBPtr->SetBitField (NBPtr, BFTrDimmSel, Dimm);
+
+ TechPtr->TargetDIMM = Dimm;
+ NBPtr->FamilySpecificHook[InitPerNibbleTrn] (NBPtr, NULL);
+ for (TechPtr->TrnNibble = NIBBLE_0; TechPtr->TrnNibble <= (NBPtr->FamilySpecificHook[TrainWlPerNibble] (NBPtr, &Dimm)? NIBBLE_0 : NIBBLE_1); TechPtr->TrnNibble++) {
+ // 2. Prepare the DIMMs for write levelization using DDR3-defined
+ // MR commands.
+ MemTPrepareDIMMs3 (TechPtr, Dimm, TRUE);
+
+ // 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
+ // satisfy DDR3-defined internal DRAM timing.
+ NBPtr->WaitXMemClks (NBPtr, 40);
+
+ // 4. Configure the processor's DDR phy for write levelization training:
+ MemTProcConfig3 (TechPtr, Dimm, Pass);
+
+ // 5. Begin write levelization training
+ MemTBeginWLTrain3 (TechPtr, Dimm);
+ }
+ // 7. Program the target Dimm back to normal operation
+ MemTPrepareDIMMs3 (TechPtr, Dimm, FALSE);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function prepares the DIMMS for Write Levelization
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] TargetDIMM - DIMM to be trained
+ * @param[in] Wl - Indicates if WL mode should be enabled
+ *
+ */
+
+VOID
+STATIC
+MemTPrepareDIMMs3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 TargetDIMM,
+ IN BOOLEAN Wl
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 ChipSel;
+
+ NBPtr = TechPtr->NBPtr;
+
+ AGESA_TESTPOINT (TpProcMemWlPrepDimms, &(NBPtr->MemPtr->StdHeader));
+ ASSERT (TargetDIMM < MAX_DIMMS_PER_CHANNEL);
+ TechPtr->TargetDIMM = TargetDIMM;
+ if (!(TechPtr->TechnologySpecificHook[WlTrainingPrepareLrdimm] (TechPtr, &Wl))) {
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
+ if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
+ if (Wl) {
+ // Program WrLvOdt
+ NBPtr->SetBitField (NBPtr, BFWrLvOdt, NBPtr->ChannelPtr->PhyWLODT[ChipSel >> 1]);
+ }
+ NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
+ // Set MR1 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
+ MemTEMRS13 (TechPtr, Wl, TargetDIMM);
+ NBPtr->SendMrsCmd (NBPtr);
+ // Set MR2 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
+ MemTEMRS23 (TechPtr);
+ // Send command
+ NBPtr->SendMrsCmd (NBPtr);
+ }
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs seed values for Write Levelization
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dimm - DIMM to be trained
+ * @param[in] Pass - Pass for WL training (1 - 400Mhz or 2 - >400Mhz)
+ *
+ */
+
+VOID
+STATIC
+MemTProcConfig3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Pass
+ )
+{
+ DIE_STRUCT *MCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT16 WrDqsDly;
+ // Memclk Delay incurred by register.
+ UINT8 MemClkRegDly;
+ UINT8 ByteLane;
+ UINT8 DefaultSeed;
+ UINT8 CurrentSeed;
+ UINT8 *Seed;
+ UINT8 RCW2;
+ UINT16 Speed;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ AGESA_TESTPOINT (TpProcMemWlConfigDimms, &(NBPtr->MemPtr->StdHeader));
+ RCW2 = ChannelPtr->CtrlWrd02[Dimm];
+ Speed = TechPtr->NBPtr->DCTPtr->Timings.Speed;
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeeds: ");
+ // Program an initialization Value to registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to set
+ // the gross and fine delay for all the byte lane fields. If the target frequency is different than 400MHz,
+ // BIOS must execute two training passes for each Dimm. For pass 1 at a 400MHz MEMCLK frequency,
+ // use an initial total delay value.
+ if (Pass == 1) {
+ //
+ // Get the default value of seed
+ //
+ if (MCTPtr->Status[SbRegistered]) {
+ //
+ // RDIMM
+ //
+ if (Speed == DDR667_FREQUENCY) {
+ DefaultSeed = ((RCW2 & BIT0) == 0) ? 0x3B : 0x4B;
+ } else {
+ DefaultSeed = ((RCW2 & BIT0) == 0) ? 0x41 : 0x51;
+ }
+ } else if (ChannelPtr->SODimmPresent != 0) {
+ //
+ // SODIMMM
+ //
+ DefaultSeed = 0x12;
+ } else if (MCTPtr->Status[SbLrdimms]) {
+ //
+ // LRDIMM
+ //
+ DefaultSeed = 0x0;
+ } else {
+ //
+ // UDIMMM
+ //
+ DefaultSeed = 0x1A;
+ }
+
+ ASSERT (Speed >= DDR667_FREQUENCY);
+
+ // Get platform override seed
+ Seed = (UINT8 *) FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_WL_SEED, MCTPtr->SocketId, ChannelPtr->ChannelID);
+
+ for (ByteLane = 0; ByteLane < TechPtr->DlyTableWidth (); ByteLane++) {
+ // This includes ECC as byte 8
+ CurrentSeed = ((Seed != NULL) ? Seed[ByteLane] : DefaultSeed);
+ ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane] = CurrentSeed;
+
+ if (NBPtr->IsSupported[WLSeedAdjust]) {
+ if ((CurrentSeed & 0x20) != 0) {
+ // If (SeedGross is odd) then SeedPreGross = 1
+ CurrentSeed = (CurrentSeed & 0x1F) | 0x20;
+ } else {
+ // If (SeedGross is even) then SeedPreGross = 2
+ CurrentSeed = (CurrentSeed & 0x1F) | 0x40;
+ }
+ }
+
+ NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), CurrentSeed);
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", CurrentSeed);
+ }
+ } else {
+ //10.Multiply the previously saved delay values in Pass 1, step #5 by (target frequency)/400 to find
+ //the gross and fine delay initialization values at the target frequency. Use these values as the initial
+ //seed values when executing Pass 2, step #4.
+ for (ByteLane = 0; ByteLane < TechPtr->DlyTableWidth (); ByteLane++) {
+ // This includes ECC as byte 8
+ WrDqsDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane];
+ TechPtr->Bytelane = ByteLane;
+ NBPtr->FamilySpecificHook[TrainWlPerNibbleSeed] (NBPtr, &WrDqsDly);
+ //
+ // For Registered Dimms
+ //
+ if (MCTPtr->Status[SbRegistered]) {
+ MemClkRegDly = ((RCW2 & BIT0) == 0) ? 0x20 : 0x30;
+ WrDqsDly = (UINT16) (MemClkRegDly + ((((UINT32) WrDqsDly - MemClkRegDly) * Speed) / TechPtr->PrevSpeed));
+ } else {
+ //
+ // Unbuffered Dimms and LRDIMMs
+ //
+ WrDqsDly = (UINT16) (((UINT32) WrDqsDly * Speed) / TechPtr->PrevSpeed);
+ }
+
+ ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane] = (UINT8) WrDqsDly;
+
+ if (NBPtr->IsSupported[WLSeedAdjust]) {
+ if ((WrDqsDly & 0x20) != 0) {
+ // If (SeedGross is odd) then SeedPreGross = 1
+ WrDqsDly = (WrDqsDly & 0x1F) | 0x20;
+ } else {
+ // If (SeedGross is even) then SeedPreGross = 2
+ WrDqsDly = (WrDqsDly & 0x1F) | 0x40;
+ }
+ }
+ NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqsDly);
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", WrDqsDly);
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function begins WL training for a specific DIMM
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dimm - DIMM to be trained
+ *
+ */
+
+VOID
+STATIC
+MemTBeginWLTrain3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm
+ )
+{
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 ByteLane;
+ UINT8 Seed;
+ UINT8 Delay;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ // Assert ODT pins for write leveling
+ NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 1);
+
+ // Wait 10 MEMCLKs to allow for ODT signal settling.
+ NBPtr->WaitXMemClks (NBPtr, 10);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrtLvTrEn = 1\n");
+ // Program F2x[1, 0]9C_x08[WrtLlTrEn]=1.
+ NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 1);
+
+ // Wait 200 MEMCLKs.
+ NBPtr->WaitXMemClks (NBPtr, 200);
+
+ // Program F2x[1, 0]9C_x08[WrtLlTrEn]=0.
+ NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 0);
+
+ // Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to get the gross and fine Delay settings
+ // for the target Dimm and save these values.
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t PRE: ");
+ for (ByteLane = 0; ByteLane < (MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
+ // This includes ECC as byte 8
+ Seed = NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane];
+ Delay = (UINT8)NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane));
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Delay);
+
+ if (NBPtr->IsSupported[WLSeedAdjust]) {
+ // Recover WrDqsGrossDly:
+ // WrDqsGrossDly = SeedGross + PhRecGrossDlyByte - SeedPreGross
+ if ((Seed & 0x20) != 0) {
+ // If (SeedGross is odd) then SeedPreGross = 1
+ Delay += (Seed & 0xE0) - 0x20;
+ } else {
+ // If (SeedGross is even) then SeedPreGross = 2
+ if (((Seed & 0xE0) == 0) && (Delay < 0x40)) {
+ // If SeedGross is 0 and PhRecGrossDlyByte is less than SeedPreGross,
+ // we have a negative result and need to program the delay to 0
+ if (NBPtr->IsSupported[WLNegativeDelay]) {
+ //
+ // Save the lowest negative delay value across all Dimms and Bytelanes
+ //
+ TechPtr->WLCriticalDelay = MIN (TechPtr->WLCriticalDelay, (INT16)Delay - 0x40);
+ Delay -= 0x40;
+ } else {
+ Delay = 0;
+ }
+ } else {
+ Delay += (Seed & 0xE0) - 0x40;
+ }
+ }
+ } else if (((Seed >> 5) == 0) && ((Delay >> 5) == 3)) {
+ IDS_OPTION_HOOK (IDS_CHECK_NEGATIVE_WL, &Delay, &(TechPtr->NBPtr->MemPtr->StdHeader));
+ // If seed has gross delay of 0 and PRE has gross delay of 3,
+ // then round the total delay of TxDqs to 0.
+ Delay = 0;
+ }
+
+ if ((Delay > (Seed + 0x20)) || (Seed > (Delay + 0x20))) {
+ //
+ // If PRE comes back with more than Seed +/- 0x20, then this is an
+ // unexpected condition. Log the condition.
+ //
+ PutEventLog (AGESA_ERROR, MEM_ERROR_WL_PRE_OUT_OF_RANGE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ((Seed << 8) + Delay), &NBPtr->MemPtr->StdHeader);
+ }
+
+ TechPtr->Bytelane = ByteLane;
+ TechPtr->TargetDIMM = Dimm;
+ NBPtr->FamilySpecificHook[TrainWlPerNibbleAdjustWLDly] (NBPtr, &Delay);
+ NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), Delay);
+ NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane] = Delay;
+ }
+
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrDqs: ");
+ for (ByteLane = 0; ByteLane < (MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
+ );
+
+ // Disable write leveling ODT pins
+ NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 0);
+
+ // Wait 10 MEMCLKs to allow for ODT signal settling.
+ NBPtr->WaitXMemClks (NBPtr, 10);
+
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs register after Phy assisted training is finish.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTExitPhyAssistedTrainingClient3 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 Dct;
+ UINT8 ChipSel;
+ NBPtr = TechPtr->NBPtr;
+
+ NBPtr->FamilySpecificHook[ReEnablePhyComp] (NBPtr, NBPtr);
+ NBPtr->BrdcstSet (NBPtr, BFRxPtrInitReq, 1);
+ NBPtr->PollBitField (NBPtr, BFRxPtrInitReq, 0, PCI_ACCESS_TIMEOUT, TRUE);
+ NBPtr->BrdcstSet (NBPtr, BFDisDllShutdownSR, 1);
+ NBPtr->BrdcstSet (NBPtr, BFEnterSelfRef, 1);
+ NBPtr->PollBitField (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign = 2\n");
+ NBPtr->BrdcstSet (NBPtr, BFDbeGskMemClkAlignMode, 2);
+ NBPtr->BrdcstSet (NBPtr, BFExitSelfRef, 1);
+ NBPtr->PollBitField (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
+ NBPtr->BrdcstSet (NBPtr, BFDisDllShutdownSR, 0);
+
+ // Calculate Max Latency for both channels to prepare for position training
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) {
+ NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat);
+ }
+ }
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+