aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/Proc/Mem/Tech
diff options
context:
space:
mode:
authorFrank Vibrans <frank.vibrans@amd.com>2011-02-14 18:30:54 +0000
committerMarc Jones <marc.jones@amd.com>2011-02-14 18:30:54 +0000
commit2b4c831b4d16b55a7abdea20bce82cccd168232c (patch)
tree95a35c737d16119f1dfa9c1c9d7700710d8a04f7 /src/vendorcode/amd/agesa/Proc/Mem/Tech
parent74ad66cdc143e04f976ba21e538e02b20362d7e6 (diff)
Add AMD Agesa and AMD CIMx SB800 code. Patch 1 of 8.
This code currently generates many warnings that are functionally benign. These are being addressed, but the wheels of bureaucracy turn slowly. This drop supports AMD cpu families 10h and 14h. Only Family 14h is used as an example in this set of patches. Other cpu families are supported by the infrastructure, but their specific support is not included herein. This patch is functionally independent of the other patches in this set. Signed-off-by: Frank Vibrans <frank.vibrans@amd.com> Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Acked-by: Marc Jones <marcj303@gmail.com> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6344 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/vendorcode/amd/agesa/Proc/Mem/Tech')
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.c234
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.h126
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.c164
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.h90
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.c1117
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.h184
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mt3.c237
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mt3.h136
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtlrdimm3.c1102
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtlrdimm3.h127
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtot3.c170
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtot3.h92
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtrci3.c297
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtrci3.h89
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtsdi3.c493
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtsdi3.h98
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtspd3.c1153
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtspd3.h177
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mttecc3.c166
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mttwl3.c686
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mt.c264
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mthdi.c127
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.c896
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.h119
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttdimbt.c1279
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttecc.c209
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mtthrc.c306
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttml.c255
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttoptsrc.c427
-rw-r--r--src/vendorcode/amd/agesa/Proc/Mem/Tech/mttsrc.c346
30 files changed, 11166 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.c
new file mode 100644
index 0000000000..9a68725da1
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.c
@@ -0,0 +1,234 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mt2.c
+ *
+ * Common Technology functions for DDR2
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 "AdvancedApi.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mt.h"
+#include "mt2.h"
+#include "mtspd2.h"
+#include "mtot2.h"
+#include "OptionMemory.h"
+#include "PlatformMemoryConfiguration.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+/* features */
+#include "mftds.h"
+#define FILECODE PROC_MEM_TECH_DDR2_MT2_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
+MemConstructTechBlock2 (
+ 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 != DDR2_TECHNOLOGY) {
+ return FALSE;
+ }
+ }
+
+
+ TechPtr->NBPtr = NBPtr;
+ TechPtr->RefPtr = NBPtr->RefPtr;
+ MCTPtr = NBPtr->MCTPtr;
+
+ TechPtr->NBPtr = NBPtr;
+ TechPtr->RefPtr = NBPtr->RefPtr;
+
+ TechPtr->SetDramMode = MemTSetDramMode2;
+ TechPtr->DimmPresence = MemTDIMMPresence2;
+ TechPtr->SpdCalcWidth = MemTSPDCalcWidth2;
+ TechPtr->SpdGetTargetSpeed = MemTSPDGetTargetSpeed2;
+ TechPtr->AutoCycTiming = MemTAutoCycTiming2;
+ TechPtr->SpdSetBanks = MemTSPDSetBanks2;
+ TechPtr->SetDqsEccTmgs = MemTSetDQSEccTmgs;
+ TechPtr->GetCSIntLvAddr = MemTGetCSIntLvAddr2;
+ TechPtr->AdjustTwrwr = MemTAdjustTwrwr2;
+ TechPtr->AdjustTwrrd = MemTAdjustTwrrd2;
+ TechPtr->GetDimmSpdBuffer = MemTGetDimmSpdBuffer2;
+ TechPtr->GetLD = MemTGetLD2;
+ 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 (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 = DDR2_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_DM_BANKS] >> 3) & 0x07) + 1) > 2) {
+ ChannelPtr->DimmSpdPtr[i + 2] = &(ChannelPtr->SpdPtr[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.h
new file mode 100644
index 0000000000..ded211b691
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mt2.h
@@ -0,0 +1,126 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mt2.h
+ *
+ * Common Technology
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 _MT2_H_
+#define _MT2_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemConstructTechBlock2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT MEM_NB_BLOCK *NBPtr
+ );
+
+BOOLEAN
+MemTSetDramMode2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTDIMMPresence2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDCalcWidth2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDGetTargetSpeed2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTAutoCycTiming2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+MemTSPDSetBanks2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTGetCSIntLvAddr2 (
+ IN UINT8 BankEnc,
+ OUT UINT8 *LowBit,
+ OUT UINT8 *HiBit
+ );
+
+BOOLEAN
+MemTGetDimmSpdBuffer2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 **SpdBuffer,
+ IN UINT8 Dimm
+ );
+
+#endif /* _MT2_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.c
new file mode 100644
index 0000000000..4e6e5fbd92
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.c
@@ -0,0 +1,164 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtot2.c
+ *
+ * Technology Non-SPD Timings for DDR2
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 "mtot2.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR2_MTOT2_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function adjusts the Twrwr value for DDR2.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTAdjustTwrwr2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ DCT_STRUCT *DCTPtr;
+
+ DCTPtr = TechPtr->NBPtr->DCTPtr;
+
+ // For DDR2, 1 clock has encoded value of 0.
+ // Need to transfer clk value to encoded value.
+ if (DCTPtr->Timings.Twrwr >= 1) {
+ DCTPtr->Timings.Twrwr -= 1;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function adjusts the Twrrd value for DDR2.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTAdjustTwrrd2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ DCT_STRUCT *DCTPtr;
+
+ DCTPtr = TechPtr->NBPtr->DCTPtr;
+
+ // For DDR2, 1 clock has encoded value of 0.
+ // Need to transfer clk value to encoded value.
+ if (DCTPtr->Timings.Twrrd >= 1) {
+ DCTPtr->Timings.Twrrd -= 1;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function gets the LD value for DDR2
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return value of LD
+ */
+
+INT8
+MemTGetLD2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ INT8 LD;
+
+ // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
+ LD = 1;
+
+ return LD;
+}
+
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.h
new file mode 100644
index 0000000000..c2429ef656
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtot2.h
@@ -0,0 +1,90 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtot2.h
+ *
+ * Technology Non-SPD timings for DDR2
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 _MTOT2_H_
+#define _MTOT2_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+VOID
+MemTAdjustTwrwr2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+MemTAdjustTwrrd2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+INT8
+MemTGetLD2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+#endif /* _MTOT2_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.c
new file mode 100644
index 0000000000..f9aeeedb50
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.c
@@ -0,0 +1,1117 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtspd2.c
+ *
+ * Technology SPD supporting functions for DDR2
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 "AdvancedApi.h"
+#include "amdlib.h"
+#include "Ids.h"
+#include "mport.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "mu.h"
+#include "mt2.h"
+#include "mtspd2.h"
+#include "mftds.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_DDR2_MTSPD2_FILECODE
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+UINT8
+STATIC
+MemTSPDGetTCL2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+STATIC
+MemTSysCapability2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 k,
+ IN UINT16 j
+ );
+
+BOOLEAN
+STATIC
+MemTDimmSupports2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 k,
+ IN UINT8 j,
+ IN UINT8 i
+ );
+
+UINT8
+STATIC
+MemTGetTk2 (
+ IN UINT8 k
+ );
+
+UINT8
+STATIC
+MemTGetBankAddr2 (
+ IN UINT8 k
+ );
+
+/*----------------------------------------------------------------------------
+ * 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 DDR2
+ */
+
+BOOLEAN
+MemTSetDramMode2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
+ 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
+MemTDIMMPresence2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 *SpdBufferPtr;
+ MEM_PARAMETER_STRUCT *RefPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT16 Checksum;
+ UINT16 Value16;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 i;
+ UINT8 ByteNum;
+ UINT8 Devwidth;
+ UINT8 Value8;
+ UINT8 MaxDimms;
+ UINT8 DimmSlots;
+ UINT16 DimmMask;
+ BOOLEAN SPDCtrl;
+
+ 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
+ DimmSlots = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration,
+ MCTPtr->SocketId,
+ NBPtr->GetSocketRelativeChannel (NBPtr, Dct, Channel)
+ );
+ MaxDimms = MAX_DIMMS_PER_CHANNEL;
+ for (i = 0; i < MaxDimms; i++) {
+ // Bitmask representing dimm #i.
+ DimmMask = (UINT16)1 << i;
+
+ if ((ChannelPtr->DimmQrPresent & DimmMask) || (i < DimmSlots)) {
+ if (MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i)) {
+ MCTPtr->DimmPresent |= DimmMask;
+
+ // Start by computing checksum for this SPD
+ Checksum = 0;
+ for (ByteNum = 0; ByteNum < SPD_CHECKSUM; ByteNum++) {
+ Checksum = Checksum + (UINT16) SpdBufferPtr[ByteNum];
+ }
+ // Check for valid checksum value
+ AGESA_TESTPOINT (TpProcMemSPDChecking, &(NBPtr->MemPtr->StdHeader));
+
+ if (SpdBufferPtr[SPD_TYPE] == JED_DDR2_SDRAM) {
+ ChannelPtr->ChDimmValid |= DimmMask;
+ MCTPtr->DimmValid |= DimmMask;
+ } else {
+ // Current socket is set up to only support DDR2 dimms.
+ IDS_ERROR_TRAP;
+ }
+ if ((SpdBufferPtr[SPD_CHECKSUM] != (UINT8)Checksum) && !SPDCtrl) {
+ //
+ // if 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_REG_ADC_MSK) {
+ ChannelPtr->RegDimmPresent |= DimmMask;
+ MCTPtr->RegDimmPresent |= DimmMask;
+ }
+
+ if (SpdBufferPtr[SPD_DIMM_TYPE] & JED_SODIMM) {
+ ChannelPtr->SODimmPresent |= DimmMask;
+ }
+
+ // Check error correction type
+ if (SpdBufferPtr[SPD_EDC_TYPE] & JED_ECC) {
+ MCTPtr->DimmEccPresent |= DimmMask; // Dimm has ECC
+ }
+ if (SpdBufferPtr[SPD_EDC_TYPE] & JED_ADRC_PAR) {
+ MCTPtr->DimmParPresent |= DimmMask; // Dimm has parity
+ }
+
+ // Get the Dimm width data
+ Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0xFE;
+ if (Devwidth == 4) {
+ ChannelPtr->Dimmx4Present |= DimmMask; // Dimm has parity
+ } else if (Devwidth == 8) {
+ ChannelPtr->Dimmx8Present |= DimmMask; // Dimm has parity
+ } else if (Devwidth == 16) {
+ ChannelPtr->Dimmx16Present |= DimmMask; // Dimm has parity
+ }
+
+ // Determine the page size.
+ // page_size = 2^COLBITS * Devwidth/8
+ //
+ Value16 = (((UINT16)1 << SpdBufferPtr[SPD_COL_SZ]) * Devwidth) / 8;
+ if (!(Value16 >> 11)) {
+ DCTPtr->Timings.DIMM1KPage |= DimmMask;
+ }
+
+ // Check for 'analysis probe installed'
+ if (SpdBufferPtr[SPD_ATTRIB] & JED_PROBE_MSK) {
+ MCTPtr->Status[SbDiagClks] = TRUE;
+ }
+
+ // Determine the geometry of the DIMM module
+ if (SpdBufferPtr[SPD_DM_BANKS] & SP_DPL_BIT) {
+ ChannelPtr->DimmPlPresent |= DimmMask; // Dimm is planar
+ }
+
+ // specify the number of ranks
+ Value8 = (SpdBufferPtr[SPD_DM_BANKS] & 0x07) + 1;
+ if (Value8 > 2) {
+ if (ChannelPtr->DimmQrPresent == 0) {
+ // if any DIMMs are QR,
+ // we have to make two passes through DIMMs
+ //
+ MaxDimms = MaxDimms << 1;
+ }
+
+ if (i < DimmSlots) {
+ ChannelPtr->DimmQrPresent |= DimmMask;
+ ChannelPtr->DimmQrPresent |= (DimmMask << 2);
+ }
+ Value8 = 2;
+ } else if (Value8 == 2) {
+ ChannelPtr->DimmDrPresent |= DimmMask; // Dual 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
+ if (Value8 == 2) {
+ Devwidth = Devwidth << 1;
+ }
+
+ ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
+ ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
+ ChannelPtr->Dimms++;
+
+ // Now examine the dimm packaging dates
+ Value8 = SpdBufferPtr[SPD_MAN_DATE_YR];
+ if (Value8 < M_YEAR_06) {
+ ChannelPtr->DimmYr06 |= DimmMask; // Built before end of 2006
+ ChannelPtr->DimmWk2406 |= DimmMask; // Built before end of week 24,2006
+ } else if (Value8 == M_YEAR_06) {
+ ChannelPtr->DimmYr06 |= DimmMask; // Built before end of 2006
+ if (SpdBufferPtr[SPD_MAN_DATE_WK] <= M_WEEK_24) {
+ ChannelPtr->DimmWk2406 |= DimmMask; // Built before end of week 24,2006
+ }
+ }
+ } // if DIMM present
+ } // Quadrank
+ } // Dimm loop
+
+ if (Channel == 0) {
+ DCTPtr->Timings.DctDimmValid = ChannelPtr->ChDimmValid;
+ DCTPtr->Timings.DimmSpdCse = ChannelPtr->DimmSpdCse;
+ DCTPtr->Timings.DimmQrPresent = ChannelPtr->DimmQrPresent;
+ DCTPtr->Timings.DimmDrPresent = ChannelPtr->DimmDrPresent;
+ 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->DimmEccPresent <<= 8;
+ MCTPtr->DimmParPresent <<= 8;
+ }
+ } // Channel loop
+ } // DCT loop
+
+
+ // If we have DIMMs, some further general characteristics checking
+ if (MCTPtr->DimmValid) {
+ // If there are registered dimms, all the dimms must be registered
+ if (MCTPtr->RegDimmPresent == MCTPtr->DimmValid) {
+ // All dimms registered
+ MCTPtr->Status[SbRegistered] = TRUE;
+ } else if (MCTPtr->RegDimmPresent) {
+ // 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
+ }
+
+ // check the parity capability of the DIMMs
+ if (MCTPtr->DimmParPresent == MCTPtr->DimmValid) {
+ MCTPtr->Status[SbParDimms] = TRUE; // All dimms parity capable
+ }
+ } else {
+ }
+
+ NBPtr->SwitchDCT (NBPtr, 0);
+ NBPtr->SwitchChannel (NBPtr, 0);
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the best T and CL primary timing parameter pair, per Mfg.,for the given
+ * set of DIMMs, and store into DIE_STRUCT(.Speed and .Casl).
+ * See "Global relationship between index values and item values" for definition of
+ * CAS latency index (j) and Frequency index (k).
+ *
+ * @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
+MemTSPDGetTargetSpeed2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ CONST UINT16 SpeedCvt[] = {
+ DDR400_FREQUENCY,
+ DDR533_FREQUENCY,
+ DDR667_FREQUENCY,
+ DDR800_FREQUENCY,
+ DDR1066_FREQUENCY
+ };
+ INT8 i;
+ INT8 j;
+ INT8 k;
+ INT8 Dct;
+ INT8 Channel;
+ UINT8 T1min;
+ UINT8 CL1min;
+ BOOLEAN IsSupported;
+ MEM_NB_BLOCK *NBPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = TechPtr->NBPtr->MCTPtr;
+
+ CL1min = 0xFF;
+ T1min = 0xFF;
+
+ // For DDR2, run SyncTargetSpeed first to get frequency limit into DCTPtr->Timings.Speed
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ NBPtr->DCTPtr->Timings.TargetSpeed = 16; // initialized with big number
+ }
+ NBPtr->SyncTargetSpeed (NBPtr);
+
+ // Find target frequency and Tcl
+ for (k = K_MAX; k >= K_MIN; k--) {
+ for (j = J_MIN; j <= J_MAX; j++) {
+ if (MemTSysCapability2 (TechPtr, k, j)) {
+ IsSupported = TRUE;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
+ NBPtr->SwitchChannel (NBPtr, Channel);
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
+ if (ChannelPtr->ChDimmValid & ((UINT8)1 << i)) {
+ if (!MemTDimmSupports2 (TechPtr, k, j, i)) {
+ IsSupported = FALSE;
+ Dct = NBPtr->DctCount;
+ Channel = NBPtr->ChannelCount;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (IsSupported) {
+ T1min = k;
+ CL1min = j;
+ // Kill the loops...
+ k = K_MIN - 1;
+ j = J_MAX + 1;
+ }
+ }
+ }
+ }
+
+ if (T1min == 0xFF) {
+ // Failsafe values, running in minimum mode
+ PutEventLog (AGESA_FATAL, MEM_ERROR_MISMATCH_DIMM_CLOCKS, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ PutEventLog (AGESA_FATAL, MEM_ERROR_MINIMUM_MODE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+
+ T1min = T_DEF;
+ CL1min = CL_DEF;
+ }
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+ DCTPtr->Timings.TargetSpeed = SpeedCvt[T1min - 1];
+ }
+
+ // 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);
+ DCTPtr = NBPtr->DCTPtr;
+ DCTPtr->Timings.Speed = DCTPtr->Timings.TargetSpeed;
+ DCTPtr->Timings.CasL = CL1min + 2; // Convert to clocks
+ }
+
+ return (BOOLEAN) (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
+MemTSPDCalcWidth2 (
+ 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;
+ 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 (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) {
+ NBPtr->SwitchDCT (NBPtr, 0);
+ MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferAPtr, i);
+ NBPtr->SwitchDCT (NBPtr, 1);
+ MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferBPtr, i);
+
+ if ((SpdBufferAPtr[SPD_ROW_SZ]&0x1F) != (SpdBufferBPtr[SPD_ROW_SZ]&0x1F)) {
+ break;
+ }
+
+ if ((SpdBufferAPtr[SPD_COL_SZ]&0x1F) != (SpdBufferBPtr[SPD_COL_SZ]&0x1F)) {
+ break;
+ }
+
+ if (SpdBufferAPtr[SPD_BANK_SZ] != SpdBufferBPtr[SPD_BANK_SZ]) {
+ break;
+ }
+
+ if ((SpdBufferAPtr[SPD_DEV_WIDTH]&0x7F) != (SpdBufferBPtr[SPD_DEV_WIDTH]&0x7F)) {
+ break;
+ }
+
+ if ((SpdBufferAPtr[SPD_DM_BANKS]&0x07) != (SpdBufferBPtr[SPD_DM_BANKS]&0x07)) {
+ 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 if (!UngangMode) {
+ 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
+MemTAutoCycTiming2 (
+ 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
+ };
+ CONST UINT8 Multiples[] = {10, 10, 10, 40, 40, 10, 10, 10};
+
+ CONST UINT8 Tab1KTfawTK[] = {8, 10, 13, 14, 0, 20};
+ CONST UINT8 Tab2KTfawTK[] = {10, 14, 17, 18, 0, 24};
+ CONST UINT8 TabDefTrcK[] = {0x41, 0x3C, 0x3C, 0x3A, 0, 0x3A};
+
+ UINT8 MiniMaxTmg[GET_SIZE_OF (SpdIndexes)];
+ UINT8 MiniMaxTrfc[4];
+
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT16 DimmMask;
+ UINT16 Value16;
+ UINT16 Tk40;
+ UINT8 i;
+ UINT8 j;
+ UINT8 Value8;
+ UINT8 Temp8;
+ UINT8 *StatTmgPtr;
+ UINT16 *StatDimmTmgPtr;
+ BOOLEAN Is1066;
+ UINT8 *SpdBufferPtr;
+
+ 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) {
+ MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i);
+ for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
+ Value8 = SpdBufferPtr[SpdIndexes[j]];
+ if (SpdIndexes[j] == SPD_TRC) {
+ if (Value8 == 0 || Value8 == 0xFF) {
+ PutEventLog (AGESA_WARNING, MEM_WARNING_NO_SPDTRC_FOUND, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, i, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_WARNING, MCTPtr);
+ Value8 = TabDefTrcK[(DCTPtr->Timings.Speed / 66) - 3];
+ }
+ }
+ if (MiniMaxTmg[j] < Value8) {
+ MiniMaxTmg[j] = Value8;
+ }
+ }
+
+ // get Trfc0 - Trfc3 values
+ Value8 = SpdBufferPtr[SPD_BANK_SZ];
+ Temp8 = (Value8 << 3) | (Value8 >> 5);
+ Value8 = SpdBufferPtr[SPD_DEV_WIDTH];
+ ASSERT (LibAmdBitScanReverse ((UINT32)Value8) <= 4);
+ Temp8 >>= 4 - LibAmdBitScanReverse ((UINT32)Value8);
+ Value8 = LibAmdBitScanReverse ((UINT32)Temp8);
+ if (MiniMaxTrfc[i] < Value8) {
+ MiniMaxTrfc[i] = Value8;
+ }
+ }
+ DimmMask <<= 1;
+ }
+
+ // ======================================================================
+ // Convert DRAM CycleTiming values and store into DCT structure
+ // ======================================================================
+ //
+ Tk40 = 40000 / DCTPtr->Timings.Speed;
+ if (DCTPtr->Timings.Speed == DDR1066_FREQUENCY) {
+ Is1066 = TRUE;
+ } else {
+ Is1066 = FALSE;
+ }
+ // Notes:
+ // 1. All secondary time values given in SPDs are in binary with UINTs of ns.
+ // 2. Some time values are scaled by four, in order to have least count of 0.25 ns
+ // (more accuracy). JEDEC SPD spec. shows which ones are x1 and x4.
+ // 3. Internally to this SW, cycle time, Tk, is scaled by 10 to affect a
+ // least count of 0.1 ns (more accuracy).
+ // 4. SPD values not scaled are multiplied by 10 and then divided by 10T to find
+ // equivalent minimum number of bus clocks (a remainder causes round-up of clocks).
+ // 5. SPD values that are prescaled by 4 are multiplied by 10 and then divided by 40T to find
+ // equivalent minimum number of bus clocks (a remainder causes round-up of clocks).
+ //
+ StatDimmTmgPtr = &DCTPtr->Timings.DIMMTrcd;
+ StatTmgPtr = &DCTPtr->Timings.Trcd;
+ for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
+ Value16 = (UINT16)MiniMaxTmg[j] * Multiples[j];
+ StatDimmTmgPtr[j] = Value16;
+
+ MiniMaxTmg[j] = (UINT8) ((Value16 + Tk40 - 1) / Tk40);
+ if (SpdIndexes[j] == SPD_TRTP) {
+ MiniMaxTmg[j] = (DCTPtr->Timings.Speed <= DDR533_FREQUENCY) ? 2 : 3; // based on BL of 32 bytes
+ }
+
+ StatTmgPtr[j] = 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 = MemTSPDGetTCL2 (TechPtr);
+
+ if (DCTPtr->Timings.DIMM1KPage) {
+ DCTPtr->Timings.Tfaw = Tab1KTfawTK[(DCTPtr->Timings.Speed / 66) - 3];
+ } else {
+ DCTPtr->Timings.Tfaw = Tab2KTfawTK[(DCTPtr->Timings.Speed / 66) - 3];
+ }
+ if (Is1066) {
+ DCTPtr->Timings.Tfaw >>= 1;
+ }
+
+ //======================================================================
+ // 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
+MemTSPDSetBanks2 (
+ 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) {
+ 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)) {
+ MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, DimmID);
+
+ // Get the basic data
+ Rows = SpdBufferPtr[SPD_ROW_SZ] & 0x1F;
+ Cols = SpdBufferPtr[SPD_COL_SZ] & 0x1F;
+ Banks = SpdBufferPtr[SPD_L_BANKS];
+ Ranks = (SpdBufferPtr[SPD_DM_BANKS] & 0x07) + 1;
+
+ // Configure the bank encoding
+ Value8 = (Cols - 9) << 3;
+ Value8 |= (Banks == 8) ? 4 : 0;
+ Value8 |= (Rows - 13);
+
+ for (i = 0; i < 12; i++) {
+ if (Value8 == MemTGetBankAddr2 (i)) {
+ break;
+ }
+ }
+
+ if (i < 12) {
+ BankAddrReg |= ((UINT32)i << (ChipSel << 1));
+
+ // Mask value=(2pow(rows+cols+banks+3)-1)>>8,
+ // or 2pow(rows+cols+banks-5)-1
+ //
+ Value8 = Rows + Cols;
+ Value8 -= (Banks == 8) ? 2:3;
+ if (MCTPtr->Status[Sb128bitmode]) {
+ Value8++;
+ }
+ CsMask = ((UINT32)1 << Value8) - 1;
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
+
+ if (Ranks >= 2) {
+ DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
+ }
+
+ // Update the DRAM CS Mask for this chipselect
+ NBPtr->SetBitField (NBPtr, BFCSMask0Reg + (ChipSel >> 1), (CsMask & 0x1FF83FE0));
+ }
+ }
+ }
+ // 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
+MemTGetCSIntLvAddr2 (
+ IN UINT8 BankEnc,
+ OUT UINT8 *LowBit,
+ OUT UINT8 *HiBit
+ )
+{
+ CONST UINT8 ArrCodesLo[] = {6, 7, 7, 8, 8, 8, 8, 8, 9, 9, 8, 9};
+ CONST UINT8 ArrCodesHi[] = {19, 20, 21, 21, 21, 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 returns the CAS latency of the current frequency.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return CAS Latency
+ */
+UINT8
+STATIC
+MemTSPDGetTCL2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return TechPtr->NBPtr->DCTPtr->Timings.CasL;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Get max frequency from OEM platform definition, from
+ * any user override (limiting) of max frequency, and
+ * from any Si Revision Specific information. Return
+ * the least of these three in DIE_STRUCT.PresetmaxFreq.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] k - Frequency index
+ * @param[in] j - CAS Latency index
+ *
+ * @return TRUE - (k << 8) | j
+ * @return FALSE - 0
+ */
+
+BOOLEAN
+STATIC
+MemTSysCapability2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 k,
+ IN UINT16 j
+ )
+{
+ if ((k > TechPtr->NBPtr->DCTPtr->Timings.TargetSpeed) || (j > J_MAX)) {
+ return FALSE;
+ }
+
+ return TRUE; //(k << 8) | j;
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Determine whether dimm(b,i) supports CL(j) and F(k)
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] k - Frequency index
+ * @param[in] j - CAS Latency index
+ * @param[in] i - DIMM number
+ *
+ * @return TRUE - DIMM supports
+ * @return FALSE - DIMM does not support
+ */
+
+BOOLEAN
+STATIC
+MemTDimmSupports2 (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 k,
+ IN UINT8 j,
+ IN UINT8 i
+ )
+{
+ CONST UINT8 SpdBytesForCL[3] = { 9, 23, 25}; // SPD bytes for CL X, CL X-.5, and CL X-1
+ UINT8 CLj;
+ UINT8 CLi;
+ UINT8 T1;
+ UINT8 T2;
+ UINT8 Tk;
+ UINT8 *SpdBufferPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i);
+ CLj = (UINT8) 1 << (j + 2);
+ CLi = SpdBufferPtr[SPD_CAS_LAT];
+
+ if (CLj & CLi) {
+ // If this dimm supports the desired CAS latency...
+ // Determine the SPD location of the dimm speed UINT8 appropriate
+ // to the CAS latency indicated by Table_CL2_j.
+ //
+ T1 = LibAmdBitScanReverse ((UINT32)CLj);
+ T2 = LibAmdBitScanReverse ((UINT32)CLi);
+ ASSERT ((T2 - T1) < 3);
+ CLi = SpdBufferPtr[SpdBytesForCL[(T2 - T1)]];
+ Tk = MemTGetTk2 (k);
+ if (CLi == 0) {
+ PutEventLog (AGESA_FATAL, MEM_ERROR_NO_CYC_TIME, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_WARNING, NBPtr->MCTPtr);
+ } else if (Tk >= CLi) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns the cycle time
+ *
+ * @param[in] k - CAS Latency index
+ *
+ * @return Tk as specified by JEDEC SPD byte 9.
+ */
+
+UINT8
+STATIC
+MemTGetTk2 (
+ IN UINT8 k
+ )
+{
+ CONST UINT8 TableTK[] = {0x00, 0x50, 0x3D, 0x30, 0x25, 0x18};
+ ASSERT (k < GET_SIZE_OF (TableTK));
+ return TableTK[k];
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function returns the encoded value of bank address.
+ *
+ * @param[in] k value
+ *
+ * @return 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.
+ */
+
+UINT8
+STATIC
+MemTGetBankAddr2 (
+ IN UINT8 k
+ )
+{
+ CONST UINT8 TabBankAddr[] = {
+ 0x00, 0x08, 0x09, 0x10, 0x0C, 0x0D,
+ 0x11, 0x0E, 0x15, 0x16, 0x0F, 0x17
+ };
+ ASSERT (k < GET_SIZE_OF (TabBankAddr));
+ return TabBankAddr[k];
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * 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
+MemTGetDimmSpdBuffer2 (
+ 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/Proc/Mem/Tech/DDR2/mtspd2.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.h
new file mode 100644
index 0000000000..b1cdf48017
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR2/mtspd2.h
@@ -0,0 +1,184 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtspd2.h
+ *
+ * Technology SPD support for DDR2
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech/DDR2)
+ * @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 _MTSPD2_H_
+#define _MTSPD2_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*===============================================================================
+ * Jedec DDR II
+ *===============================================================================
+ */
+#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 SPD_DIMM_TYPE 20
+#define SPD_ATTRIB 21
+#define JED_DIF_CK_MSK 0x20 /* Differential Clock Input */
+#define JED_REG_ADC_MSK 0x11 /* Registered Address/Control */
+#define JED_PROBE_MSK 0x40 /* Analysis Probe installed */
+#define JED_SODIMM 0x04 /* SO-DIMM */
+#define SPD_DEV_ATTRIB 22
+#define SPD_EDC_TYPE 11
+#define JED_ECC 2
+#define JED_ADRC_PAR 4
+#define SPD_ROW_SZ 3
+#define SPD_COL_SZ 4
+#define SPD_L_BANKS 17 /* number of [logical] banks on each device */
+#define SPD_DM_BANKS 5 /* number of physical banks on dimm */
+#define SP_DPL_BIT 4 /* Dram package bit */
+#define SPD_BANK_SZ 31 /* capacity of physical bank */
+#define SPD_DEV_WIDTH 13
+#define SPD_CAS_LAT 18
+#define SPD_TRP 27
+#define SPD_TRRD 28
+#define SPD_TRCD 29
+#define SPD_TRAS 30
+#define SPD_TWR 36
+#define SPD_TWTR 37
+#define SPD_TRTP 38
+#define SPD_TRC 41
+#define SPD_TRFC 42
+#define SPD_CHECKSUM 63
+#define SPD_MAN_DATE_YR 93 /* Module Manufacturing Year (BCD) */
+
+#define SPD_MAN_DATE_WK 94 /* Module Manufacturing Week (BCD) */
+
+/*-----------------------------
+ * Jedec DDR II related equates
+ *-----------------------------
+ */
+#define M_YEAR_06 0x06 /* Manufacturing Year BCD encoding of 2006 - 06d */
+#define M_WEEK_24 0x24 /* Manufacturing Week BCD encoding of June - 24d */
+
+#define J_MIN 0 /* j loop constraint. 1=CL 2.0 T */
+#define J_MAX 5 /* j loop constraint. 5=CL 7.0 T */
+#define K_MIN 1 /* k loop constraint. 1=200 MHz */
+#define K_MAX 5 /* k loop constraint. 5=533 MHz */
+#define CL_DEF 2 /* Default value for failsafe operation. 2=CL 4.0 T */
+#define T_DEF 1 /* Default value for failsafe operation. 1=5ns (cycle time) */
+
+
+#define BIAS_TCL_T 1
+#define BIAS_TRP_T 3 /* bias to convert bus clocks to bit field value */
+#define BIAS_TRRD_T 2
+#define BIAS_TRCD_T 3
+#define BIAS_TRAS_T 3
+#define BIAS_TRC_T 11
+#define BIAS_TRTP_T 1
+#define BIAS_TWR_T 3
+#define BIAS_TWTR_T 0
+#define BIAS_TFAW_T 7
+
+#define MIN_TRP_T 3 /* min programmable value in busclocks */
+#define MAX_TRP_T 6 /* max programmable value in busclocks */
+#define MIN_TRRD_T 2
+#define MAX_TRRD_T 5
+#define MIN_TRCD_T 3
+#define MAX_TRCD_T 6
+#define MIN_TRAS_T 5
+#define MAX_TRAS_T 18
+#define MIN_TRC_T 11
+#define MAX_TRC_T 26
+#define MIN_TRTP_T 2
+#define MAX_TRTP_T 4
+#define MIN_TWR_T 3
+#define MAX_TWR_T 6
+#define MIN_TWTR_T 1
+#define MAX_TWTR_T 3
+
+/* DDR2-1066 support */
+#define BIAS_TRCD_T_1066 5
+#define BIAS_TRAS_T_1066 15
+#define BIAS_TRRD_T_1066 4
+#define BIAS_TWR_T_1066 4
+#define BIAS_TRP_T_1066 5
+#define BIAS_TWTR_T_1066 4
+
+#define MIN_TRCD_T_1066 5
+#define MAX_TRCD_T_1066 12
+#define MIN_TRAS_T_1066 15
+#define MAX_TRAS_T_1066 30
+#define MIN_TRC_T_1066 11
+#define MAX_TRC_T_1066 42
+#define MIN_TRRD_T_1066 4
+#define MAX_TRRD_T_1066 7
+#define MIN_TWR_T_1066 5
+#define MAX_TWR_T_1066 8
+#define MIN_TRP_T_1066 5
+#define MAX_TRP_T_1066 12
+#define MIN_TWTR_T_1066 4
+#define MAX_TWTR_T_1066 7
+
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+#endif /* _MTSPD2_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mt3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mt3.c
new file mode 100644
index 0000000000..b1ab754103
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mt3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mt3.h
new file mode 100644
index 0000000000..6769da03ab
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtlrdimm3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtlrdimm3.c
new file mode 100644
index 0000000000..4775def8a2
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtlrdimm3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtlrdimm3.h
new file mode 100644
index 0000000000..ebbec4782a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtot3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtot3.c
new file mode 100644
index 0000000000..2163ccf919
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtot3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtot3.h
new file mode 100644
index 0000000000..8cdb9be480
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtrci3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtrci3.c
new file mode 100644
index 0000000000..106f501948
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtrci3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtrci3.h
new file mode 100644
index 0000000000..d5fdfeec7f
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtsdi3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtsdi3.c
new file mode 100644
index 0000000000..48dc007b10
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtsdi3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtsdi3.h
new file mode 100644
index 0000000000..5715a22d27
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtspd3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtspd3.c
new file mode 100644
index 0000000000..c2f93724f8
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mtspd3.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mtspd3.h
new file mode 100644
index 0000000000..97f768335c
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mttecc3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mttecc3.c
new file mode 100644
index 0000000000..5f948733a7
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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/Proc/Mem/Tech/DDR3/mttwl3.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/DDR3/mttwl3.c
new file mode 100644
index 0000000000..34e0927640
--- /dev/null
+++ b/src/vendorcode/amd/agesa/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);
+}
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mt.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mt.c
new file mode 100644
index 0000000000..70fa03974a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mt.c
@@ -0,0 +1,264 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mt.c
+ *
+ * Common Technology file
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @e \$Revision: 36981 $ @e \$Date: 2010-08-27 23:21:43 +0800 (Fri, 27 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 "amdlib.h"
+#include "mport.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_MT_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemTDefaultTechnologyHook (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ );
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function is the default return for non-training technology features
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ */
+BOOLEAN
+MemTFeatDef (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the TestFail bit for all CS that fail training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ */
+VOID
+MemTMarkTrainFail (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 Dct;
+ UINT8 ChipSel;
+
+ NBPtr = TechPtr->NBPtr;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct ++) {
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ NBPtr->DCTPtr->Timings.CsEnabled &= ~NBPtr->DCTPtr->Timings.CsTrainFail;
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel ++) {
+ if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16)1 << ChipSel)) != 0) {
+ NBPtr->SetBitField (NBPtr, (BFCSBaseAddr0Reg + ChipSel), (UINT32)1 << BFTestFail);
+ }
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the initial controller environment before training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTBeginTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ S_UINT64 SMsr;
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+
+ LibAmdReadCpuReg (CR4_REG, &TechPtr->CR4reg);
+ LibAmdWriteCpuReg (CR4_REG, TechPtr->CR4reg | ((UINT32)1 << 9)); // enable SSE2
+
+ LibAmdMsrRead (HWCR, (UINT64 *) (&SMsr), &MemPtr->StdHeader); // HWCR
+ TechPtr->HwcrLo = SMsr.lo;
+ SMsr.lo |= 0x00020000; // turn on HWCR.wrap32dis
+ SMsr.lo &= 0xFFFF7FFF; // turn off HWCR.SSEDIS
+ LibAmdMsrWrite (HWCR, (UINT64 *) (&SMsr), &MemPtr->StdHeader);
+
+ TechPtr->DramEcc = (UINT8) NBPtr->GetBitField (NBPtr, BFDramEccEn);
+ NBPtr->SetBitField (NBPtr, BFDramEccEn, 0); // Disable ECC
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the final controller environment after training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTEndTraining (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ S_UINT64 SMsr;
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+
+ LibAmdWriteCpuReg (CR4_REG, TechPtr->CR4reg);
+
+ LibAmdMsrRead (HWCR, (UINT64 *)&SMsr, &MemPtr->StdHeader);
+ SMsr.lo = TechPtr->HwcrLo;
+ LibAmdMsrWrite (HWCR, (UINT64 *)&SMsr, &MemPtr->StdHeader);
+
+ NBPtr->SetBitField (NBPtr, BFDramEccEn, TechPtr->DramEcc);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets all the bytelanes/nibbles to the same delay value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dly - Delay value to set
+ *
+ */
+
+VOID
+MemTSetDQSDelayAllCSR (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dly
+ )
+{
+ UINT8 i;
+ UINT8 MaxBytelanes;
+ MaxBytelanes = (TechPtr->NBPtr->MCTPtr->Status[SbEccDimms] && TechPtr->NBPtr->IsSupported[EccByteTraining]) ? 9 : 8;
+
+ for (i = 0; i < MaxBytelanes; i++) {
+ TechPtr->SetDQSDelayCSR (TechPtr, i, Dly);
+ }
+}
+/*-----------------------------------------------------------------------------
+ *
+ *
+ * This function is used to intialize common technology functions
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * ----------------------------------------------------------------------------
+ */
+VOID
+MemTCommonTechInit (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 i;
+ for (i = 0; i < NumberOfTechHooks; i++) {
+ TechPtr->TechnologySpecificHook[i] = MemTDefaultTechnologyHook;
+ }
+}
+/*-----------------------------------------------------------------------------
+ *
+ *
+ * This function is an empty function used to intialize TechnologySpecificHook array
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_NB_BLOCK
+ * @param[in,out] OptParam - Optional parameter
+ *
+ * @return FALSE - always
+ * ----------------------------------------------------------------------------
+ */
+BOOLEAN
+STATIC
+MemTDefaultTechnologyHook (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT VOID *OptParam
+ )
+{
+ return FALSE;
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mthdi.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mthdi.c
new file mode 100644
index 0000000000..0a95b9ba32
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mthdi.c
@@ -0,0 +1,127 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mthdi.c
+ *
+ * Common technology hardware dram init support functions
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTHDI_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initiates Hardware based dram initialization for both DCTs
+ * at the same time.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTDramInitHw (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+
+ NBPtr->BrdcstSet (NBPtr, BFInitDram, 1);
+ // Phy fence training
+ 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);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.c
new file mode 100644
index 0000000000..f87ebb1cee
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.c
@@ -0,0 +1,896 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttEdgeDetect.c
+ *
+ * DQS R/W position training utilizing Data Eye Edge Detection for optimization
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @e \$Revision: 37555 $ @e \$Date: 2010-09-08 02:17:18 +0800 (Wed, 08 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 "amdlib.h"
+#include "AdvancedApi.h"
+#include "GeneralServices.h"
+#include "Ids.h"
+#include "heapManager.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mt.h"
+#include "mport.h"
+#include "mttEdgeDetect.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTEDGEDETECT_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+#define LAST_DELAY (-128)
+#define INC_DELAY 1
+#define DEC_DELAY 0
+
+
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/**
+ * Sweep Table For Byte Training without insertion delay
+ *
+*/
+DQS_POS_SWEEP_TABLE SweepTableByte[] =
+{
+ // Begin End Inc/Dec Step EndResult Edge
+ { 0x00, 0x1F, INC_DELAY, 4, 0xFFFF, LEFT_EDGE}, /// For Left Edge, start from 0 and Increment to 0x1F by 4 until all PASS
+ { LAST_DELAY, 0x00, DEC_DELAY, -1, 0xFE00, LEFT_EDGE}, /// Then go back down to 0x00 by 1 until all FAIL
+ { 0x1F, 0x00, DEC_DELAY, -4, 0xFFFF, RIGHT_EDGE}, /// For Right Edge, start from 0x1F down to 0 until all PASS.
+ { LAST_DELAY, 0x1F, INC_DELAY, 1, 0xFE00, RIGHT_EDGE} /// Then go back up by 1 until all FAIL.
+};
+/**
+ * Sweep Table For Byte Training with insertion delay
+ *
+*/
+DQS_POS_SWEEP_TABLE InsSweepTableByte[] =
+{
+ // Begin End Inc/Dec Step EndResult Edge
+ { 0x00, -0x20, DEC_DELAY, -4, 0xFE00, LEFT_EDGE}, /// For Left Edge, start from 0 and Decrement to -0x20 by -4 until all FAIL
+ { LAST_DELAY, 0x1F, INC_DELAY, 1, 0xFFFF, LEFT_EDGE}, /// Then go back up to 0x1F by 1 until all PASS
+ { 0x1F, 0x00, DEC_DELAY, -4, 0xFFFF, RIGHT_EDGE}, /// For Right Edge, start from 0x1F down to 0 until all PASS.
+ { LAST_DELAY, 0x1F, INC_DELAY, 1, 0xFE00, RIGHT_EDGE} /// Then go back up by 1 until all FAIL.
+};
+
+BOOLEAN
+STATIC
+MemTTrainDQSRdWrEdgeDetect (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+STATIC
+MemTTrainDQSEdgeDetect (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+BOOLEAN
+STATIC
+MemTInitTestPatternAddress (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ );
+
+BOOLEAN
+STATIC
+MemTContinueSweep (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ );
+
+BOOLEAN
+STATIC
+MemTSetNextDelay (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ );
+
+UINT8
+STATIC
+MemTScaleDelayVal (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN INT8 Delay
+ );
+
+VOID
+STATIC
+MemTDataEyeSave (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr,
+ IN UINT8 ByteLane
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes DQS position training for all a Memory channel using
+ * the Edge Detection algorithm.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+BOOLEAN
+MemTTrainDQSEdgeDetectSw (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ BOOLEAN Status;
+
+ Status = FALSE;
+ NBPtr = TechPtr->NBPtr;
+ TechPtr->TrainingType = TRN_DQS_POSITION;
+ //
+ // Initialize the Pattern
+ //
+ if (AGESA_SUCCESS == NBPtr->TrainingPatternInit (NBPtr)) {
+ //
+ // Setup hardware training engine (if applicable)
+ //
+ NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType);
+ //
+ // Start Edge Detection
+ //
+ Status |= MemTTrainDQSRdWrEdgeDetect (TechPtr);
+ //
+ // Finalize the Pattern
+ //
+ Status &= (AGESA_SUCCESS == NBPtr->TrainingPatternFinalize (NBPtr));
+ }
+ return Status;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This Executes Read DQS and Write Data Position training on a chip select pair
+ * using the Edge Detection algorithm.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No Errors occurred
+ * @return FALSE - Errors occurred
+
+ */
+
+BOOLEAN
+STATIC
+MemTTrainDQSRdWrEdgeDetect (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_DATA_STRUCT *MemPtr;
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 WrDqDelay;
+ UINT8 Dct;
+ UINT8 CSPerChannel;
+ UINT8 CsPerDelay;
+ UINT8 ChipSel;
+ UINT8 i;
+ BOOLEAN Status;
+ UINT8 TimesFail;
+ UINT8 TimesRetrain;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ TimesRetrain = DEFAULT_TRAINING_TIMES;
+ IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
+ //
+ // Set environment settings before training
+ //
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Read/Write Data Eye Edge Detection.\n");
+ MemTBeginTraining (TechPtr);
+ //
+ // Do Rd DQS /Wr Data Position training for all Dcts/Chipselects
+ //
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ //
+ // Chip Select Loop
+ //
+ CSPerChannel = NBPtr->CSPerChannel (NBPtr);
+ CsPerDelay = NBPtr->CSPerDelay (NBPtr);
+ for (ChipSel = 0; ChipSel < CSPerChannel; ChipSel = ChipSel + CsPerDelay ) {
+ //
+ // Init Bit Error Masks
+ //
+ LibAmdMemFill (&NBPtr->ChannelPtr->FailingBitMask[ (ChipSel * MAX_BYTELANES_PER_CHANNEL) ],
+ 0xFF,
+ (MAX_BYTELANES_PER_CHANNEL * CsPerDelay),
+ &MemPtr->StdHeader);
+ if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) != 0) {
+ TechPtr->ChipSel = ChipSel;
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tIncrease WrDat, Train RdDqs:\n");
+
+ TechPtr->DqsRdWrPosSaved = 0;
+ //
+ // Use a list of Approximate Write Data delay values and train Read DQS Position for
+ // each until a valid Data eye is found.
+ //
+ Status = FALSE;
+ TimesFail = 0;
+ ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain) {
+ i = 0;
+ while (NBPtr->GetApproximateWriteDatDelay (NBPtr, i, &WrDqDelay)) {
+ TechPtr->SmallDqsPosWindow = FALSE;
+ //
+ // Set Write Delay approximation
+ //
+ TechPtr->Direction = DQS_WRITE_DIR;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrite Delay: %02x", WrDqDelay);
+ MemTSetDQSDelayAllCSR (TechPtr, WrDqDelay);
+ //
+ // Attempt Read Training
+ //
+ TechPtr->Direction = DQS_READ_DIR;
+ if (MemTTrainDQSEdgeDetect (TechPtr)) {
+ //
+ // If Read DQS Training was successful, Train Write Data (DQ) Position
+ //
+ TechPtr->DqsRdWrPosSaved = 0;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tTrain WrDat:\n\n");
+ TechPtr->Direction = DQS_WRITE_DIR;
+ Status = MemTTrainDQSEdgeDetect (TechPtr);
+ break;
+ }
+ i++;
+ }
+ ERROR_HANDLE_RETRAIN_END ((Status == FALSE), TimesFail)
+ }
+ //
+ // If we went through the table, Fail.
+ //
+ if (Status == FALSE) {
+ // On training failure, check and record whether training fails due to small window or no window
+ if (TechPtr->SmallDqsPosWindow) {
+ NBPtr->MCTPtr->ErrStatus[EsbSmallDqs] = TRUE;
+ } else {
+ NBPtr->MCTPtr->ErrStatus[EsbNoDqsPos] = TRUE;
+ }
+
+ SetMemError (AGESA_ERROR, NBPtr->MCTPtr);
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ PutEventLog (AGESA_ERROR, MEM_ERROR_NO_DQS_POS_RD_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ } else {
+ PutEventLog (AGESA_ERROR, MEM_ERROR_NO_DQS_POS_WR_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ }
+ NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << ChipSel;
+ // If the even chip select failed training always fail the odd, if present.
+ if ((ChipSel & 0x01) == 0) {
+ if (NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << (ChipSel + 1))) {
+ NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << (ChipSel + 1);
+ }
+ }
+ NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, NBPtr->DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader);
+ }
+ } else {
+ //
+ // Clear Bit Error Masks if these CS will not be trained.
+ //
+ LibAmdMemFill (&NBPtr->ChannelPtr->FailingBitMask[ (ChipSel * MAX_BYTELANES_PER_CHANNEL) ],
+ 0x00,
+ (MAX_BYTELANES_PER_CHANNEL * CsPerDelay),
+ &NBPtr->MemPtr->StdHeader);
+ }
+ }
+ }
+ //
+ // Restore environment settings after training
+ //
+ MemTEndTraining (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "End Read/Write Data Eye Edge Detection\n\n");
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes DQS position training for both read and write, using
+ * the Edge Detection Algorithm. This method searches for the beginning and end
+ * of the Data Eye with out scanning every DSQ delay value. The following is a
+ * detailed description of the algorithm:
+ *
+ * Four-Stage Data Eye Sweep
+ *
+ * -Search starts at Delay value of 0.
+ * -Search left in steps of 4/32UI looking for all Byte lanes Passing. Left from zero rolls over to a negative value.
+ * -Negative values are translated to the high end of the delay range, but using Insertion delay comparison.
+ * -For each passing byte lane, freeze delay at first passing value, but set mask so next steps will not compare for byte lanes that previously passed
+ * -Switch to search right in steps of 1/32UI looking for fail.
+ * -For each lane, starting delay for 1/32 sweep right is first passing delay from 4/32 sweep left.
+ * -For each failing byte lane, freeze delay at first failing value, but set mask so next steps will not compare for byte lanes that previously failed
+ * -Search right until all byte lanes have failed
+ * -For each lane, right edge used by BIOS will be first failing delay value minus 1/32
+
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - All bytelanes pass
+ * @return FALSE - Some bytelanes fail
+*/
+BOOLEAN
+STATIC
+MemTTrainDQSEdgeDetect (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ DIE_STRUCT *MCTPtr;
+ DQS_POS_SWEEP_TABLE *SweepTablePtr;
+ UINT8 SweepTableSize;
+ SWEEP_INFO SweepData;
+ BOOLEAN Status;
+ UINT16 CurrentResult;
+ UINT16 AlignedResult;
+ UINT16 OffsetResult;
+ UINT8 StageIndex;
+ UINT8 CsIndex;
+ UINT8 CsPerDelay;
+ UINT8 i;
+
+ Status = TRUE;
+ //
+ // Initialize Object Pointers
+ //
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ //
+ /// Get Pointer to Sweep Table
+ //
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ SweepTablePtr = InsSweepTableByte;
+ SweepTableSize = GET_SIZE_OF (InsSweepTableByte);
+ } else {
+ SweepTablePtr = SweepTableByte;
+ SweepTableSize = GET_SIZE_OF (SweepTableByte);
+ }
+ //
+ // Get number of CS to train
+ //
+ CsPerDelay = NBPtr->CSPerDelay (NBPtr);
+ //
+ /// Set up the test Pattern, exit if no Memory
+ //
+ if (MemTInitTestPatternAddress (TechPtr, &SweepData) == FALSE) {
+ LibAmdMemFill (&NBPtr->ChannelPtr->FailingBitMask[ (TechPtr->ChipSel * MAX_BYTELANES_PER_CHANNEL) ],
+ 0,
+ (MAX_BYTELANES_PER_CHANNEL * CsPerDelay),
+ &NBPtr->MemPtr->StdHeader);
+ return FALSE;
+ }
+ //
+ // Clear Error Flag
+ //
+ SweepData.Error = FALSE;
+ //
+ /// Process Sweep table, using entries from the table to determine Starting and Ending Delays
+ /// as well as the Step size and criteria for evaluating whether the correct result is found.
+ ///
+ /// Delay values at this level are an abstract range of values which gets scaled to the actual value
+ /// before it is written to the hardware. This allows NB specific code to handle the scaling as a
+ /// function of frequency or other conditions.
+ //
+ for (StageIndex = 0; (StageIndex < SweepTableSize) && (SweepData.Error == FALSE); StageIndex++) {
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSTAGE: %d\t", StageIndex);
+ //
+ /// Initialize SweepData variables
+ //
+ SweepData.BeginDelay = SweepTablePtr->BeginDelay;
+ SweepData.EndDelay = SweepTablePtr->EndDelay;
+ SweepData.Step = 0; /// Step Value will be 0 to start.
+ SweepData.EndResult = SweepTablePtr->EndResult;
+ if (!(MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining])) {
+ SweepData.EndResult |= 0x0100;
+ }
+ SweepData.Edge = SweepTablePtr->MinMax;
+ SweepData.InsertionDelayMsk = 0;
+ SweepData.ResultFound = 0x0000;
+ //
+ // Set Training Delays Pointer.
+ //
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ SweepData.TrnDelays = (INT8 *) ((SweepData.Edge == RIGHT_EDGE) ? NBPtr->ChannelPtr->RdDqsMaxDlys : NBPtr->ChannelPtr->RdDqsMinDlys);
+ } else {
+ SweepData.TrnDelays = (INT8 *) ((SweepData.Edge == RIGHT_EDGE) ? NBPtr->ChannelPtr->WrDatMaxDlys : NBPtr->ChannelPtr->WrDatMinDlys);
+ };
+ //
+ /// Set initial TrnDelay Values if necessary
+ //
+ IDS_HDT_CONSOLE (MEM_FLOW, "Sweeping %s DQS, %s from ", (TechPtr->Direction == DQS_READ_DIR) ?"Read":"Write", (SweepTablePtr->ScanDir == INC_DELAY) ? "incrementing":"decrementing");
+ if (SweepData.BeginDelay != LAST_DELAY) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%02x", (UINT16) MemTScaleDelayVal (TechPtr, SweepData.BeginDelay));
+ for (i = 0; i < ((MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); i++) {
+ SweepData.TrnDelays[i] = SweepData.BeginDelay;
+ }
+ } else {
+ IDS_HDT_CONSOLE (MEM_FLOW, "Current Delay");
+ SweepData.Step = SweepTablePtr->Step;
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, " by %02x, until all bytelanes %s.\n\n", (UINT16) MemTScaleDelayVal (TechPtr, ABS (SweepTablePtr->Step)), (SweepData.EndResult == 0xFFFF)?"PASS":"FAIL");
+
+ //-------------------------------------------------------------------
+ // Sweep DQS Delays
+ // MemTContinueSweep function returns false to break out of loop.
+ // There are no other breaks out of this loop.
+ //-------------------------------------------------------------------
+ while (MemTContinueSweep (TechPtr, &SweepData)) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tByte Lane : 08 07 06 05 04 03 02 01 00\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tDQS Delays : %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[8]),
+ (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[7]), (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[6]),
+ (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[5]), (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[4]),
+ (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[3]), (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[2]),
+ (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[1]), (UINT16) MemTScaleDelayVal (TechPtr, SweepData.TrnDelays[0])
+ );
+ //
+ /// Set Step Value
+ //
+ SweepData.Step = SweepTablePtr->Step;
+ CurrentResult = 0xFFFF;
+ //
+ /// Chip Select Loop: Test the Pattern for all populated CS that are controlled by the current delay registers
+ //
+ for (CsIndex = 0; CsIndex < CsPerDelay ; CsIndex++, TechPtr->ChipSel++) {
+ ASSERT (CsIndex < MAX_CS_PER_CHANNEL);
+ ASSERT (TechPtr->ChipSel < MAX_CS_PER_CHANNEL);
+ if (SweepData.CsAddrValid[CsIndex] == TRUE) {
+ //
+ /// If this is a Write Dqs sweep, Write the pattern now.
+ //
+ if (TechPtr->Direction == DQS_WRITE_DIR) {
+ NBPtr->WritePattern (NBPtr, SweepData.TestAddrRJ16[CsIndex], TechPtr->PatternBufPtr, TechPtr->PatternLength);
+ }
+ //
+ /// Read the Pattern Back
+ //
+ NBPtr->ReadPattern (NBPtr, TechPtr->TestBufPtr, SweepData.TestAddrRJ16[CsIndex], TechPtr->PatternLength);
+ //
+ /// Compare the Pattern and Merge the results using InsertionDelayMsk
+ //
+ AlignedResult = NBPtr->CompareTestPattern (NBPtr, TechPtr->TestBufPtr, TechPtr->PatternBufPtr, TechPtr->PatternLength * 64);
+ CurrentResult &= AlignedResult | SweepData.InsertionDelayMsk;
+ if (SweepData.InsertionDelayMsk != 0) {
+ OffsetResult = NBPtr->InsDlyCompareTestPattern (NBPtr, TechPtr->TestBufPtr, TechPtr->PatternBufPtr, TechPtr->PatternLength * 64);
+ CurrentResult &= (OffsetResult | (~SweepData.InsertionDelayMsk));
+ }
+ //
+ /// Flush the Test Pattern
+ //
+ NBPtr->FlushPattern (NBPtr, SweepData.TestAddrRJ16[CsIndex], TechPtr->PatternLength);
+ NBPtr->FamilySpecificHook[ResetRxFifoPtr] (NBPtr, NBPtr);
+ }
+ } /// End Chip Select Loop
+ TechPtr->ChipSel = TechPtr->ChipSel - CsIndex;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tResult : %c %c %c %c %c %c %c %c %c \n",
+ (SweepData.ResultFound & ((UINT16) 1 << (8))) ? ' ':(CurrentResult & ((UINT16) 1 << (8))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (7))) ? ' ':(CurrentResult & ((UINT16) 1 << (7))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (6))) ? ' ':(CurrentResult & ((UINT16) 1 << (6))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (5))) ? ' ':(CurrentResult & ((UINT16) 1 << (5))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (4))) ? ' ':(CurrentResult & ((UINT16) 1 << (4))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (3))) ? ' ':(CurrentResult & ((UINT16) 1 << (3))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (2))) ? ' ':(CurrentResult & ((UINT16) 1 << (2))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (1))) ? ' ':(CurrentResult & ((UINT16) 1 << (1))) ? 'P':'.',
+ (SweepData.ResultFound & ((UINT16) 1 << (0))) ? ' ':(CurrentResult & ((UINT16) 1 << (0))) ? 'P':'.'
+ );
+ //
+ /// Merge current result into cumulative result and make it positive.
+ //
+ SweepData.ResultFound |= ~(CurrentResult ^ SweepData.EndResult);
+
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tResultFound : %c %c %c %c %c %c %c %c %c \n\n",
+ (SweepData.ResultFound & ((UINT16) 1 << (8))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (7))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (6))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (5))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (4))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (3))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (2))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (1))) ? 'Y':' ',
+ (SweepData.ResultFound & ((UINT16) 1 << (0))) ? 'Y':' '
+ );
+ } /// End of Delay Sweep
+ //
+ /// Place Final delay values at last passing delay.
+ //
+ if (SweepData.ResultFound == 0xFFFF) {
+ if ( ABS (SweepData.Step) == 1) {
+ for (i = 0; i < ((MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8) ; i++) {
+ if ((SweepData.EndResult & ((UINT16) (1 << i))) == 0) {
+ SweepData.TrnDelays[i] = SweepData.TrnDelays[i] - SweepData.Step;
+ }
+ }
+ }
+ }
+ //
+ // Update Pointer to Sweep Table
+ //
+ SweepTablePtr++;
+ }///End of Edge Detect loop
+ //
+ /// If No Errors are detected, Calculate Data Eye Width and Center
+ //
+ if (SweepData.Error == FALSE) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tData Eye Results:\n\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tByte Left Right\n");
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tLane Edge Edge Width Center\n");
+ for (i = 0; i < ((MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8) ; i++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t %0d", i);
+ MemTDataEyeSave (TechPtr, &SweepData, i);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ if (SweepData.Error == TRUE) {
+ Status = FALSE;
+ }
+ }
+ } else {
+ Status = FALSE;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t--DATA EYE NOT FOUND--\n\n");
+ }
+ return Status;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * Initialize the Test Pattern Address for two chip selects and, if this
+ * is a Write Data Eye, write the initial test pattern.
+ *
+ * Test Address is stored in the Sweep info struct. If Memory is not present
+ * then return with False.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *SweepPtr - Pointer to SWEEP_INFO structure.
+ *
+ * @return BOOLEAN
+ * TRUE - Memory is present
+ * FALSE - No memory present on this Chip Select pair.
+ *
+**
+ */
+BOOLEAN
+STATIC
+MemTInitTestPatternAddress (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 ChipSel;
+ UINT8 CsPerDelay;
+ UINT8 CsIndex;
+ BOOLEAN BanksPresent;
+
+ NBPtr = TechPtr->NBPtr;
+ BanksPresent = FALSE;
+ CsPerDelay = NBPtr->CSPerDelay (NBPtr);
+ ChipSel = TechPtr->ChipSel;
+ for (CsIndex = 0; CsIndex < CsPerDelay; ChipSel++, CsIndex++, TechPtr->ChipSel++) {
+ ASSERT (CsIndex < MAX_CS_PER_CHANNEL);
+ ASSERT (ChipSel < MAX_CS_PER_CHANNEL);
+ ASSERT (TechPtr->ChipSel < MAX_CS_PER_CHANNEL);
+ //
+ /// If memory is present on this cs, get the test addr
+ //
+ if (NBPtr->GetSysAddr (NBPtr, ChipSel, &(SweepPtr->TestAddrRJ16[CsIndex]))) {
+ if (!(NBPtr->MCTPtr->Status[SbLrdimms]) || ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << (ChipSel >> 1))) != 0)) {
+ BanksPresent = TRUE;
+ SweepPtr->CsAddrValid[CsIndex] = TRUE;
+ //
+ /// If this is a Read Dqs sweep, Write the pattern now.
+ //
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\tTestAddr: %x0000\n", SweepPtr->TestAddrRJ16[CsIndex]);
+ NBPtr->WritePattern (NBPtr, SweepPtr->TestAddrRJ16[CsIndex], TechPtr->PatternBufPtr, TechPtr->PatternLength);
+ }
+ }
+ } else {
+ SweepPtr->CsAddrValid[CsIndex] = FALSE;
+ }
+ } /// End Chip Select Loop
+ TechPtr->ChipSel = TechPtr->ChipSel - CsIndex;
+ //
+ /// return FALSE if no ChipSelects present.
+ //
+ return BanksPresent;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ * Test Conditions for exiting the training loop, set the next delay value,
+ * and return status
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *SweepPtr - Pointer to SWEEP_INFO structure.
+ *
+ * @return BOOLEAN
+ * TRUE - Continue to test with next delay setting
+ * FALSE - Exit training loop. Either the result has been found or
+ * end of delay range has been reached.
+*/
+BOOLEAN
+STATIC
+MemTContinueSweep (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ )
+{
+ BOOLEAN Status;
+ Status = FALSE;
+ if (SweepPtr->ResultFound != 0xFFFF) {
+ Status = MemTSetNextDelay (TechPtr, SweepPtr);
+ }
+ return Status;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the next delay value for each bytelane that needs to
+ * be advanced. It checks the bounds of the delay to see if we are at the
+ * end of the range. If we are to close to advance a whole step value, but
+ * not at the boundary, then we set the delay to the boundary.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *SweepPtr - Pointer to SWEEP_INFO structure.
+ *
+ */
+
+BOOLEAN
+STATIC
+MemTSetNextDelay (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr
+ )
+{
+ DIE_STRUCT *MCTPtr;
+ UINT8 i;
+
+ MCTPtr = TechPtr->NBPtr->MCTPtr;
+ //
+ ///< Loop through bytelanes
+ //
+ for (i = 0; i < ((MCTPtr->Status[SbEccDimms] && TechPtr->NBPtr->IsSupported[EccByteTraining]) ? 9 : 8) ; i++) {
+ //
+ /// Skip Bytelanes that have already reached the desired result
+ //
+ if ( (SweepPtr->ResultFound & ((UINT16)1 << i)) == 0) {
+ //
+ /// If a bytelane has reached the end, flag an error and exit
+ //
+ if (SweepPtr->TrnDelays[i] == SweepPtr->EndDelay) {
+ if ((SweepPtr->EndResult & ((UINT16) (1 << i))) != 0) {
+ MCTPtr->ErrStatus[EsbNoDqsPos] = TRUE;
+ SweepPtr->Error = TRUE;
+ }
+ return FALSE;
+ }
+ //
+ /// If the Current delay value is less than a step away from EndDelay,
+ //
+ if ( ABS (SweepPtr->EndDelay - SweepPtr->TrnDelays[i]) < ABS (SweepPtr->Step)) {
+ /// set to EndDelay.
+ //
+ SweepPtr->TrnDelays[i] = SweepPtr->EndDelay;
+ } else {
+ //
+ /// Otherwise, add the step value to it
+ SweepPtr->TrnDelays[i] = SweepPtr->TrnDelays[i] + SweepPtr->Step;
+ }
+ //
+ /// Set InsertionDelayMsk bit if Delay < 0 for this bytelane
+ //
+ if (SweepPtr->TrnDelays[i] < 0) {
+ SweepPtr->InsertionDelayMsk |= ((UINT16) 1 << i);
+ } else {
+ SweepPtr->InsertionDelayMsk &= ~((UINT16) 1 << i);
+ }
+ //
+ /// Write the scaled value to the Delay Register
+ //
+ TechPtr->SetDQSDelayCSR (TechPtr, i, MemTScaleDelayVal (TechPtr, SweepPtr->TrnDelays[i]));
+ }
+ }
+ return TRUE;
+}
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function accepts a delay value in 32nd of a UI and converts it to an
+ * actual register value, taking into consideration NB type, rd/wr,
+ * and frequency.
+ *
+ * Delay = (Min + (Delay * ( (Max - Min) / TRN_DELAY_MAX) )) & Mask
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *Delay - INT8 of delay value;
+ *
+ * @return UINT8 of the adjusted delay value
+*/
+UINT8
+STATIC
+MemTScaleDelayVal (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN INT8 Delay
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ TRN_DLY_PARMS Parms;
+ TRN_DLY_TYPE DelayType;
+ UINT8 NewDelay;
+ INT8 Factor;
+ INT8 ScaledDelay;
+
+ NBPtr = TechPtr->NBPtr;
+ //
+ // Determine Delay Type, Get Delay Parameters, and return scaled Delay value
+ //
+ DelayType = (TechPtr->Direction == DQS_WRITE_DIR) ? AccessWrDatDly : AccessRdDqsDly;
+ NBPtr->GetTrainDlyParms (NBPtr, DelayType, &Parms);
+ Factor = ((Parms.Max - Parms.Min) / TRN_DELAY_MAX);
+ ScaledDelay = Delay * Factor;
+ NewDelay = (Parms.Min + ScaledDelay) & Parms.Mask;
+ return NewDelay;
+}
+
+
+
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the Center of the Data eye for the specified byte lane
+ * and stores its DQS Delay value for reference.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *SweepPtr - Pointer to SWEEP_INFO structure.
+ * @param[in] ByteLane - Bytelane number being targeted
+ *
+ */
+VOID
+STATIC
+MemTDataEyeSave (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT SWEEP_INFO *SweepPtr,
+ IN UINT8 ByteLane
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT8 EyeCenter;
+ UINT8 DlyMin;
+ UINT8 DlyMax;
+ UINT8 EyeWidth;
+ UINT8 Dimm;
+ CH_DEF_STRUCT *ChanPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChanPtr = NBPtr->ChannelPtr;
+
+ ASSERT (ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8));
+ //
+ // Calculate Data Eye edges, Width, and Center in real terms.
+ //
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ DlyMin = MemTScaleDelayVal (TechPtr, ChanPtr->RdDqsMinDlys[ByteLane]);
+ DlyMax = MemTScaleDelayVal (TechPtr, ChanPtr->RdDqsMaxDlys[ByteLane]);
+ EyeWidth = MemTScaleDelayVal (TechPtr, (ChanPtr->RdDqsMaxDlys[ByteLane] - ChanPtr->RdDqsMinDlys[ByteLane]));
+ EyeCenter = MemTScaleDelayVal (TechPtr, ((ChanPtr->RdDqsMinDlys[ByteLane] + ChanPtr->RdDqsMaxDlys[ByteLane] + 1) / 2));
+ ChanPtr->RdDqsMinDlys[ByteLane] = DlyMin;
+ ChanPtr->RdDqsMaxDlys[ByteLane] = DlyMax;
+ NBPtr->FamilySpecificHook[ForceRdDqsPhaseB] (NBPtr, &EyeCenter);
+ } else {
+ DlyMin = MemTScaleDelayVal (TechPtr, ChanPtr->WrDatMinDlys[ByteLane]);
+ DlyMax = MemTScaleDelayVal (TechPtr, ChanPtr->WrDatMaxDlys[ByteLane]);
+ EyeWidth = MemTScaleDelayVal (TechPtr, (ChanPtr->WrDatMaxDlys[ByteLane] - ChanPtr->WrDatMinDlys[ByteLane]));
+ EyeCenter = MemTScaleDelayVal (TechPtr, ((ChanPtr->WrDatMinDlys[ByteLane] + ChanPtr->WrDatMaxDlys[ByteLane] + 1) / 2));
+ ChanPtr->WrDatMinDlys[ByteLane] = DlyMin;
+ ChanPtr->WrDatMaxDlys[ByteLane] = DlyMax;
+ }
+ //
+ // Flag error for small window.
+ //
+ if (EyeWidth < MemTScaleDelayVal (TechPtr, NBPtr->MinDataEyeWidth (NBPtr))) {
+ TechPtr->SmallDqsPosWindow = TRUE;
+ SweepPtr->Error = TRUE;
+ }
+
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x %02x %02x %02x", DlyMin, DlyMax, EyeWidth, EyeCenter);
+
+ TechPtr->SetDQSDelayCSR (TechPtr, ByteLane, EyeCenter);
+ TechPtr->DqsRdWrPosSaved |= (UINT8)1 << ByteLane;
+ TechPtr->DqsRdWrPosSaved |= 0xFE00;
+
+ Dimm = (TechPtr->ChipSel / 2) * TechPtr->DlyTableWidth () + ByteLane;
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ ChanPtr->RdDqsDlys[Dimm] = EyeCenter;
+ } else {
+ ChanPtr->WrDatDlys[Dimm] = EyeCenter + ChanPtr->WrDqsDlys[Dimm];
+ }
+}
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.h b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.h
new file mode 100644
index 0000000000..73bb6301be
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttEdgeDetect.h
@@ -0,0 +1,119 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttEdgeDetect.h
+ *
+ * Technology Common Training Header file
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem)
+ * @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 _MTTEDGEDETECT_H_
+#define _MTTEDGEDETECT_H_
+
+/*----------------------------------------------------------------------------
+ * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+
+#define SCAN_LEFT 0 ///< Scan Down
+#define SCAN_RIGHT 1 ///< Scan Up
+#define LEFT_EDGE 0 ///< searching for the left edge
+#define RIGHT_EDGE 1 ///< searching for the right edge
+
+#define SweepStages 4
+#define TRN_DELAY_MAX 31 ///< Max Virtual delay value for DQS Position Training
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/**
+ * Sweep Table Structure. ROM based table defining parameters for DQS position
+ * training delay sweep.
+*/
+typedef struct {
+ INT8 BeginDelay; ///< Starting Delay Value
+ INT8 EndDelay; ///< Ending Delay Value
+ BOOLEAN ScanDir; ///< Scan Direction. 0 = down, 1 = up
+ INT8 Step; ///< Amount to increment delay value
+ UINT16 EndResult; ///< Result value to stop sweeping (to compare with failure mask)
+ BOOLEAN MinMax; ///< Flag indicating lower (left edge) or higher(right edge)
+} DQS_POS_SWEEP_TABLE;
+
+/**
+ * Sweep Information Struct - Used to track data through the DQS Delay Sweep
+ *
+*/
+typedef struct _SWEEP_INFO {
+ BOOLEAN Error; ///< Indicates an Error has been found
+ UINT32 TestAddrRJ16[MAX_CS_PER_CHANNEL]; ///< System address of chipselects RJ 16 bits (Addr[47:16])
+ BOOLEAN CsAddrValid[MAX_CS_PER_CHANNEL]; ///< Indicates which chipselects to test
+ INT8 BeginDelay; ///< Beginning Delay value (Virtual)
+ INT8 EndDelay; ///< Ending Delay value (Virtual)
+ INT8 Step; ///< Amount to Inc or Dec Virtual Delay value
+ BOOLEAN Edge; ///< Left or right edge (0 = LEFT, 1= RIGHT)
+ UINT16 EndResult; ///< Result value that will stop a Dqs Sweep
+ UINT16 InsertionDelayMsk; ///< Mask of Byte Lanes that should use ins. dly. comparison
+ UINT16 LaneMsk; ///< Mask indicating byte lanes to update
+ UINT16 ResultFound; ///< Mask indicating byte lanes where desired result was found on a sweep
+ INT8 *TrnDelays; ///< Delay Values for each byte (Virtual). Points into the delay values
+} SWEEP_INFO; ///< stored in the CH_DEF_STRUCT.
+
+/*----------------------------------------------------------------------------
+ * FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+
+#endif /* _MTTEDGEDETECT_H_ */
+
+
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttdimbt.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttdimbt.c
new file mode 100644
index 0000000000..29ba56e07a
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttdimbt.c
@@ -0,0 +1,1279 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttdimmbt.c
+ *
+ * Technology Dimm Based Training
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "GeneralServices.h"
+#include "heapManager.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTDIMBT_FILECODE
+
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+#define MAX_BYTELANES 8 /* 8 byte lanes */
+#define MAX_DELAYS 9 /* 8 data bytes + 1 ECC byte */
+#define MAX_DIMMS 4 /* 4 DIMMs per channel */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+STATIC
+MemTInitDqsPos4RcvrEnByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ );
+
+VOID
+STATIC
+MemTSetRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly
+ );
+
+VOID
+STATIC
+MemTLoadRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ );
+
+BOOLEAN
+STATIC
+MemTSaveRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly,
+ IN UINT16 CmpResultRank0,
+ IN UINT16 CmpResultRank1
+ );
+
+VOID
+STATIC
+MemTResetDctWrPtrByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ );
+
+UINT16
+STATIC
+MemTCompare1ClPatternByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Buffer[],
+ IN UINT8 Pattern[]
+ );
+
+VOID
+STATIC
+MemTSkipChipSelPass1Byte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 *ChipSelPtr
+ );
+
+VOID
+STATIC
+MemTSkipChipSelPass2Byte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 *ChipSelPtr
+ );
+
+UINT8
+STATIC
+MemTMaxByteLanesByte ();
+
+UINT8
+STATIC
+MemTDlyTableWidthByte ();
+
+VOID
+STATIC
+MemTSetDqsDelayCsrByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ByteLane,
+ IN UINT8 Dly
+ );
+
+VOID
+STATIC
+MemTDqsWindowSaveByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ByteLane,
+ IN UINT8 DlyMin,
+ IN UINT8 DlyMax
+ );
+
+BOOLEAN
+STATIC
+MemTFindMaxRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ OUT UINT8 *ChipSel
+ );
+
+UINT16
+STATIC
+MemTCompare1ClPatternOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Buffer[],
+ IN UINT8 Pattern[],
+ IN UINT8 Side,
+ IN UINT8 Receiver,
+ IN BOOLEAN Side1En
+ );
+
+VOID
+STATIC
+MemTLoadRcvrEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ );
+
+VOID
+STATIC
+MemTSetRcvrEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly
+ );
+
+VOID
+STATIC
+MemTLoadInitialRcvEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ );
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function enables byte based training if called
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+MemTDimmByteTrainInit (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 DctCount;
+ UINT8 ChannelCount;
+ DIE_STRUCT *MCTPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+
+ TechPtr->InitDQSPos4RcvrEn = MemTInitDqsPos4RcvrEnByte;
+ TechPtr->SetRcvrEnDly = MemTSetRcvrEnDlyByte;
+ TechPtr->LoadRcvrEnDly = MemTLoadRcvrEnDlyByte;
+ TechPtr->SaveRcvrEnDly = MemTSaveRcvrEnDlyByte;
+ TechPtr->SaveRcvrEnDlyFilter = MemTSaveRcvrEnDlyByteFilterOpt;
+ TechPtr->ResetDCTWrPtr = MemTResetDctWrPtrByte;
+ TechPtr->Compare1ClPattern = MemTCompare1ClPatternByte;
+ TechPtr->SkipChipSelPass1 = MemTSkipChipSelPass1Byte;
+ TechPtr->SkipChipSelPass2 = MemTSkipChipSelPass2Byte;
+ TechPtr->MaxByteLanes = MemTMaxByteLanesByte;
+ TechPtr->DlyTableWidth = MemTDlyTableWidthByte;
+ TechPtr->SetDQSDelayCSR = MemTSetDqsDelayCsrByte;
+ TechPtr->DQSWindowSave = MemTDqsWindowSaveByte;
+ TechPtr->FindMaxDlyForMaxRdLat = MemTFindMaxRcvrEnDlyByte;
+ TechPtr->Compare1ClPatternOpt = MemTCompare1ClPatternOptByte;
+ TechPtr->LoadRcvrEnDlyOpt = MemTLoadRcvrEnDlyOptByte;
+ TechPtr->SetRcvrEnDlyOpt = MemTSetRcvrEnDlyOptByte;
+ TechPtr->InitializeVariablesOpt = MemTInitializeVariablesOptByte;
+ TechPtr->GetMaxValueOpt = MemTGetMaxValueOptByte;
+ TechPtr->SetSweepErrorOpt = MemTSetSweepErrorOptByte;
+ TechPtr->CheckRcvrEnDlyLimitOpt = MemTCheckRcvrEnDlyLimitOptByte;
+ TechPtr->LoadInitialRcvrEnDlyOpt = MemTLoadInitialRcvEnDlyOptByte;
+ // Dynamically allocate buffers for storing trained timings.
+ DctCount = MCTPtr->DctCount;
+ ChannelCount = MCTPtr->DctData[0].ChannelCount;
+ AllocHeapParams.RequestedBufferSize = ((DctCount * ChannelCount) *
+ ((MAX_DIMMS * MAX_DELAYS * NUMBER_OF_DELAY_TABLES) +
+ (MAX_DELAYS * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES)
+ )
+ );
+ AllocHeapParams.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_TRN_DATA_HANDLE, MCTPtr->NodeId, 0, 0);
+ AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
+ if (HeapAllocateBuffer (&AllocHeapParams, &NBPtr->MemPtr->StdHeader) == AGESA_SUCCESS) {
+ for (Dct = 0; Dct < DctCount; Dct++) {
+ for (Channel = 0; Channel < ChannelCount; Channel++) {
+ MCTPtr->DctData[Dct].ChData[Channel].RowCount = MAX_DIMMS;
+ MCTPtr->DctData[Dct].ChData[Channel].ColumnCount = MAX_DELAYS;
+
+ MCTPtr->DctData[Dct].ChData[Channel].RcvEnDlys = (UINT16 *) AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS) * 2;
+ MCTPtr->DctData[Dct].ChData[Channel].WrDqsDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsMinDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].RdDqsMaxDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatMinDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].WrDatMaxDlys = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
+ MCTPtr->DctData[Dct].ChData[Channel].FailingBitMask = AllocHeapParams.BufferPtr;
+ AllocHeapParams.BufferPtr += (MAX_CS_PER_CHANNEL * MAX_DELAYS);
+ }
+ }
+ } else {
+ PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_DYN_STORING_OF_TRAINED_TIMINGS, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_FATAL, MCTPtr);
+ ASSERT(FALSE); // Could not dynamically allocate buffers for storing trained timings
+ }
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function initializes the DQS Positions in preparation for Receiver Enable Training.
+ * Write Position is no delay, Read Position is 1/2 Memclock delay
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ */
+
+VOID
+STATIC
+MemTInitDqsPos4RcvrEnByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dimm;
+ UINT8 ByteLane;
+ UINT8 WrDqs;
+
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ for (ByteLane = 0; ByteLane < MAX_DELAYS; ByteLane++) {
+ WrDqs = TechPtr->NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_DELAYS) + ByteLane];
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqs);
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), 0x3F);
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ * @param[in] RcvEnDly - receiver enable delay to be saved
+ */
+
+VOID
+STATIC
+MemTSetRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly
+ )
+{
+ UINT8 ByteLane;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES; ByteLane++) {
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, ByteLane), RcvEnDly);
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function loads the DqsRcvEnDly from saved data and program to additional index
+ * for DQS receiver enabled training
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ *
+ */
+
+VOID
+STATIC
+MemTLoadRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ UINT16 Saved;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ Dimm = Receiver >> 1;
+ Saved = TechPtr->DqsRcvEnSaved;
+ for (i = 0; i < MAX_BYTELANES; i++) {
+ if (Saved & 1) {
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, i),
+ ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i]);
+ }
+ Saved >>= 1;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function saves passing DqsRcvEnDly values to the stack
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ * @param[in] RcvEnDly - receiver enable delay to be saved
+ * @param[in] CmpResultRank0 - compare result for Rank 0
+ * @param[in] CmpResultRank1 - compare result for Rank 1
+ *
+ * @return TRUE - All bytelanes pass
+ * @return FALSE - Some bytelanes fail
+ */
+
+BOOLEAN
+STATIC
+MemTSaveRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly,
+ IN UINT16 CmpResultRank0,
+ IN UINT16 CmpResultRank1
+ )
+{
+ UINT8 i;
+ UINT8 Passed;
+ UINT8 Saved;
+ UINT8 Mask;
+ UINT8 Dimm;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
+
+ Saved = (UINT8) (TechPtr->DqsRcvEnSaved & Passed); //@attention - false passes filter (subject to be replaced with a better solution)
+ Dimm = Receiver >> 1;
+ Mask = 1;
+ for (i = 0; i < MAX_BYTELANES; i++) {
+ if (Passed & Mask) {
+ if (!(Saved & Mask)) {
+ ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i] = RcvEnDly + 0x20; // @attention -1 pass only
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tBL %d = %02x", i, RcvEnDly + 0x20);
+ }
+ Saved |= Mask;
+ }
+ Mask <<= 1;
+ }
+ TechPtr->DqsRcvEnSaved = Saved;
+
+ if (Saved == 0xFF) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function performs a filtering functionality and saves passing DqsRcvEnDly
+ * values to the stack
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ * @param[in] RcvEnDly - receiver enable delay to be saved
+ * @param[in] CmpResultRank0 - compare result for Rank 0
+ * @param[in] CmpResultRank1 - compare result for Rank 1
+ *
+ * @return TRUE - All bytelanes pass
+ * @return FALSE - Some bytelanes fail
+ */
+
+BOOLEAN
+MemTSaveRcvrEnDlyByteFilter (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly,
+ IN UINT16 CmpResultRank0,
+ IN UINT16 CmpResultRank1
+ )
+{
+ UINT8 i;
+ UINT8 Passed;
+ UINT8 Saved;
+ UINT8 Mask;
+ UINT8 Dimm;
+ UINT8 MaxFilterDly;
+ CH_DEF_STRUCT *ChannelPtr;
+ MEM_DCT_CACHE *DctCachePtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+ DctCachePtr = TechPtr->NBPtr->DctCachePtr;
+
+ MaxFilterDly = TechPtr->MaxFilterDly;
+ Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
+
+ Dimm = Receiver >> 1;
+ Saved = (UINT8) TechPtr->DqsRcvEnSaved;
+ Mask = 1;
+ for (i = 0; i < MAX_BYTELANES; i++) {
+ if ((Passed & Mask) != 0) {
+ DctCachePtr->RcvEnDlyCounts [i] += 1;
+ if ((Saved & Mask) == 0) {
+ ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i] = RcvEnDly + 0x20;
+ Saved |= Mask;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tBL %d = %02x", i, RcvEnDly + 0x20);
+ }
+ } else {
+ if (DctCachePtr->RcvEnDlyCounts [i] <= MaxFilterDly) {
+ DctCachePtr->RcvEnDlyCounts [i] = 0;
+ Saved &= ~Mask;
+ }
+ }
+ Mask <<= 1;
+ }
+
+ //-----------------------
+ TechPtr->DqsRcvEnSaved = (UINT16) Saved;
+
+ Saved = 0;
+ for (i = 0; i < MAX_BYTELANES; i++) {
+ if (DctCachePtr->RcvEnDlyCounts [i] >= MaxFilterDly) {
+ Saved |= (UINT8) 1 << i;
+ }
+ }
+
+ if (Saved == 0xFF) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function compares test pattern with data in buffer and return a pass/fail bitmap
+ * for 8 Bytes
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare
+ * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
+ *
+ * @return PASS - Bit map of results of comparison
+ */
+
+UINT16
+STATIC
+MemTCompare1ClPatternByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Buffer[],
+ IN UINT8 Pattern[]
+ )
+{
+ UINT16 i;
+ UINT16 j;
+ UINT16 Pass;
+ DIE_STRUCT *MCTPtr;
+
+ MCTPtr = TechPtr->NBPtr->MCTPtr;
+ if (MCTPtr->GangedMode && MCTPtr->Dct) {
+ j = 8;
+ } else {
+ j = 0;
+ }
+
+ Pass = 0xFFFF;
+ IDS_HDT_CONSOLE (MEM_FLOW, " -");
+ for (i = 0; i < 8; i++) {
+ if (Buffer[j] != Pattern[j]) {
+ // if bytelane n fails
+ Pass &= ~((UINT16)1 << (j % 8)); // clear bit n
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, " %c", (Buffer[j] == Pattern[j]) ? 'P' : '.');
+ j++;
+ }
+
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t -");
+ for (i = 0, j -= 8; i < 8; i++, j++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Buffer[j]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t -");
+ for (i = 0, j -= 8; i < 8; i++, j++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Pattern[j]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
+ );
+
+ return Pass;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * The function resets the DCT input buffer write pointer.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Chip select
+ *
+ */
+
+VOID
+STATIC
+MemTResetDctWrPtrByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ )
+{
+ UINT8 i;
+ UINT16 RcvEnDly;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ for (i = 0; i < MAX_BYTELANES; i++) {
+ RcvEnDly = (UINT16) TechPtr->NBPtr->GetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver / 2, i));
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver / 2, i), RcvEnDly);
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function skips odd chip select if training at 800MT or above.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] *ChipSelPtr - Pointer to variable contains Chip select index
+ *
+ */
+
+VOID
+STATIC
+MemTSkipChipSelPass1Byte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 *ChipSelPtr
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ // if the even chip select failed training, need to set CsTrainFail for odd chip select if present.
+ if (NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ((*ChipSelPtr) + 1))) {
+ if (NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16)1 << *ChipSelPtr)) {
+ NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << ((*ChipSelPtr) + 1);
+ NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, NBPtr->DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader);
+ }
+ }
+ (*ChipSelPtr)++;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * MemTSkipChipSelPass2Byte:
+ *
+ * This function skips odd chip select if training at 800MT or above.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in,out] *ChipSelPtr - Pointer to variable contains Chip select index
+ *
+ */
+
+VOID
+STATIC
+MemTSkipChipSelPass2Byte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN OUT UINT8 *ChipSelPtr
+ )
+{
+ if (*ChipSelPtr & 1) {
+ *ChipSelPtr = MAX_CS_PER_CHANNEL; // skip all successions
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines the maximum number of byte lanes
+ *
+ * @return Max number of Bytelanes
+ */
+
+UINT8
+STATIC
+MemTMaxByteLanesByte ()
+{
+ return MAX_BYTELANES;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function determines the width of the delay tables (eg. RcvEnDlys, WrDqsDlys,...)
+ *
+ * @return Delay table width in bytes
+ */
+
+UINT8
+STATIC
+MemTDlyTableWidthByte ()
+{
+ return MAX_DELAYS;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function writes the Delay value to a certain byte lane
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ByteLane - Bytelane number being targeted
+ * @param[in] Dly - Delay value
+ *
+ */
+
+VOID
+STATIC
+MemTSetDqsDelayCsrByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ByteLane,
+ IN UINT8 Dly
+ )
+{
+ UINT8 Reg;
+ UINT8 Dimm;
+
+ ASSERT (ByteLane <= MAX_BYTELANES);
+
+ if (!(TechPtr->DqsRdWrPosSaved & ((UINT8)1 << ByteLane))) {
+ Dimm = (TechPtr->ChipSel >> 1);
+
+ if (TechPtr->Direction == DQS_WRITE_DIR) {
+ Dly = Dly + ((UINT8) TechPtr->NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_DELAYS) + ByteLane]);
+ Reg = AccessWrDatDly;
+ } else {
+ Reg = AccessRdDqsDly;
+ }
+
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, Reg, DIMM_BYTE_ACCESS (Dimm, ByteLane), Dly);
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs the trained DQS delay for the specified byte lane
+ * and stores its DQS window for reference.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ByteLane - Bytelane number being targeted
+ * @param[in] DlyMin - Minimum delay value
+ * @param[in] DlyMax- Maximum delay value
+ *
+ */
+
+VOID
+STATIC
+MemTDqsWindowSaveByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ByteLane,
+ IN UINT8 DlyMin,
+ IN UINT8 DlyMax
+ )
+{
+ UINT8 DqsDelay;
+ UINT8 Dimm;
+ CH_DEF_STRUCT *ChanPtr;
+
+ ASSERT (ByteLane <= MAX_BYTELANES);
+ ChanPtr = TechPtr->NBPtr->ChannelPtr;
+
+ DqsDelay = ((DlyMin + DlyMax + 1) / 2) & 0x3F;
+ MemTSetDqsDelayCsrByte (TechPtr, ByteLane, DqsDelay);
+ TechPtr->DqsRdWrPosSaved |= (UINT8)1 << ByteLane;
+ TechPtr->DqsRdWrPosSaved |= 0xFF00;
+
+ Dimm = (TechPtr->ChipSel / 2) * MAX_DELAYS + ByteLane;
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ ChanPtr->RdDqsDlys[Dimm] = DqsDelay;
+ } else {
+ ChanPtr->WrDatDlys[Dimm] = DqsDelay + ChanPtr->WrDqsDlys[Dimm];
+ }
+
+ if (TechPtr->Direction == DQS_READ_DIR) {
+ ChanPtr->RdDqsMinDlys[ByteLane] = DlyMin;
+ ChanPtr->RdDqsMaxDlys[ByteLane] = DlyMax;
+ } else {
+ ChanPtr->WrDatMinDlys[ByteLane] = DlyMin;
+ ChanPtr->WrDatMaxDlys[ByteLane] = DlyMax;
+ }
+
+}
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the DIMM that has the largest receiver enable delay.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[out] *ChipSel - Pointer to the Chip select that has the largest receiver enable delay.
+ *
+ * @return TRUE - A chip select can be found.
+ * @return FALSE - A chip select cannot be found.
+ */
+
+BOOLEAN
+STATIC
+MemTFindMaxRcvrEnDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ OUT UINT8 *ChipSel
+ )
+{
+ UINT8 Dimm;
+ UINT8 ByteLane;
+ UINT16 RcvEnDly;
+ UINT16 MaxDly;
+ UINT8 MaxDlyDimm;
+ BOOLEAN RetVal;
+
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = NBPtr->ChannelPtr;
+
+ RetVal = FALSE;
+ MaxDly = 0;
+ MaxDlyDimm = 0;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16) 3 << (Dimm << 1))) == 0) {
+ // Only choose the dimm that does not fail training
+ for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
+ RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
+ if (RcvEnDly > MaxDly) {
+ MaxDly = RcvEnDly;
+ MaxDlyDimm = Dimm;
+ RetVal = TRUE;
+ }
+ }
+ }
+ }
+
+ if (NBPtr->MCTPtr->Status[Sb128bitmode] != 0) {
+ //The RcvrEnDlys of DCT1 DIMMs should also be considered while ganging.
+ NBPtr->SwitchDCT (NBPtr, 1);
+ ChannelPtr = NBPtr->ChannelPtr;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
+ RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
+ if (RcvEnDly > MaxDly) {
+ MaxDly = RcvEnDly;
+ MaxDlyDimm = Dimm;
+ }
+ }
+ }
+ NBPtr->SwitchDCT (NBPtr, 0);
+ }
+
+ TechPtr->MaxDlyForMaxRdLat = MaxDly;
+ *ChipSel = (MaxDlyDimm * 2);
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function finds the DIMM that has the largest receiver enable delay + Read DQS Delay.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[out] *ChipSel - Pointer to the Chip select that has the largest receiver enable delay
+ * + Read DQS Delay.
+ *
+ * @return TRUE - A chip select can be found.
+ * @return FALSE - A chip select cannot be found.
+ */
+
+BOOLEAN
+MemTFindMaxRcvrEnDlyRdDqsDlyByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ OUT UINT8 *ChipSel
+ )
+{
+ UINT8 Dimm;
+ UINT8 ByteLane;
+ UINT16 RcvEnDly;
+ UINT16 RdDqsDly;
+ UINT16 TotalDly;
+ UINT16 MaxDly;
+ UINT8 MaxDlyDimm;
+ BOOLEAN RetVal;
+
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = NBPtr->ChannelPtr;
+
+ RetVal = FALSE;
+ MaxDly = 0;
+ MaxDlyDimm = 0;
+ for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
+ if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16) 3 << (Dimm << 1))) == 0) {
+ // Only choose the dimm that does not fail training
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES; ByteLane++) {
+ RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
+ // Before Dqs Position Training, this value is 0. So the maximum value for
+ // RdDqsDly needs to be added later when calculating the MaxRdLatency value
+ // after RcvEnDly training but before DQS Position Training.
+ RdDqsDly = ChannelPtr->RdDqsDlys[Dimm * MAX_DELAYS + ByteLane];
+ TotalDly = RcvEnDly + (RdDqsDly >> 1);
+ if (TotalDly > MaxDly) {
+ MaxDly = TotalDly;
+ MaxDlyDimm = Dimm;
+ RetVal = TRUE;
+ }
+ }
+ }
+ }
+
+ TechPtr->MaxDlyForMaxRdLat = MaxDly;
+ *ChipSel = (MaxDlyDimm * 2);
+ return RetVal;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function compares test pattern with data in buffer and return a pass/fail bitmap
+ * for 8 Bytes for optimized receiver enable training
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare
+ * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
+ * @param[in] Side - current side being targeted
+ * @param[in] Receiver - Current receiver value
+ * @param[in] Side1En - Indicates if the second side of the DIMM is being used
+ * @return PASS - Bit map of results of comparison
+ */
+
+UINT16
+STATIC
+MemTCompare1ClPatternOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Buffer[],
+ IN UINT8 Pattern[],
+ IN UINT8 Side,
+ IN UINT8 Receiver,
+ IN BOOLEAN Side1En
+ )
+{
+ UINT16 i;
+ UINT16 j;
+ UINT16 Pass;
+ DIE_STRUCT *MCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+ MCTPtr = TechPtr->NBPtr->MCTPtr;
+
+ if (MCTPtr->GangedMode && MCTPtr->Dct) {
+ j = 8;
+ } else {
+ j = 0;
+ }
+
+ Pass = 0xFFFF;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDelay[BL] -");
+ for (i = 0; i < 8; i++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x", TechPtr->RcvrEnDlyOpt[i] & 0xFF);
+ if (Buffer[j] != Pattern[j]) {
+ // if bytelane n fails
+ Pass &= ~((UINT16)1 << (j % 8)); // clear bit n
+ TechPtr->DqsRcvEnFirstPassValOpt[i] = 0;
+ TechPtr->GetFirstPassValOpt[i] = FALSE;
+ TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
+ TechPtr->DqsRcvEnSavedOpt[i] = FALSE;
+ if (TechPtr->FilterStatusOpt[i] != DONE_FILTER) {
+ if (Side == ((Side1En ? 4 : 2) - 1)) {
+ TechPtr->RcvrEnDlyOpt[i] += FILTER_FIRST_STAGE_COUNT;
+ }
+ }
+ } else {
+ if (TechPtr->FilterSidePassCountOpt[i] == ((Side1En ? 4 : 2) - 1)) {
+ //Only apply filter if all sides have passed
+ if (TechPtr->FilterStatusOpt[i] != DONE_FILTER) {
+ if (TechPtr->GetFirstPassValOpt[i] == FALSE) {
+ // This is the first Pass, mark the start of filter check
+ TechPtr->DqsRcvEnFirstPassValOpt[i] = TechPtr->RcvrEnDlyOpt[i];
+ TechPtr->GetFirstPassValOpt[i] = TRUE;
+ TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
+ TechPtr->RcvrEnDlyOpt[i]++;
+ } else {
+ if ((TechPtr->RcvrEnDlyOpt[i] - TechPtr->DqsRcvEnFirstPassValOpt[i]) < FILTER_WINDOW_SIZE) {
+ if (TechPtr->IncBy1ForNextCountOpt[i] == FALSE) {
+ TechPtr->RcvrEnDlyOpt[i] += FILTER_SECOND_STAGE_COUNT;
+ TechPtr->IncBy1ForNextCountOpt[i] = TRUE;
+ } else {
+ TechPtr->RcvrEnDlyOpt[i]++;
+ TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
+ }
+ } else {
+ // End sweep and add offset to first pass
+ TechPtr->MaxRcvrEnDlyBlOpt[i] = TechPtr->DqsRcvEnFirstPassValOpt[i];
+ TechPtr->RcvrEnDlyOpt[i] = TechPtr->DqsRcvEnFirstPassValOpt[i] + FILTER_OFFSET_VALUE;
+ TechPtr->FilterStatusOpt[i] = DONE_FILTER;
+ TechPtr->FilterCountOpt++;
+ }
+ }
+ } else {
+ TechPtr->FilterSidePassCountOpt[i]++;
+ }
+ } else {
+ if (TechPtr->GetFirstPassValOpt[i] == FALSE) {
+ if (Side == ((Side1En ? 4 : 2) - 1)) {
+ TechPtr->RcvrEnDlyOpt[i] += FILTER_FIRST_STAGE_COUNT;
+ }
+ }
+ TechPtr->FilterSidePassCountOpt[i]++;
+ }
+ TechPtr->DqsRcvEnSavedOpt[i] = TRUE;
+ ChannelPtr->RcvEnDlys[(Receiver >> 1) * MAX_DELAYS + i] = TechPtr->RcvrEnDlyOpt[i];
+ }
+ if (Side == ((Side1En ? 4 : 2) - 1)) {
+ TechPtr->FilterSidePassCountOpt[i] = 0;
+ }
+ if (TechPtr->RcvrEnDlyOpt[i] >= TechPtr->RcvrEnDlyLimitOpt[i]) {
+ TechPtr->FilterCountOpt++;
+ }
+
+ j++;
+ }
+
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tPass/Fail -");
+ for (i = 0, j -= 8; i < 8; i++, j++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %c", (Buffer[j] == Pattern[j]) ? 'P' : '.');
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Measured -");
+ for (i = 0, j -= 8; i < 8; i++, j++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Buffer[j]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Expected -");
+ for (i = 0, j -= 8; i < 8; i++, j++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Pattern[j]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
+ );
+
+ return Pass;
+}
+/*-----------------------------------------------------------------------------
+ *
+ * This function initializes variables for optimized training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * ----------------------------------------------------------------------------
+ */
+VOID
+MemTInitializeVariablesOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 ByteLane;
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
+ TechPtr->RcvrEnDlyLimitOpt[ByteLane] = FILTER_MAX_REC_EN_DLY_VALUE; // @attention - limit depends on proc type
+ TechPtr->DqsRcvEnSavedOpt[ByteLane] = FALSE;
+ TechPtr->RcvrEnDlyOpt[ByteLane] = FILTER_NEW_RECEIVER_START_VALUE;
+ TechPtr->GetFirstPassValOpt[ByteLane] = FALSE;
+ TechPtr->DqsRcvEnFirstPassValOpt[ByteLane] = 0;
+ TechPtr->RevertPassValOpt[ByteLane] = FALSE;
+ TechPtr->MaxRcvrEnDlyBlOpt[ByteLane] = 0;
+ TechPtr->FilterStatusOpt[ByteLane] = START_FILTER;
+ TechPtr->FilterCountOpt = 0;
+ TechPtr->FilterSidePassCountOpt[ByteLane] = 0;
+ TechPtr->IncBy1ForNextCountOpt[ByteLane] = FALSE;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function loads the DqsRcvEnDly from saved data and program to additional index
+ * for optimized DQS receiver enabled training
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ *
+ */
+
+VOID
+STATIC
+MemTLoadRcvrEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ Dimm = Receiver >> 1;
+ for (i = 0; i < 8; i++) {
+ if (TechPtr->DqsRcvEnSavedOpt[i]) {
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, i),
+ ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i]);
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ * @param[in] RcvEnDly - receiver enable delay to be saved
+ */
+
+VOID
+STATIC
+MemTSetRcvrEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly
+ )
+{
+ UINT8 ByteLane;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+
+ for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+ if (TechPtr->FilterStatusOpt[ByteLane] != DONE_FILTER) {
+ TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, ByteLane), TechPtr->RcvrEnDlyOpt[ByteLane]);
+ }
+ }
+}
+/*-----------------------------------------------------------------------------
+ *
+ * This sets any Errors generated from Dly sweep
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] DCT - current DCT
+ * @param[in] Receiver - current receiver
+ *
+ * @return FALSE - Fatal error occurs.
+ * @return TRUE - No fatal error occurs.
+ * ----------------------------------------------------------------------------
+ */
+BOOLEAN
+MemTSetSweepErrorOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT8 Dct,
+ IN BOOLEAN ErrorCheck
+ )
+{
+ UINT8 ByteLane;
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ DCTPtr = NBPtr->DCTPtr;
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
+ if (TechPtr->RcvrEnDlyOpt[ByteLane] == TechPtr->RcvrEnDlyLimitOpt[ByteLane]) {
+ // no passing window
+ if (ErrorCheck) {
+ return FALSE;
+ }
+ PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_NO_PASSING_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ByteLane, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ }
+ if (TechPtr->RcvrEnDlyOpt[ByteLane] > (TechPtr->RcvrEnDlyLimitOpt[ByteLane] - 1)) {
+ // passing window too narrow, too far delayed
+ if (ErrorCheck) {
+ return FALSE;
+ }
+ PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_VALUE_TOO_LARGE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ByteLane, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ DCTPtr->Timings.CsTrainFail |= (UINT16) (3 << Receiver) & DCTPtr->Timings.CsPresent;
+ MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct;
+ if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, DCTPtr->Timings.CsTrainFail, &MemPtr->StdHeader)) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * This function determines the maximum receiver delay value
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @retval MaxRcvrValue - Maximum receiver delay value for all bytelanes
+ * ----------------------------------------------------------------------------
+ */
+
+UINT16
+MemTGetMaxValueOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 ByteLane;
+ UINT16 MaxRcvrValue;
+ MaxRcvrValue = 0;
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
+ if (TechPtr->MaxRcvrEnDlyBlOpt[ByteLane] > MaxRcvrValue) {
+ MaxRcvrValue = TechPtr->MaxRcvrEnDlyBlOpt[ByteLane];
+ }
+ }
+ MaxRcvrValue += FILTER_OFFSET_VALUE;
+ return MaxRcvrValue;
+}
+/*-----------------------------------------------------------------------------
+ *
+ * This function determines if the sweep loop should complete.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @retval TRUE - All bytelanes pass
+ * FALSE - Some bytelanes fail
+ * ----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemTCheckRcvrEnDlyLimitOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ if (TechPtr->FilterCountOpt >= (UINT16)MAX_CS_PER_CHANNEL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function load the result of write levelization training into RcvrEnDlyOpt,
+ * using it as the initial value for Receiver DQS training.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ */
+VOID
+STATIC
+MemTLoadInitialRcvEnDlyOptByte (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver
+ )
+{
+ UINT8 ByteLane;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
+ TechPtr->RcvrEnDlyOpt[ByteLane] = NBPtr->ChannelPtr->WrDqsDlys[((Receiver >> 1) * TechPtr->DlyTableWidth ()) + ByteLane];
+ }
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttecc.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttecc.c
new file mode 100644
index 0000000000..01d5c2913b
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttecc.c
@@ -0,0 +1,209 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttecc.c
+ *
+ * Technology ECC byte support
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTECC_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+STATIC
+MemTCalcDQSEccTmg (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Type,
+ IN OUT VOID *DlyArray
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function sets the DQS ECC timings
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTSetDQSEccTmgs (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT8 Dct;
+ UINT8 Dimm;
+ UINT8 i;
+
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ 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)1 << (Dimm * 2))) {
+ i = Dimm * TechPtr->DlyTableWidth ();
+ MemTCalcDQSEccTmg (TechPtr, Dimm, AccessRcvEnDly, &ChannelPtr->RcvEnDlys[i]);
+ MemTCalcDQSEccTmg (TechPtr, Dimm, AccessRdDqsDly, &ChannelPtr->RdDqsDlys[i]);
+ MemTCalcDQSEccTmg (TechPtr, Dimm, AccessWrDatDly, &ChannelPtr->WrDatDlys[i]);
+ }
+ }
+ }
+ }
+ }
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates the DQS ECC timings
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Dimm - Dimm number
+ * @param[in] Type - Type of DQS timing
+ * @param[in,out] *DlyArray - Pointer to the array of delays per this Dimm
+ *
+ */
+
+VOID
+STATIC
+MemTCalcDQSEccTmg (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Dimm,
+ IN UINT8 Type,
+ IN OUT VOID *DlyArray
+ )
+{
+ UINT8 i;
+ UINT8 j;
+ UINT8 Scale;
+ UINT8 EccByte;
+ UINT16 ByteiDly;
+ UINT16 BytejDly;
+ UINT16 EccDly;
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = NBPtr->ChannelPtr;
+
+ EccByte = TechPtr->MaxByteLanes ();
+ i = (UINT8) (ChannelPtr->DctEccDqsLike & 0xFF);
+ j = (UINT8) (ChannelPtr->DctEccDqsLike >> 8);
+ Scale = ChannelPtr->DctEccDqsScale;
+
+ if (Type == AccessRcvEnDly) {
+ ByteiDly = ((UINT16 *) DlyArray)[i];
+ BytejDly = ((UINT16 *) DlyArray)[j];
+ } else {
+ ByteiDly = ((UINT8 *) DlyArray)[i];
+ BytejDly = ((UINT8 *) DlyArray)[j];
+ }
+
+ if (BytejDly > ByteiDly) {
+ EccDly = ByteiDly + (UINT8) (((UINT16) (BytejDly - ByteiDly) * Scale + 0x77) / 0xFF);
+ // Round up --^
+ } else {
+ EccDly = BytejDly + (UINT8) (((UINT16) (ByteiDly - BytejDly) * (0xFF - Scale) + 0x77) / 0xFF);
+ // Round up --^
+ }
+
+ if (Type == AccessRcvEnDly) {
+ ((UINT16 *) DlyArray)[EccByte] = EccDly;
+ } else {
+ ((UINT8 *) DlyArray)[EccByte] = (UINT8) EccDly;
+ }
+ NBPtr->SetTrainDly (NBPtr, Type, DIMM_BYTE_ACCESS (Dimm, EccByte), EccDly);
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mtthrc.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mtthrc.c
new file mode 100644
index 0000000000..ecfa3db88f
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mtthrc.c
@@ -0,0 +1,306 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mtthrc.c
+ *
+ * Phy assisted DQS receiver enable training
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "amdlib.h"
+#include "Ids.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_MTTHRC_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+VOID
+STATIC
+MemTProgramRcvrEnDly (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel,
+ IN UINT8 Pass
+ );
+
+BOOLEAN
+STATIC
+MemTDqsTrainRcvrEnHw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+extern UINT16 T1minToFreq[];
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes first pass of Phy assisted receiver enable training
+ * for current node at DDR800 and below.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @pre Auto refresh and ZQCL must be disabled
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+BOOLEAN
+MemTDqsTrainRcvrEnHwPass1 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return MemTDqsTrainRcvrEnHw (TechPtr, 1);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes second pass of Phy assisted receiver enable training
+ * for current node at DDR1066 and above.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @pre Auto refresh and ZQCL must be disabled
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+BOOLEAN
+MemTDqsTrainRcvrEnHwPass2 (
+ 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 MemTDqsTrainRcvrEnHw (TechPtr, 2);
+ }
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes Phy assisted receiver enable training for current node.
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Pass - Pass of the receiver training
+ *
+ * @pre Auto refresh and ZQCL must be disabled
+ *
+ */
+BOOLEAN
+STATIC
+MemTDqsTrainRcvrEnHw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ UINT32 TestAddrRJ16;
+ UINT8 Dct;
+ UINT8 ChipSel;
+ NBPtr = TechPtr->NBPtr;
+
+ TechPtr->TrainingType = TRN_RCVR_ENABLE;
+
+ AGESA_TESTPOINT (TpProcMemReceiverEnableTraining , &(NBPtr->MemPtr->StdHeader));
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart HW RxEn training\n");
+
+ // Set environment settings before training
+ MemTBeginTraining (TechPtr);
+ //
+ // Setup hardware training engine (if applicable)
+ //
+ NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType);
+
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ //training for each rank
+ for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
+ if (NBPtr->GetSysAddr (NBPtr, ChipSel, &TestAddrRJ16)) {
+ if (!(NBPtr->MCTPtr->Status[SbLrdimms]) || ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << (ChipSel >> 1))) != 0)) {
+ // 1.Prepare the DIMMs for training
+ NBPtr->SetBitField (NBPtr, BFTrDimmSel, ChipSel >> 1);
+
+ TechPtr->ChipSel = ChipSel;
+ TechPtr->Pass = Pass;
+ NBPtr->FamilySpecificHook[InitPerNibbleTrn] (NBPtr, NULL);
+ for (TechPtr->TrnNibble = NIBBLE_0; TechPtr->TrnNibble <= (NBPtr->FamilySpecificHook[TrainRxEnPerNibble] (NBPtr, &ChipSel)? NIBBLE_0 : NIBBLE_1); TechPtr->TrnNibble++) {
+ // 2.Prepare the phy for DQS receiver enable training.
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tTestAddr %x0000\n", TestAddrRJ16);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n");
+ NBPtr->MemNPrepareRcvrEnDlySeed (NBPtr);
+
+ // 3.BIOS initiates the phy assisted receiver enable training
+ NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 1);
+
+ // 4.BIOS begins sending out of back-to-back reads to create
+ // a continuous stream of DQS edges on the DDR interface
+ NBPtr->GenHwRcvEnReads (NBPtr, TestAddrRJ16);
+
+ // 7.Program [DqsRcvTrEn]=0 to stop the DQS receive enable training.
+ NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 0);
+
+ // 8.Get the gross and fine delay values.
+ // 9.Calculate the corresponding final delay values
+ MemTProgramRcvrEnDly (TechPtr, ChipSel, Pass);
+ }
+ }
+ }
+ }
+ }
+ // Restore environment settings after training
+ MemTEndTraining (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "End HW RxEn training\n\n");
+
+ return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function calculates final RcvrEnDly for each rank
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] ChipSel - Rank to be trained
+ * @param[in] Pass - Pass of the receiver training
+ *
+ */
+VOID
+STATIC
+MemTProgramRcvrEnDly (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 ChipSel,
+ IN UINT8 Pass
+ )
+{
+ MEM_NB_BLOCK *NBPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ UINT8 ByteLane;
+ UINT16 RcvEnDly;
+ UINT16 CsPairRcvEnDly;
+ UINT16 RankRcvEnDly[9];
+ NBPtr = TechPtr->NBPtr;
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t PRE: ");
+ for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8) ; ByteLane++) {
+ RcvEnDly = (UINT8) NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (ChipSel >> 1, ByteLane));
+ IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RcvEnDly);
+
+ RcvEnDly = RcvEnDly + TechPtr->DiffSeedGrossSeedPreGross[ByteLane];
+
+ // Add 1 UI to get to the midpoint of preamble
+ RcvEnDly += 0x20;
+ TechPtr->Bytelane = ByteLane;
+ RankRcvEnDly[ByteLane] = RcvEnDly;
+ if (NBPtr->FamilySpecificHook[TrainRxEnAdjustDlyPerNibble] (NBPtr, &RcvEnDly)) {
+ if ((ChipSel & 1) == 1) {
+ // For each rank pair on a dual-rank DIMM, compute the average value of the total delays saved during the
+ // training of each rank and program the result in D18F2x[1,0]9C_x0000_00[24:10][DqsRcvEnGrossDelay,
+ // DqsRcvEnFineDelay].
+ CsPairRcvEnDly = ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane];
+ RcvEnDly = (CsPairRcvEnDly + RcvEnDly + 1) / 2;
+ }
+ }
+ ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane] = RcvEnDly;
+ NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS ((ChipSel >> 1), ByteLane), RcvEnDly);
+ }
+
+ IDS_HDT_CONSOLE_DEBUG_CODE (
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t RxEn: ");
+ for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RankRcvEnDly[ByteLane]);
+ }
+ if (NBPtr->FamilySpecificHook[TrainRxEnGetAvgDlyPerNibble] (NBPtr, NULL)) {
+ if ((ChipSel & 1) == 1) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Avg: ");
+ for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
+ IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane]);
+ }
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
+ );
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttml.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttml.c
new file mode 100644
index 0000000000..06d583fb29
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttml.c
@@ -0,0 +1,255 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttml.c
+ *
+ * Technology Max Latency Training support
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "merrhdl.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTML_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function trains Max latency for all dies
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTTrainMaxLatency (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ UINT32 TestAddrRJ16;
+ UINT8 Dct;
+ UINT8 ChipSel;
+ UINT8 *PatternBufPtr;
+ UINT8 *TestBufferPtr;
+ UINT16 CalcMaxLatDly;
+ UINT16 MaxLatDly;
+ UINT16 MaxLatLimit;
+ UINT16 Margin;
+ UINT16 CurTest;
+ UINT16 _CL_;
+ UINT8 TimesFail;
+ UINT8 TimesRetrain;
+ UINT16 i;
+
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ MemPtr = NBPtr->MemPtr;
+ TechPtr->TrainingType = TRN_MAX_READ_LATENCY;
+ TimesRetrain = DEFAULT_TRAINING_TIMES;
+ IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart MaxRdLat training\n");
+ // Set environment settings before training
+ AGESA_TESTPOINT (TpProcMemMaxRdLatencyTraining, &(MemPtr->StdHeader));
+ MemTBeginTraining (TechPtr);
+ //
+ // Initialize the Training Pattern
+ //
+ if (AGESA_SUCCESS != NBPtr->TrainingPatternInit (NBPtr)) {
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+ }
+ TechPtr->PatternLength = (MCTPtr->Status[Sb128bitmode]) ? 6 : 3;
+ //
+ // Setup hardware training engine (if applicable)
+ //
+ NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType);
+
+ MaxLatDly = 0;
+ _CL_ = TechPtr->PatternLength;
+ PatternBufPtr = TechPtr->PatternBufPtr;
+ TestBufferPtr = TechPtr->TestBufPtr;
+ //
+ // Begin max latency training
+ //
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ if (MCTPtr->Status[Sb128bitmode] && (Dct != 0)) {
+ break;
+ }
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+
+ if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
+ if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) {
+
+ if (NBPtr->GetSysAddr (NBPtr, ChipSel, &TestAddrRJ16)) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to address: %04x0000\n", TestAddrRJ16);
+
+ // Write the test patterns
+ AGESA_TESTPOINT (TpProcMemMaxRdLatWritePattern, &(MemPtr->StdHeader));
+ NBPtr->WritePattern (NBPtr, TestAddrRJ16, PatternBufPtr, _CL_);
+
+ // Sweep max latency delays
+ NBPtr->getMaxLatParams (NBPtr, TechPtr->MaxDlyForMaxRdLat, &CalcMaxLatDly, &MaxLatLimit, &Margin);
+ AGESA_TESTPOINT (TpProcMemMaxRdLatStartSweep, &(MemPtr->StdHeader));
+
+ TimesFail = 0;
+ ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain)
+ {
+ MaxLatDly = CalcMaxLatDly;
+ for (i = 0; i < (MaxLatLimit - CalcMaxLatDly); i++) {
+ NBPtr->SetBitField (NBPtr, BFMaxLatency, MaxLatDly);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", MaxLatDly);
+ TechPtr->ResetDCTWrPtr (TechPtr, 6);
+
+ AGESA_TESTPOINT (TpProcMemMaxRdLatReadPattern, &(MemPtr->StdHeader));
+ NBPtr->ReadPattern (NBPtr, TestBufferPtr, TestAddrRJ16, _CL_);
+ AGESA_TESTPOINT (TpProcMemMaxRdLatTestPattern, &(MemPtr->StdHeader));
+ CurTest = NBPtr->CompareTestPattern (NBPtr, TestBufferPtr, PatternBufPtr, _CL_ * 64);
+ NBPtr->FlushPattern (NBPtr, TestAddrRJ16, _CL_);
+
+ if (NBPtr->IsSupported[ReverseMaxRdLatTrain]) {
+ // Reverse training decrements MaxLatDly whenever the test passes
+ // and uses the last passing MaxLatDly as left edge
+ if (CurTest == 0xFFFF) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " P");
+ if (MaxLatDly == 0) {
+ break;
+ } else {
+ MaxLatDly--;
+ }
+ }
+ } else {
+ // Traditional training increments MaxLatDly until the test passes
+ // and uses it as left edge
+ if (CurTest == 0xFFFF) {
+ IDS_HDT_CONSOLE (MEM_FLOW, " P");
+ break;
+ } else {
+ MaxLatDly++;
+ }
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+ }// End of delay sweep
+ ERROR_HANDLE_RETRAIN_END ((MaxLatDly >= MaxLatLimit), TimesFail)
+ }
+
+ AGESA_TESTPOINT (TpProcMemMaxRdLatSetDelay, &(MemPtr->StdHeader));
+
+ if (MaxLatDly >= MaxLatLimit) {
+ PutEventLog (AGESA_ERROR, MEM_ERROR_MAX_LAT_NO_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ NBPtr->DCTPtr->Timings.CsTrainFail |= NBPtr->DCTPtr->Timings.CsPresent;
+ MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct;
+ if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, EXCLUDE_ALL_CHIPSEL, &NBPtr->MemPtr->StdHeader)) {
+ return FALSE;
+ }
+ } else {
+ NBPtr->FamilySpecificHook[AddlMaxRdLatTrain] (NBPtr, &TestAddrRJ16);
+
+ MaxLatDly = MaxLatDly + Margin;
+ if (NBPtr->IsSupported[ReverseMaxRdLatTrain]) {
+ MaxLatDly++; // Add 1 to get back to the last passing value
+ }
+ // Set final delays
+ NBPtr->SetBitField (NBPtr, BFMaxLatency, MaxLatDly);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tFinal MaxRdLat: %03x\n", MaxLatDly);
+ }
+ }
+ }
+ }
+ }
+
+ // Restore environment settings after training
+ MemTEndTraining (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "End MaxRdLat training\n\n");
+ //
+ // Finalize the Pattern
+ //
+ NBPtr->TrainingPatternFinalize (NBPtr);
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttoptsrc.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttoptsrc.c
new file mode 100644
index 0000000000..504365703c
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttoptsrc.c
@@ -0,0 +1,427 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttoptsrc.c
+ *
+ * New Technology Software based DQS receiver enable training
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "AdvancedApi.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mt.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTOPTSRC_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+STATIC
+MemTDqsTrainOptRcvrEnSw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ );
+
+BOOLEAN
+MemTNewRevTrainingSupport (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes first pass of receiver enable training for all dies
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTTrainOptRcvrEnSwPass1 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return MemTDqsTrainOptRcvrEnSw (TechPtr, 1);
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes receiver enable training for a specific die
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Pass - Pass of the receiver training
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+BOOLEAN
+STATIC
+MemTDqsTrainOptRcvrEnSw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ )
+{
+ _16BYTE_ALIGN UINT8 PatternBuffer[6 * 64];
+ UINT8 TestBuffer[256];
+ UINT8 *PatternBufPtr[6];
+ UINT8 *TempPtr;
+ UINT32 TestAddrRJ16[4];
+ UINT32 TempAddrRJ16;
+ UINT32 RealAddr;
+ UINT16 CurTest[4];
+ UINT8 Dct;
+ UINT8 Receiver;
+ UINT8 i;
+ UINT8 TimesFail;
+ UINT8 TimesRetrain;
+ UINT16 RcvrEnDly;
+ UINT16 MaxRcvrEnDly;
+ UINT16 RcvrEnDlyLimit;
+ UINT16 MaxDelayCha;
+ BOOLEAN IsDualRank;
+ BOOLEAN S0En;
+ BOOLEAN S1En;
+
+
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ TechPtr->TrainingType = TRN_RCVR_ENABLE;
+
+
+ TempAddrRJ16 = 0;
+ TempPtr = NULL;
+ MaxDelayCha = 0;
+ TimesRetrain = DEFAULT_TRAINING_TIMES;
+ IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Optimized SW RxEn training\n");
+ // Set environment settings before training
+ MemTBeginTraining (TechPtr);
+
+ PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer;
+ // These two patterns used for first Test Address
+ MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64);
+ // Second Cacheline used for Dummy Read is the inverse of
+ // the first so that is is not mistaken for the real read
+ MemUFillTrainPattern (TestPattern1, PatternBufPtr[0] + 64, 64);
+ PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128;
+ // These two patterns used for second Test Address
+ MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64);
+ // Second Cacheline used for Dummy Read is the inverse of
+ // the first so that is is not mistaken for the real read
+ MemUFillTrainPattern (TestPattern0, PatternBufPtr[1] + 64, 64);
+
+ // Fill pattern for flush after every sweep
+ PatternBufPtr[4] = PatternBufPtr[0] + 256;
+ MemUFillTrainPattern (TestPattern3, PatternBufPtr[4], 64);
+
+ // Fill pattern for initial dummy read
+ PatternBufPtr[5] = PatternBufPtr[0] + 320;
+ MemUFillTrainPattern (TestPattern4, PatternBufPtr[5], 64);
+
+
+ // Begin receiver enable training
+ AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+
+ // Set training bit
+ NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1);
+
+ // Relax Max Latency before training
+ NBPtr->SetMaxLatency (NBPtr, 0xFFFF);
+
+ if (Pass == FIRST_PASS) {
+ TechPtr->InitDQSPos4RcvrEn (TechPtr);
+ }
+
+ // there are four receiver pairs, loosely associated with chipselects.
+ Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8;
+ for (; Receiver < 8; Receiver += 2) {
+ S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]);
+ S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]);
+ if (S0En) {
+ TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16;
+ }
+ if (S1En) {
+ TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16;
+ }
+ if (S0En && S1En) {
+ IsDualRank = TRUE;
+ } else {
+ IsDualRank = FALSE;
+ }
+ if (S0En || S1En) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Receiver);
+
+ RcvrEnDlyLimit = 0x1FF; // @attention - limit depends on proc type
+ TechPtr->DqsRcvEnSaved = 0;
+ RcvrEnDly = RcvrEnDlyLimit;
+ RealAddr = 0;
+
+ TechPtr->GetFirstPassVal = FALSE;
+ TechPtr->DqsRcvEnFirstPassVal = 0;
+ TechPtr->RevertPassVal = FALSE;
+ TechPtr->InitializeVariablesOpt (TechPtr);
+
+ // Write the test patterns
+ AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader));
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses: ");
+ for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
+ RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
+ // One cacheline of data to be tested and one of dummy data
+ MemUWriteCachelines (RealAddr, PatternBufPtr[i], 2);
+ // This is dummy data with a different pattern used for the first dummy read.
+ MemUWriteCachelines (RealAddr + 128, PatternBufPtr[5], 1);
+ IDS_HDT_CONSOLE (MEM_FLOW, " %04x0000 ", TestAddrRJ16[i]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+
+ // Sweep receiver enable delays
+ AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
+ TimesFail = 0;
+ ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain)
+ {
+ TechPtr->LoadInitialRcvrEnDlyOpt (TechPtr, Receiver);
+ while (!TechPtr->CheckRcvrEnDlyLimitOpt (TechPtr)) {
+ AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader));
+ TechPtr->SetRcvrEnDlyOpt (TechPtr, Receiver, RcvrEnDly);
+ // Read and compare the first beat of data
+ for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
+ AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader));
+ RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
+ //
+ // Issue dummy cacheline reads
+ //
+ MemUReadCachelines (TestBuffer + 128, RealAddr + 128, 1);
+ MemUReadCachelines (TestBuffer, RealAddr, 1);
+ MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr);
+ //
+ // Perform actual read which will be compared
+ //
+ MemUReadCachelines (TestBuffer + 64, RealAddr + 64, 1);
+ AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader));
+ CurTest[i] = TechPtr->Compare1ClPatternOpt (TechPtr, TestBuffer + 64 , PatternBufPtr[i] + 64, i, Receiver, S1En);
+ // Due to speculative execution during MemUReadCachelines, we must
+ // flush one more cache line than we read.
+ MemUProcIOClFlush (TestAddrRJ16[i], 4, MemPtr);
+ TechPtr->ResetDCTWrPtr (TechPtr, Receiver);
+
+ //
+ // Swap the test pointers such that even and odd steps alternate.
+ //
+ if ((i % 2) == 0) {
+ TempPtr = PatternBufPtr[i];
+ PatternBufPtr[i] = PatternBufPtr[i + 1];
+
+ TempAddrRJ16 = TestAddrRJ16[i];
+ TestAddrRJ16[i] = TestAddrRJ16[i + 1];
+ } else {
+ PatternBufPtr[i] = TempPtr;
+ TestAddrRJ16[i] = TempAddrRJ16;
+ }
+ }
+ } // End of delay sweep
+ ERROR_HANDLE_RETRAIN_END (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, TRUE), TimesFail)
+ }
+
+ if (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, FALSE)) {
+ return FALSE;
+ }
+
+ TechPtr->LoadRcvrEnDlyOpt (TechPtr, Receiver); // set final delays
+ //
+ // Flush AA and 55 patterns by reading a dummy pattern to fill in FIFO
+ //
+ // Aquire a new FSBase, based on the last test address that we stored.
+ RealAddr = MemUSetUpperFSbase (TempAddrRJ16, MemPtr);
+ ASSERT (RealAddr != 0);
+ MemUWriteCachelines (RealAddr, PatternBufPtr[4], 1);
+ MemUWriteCachelines (RealAddr + 64, PatternBufPtr[4], 1);
+ MemUReadCachelines (TestBuffer, RealAddr, 2);
+ // Due to speculative execution during MemUReadCachelines, we must
+ // flush one more cache line than we read.
+ MemUProcIOClFlush (TempAddrRJ16, 3, MemPtr);
+ }
+ } // End while Receiver < 8
+
+ // Clear training bit when done
+ NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
+
+ // Set Max Latency for both channels
+ MaxRcvrEnDly = TechPtr->GetMaxValueOpt (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", MaxRcvrEnDly);
+ if (MCTPtr->GangedMode) {
+ if (Dct == 0) {
+ MaxDelayCha = MaxRcvrEnDly;
+ } else if (MaxRcvrEnDly > MaxDelayCha) {
+ NBPtr->SwitchDCT (NBPtr, 0);
+ NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
+ }
+ } else {
+ NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
+ }
+ TechPtr->ResetDCTWrPtr (TechPtr, 6);
+ }
+
+ // Restore environment settings after training
+ MemTEndTraining (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "End Optimized SW RxEn training\n\n");
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * This function saves passing DqsRcvEnDly values to the stack
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Receiver - Current Chip select value
+ * @param[in] RcvEnDly - receiver enable delay to be saved
+ * @param[in] cmpResultRank0 - compare result for Rank 0
+ * @param[in] cmpResultRank0 - compare result for Rank 1
+ *
+ * @retval TRUE - All bytelanes pass
+ * FALSE - Some bytelanes fail
+ * ----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+MemTSaveRcvrEnDlyByteFilterOpt (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Receiver,
+ IN UINT16 RcvEnDly,
+ IN UINT16 CmpResultRank0,
+ IN UINT16 CmpResultRank1
+ )
+{
+ UINT8 i;
+ UINT8 Passed;
+ UINT8 Dimm;
+ CH_DEF_STRUCT *ChannelPtr;
+
+ ASSERT (Receiver < MAX_CS_PER_CHANNEL);
+ ChannelPtr = TechPtr->NBPtr->ChannelPtr;
+
+ Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
+
+ Dimm = Receiver >> 1;
+
+ if (TechPtr->GetFirstPassVal && (RcvEnDly - TechPtr->DqsRcvEnFirstPassVal) >= 0x30) {
+ for (i = 0; i < 8; i++) {
+ ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i] = TechPtr->DqsRcvEnFirstPassVal + NEW_RECEIVER_FINAL_OFFSETVALUE;
+ }
+ TechPtr->DqsRcvEnSaved = 0xFF;
+ }
+
+ if (Passed == 0xFF) {
+ if (!TechPtr->GetFirstPassVal) {
+ TechPtr->DqsRcvEnFirstPassVal = RcvEnDly;
+ TechPtr->GetFirstPassVal = TRUE;
+ }
+ return TRUE;
+ } else {
+ TechPtr->DqsRcvEnFirstPassVal = 0;
+
+ // We have got first passing value, but later, we meet with glitch
+ if (TechPtr->GetFirstPassVal) {
+ TechPtr->DqsRcvEnFirstPassVal = 0xFF;
+ TechPtr->GetFirstPassVal = FALSE;
+ }
+ return FALSE;
+ }
+}
diff --git a/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttsrc.c b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttsrc.c
new file mode 100644
index 0000000000..1686bacb22
--- /dev/null
+++ b/src/vendorcode/amd/agesa/Proc/Mem/Tech/mttsrc.c
@@ -0,0 +1,346 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mttsrc.c
+ *
+ * Technology Software based DQS receiver enable training
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Tech)
+ * @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 "AdvancedApi.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "mt.h"
+#include "GeneralServices.h"
+#include "merrhdl.h"
+#include "Filecode.h"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_MEM_TECH_MTTSRC_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BOOLEAN
+STATIC
+MemTDqsTrainRcvrEnSw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes first pass of receiver enable training for all dies
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+
+BOOLEAN
+MemTTrainRcvrEnSwPass1 (
+ IN OUT MEM_TECH_BLOCK *TechPtr
+ )
+{
+ return MemTDqsTrainRcvrEnSw (TechPtr, 1);
+}
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ * This function executes receiver enable training for a specific die
+ *
+ * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
+ * @param[in] Pass - Pass of the receiver training
+ *
+ * @return TRUE - No fatal error occurs.
+ * @return FALSE - Fatal error occurs.
+ */
+BOOLEAN
+STATIC
+MemTDqsTrainRcvrEnSw (
+ IN OUT MEM_TECH_BLOCK *TechPtr,
+ IN UINT8 Pass
+ )
+{
+ _16BYTE_ALIGN UINT8 PatternBuffer[3 * 64];
+ UINT8 TestBuffer[120];
+ UINT8 *PatternBufPtr[4];
+ UINT8 *TempPtr;
+ UINT32 TestAddrRJ16[4];
+ UINT32 TempAddrRJ16;
+ UINT32 RealAddr;
+ UINT16 CurTest[4];
+ UINT8 Dct;
+ UINT8 Receiver;
+ UINT8 i;
+ UINT8 TimesFail;
+ UINT8 TimesRetrain;
+ UINT16 RcvrEnDly;
+ UINT16 MaxRcvrEnDly;
+ UINT16 RcvrEnDlyLimit;
+ UINT16 MaxDelayCha;
+ BOOLEAN IsDualRank;
+ BOOLEAN S0En;
+ BOOLEAN S1En;
+ UINT8 MaxFilterDly;
+
+ MEM_DATA_STRUCT *MemPtr;
+ DIE_STRUCT *MCTPtr;
+ DCT_STRUCT *DCTPtr;
+ MEM_NB_BLOCK *NBPtr;
+
+ NBPtr = TechPtr->NBPtr;
+ MemPtr = NBPtr->MemPtr;
+ MCTPtr = NBPtr->MCTPtr;
+ TechPtr->TrainingType = TRN_RCVR_ENABLE;
+
+
+ TempAddrRJ16 = 0;
+ TempPtr = NULL;
+ MaxDelayCha = 0;
+ MaxFilterDly = TechPtr->MaxFilterDly;
+ RcvrEnDlyLimit = NBPtr->RcvrEnDlyLimit;
+ TimesRetrain = DEFAULT_TRAINING_TIMES;
+ IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
+
+ IDS_HDT_CONSOLE (MEM_STATUS, "\nStart SW RxEn training\n");
+ // Set environment settings before training
+ MemTBeginTraining (TechPtr);
+
+ PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer;
+ MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64);
+ PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128;
+ MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64);
+
+ // Begin receiver enable training
+ AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
+ MaxRcvrEnDly = 0;
+ for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
+ NBPtr->SwitchDCT (NBPtr, Dct);
+ DCTPtr = NBPtr->DCTPtr;
+
+ // Set training bit
+ NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1);
+
+ // Relax Max Latency before training
+ NBPtr->SetMaxLatency (NBPtr, 0xFFFF);
+
+ if (Pass == FIRST_PASS) {
+ TechPtr->InitDQSPos4RcvrEn (TechPtr);
+ }
+
+ // there are four receiver pairs, loosely associated with chipselects.
+ Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8;
+ for (; Receiver < 8; Receiver += 2) {
+ TechPtr->DqsRcvEnSaved = 0;
+ RcvrEnDly = RcvrEnDlyLimit;
+ S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]);
+ S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]);
+ if (S0En) {
+ TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16;
+ }
+ if (S1En) {
+ TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16;
+ }
+ if (S0En && S1En) {
+ IsDualRank = TRUE;
+ } else {
+ IsDualRank = FALSE;
+ }
+
+ if (S0En || S1En) {
+ IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Receiver);
+
+ // Write the test patterns
+ AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader));
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses: ");
+ for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
+ RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
+ MemUWriteCachelines (RealAddr, PatternBufPtr[i], 1);
+ IDS_HDT_CONSOLE (MEM_FLOW, " %04x0000 ", TestAddrRJ16[i]);
+ }
+ IDS_HDT_CONSOLE (MEM_FLOW, "\n");
+
+ // Initialize RcvrEnDly value and other DCT stored values
+ // MCTPtr->DqsRcvEnPass = Pass ? 0xFF : 0;
+
+ // Sweep receiver enable delays
+ AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
+ TimesFail = 0;
+ ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain)
+ {
+ for (RcvrEnDly = 0; RcvrEnDly < RcvrEnDlyLimit; RcvrEnDly++) {
+ AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader));
+ TechPtr->SetRcvrEnDly (TechPtr, Receiver, RcvrEnDly);
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", RcvrEnDly);
+
+ // Read and compare the first beat of data
+ for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
+ AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader));
+ RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
+ MemUReadCachelines (TestBuffer, RealAddr, 1);
+ AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader));
+ CurTest[i] = TechPtr->Compare1ClPattern (TechPtr, TestBuffer, PatternBufPtr[i]);
+ // Due to speculative execution during MemUReadCachelines, we must
+ // flush one more cache line than we read.
+ MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr);
+ TechPtr->ResetDCTWrPtr (TechPtr, Receiver);
+
+ //
+ // Swap the test pointers such that even and odd steps alternate.
+ //
+ if ((i % 2) == 0) {
+ TempPtr = PatternBufPtr[i];
+ PatternBufPtr[i] = PatternBufPtr[i + 1];
+
+ TempAddrRJ16 = TestAddrRJ16[i];
+ TestAddrRJ16[i] = TestAddrRJ16[i + 1];
+ } else {
+ PatternBufPtr[i] = TempPtr;
+ TestAddrRJ16[i] = TempAddrRJ16;
+ }
+ }
+
+ if (TechPtr->SaveRcvrEnDly (TechPtr, Receiver, RcvrEnDly, S0En ? (CurTest[0] & CurTest[1]) : 0xFFFF, S1En ? (CurTest[2] & CurTest[3]) : 0xFFFF)) {
+ // if all bytelanes pass
+ if (MaxRcvrEnDly < (RcvrEnDly - MaxFilterDly)) {
+ MaxRcvrEnDly = RcvrEnDly - MaxFilterDly;
+ }
+ break;
+ }
+ } // End of delay sweep
+ ERROR_HANDLE_RETRAIN_END ((RcvrEnDly > (RcvrEnDlyLimit - 1)), TimesFail)
+ }
+
+ if (RcvrEnDly == RcvrEnDlyLimit) {
+ // no passing window
+ PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_NO_PASSING_WINDOW_EQUAL_LIMIT, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ }
+
+ if (RcvrEnDly > (RcvrEnDlyLimit - 1)) {
+ // passing window too narrow, too far delayed
+ PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_VALUE_TOO_LARGE_LIMIT_LESS_ONE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
+ SetMemError (AGESA_ERROR, MCTPtr);
+ DCTPtr->Timings.CsTrainFail |= DCTPtr->Timings.CsPresent & (UINT16) (3 << Receiver);
+ MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct;
+ if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader)) {
+ return FALSE;
+ }
+ }
+ }
+
+ TechPtr->LoadRcvrEnDly (TechPtr, Receiver); // set final delays
+ } // End while Receiver < 8
+
+ // Clear training bit when done
+ NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
+
+ // Set Max Latency for both channels
+ MaxRcvrEnDly += 0x20; // @attention -
+ IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", MaxRcvrEnDly);
+ if (MCTPtr->GangedMode) {
+ if (Dct == 0) {
+ MaxDelayCha = MaxRcvrEnDly;
+ } else if (MaxRcvrEnDly > MaxDelayCha) {
+ NBPtr->SwitchDCT (NBPtr, 0);
+ NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
+ }
+ } else {
+ NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
+ }
+ TechPtr->ResetDCTWrPtr (TechPtr, 6);
+ }
+
+ // Restore environment settings after training
+ MemTEndTraining (TechPtr);
+ IDS_HDT_CONSOLE (MEM_FLOW, "End SW RxEn training\n\n");
+ return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+